Sangfor华东天勇战队:某咖啡还原密钥

news2024/10/1 21:27:55

最近学习了密钥还原,复现下并记录思路


function wbaes_encrypt_ecb(){
    var module_base = Module.findBaseAddress("libcryptoDD.so")
    var func_base = module_base.add(0x17BD4+1)
    Interceptor.attach(func_base,{
        onEnter:function (args){
            console.log("Enter wbaes_encrypt_ecb....")
        }
    })
}

双进程保护
在这里插入图片描述
然后我们查看进程在这里插入图片描述
绕过双进程保护方式,使用spwan方法来进行frida hook
在这里插入图片描述
可以看到成功绕过,我们看看我们写的函数经过吗
在这里插入图片描述
发现frida15.2.2存在bug,就是上面这样,不能执行函数,我们换成12.8.0来试试
在这里插入图片描述
可以看到成功打印,说明经过此函数
然后我们看看它的参数和返回值
在这里插入图片描述
发现有四个参数,分别是in、in_len 、out 、mode ,然后我们打印来看看

function wbaes_encrypt_ecb(){
    var module_base = Module.findBaseAddress("libcryptoDD.so")
    var func_base = module_base.add(0x17BD4+1)
    Interceptor.attach(func_base,{
        onEnter:function (args){
            this.in = args[0]
            this.in_len = args[1].toInt32()    //将指针转换成int32
            this.out = args[2]
            this.mode = args[3].toInt32()
            console.log("Input && len:",this.in_len," && mode:",this.mode)          //打印输入
            console.log(hexdump(this.in,{length:this.in_len}))
        }
    })
}

在这里插入图片描述
然后来打印下返回值

function wbaes_encrypt_ecb(){
    var module_base = Module.findBaseAddress("libcryptoDD.so")
    var func_base = module_base.add(0x17BD4+1)
    Interceptor.attach(func_base,{
        onEnter:function (args){
            this.in = args[0]
            this.in_len = args[1].toInt32()    //将指针转换成int32
            this.out = args[2]
            this.mode = args[3].toInt32()
            console.log("Input && len:",this.in_len," && mode:",this.mode)          //打印输入
            console.log(hexdump(this.in,{length:this.in_len}))
        },
        onLeave:function(){
            console.log("Output ....")
            console.log(hexdump(this.out,{length:this.in_len}))
        }
    })
}

在这里插入图片描述
单独拿出这一段看

Input && len: 96  && mode: 0
0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
f589c740  7b 22 70 61 67 65 54 79 70 65 22 3a 22 32 22 2c  {"pageType":"2",
f589c750  22 74 61 67 49 6e 64 65 78 22 3a 22 22 2c 22 61  "tagIndex":"","a
f589c760  70 70 76 65 72 73 69 6f 6e 22 3a 22 34 39 33 30  ppversion":"4930
f589c770  22 2c 22 70 61 67 65 22 3a 31 2c 22 72 6f 77 73  ","page":1,"rows
f589c780  22 3a 31 36 2c 22 62 72 61 6e 64 43 6f 64 65 22  ":16,"brandCode"
f589c790  3a 22 4c 4b 30 30 31 22 7d 07 07 07 07 07 07 07  :"LK001"}.......
Output ....
0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
f589ca40  53 bd 58 25 98 ba ac 09 40 1e 71 fb ae 66 07 44  S.X%....@.q..f.D
f589ca50  8e d3 43 5e 8c f1 5d cd 36 2e f2 6f 81 6a 79 1f  ..C^..].6..o.jy.
f589ca60  91 39 c0 3e 99 0d 0a d7 fe 4a 1f dd c7 0f 08 a6  .9.>.....J......
f589ca70  50 b4 81 a1 7e 6c 21 c2 f8 cd 30 68 7a 53 ab 8c  P...~l!...0hzS..
f589ca80  f8 e8 a7 a0 95 e1 c1 4c db 92 c1 a8 d8 04 43 30  .......L......C0
f589ca90  9f 35 a4 a5 58 92 e6 3c 29 17 0e 30 11 8d c5 e8  .5..X..<)..0....

接下来尝试做一个主动调用,看看我们利用主动创建一个native函数来模拟算法和这里的结果一样不,看看有没有中间加一些时间戳之类的
脚本如下

// function wbaes_encrypt_ecb(){
//     var module_base = Module.findBaseAddress("libcryptoDD.so")
//     var func_base = module_base.add(0x17BD4+1)
//     Interceptor.attach(func_base,{
//         onEnter:function (args){
//             this.in = args[0]
//             this.in_len = args[1].toInt32()    //将指针转换成int32
//             this.out = args[2]
//             this.mode = args[3].toInt32()
//             console.log("Input && len:",this.in_len," && mode:",this.mode)          //打印输入
//             console.log(hexdump(this.in,{length:this.in_len}))
//         },
//         onLeave:function(){
//             console.log("Output ....")
//             console.log(hexdump(this.out,{length:this.in_len}))
//         }
//     })
// }


function hexToBytes(hex){   //十六进制转字节
    for (var bytes = [],c=0;c<hex.length;c+=2){
        bytes.push(parseInt(hex.substr(c,2),16))
    }
    return bytes
}

function invoke_wb_aes_ecb(data){
    var module_base = Module.findBaseAddress("libcryptoDD.so")
    var func_base = module_base.add(0x17BD4+1)
    var wb_aes_ecb_native = new NativeFunction(func_base,"int",["pointer","int","pointer","int"])   //参考frida api,第一个参数地址,第二个返回值,第三个参数
    var inputPtr = Memory.alloc(0x60)   //输入内存大小正好0x60
    var inputData = hexToBytes(data)        //输入的数据
    Memory.writeByteArray(inputPtr,inputData)    //数据写入地址
    var outputPtr = Memory.alloc(0x60)   //输出内存大小正好0x60
    wb_aes_ecb_native(inputPtr,0x60,outputPtr,0)    //wb_aes_ecb_native函数调用,参数对应
    console.log(hexdump(outputPtr,{length:0x60}))   //打印输出值
}

function call_wb_aes(){
    var data1 = "7b227061676554797065223a2232222c22746167496e646578223a22222c2261707076657273696f6e223a2234393330222c2270616765223a312c22726f7773223a31362c226272616e64436f6465223a224c4b303031227d07070707070707"
    invoke_wb_aes_ecb(data1)    //调用
}
f589c740  7b 22 70 61 67 65 54 79 70 65 22 3a 22 32 22 2c  {"pageType":"2",
f589c750  22 74 61 67 49 6e 64 65 78 22 3a 22 22 2c 22 61  "tagIndex":"","a
f589c760  70 70 76 65 72 73 69 6f 6e 22 3a 22 34 39 33 30  ppversion":"4930
f589c770  22 2c 22 70 61 67 65 22 3a 31 2c 22 72 6f 77 73  ","page":1,"rows
f589c780  22 3a 31 36 2c 22 62 72 61 6e 64 43 6f 64 65 22  ":16,"brandCode"
f589c790  3a 22 4c 4b 30 30 31 22 7d 07 07 07 07 07 07 07  :"LK001"}.......

输入这段转成hex,如下,要先from hexdump然后to hex
在这里插入图片描述
然后放到代码中
frida运行此脚本
在这里插入图片描述
可以看到得到的结果和刚才输出的结果一样,如下
在这里插入图片描述
如果数据量很大不好一个个看,就用md5去比较,如下这样去比较
在这里插入图片描述
在这里插入图片描述
可以看到相等

那么接下来可以DFA了,
先找到轮,注入时机,状态矩阵

轮的寻找方法:先看子函数
在wbaes_encrypt_ecb下找子函数,
在这里插入图片描述
在这里插入图片描述
有很多子函数,我们先来看aes128_enc_wb_coff,aes128_enc_wb_xlc看看有没有走这里,老样子,还是先Interceptor.attach看看
然后写一个调用的函数process_web_aes()

// function wbaes_encrypt_ecb(){
//     var module_base = Module.findBaseAddress("libcryptoDD.so")
//     var func_base = module_base.add(0x17BD4+1)
//     Interceptor.attach(func_base,{
//         onEnter:function (args){
//             this.in = args[0]
//             this.in_len = args[1].toInt32()    //将指针转换成int32
//             this.out = args[2]
//             this.mode = args[3].toInt32()
//             console.log("Input && len:",this.in_len," && mode:",this.mode)          //打印输入
//             console.log(hexdump(this.in,{length:this.in_len}))
//         },
//         onLeave:function(){
//             console.log("Output ....")
//             console.log(hexdump(this.out,{length:this.in_len}))
//         }
//     })
// }


function hexToBytes(hex){   //十六进制转字节
    for (var bytes = [],c=0;c<hex.length;c+=2){
        bytes.push(parseInt(hex.substr(c,2),16))
    }
    return bytes
}

function invoke_wb_aes_ecb(data){
    var module_base = Module.findBaseAddress("libcryptoDD.so")
    var func_base = module_base.add(0x17BD4+1)
    var wb_aes_ecb_native = new NativeFunction(func_base,"int",["pointer","int","pointer","int"])   //参考frida api,第一个参数地址,第二个返回值,第三个参数
    var inputPtr = Memory.alloc(0x60)   //输入内存大小正好0x60
    var inputData = hexToBytes(data)        //输入的数据
    Memory.writeByteArray(inputPtr,inputData)    //数据写入地址
    var outputPtr = Memory.alloc(0x60)   //输出内存大小正好0x60
    wb_aes_ecb_native(inputPtr,0x60,outputPtr,0)    //wb_aes_ecb_native函数调用,参数对应
    console.log(hexdump(outputPtr,{length:0x60}))   //打印输出值
}

function call_wb_aes(){
    var data1 = "7b227061676554797065223a2232222c22746167496e646578223a22222c2261707076657273696f6e223a2234393330222c2270616765223a312c22726f7773223a31362c226272616e64436f6465223a224c4b303031227d07070707070707"
    invoke_wb_aes_ecb(data1)    //调用
}

//aes128_enc_wb_coff
function aes128_enc_wb_coff(){
    var baseAddr = Module.findBaseAddress("libcryptoDD.so")
    var func_addr = baseAddr.add(0x15320+1)
    Interceptor.attach(func_addr,{
        onEnter:function (args){
            console.log("Enter aes128_enc_wb_coff")
        }
    })
}

//aes128_enc_wb_xlc
function aes128_enc_wb_xlc(){
    var baseAddr = Module.findBaseAddress("libcryptoDD.so")
    var func_addr = baseAddr.add(0x15C8C + 1)  // thumb
    Interceptor.attach(func_addr,{
        onEnter:function(args){
            console.log("Enter aes128_enc_wb_xlc")
        }
    })
}

function process_wb_aes(){
    aes128_enc_wb_coff()
    aes128_enc_wb_xlc()
    call_wb_aes()
}

在这里插入图片描述
可以看到总共两个子函数,只经过aes128_enc_wb_coff
那么我们进入aes128_enc_wb_coff看看
在这里插入图片描述
可以看到有Tyboxes和Txor说明是表查询部分,且进行异或运算

这里我们先要验证模式,虽然它写的是ecb命名,很有可能是欺骗我们
这里要介绍一段数字30313233343536373839616263646566
在这里插入图片描述
这串数字用来验证AES模块
因为AES是一个块加密,我们拿两块进行验证,结果一致是ecb,不一致就是别的模式

function invoke_wb_aes_ecb(data,len){
    var module_base = Module.findBaseAddress("libcryptoDD.so")
    var func_base = module_base.add(0x17BD4+1)
    var wb_aes_ecb_native = new NativeFunction(func_base,"int",["pointer","int","pointer","int"])   //参考frida api,第一个参数地址,第二个返回值,第三个参数
    var inputPtr = Memory.alloc(len)   //输入内存大小正好0x60
    var inputData = hexToBytes(data)        //输入的数据
    Memory.writeByteArray(inputPtr,inputData)    //数据写入地址
    var outputPtr = Memory.alloc(len)   //输出内存大小正好0x60
    wb_aes_ecb_native(inputPtr,len,outputPtr,0)    //wb_aes_ecb_native函数调用,参数对应
    console.log(hexdump(outputPtr,{length:len}))   //打印输出值
}

function call_wb_aes(){
    var data1 = "7b227061676554797065223a2232222c22746167496e646578223a22222c2261707076657273696f6e223a2234393330222c2270616765223a312c22726f7773223a31362c226272616e64436f6465223a224c4b303031227d07070707070707"
    var data2 = "3031323334353637383961626364656630313233343536373839616263646566"
    var data3 = "30313233343536373839616263646566"

    invoke_wb_aes_ecb(data2,0x20)    //调用
}

这里是两个块,所以长度写0x20
在这里插入图片描述
可以看到两个块加密后结果一样,说明是ecb模式
模式确认好之后,开始找轮
在这里插入图片描述
这是行位移的一个明显函数wbShiftRows(),传入的参数out就是我们的输出值,是我们要的状态矩阵
那么我们打印下,看看有几轮
修改:
将如下块改为1块,长度改为0x10
在这里插入图片描述
加入如下代码
在这里插入图片描述
效果如下
在这里插入图片描述
可以看到总共运行了十轮,那么说明是AES128

同时也看到正常的密文
e5af8b10 b0 f5 9c 0d 48 c1 45 91 5f c8 f6 a8 42 c4 d5 eb …H.E._…B…

然后进行DFA攻击
原理:需要在倒数后两轮找的一个区间内,找的一个完整的地方插入,也就是第9轮,找的一个子函数,也就是wbShiftRows()进行故障的注入

function wbShiftRows(){
    var count = 0
    var baseAddr = Module.findBaseAddress("libcryptoDD.so")
    var func_addr = baseAddr.add(0x14F98 + 1)  // thumb
    Interceptor.attach(func_addr,{
        onEnter:function(args){
            count += 1
            console.log("current count => ", count)
            if(count === 9){
                args[0].writeS8(0x0)
            //     args[0].add(randomNum(0,15)).writeS8(randomNum(0,0xff))
            }
        }
    })
}

在这里插入图片描述
db8f45b0 2d f5 9c 0d 48 c1 45 eb 5f c8 c0 a8 42 78 d5 eb -…H.E._…Bx…
对比以下
在这里插入图片描述
可以看到不一样,并且四个字节不一样,符合DFA差分故障分析的一个结果

接下来批量注入,一般20次就出来了,我们这里注入200次,批量注入注意要随机注入,通过crack_aes_key.py脚本进行还原

// function wbaes_encrypt_ecb(){
//     var module_base = Module.findBaseAddress("libcryptoDD.so")
//     var func_base = module_base.add(0x17BD4+1)
//     Interceptor.attach(func_base,{
//         onEnter:function (args){
//             this.in = args[0]
//             this.in_len = args[1].toInt32()    //将指针转换成int32
//             this.out = args[2]
//             this.mode = args[3].toInt32()
//             console.log("Input && len:",this.in_len," && mode:",this.mode)          //打印输入
//             console.log(hexdump(this.in,{length:this.in_len}))
//         },
//         onLeave:function(){
//             console.log("Output ....")
//             console.log(hexdump(this.out,{length:this.in_len}))
//         }
//     })
// }


function hexToBytes(hex){   //十六进制转字节
    for (var bytes = [],c=0;c<hex.length;c+=2){
        bytes.push(parseInt(hex.substr(c,2),16))
    }
    return bytes
}

// function bufferToHex(buffer) { // buffer is an ArrayBuffer
//     return [...new Uint8Array(buffer)]
//         .map(x => x.toString(16).padStart(2, '0'))
//         .join('');
// }
//
// // EXAMPLE:
// const buffer = new Uint8Array([ 4, 8, 12, 16 ]).buffer;
// console.log(bufferToHex(buffer)); // = 04080c10

function invoke_wb_aes_ecb(data,len){
    var module_base = Module.findBaseAddress("libcryptoDD.so")
    var func_base = module_base.add(0x17BD4+1)
    var wb_aes_ecb_native = new NativeFunction(func_base,"int",["pointer","int","pointer","int"])   //参考frida api,第一个参数地址,第二个返回值,第三个参数
    var inputPtr = Memory.alloc(len)   //输入内存大小正好0x60
    var inputData = hexToBytes(data)        //输入的数据
    Memory.writeByteArray(inputPtr,inputData)    //数据写入地址
    var outputPtr = Memory.alloc(len)   //输出内存大小正好0x60
    wb_aes_ecb_native(inputPtr,len,outputPtr,0)    //wb_aes_ecb_native函数调用,参数对应
    console.log(hexdump(outputPtr,{length:len}))   //打印输出值
    // var output = Memory.readByteArray(outputPtr,0x10)
    // console.log(bufferToHex(output))
}

function call_wb_aes(){
    var data1 = "7b227061676554797065223a2232222c22746167496e646578223a22222c2261707076657273696f6e223a2234393330222c2270616765223a312c22726f7773223a31362c226272616e64436f6465223a224c4b303031227d07070707070707"
    var data2 = "3031323334353637383961626364656630313233343536373839616263646566"
    var data3 = "30313233343536373839616263646566"

    invoke_wb_aes_ecb(data3,0x10)    //调用
}

//aes128_enc_wb_coff
function aes128_enc_wb_coff(){
    var baseAddr = Module.findBaseAddress("libcryptoDD.so")
    var func_addr = baseAddr.add(0x15320+1)
    Interceptor.attach(func_addr,{
        onEnter:function (args){
            console.log("Enter aes128_enc_wb_coff")
        }
    })
}

//aes128_enc_wb_xlc
function aes128_enc_wb_xlc(){
    var baseAddr = Module.findBaseAddress("libcryptoDD.so")
    var func_addr = baseAddr.add(0x15C8C + 1)  // thumb
    Interceptor.attach(func_addr,{
        onEnter:function(args){
            console.log("Enter aes128_enc_wb_xlc")
        }
    })
}


function process_wb_aes(){
    // wbShiftRows()
    // aes128_enc_wb_coff()
    // aes128_enc_wb_xlc()
    // call_wb_aes()

    // DFA crack
    wbShiftRows()
    for(var i=0;i<200;i++){
        sleep(10)
        call_wb_aes()
    }
}

function randomNum(minNum,maxNum){
    if (arguments.length === 1) {
        return parseInt(Math.random() * minNum + 1, 10);
    } else if (arguments.length === 2) {
        return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10);
    } else {
        return 0;
    }
}

function wbShiftRows(){
    var count = 0
    var baseAddr = Module.findBaseAddress("libcryptoDD.so")
    var func_addr = baseAddr.add(0x14F98 + 1)  // thumb
    Interceptor.attach(func_addr,{
        onEnter:function(args){
            count += 1
            // console.log("current count => ", count)
            if(count%9 === 0){
                // args[0].writeS8(0x0)
                args[0].add(randomNum(0,15)).writeS8(randomNum(0,0xff))
            }
        }
    })
}

function sleep(time) {
    var timeStamp = new Date().getTime();
    var endTime = timeStamp + time;
    while (true) {
        if (new Date().getTime() > endTime) {
            return;
        }
    }
}




在这里插入图片描述
在这里插入图片描述
这里费劲了,本来注释的这一块bufferToHex函数是可以用的,我这里用不了,报语法错,那么我hexdump下来之后手动整理如上图右侧notepad++
然后将总共200行粘贴进来crack_aes_key.py
注意4行的b0f59c0d48c145915fc8f6a842c4d5eb是固定的,所以只要粘贴到红框那里就行,很整齐
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
可以看到出来了869D92BBB700D0D25BD9FD3E224B5DF2

还需要一部,因为我们得到的是第十轮的结果,需要给他倒推
在这里插入图片描述

那么就是K00了,64开头的是我们的结果

然后我们来验证
在这里插入图片描述
在这里插入图片描述
多出来一块内容,前面是一样的,后面的是多出来的,pkcs7,前面填满了就会填充后面,填充进去会计算,那么我们还原的密钥是正确的

还原密钥key完结

写在最后,小技巧
在这里插入图片描述

这里有个WBAES.c,很明显AES的特征
接下来看导出这边
PKCS5Padding一般是使用了DES和AES中,基本定位到了算法的区间

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/686809.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

风控引擎如何快速接入不同的数据源?

目录 数据是风控引擎的重要组成 风控引擎的数据接入 风控引擎是一种基于数据分析和机器学习算法的系统&#xff0c;能够实时识别和处理各种风险问题&#xff0c;适用于金融、电商、智能制造、交通运输等各领域&#xff0c;能够提高企业的风险管理水平和业务效率。 风控引擎主…

我心中的TOP1编程语言—JavaScript

作为一名研发工程师&#xff08;程序员&#xff09;&#xff0c;平时工作中肯定会接触或了解很多编程语言。每个人都会有自己工作中常用的语言&#xff0c;也会有偏爱的一些编程语言。而我心中的最爱&#xff0c;毫无疑问&#xff0c;就是 JavaScript。 JavaScript 是一门编程…

23. 数据结构之位图

前言 之前在讲散列表的时候&#xff0c;提到过位图的概念。位图&#xff08;Bitmap&#xff09;作为一种特殊的数据结构&#xff0c;它使用一系列位来表示数据&#xff0c;每个位只有两个状态&#xff08;0或1&#xff09;。由于它的高效性和节省空间的特性&#xff0c;位图在…

SpringBoot的配置环境属性

SpringBoot的配置环境属性 在本文中&#xff0c;我们将讨论SpringBoot的配置环境属性。我们将了解如何使用这些属性来配置我们的应用程序&#xff0c;以便在不同的环境中运行。我们还将了解如何使用SpringBoot的配置文件来管理这些属性。最后&#xff0c;我们将介绍一些最佳实…

java的嵌套类(nested class)、内部类(inner class)的区别

嵌套类即nested class&#xff0c;内部类即Inner class。 概括来说&#xff0c;嵌套类的概念比内部类概念大。嵌套类包含内部类和非内部类。一个内部类一定是一个嵌套类&#xff0c;但一个嵌套类不一定是一个内部类。 在一个类内部或者接口内部声明的类是嵌套类。 下面这些类是…

《Java面向对象程序设计教程》课后编程题

文章目录 第 1 章 Java 概述第 2 章 Java 语言基础第 3 章 Java 面向对象编程第 4 章 Java 图形用户界面程序设计第 5 章 Applet 设计第 6 章 Java 输入输出流与文件操作第 7 章 Java 的多线程机制第 9 章 常用工具类与集合框架 第 1 章 Java 概述 试编写 Java 程序&#xff0…

Android studio新建项目运行遇到的问题

文章目录 The emulator process for AVD xxx has terminated原因&#xff08;环境变量问题&#xff09;解决其他原因 新建的练习项目更改SDK默认位置更改方法 The emulator process for AVD xxx has terminated 运行虚拟机时报此错误 原因&#xff08;环境变量问题&#xff0…

555 timer circuit

#1, Block & principle 1.1&#xff0c; The threshold and trigger levels normally are two- thirds and one-third, respectively, of VCC.(分压&#xff09; 1.2&#xff0c;These levels can be altered by use of the control-voltage terminal. When the trigger in…

生成式 AI:通信服务提供商云转型的下一阶段

【本文由Cloud Ace 整理发布。Cloud Ace 是谷歌云全球战略合作伙伴&#xff0c;拥有 300 多名工程师&#xff0c;也是谷歌最高级别合作伙伴&#xff0c;多次获得 Google Cloud 合作伙伴奖。作为谷歌托管服务商&#xff0c;我们提供谷歌云、谷歌地图、谷歌办公套件、谷歌云认证培…

spring boot引入swagger报错处理

目录 1. 报错说明 2. 查找原因 2.1 此前笔者的代码 3. 问题解决说明 4. 解决方案 4.1 在pom.xml引入springdoc包 4.2 创建配置文件&#xff08;可省略&#xff09; 4.3 在controller加入注解 4.4 查看接口文档 4.5 常用注解 1. 报错说明 在java项目中引入swagger 2.9.2…

Linux设置进程名称(标题) ( 7) -【Linux通信架构系列 】

系列文章目录 C技能系列 Linux通信架构系列 C高性能优化编程系列 深入理解软件架构设计系列 高级C并发线程编程 期待你的关注哦&#xff01;&#xff01;&#xff01; 现在的一切都是为将来的梦想编织翅膀&#xff0c;让梦想在现实中展翅高飞。 Now everything is for the…

技术管理三板斧之第一板斧拿结果-定目标

一、现状&#xff1a; 去年年底今年年初&#xff0c;帮助一家公司做了一次大的系统重构&#xff0c;30多小伙伴&#xff0c;经历一次洗礼&#xff0c;对产品定位&#xff0c;技术选型&#xff0c;目标制定&#xff0c;任务分配&#xff0c;协同开发&#xff0c;测试上线&#x…

JS 启动一个计时器来跟踪某一个操作的占用时长

文章目录 需求分析代码 需求 JS 中想要记录一个操作的占用时长 分析 可以启动一个计时器console.time(name:string)来跟踪某一个操作的占用时长。每一个计时器必须拥有唯一的名字&#xff0c;页面中最多能同时运行 10,000 个计时器。 当以此计时器名字为参数调用 console.timeE…

蓝桥杯专题-试题版-【龟兔赛跑预测】【回形取数】【阶乘计算】【矩形面积交】

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

计算机的性能指标

计算机的主要性能指标: 机器字长: 指参与运算的基本数位, 它是由加法器, 寄存器的数位决定的, 所以及其资产一般等于内部寄存器的大小 数据路通宽度: 数据总线一次能够并行传送信息的位数, 这里所说的数据通路宽度实际是指外部数据总线的宽度 主存容量: 一个存储器所能存储的…

C语言王国探险记之常量的四大护卫

王国探险记系列 文章目录&#xff08;3&#xff09; 前言 一、常量是什么&#xff1f; 二、常量的第一护卫&#xff1a;字面常量 1.什么是字面常量? 三、常量的第二护卫&#xff1a;const修饰的常变量 1.什么是const修饰的常变量? 2&#xff0c;证明const修饰的常变量…

nginx部署多个前端项目

前端采用vue框架&#xff0c;主要介绍在同一个ipport下&#xff08;或域名&#xff09;&#xff0c;通过访问不同的子路径部署多个项目 把前端打包好的项目直接放进 nginx/html 目录下面&#xff0c; 下面展示根据不同的路由模式的nginx配置&#x1f447; 路由采用hash模式 浏…

基于深度学习YOLOv5电动车头盔佩戴检测设计毕业设计

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;625头盔 获取完整源码源文件标注好的数据集(在源码文件夹->yolov5-5.0->VOCdevkit)优秀论文答辩PPT及文稿等 设计总说明 在许多非机动车交通事故中&#xff0c;未佩戴头盔是造成驾驶人受伤或死亡的主要原因&#xf…

永磁电机中的磁钢

稀土永磁最大的应用领域就是永磁电机&#xff0c;电机俗称马达&#xff0c;广义上的电机包含了将电能转换成机械能的电动机&#xff0c;和将机械能转换成电能的发电机&#xff0c;不管是电动机还是发电机&#xff0c;都是利用电磁感应定律或电磁力定律作为基础原理的电气设备。…

【教学类-36-02】动物头饰制作(midjounery动物简笔画四图)

作品展示 &#xff08;用midjounery动物简笔画四图作为头饰上的动物&#xff0c;正方形折纸的辅助黏贴物&#xff09; 背景需求&#xff1a; 1、用midjounery生成简笔画动物图案&#xff08;四张预览&#xff09; 2、收集各种不同的动物的一张图片.png 3、设计一款中班幼儿用…