当前位置: 首页 > news >正文

某app c++层3处魔改md5详解

hello everybody,本期是安卓逆向so层魔改md5教学,干货满满,可以细细品味,重点介绍的是so层魔改md5的处理.

常见的魔改md5有:

        1:明文加密前处理 2:改初始化魔数 3:改k表中的值 4:改循环左移的次数  本期遇到的是124.且循环左移的次数是动态的,需要前面的加密结果处理生成

目录

首先介绍md5的实现

说明:

登陆抓包:

sign的加密

总结:

首先介绍md5的实现

1首先对明文16进制编码,比如我的名字 杨如画 会被编码成 e6 9d a8 e5 a6 82 e7 94 bb

2把明文填充到448bit(比如e6是两个16进制字符,也就是一个字节,8bit),填充方式是先填充一个80,接着一直填充00 00 00直到448bit,

填充成这样e6 9d a8 e5 a6 82 e7 94 bb 80 00 00 00...(56个字节,448bit)

3附加消息长度,需要填充8个字节,也就是e6 9d a8 e5 a6 82 e7 94 bb的长度9个字节,72位,长度就是72,转成16进制就是48,理论上填充的长度为48 也就是

00 00 00 00 00 00 00 48,但是md5处理的时候需要把这8个字节转为小端序,什么是小端续呢?你可以上网查,我简单说一下这里的小端序就是把这8个字节,注意是以字节为单位把最后一个放到第一个,倒数第二个放到第二个,以此类推,最终结果是48 00 00 00 00 00 00 00.  md5的输入长度是无限长的,如果64bit位放不下,也就是长度大于2的64次方的话,会取低64bit,也是按照小端序来取的.  此外sha3算法也是明文无限长,其他hash算法不是.

4最终明文处理成e6 9d a8 e5 a6 82 e7 94 bb 80 00 00 00...48 00 00 00 00 00 00 00,一共512bit,如果输入的数据刚好为448bit,那么就需要填充512bit,再加上附加消息长度64bit,一共1024bit,因为md5的分组长度为512bit,所以需要进行分组处理

至于k表和初始化魔数和循环左移我们待会再说,先对md5的明文处理有一个概念,注意这很重要,后续需要用到.

概念介绍完了,我们来实战吧

说明:

设备: pixel4 XL android10

抓包:charles配合socksdroid

下载地址:aHR0cHM6Ly93d3cud2FuZG91amlhLmNvbS9hcHBzLzMwNjM5OS9oaXN0b3J5X3YzNjA=

frida版本:16.0.1

此版本是旧版本,新版本算法并没有改,流程也大致差不多,复杂的话可以frida trace,后续也会介绍到,事实上这也是我为了逆这个算法现学的,介绍一下背景,我是学了frida rpc接触到了这个app,当时逆登陆的时候有个sign,当时用的是rpc,因为rpc需要开着手机,我想着能不能逆向出完整的算法呢?这期间遇到了非常大的挑战,因为很多frida的api我也不太熟悉,我也是现学现用,后续会一一介绍,整个魔改md5耗时3天.

登陆抓包:

1 查询参数没什么特别的,重点看表单,username是手机号,密码加密了,还有一个用作验签的sign,这个sign的作用我之前说过很多次了,他是用来验签的,通常是把查询参数或者表单中的参数除sign之外的其他值拼接起来加密,防止数据包被恶意篡改,当然也不是不能篡改,把这个sign逆了不就行了吗

2 password的我就不说了,在java层,我直接给出代码吧  定位可以搜字符串,hook java层系统函数等等

# 128位密钥
_str = hashlib.md5('16751641924'.encode('utf-8')).hexdigest()
key = _str[0:16].encode('utf-8')# 128位IV(Initialization Vector)
iv = 'yoloho_dayima!%_'.encode('utf-8')# 明文
plaintext = "1472580369Xx"  # 不能超过31个字符
# 加密
cipher = AES.new(key, AES.MODE_CBC, iv)
padded_data = pad(plaintext.encode(), AES.block_size)
ciphertext = cipher.encrypt(padded_data)# 将密文以Base64格式输出
password = base64.b64encode(ciphertext).decode()
print(password)

sign的加密

3 定位我也不说了,搜字符串,hook什么hashmap,hashset,stringbuilder之类的你都试试吧,总能找到的,我就贴下面了

4 hook encrypt_data这个native函数,返回的就是sign,直接右键复制为frida片段

5 有java的api 要包在Java.perform里 

Java.perform(function (){let Crypt = Java.use("com.yoloho.libcore.util.Crypt");
Crypt["encrypt_data"].implementation = function (j, str, j2) {console.log(`Crypt.encrypt_data is called: j=${j}, str=${str}, j2=${j2}`);let result = this["encrypt_data"](j, str, j2);console.log(`Crypt.encrypt_data result=${result}`);return result;
};
})

6 配合着抓包,点击一下登陆,发现加密的结果与抓包中一样,那铁定是这里了

7 接下来为了避免一直手点登陆,可以进行java层主动调用

function call(){Java.perform(function (){let Crypt = Java.use("com.yoloho.libcore.util.Crypt");
var res = Crypt["encrypt_data"](0, '23eedd78b2b95ef16b82da4fe2177bdcb1920dd6user/login16751641924oKc0ZztEbNCIcDKL3hoF/A==', 85)console.log(res);
})
}

8 我建议你采用我这个主动调用,这样最终加密出来的结果会和我的一样,方便你调试

9 接下来我们把libCrypt.so拖到ida32中反编译,Crypt名字在上面的java代码中出现了,只有32位的所以拖到ida32中

10 反编译后搜一下java发现是静态注册,这里名字叫encrypt_1data是因为进行了符号修饰

11 这里直接点进去看内部逻辑

12 转换一下JNIEnv对象,ida7.5以后可以不用导头文件,直接改类型

13 看到NewStringUTF,第一个参数是JNIEnv,第二个参数是CString,这里是把CString转为JString再返回给java层,所以最终加密的结果就是v12

14 这里可以hook 1B88这个函数,这种没有名字的通常后面就是偏移量,不放心的话可以点进去看看,加上so基值就可以得到函数内存地址了,这是arm指令的,如果是thubm指令的就得+1,如果你不会看arm还是thumb指令就看so是32还是64,32的一般是thumb,64的一般是arm指令

15 接下来hook sub_1B88这个函数,这是修改过后的,一开始你不知道哪些是地址就把所有参数打印一遍,是地址再dump,因为你dump数字的话是会报错的

var soAddr = Module.findBaseAddress("libCrypt.so");
var funcAddr = soAddr.add(0x1B88+1)  //32位+1Interceptor.attach(funcAddr,{onEnter: function(args){console.log('onEnter arg[0]: ',args[0])console.log('onEnter arg[1]: ',args[1])console.log('onEnter arg[2]: ',hexdump(args[2]))console.log('onEnter arg[3]: ',args[3])console.log('onEnter arg[4]: ',args[4])console.log('onEnter arg[5]: ',args[5])console.log('onEnter arg[6]: ',args[6])this.arg2 = args[2]this.arg6 = args[6]},onLeave: function(retval){console.log('onLeave arg[2]: ',hexdump(this.arg2))console.log('onLeave arg[6]: ',hexdump(this.arg6))console.log('onLeave result: ',retval)}});

16这里开着两个hook脚本,java层主动调用,分析so的结果,后面这张图我就不贴了,就是java层的主动调用

17 我们可以看到结果在arg6中,也就是第7个参数,证明结果确实来自v12

18 而arg2就是我们从java层传进的第二个明文参数,只有这个是重要的,其他不重要的就不要输出,影响判断 

19 接下来我们从1B88点进去看看,点进去后发现这里面调用了很多函数,我是把这些函数都hook了一般,但是感觉很乱,有好几个函数被调用了好几次,有的函数内部有if判断还有嵌套函数,极大影响我们的思路,这里可以使用frida trace工具来帮我们分析调用流程

20 frida trace是github上的一个工具,可以自行去下载解压后放到ida的plugis目录下,重启ida 

21 这里还有几个好用的ida插件signsrch,findhash,可以识别一些加密特征来判断是什么加密. 这里直接点一下traceNatives会生成一条命令,终端执行一下 

22 接下来主动调用一下java层的函数,它会给我们打印函数调用流程,这样就清晰多了,这里的函数地址默认都加了1,因为这个so是thumb指令的

23 我们上面分析到1B88,后面的函数你可以一一hook,到这里我感觉写的内容有点多了,我怕你们没耐心看完,所以就不带你们一个一个函数hook了

24 这个sub1105就是魔改的md5算法 

25 最终会加密3次md5,每一次md5都是魔改的,共同的魔改是这里传进去的都是md5 update的字节,而且这个字节你实现的话必须要魔改原本的md5算法.除此以外,第一次还魔改了循环左移,第二次还魔改了初始化魔数和循环左移,并且初始化魔数并不是固定的,而是由第一次加密的md5结果处理生成的,第三次加密的字节需要由第二次加密的结果提供,也就是说,最终的加密结果需要依靠前两次加密的

26 说完了这些我们直接开始hook,下面的代码是简化后的,略去了无效的输出,方便阅读

var soAddr = Module.findBaseAddress("libCrypt.so");
var funcAddr = soAddr.add(0x1104+1)  //32位+1var num = 0
Interceptor.attach(funcAddr,{onEnter: function(args){num+=1console.log(`===============${num}============================`)console.log('onEnter arg[0]: ',hexdump(args[0]))console.log('onEnter arg[1]: ',hexdump(args[1]))console.log('onEnter arg[2]: ',hexdump(args[2]))this.arg1 = args[1]},onLeave: function(retval){console.log('onLeave arg[1]: ',hexdump(this.arg1))}});

27 这里我结合ida中的代码分析a1和a2,a3是什么

28 选中a1,发现它一直在被32减去它的一个值并赋值给另一个值,而复制的值参与了64轮加密

29 这里我们把减号改成加号再转hex,接着对比着c++中的md5可以发现k值并没有被魔改,7,12,17,22是循环左移的次数,并且他是交替着的,我们发现下图中的v82 v83 v6 v76也是交替着的,这也就意味着a1就是循环左移的次数,循环左移你们可以上网搜索了解一下, 4个字节32位,它一直要被32减去的原因可能是他在循环右移,因为32字节的数左移一个数相当于右移32减去这个数

30我们来看看传进去的3个a1参数长啥样

31 第一组

32 第二组 

33 第三组,07 0c 11 16十进制也就是07 12 17 22,这不就是循环左移的次数吗,对比了下剩下的,发现第三个加密循环左移是标准的

34 如果你分不清是so层是循环左移还是右移那你可以拿这16个字节和被32减去的数值分别进行加密,如果其他地方没有被魔改,那么一定有一个是对的

好了,接下来看a2参数,看到01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10 这组数据你就应该想到md5加密的4组初始化魔数

35 对比着C++中的md5,注意这里同样是以4个字节进行小端序排列

36 从so中的取值中也能判断出来 

37 参数3是md5明文updata后的字节,注意这是被填充过的,从终端可以看出

38 接下来分析3个魔改加密的实现,我喜欢从后往前推

39 把看似明文的东西md5以下,发现结果是正确的,但你千万不要觉得传进去的是明文,我上面圈了80 00 ...和c0 00 00 00 00 00 00 00,还记得前面介绍的填充和附加消息长度吗,就是这两个,所以传进去的是updata的字节!我前后强调很多遍了!!!

 40 那么接下来就应该分析j79Yb6ILYA602iiagzMVUw==是哪来的 你不用想也知道这肯定是第二次的加密结果某种形式变化的

 

41 也就是说8f bf 58 6f a2 0b 60 0e b4 da 28 9a 83 33 15 53怎么变成j79Yb6ILYA602iiagzMVUw==的

42 大胆猜测一下,第二次加密和第三次加密前不是进行了一堆函数操作吗,当然只有部分函数做了处理,还有一些加密的准备工作

43 这里我就大胆猜测 

44 j79Yb6ILYA602iiagzMVUw==看着像base64,把它from base64一下看看

45 啥,乱码?别急,转16进制看看,上面的 8f bf 58 6f a2 0b 60 0e b4 da 28 9a 83 33 15 53不就是16进制的吗,你猜怎么着?

46 结果很显然了, 8f bf 58 6f a2 0b 60 0e b4 da 28 9a 83 33 15 53from hex 后to base64就是j79Yb6ILYA602iiagzMVUw==

47 所以接下来就清晰了,分析第二次加密

48 明文是0ZztEbNCIcDKL3hoF/A==,这是我们主动调用的加密字符串的一部分,那另一部分呢,等等,另一部分是64字节,512bit,这不就是md5的分组长度吗

49  我们再来看看第一次加密的参数,正是我们所说的前512bit

50 也就是说so把23eedd78b2b95ef16b82da4fe2177bdcb1920dd6user/login16751641924oKc0ZztEbNCIcDKL3hoF/A==,这整个字符串进行updata和填充到1024bit,因为md5处理的字节必须是512的整数倍,并分了两组,第一组由第一次加密得到,得到的结果做为第二次加密的初始化魔数传入,并加密第二组的512bit得到第三次加密的16进制参数

51好像是这样,那怎么验证呢,因为这两次md5传入的字节都不是完整的,相当于让我把一个字符串update得到的两组512bit拆开加密,这该如何是好啊?

52 所以这就需要你对md5的加密流程足够了解,你才能去改md5的源代码来达到上面所说的效果,那我们先来看第一组加密的吧

53 这两次加密的循环左移都需要改,这里我提前改了

/* Round 1 */
FF(a, b, c, d, x[0], 0, 0xd76aa478); /* 1 */
FF(d, a, b, c, x[1], 1, 0xe8c7b756); /* 2 */
FF(c, d, a, b, x[2], 2, 0x242070db); /* 3 */
FF(b, c, d, a, x[3], 3, 0xc1bdceee); /* 4 */
FF(a, b, c, d, x[4], 0, 0xf57c0faf); /* 5 */
FF(d, a, b, c, x[5], 1, 0x4787c62a); /* 6 */
FF(c, d, a, b, x[6], 2, 0xa8304613); /* 7 */
FF(b, c, d, a, x[7], 3, 0xfd469501); /* 8 */
FF(a, b, c, d, x[8], 0, 0x698098d8); /* 9 */
FF(d, a, b, c, x[9], 1, 0x8b44f7af); /* 10 */
FF(c, d, a, b, x[10], 2, 0xffff5bb1); /* 11 */
FF(b, c, d, a, x[11], 3, 0x895cd7be); /* 12 */
FF(a, b, c, d, x[12], 0, 0x6b901122); /* 13 */
FF(d, a, b, c, x[13], 1, 0xfd987193); /* 14 */
FF(c, d, a, b, x[14], 2, 0xa679438e); /* 15 */
FF(b, c, d, a, x[15], 3, 0x49b40821); /* 16 *//* Round 2 */
GG(a, b, c, d, x[1], 4, 0xf61e2562); /* 17 */
GG(d, a, b, c, x[6], 5, 0xc040b340); /* 18 */
GG(c, d, a, b, x[11], 6, 0x265e5a51); /* 19 */
GG(b, c, d, a, x[0], 7, 0xe9b6c7aa); /* 20 */
GG(a, b, c, d, x[5], 4, 0xd62f105d); /* 21 */
GG(d, a, b, c, x[10], 5, 0x2441453); /* 22 */
GG(c, d, a, b, x[15], 6, 0xd8a1e681); /* 23 */
GG(b, c, d, a, x[4], 7, 0xe7d3fbc8); /* 24 */
GG(a, b, c, d, x[9], 4, 0x21e1cde6); /* 25 */
GG(d, a, b, c, x[14], 5, 0xc33707d6); /* 26 */
GG(c, d, a, b, x[3], 6, 0xf4d50d87); /* 27 */
GG(b, c, d, a, x[8], 7, 0x455a14ed); /* 28 */
GG(a, b, c, d, x[13], 4, 0xa9e3e905); /* 29 */
GG(d, a, b, c, x[2], 5, 0xfcefa3f8); /* 30 */
GG(c, d, a, b, x[7], 6, 0x676f02d9); /* 31 */
GG(b, c, d, a, x[12], 7, 0x8d2a4c8a); /* 32 *//* Round 3 */
HH(a, b, c, d, x[5], 8, 0xfffa3942); /* 33 */
HH(d, a, b, c, x[8], 9, 0x8771f681); /* 34 */
HH(c, d, a, b, x[11], 10, 0x6d9d6122); /* 35 */
HH(b, c, d, a, x[14], 11, 0xfde5380c); /* 36 */
HH(a, b, c, d, x[1], 8, 0xa4beea44); /* 37 */
HH(d, a, b, c, x[4], 9, 0x4bdecfa9); /* 38 */
HH(c, d, a, b, x[7], 10, 0xf6bb4b60); /* 39 */
HH(b, c, d, a, x[10], 11, 0xbebfbc70); /* 40 */
HH(a, b, c, d, x[13], 8, 0x289b7ec6); /* 41 */
HH(d, a, b, c, x[0], 9, 0xeaa127fa); /* 42 */
HH(c, d, a, b, x[3], 10, 0xd4ef3085); /* 43 */
HH(b, c, d, a, x[6], 11, 0x4881d05); /* 44 */
HH(a, b, c, d, x[9], 8, 0xd9d4d039); /* 45 */
HH(d, a, b, c, x[12], 9, 0xe6db99e5); /* 46 */
HH(c, d, a, b, x[15], 10, 0x1fa27cf8); /* 47 */
HH(b, c, d, a, x[2], 11, 0xc4ac5665); /* 48 *//* Round 4 */
II(a, b, c, d, x[0], 12, 0xf4292244); /* 49 */
II(d, a, b, c, x[7], 13, 0x432aff97); /* 50 */
II(c, d, a, b, x[14], 14, 0xab9423a7); /* 51 */
II(b, c, d, a, x[5], 15, 0xfc93a039); /* 52 */
II(a, b, c, d, x[12], 12, 0x655b59c3); /* 53 */
II(d, a, b, c, x[3], 13, 0x8f0ccc92); /* 54 */
II(c, d, a, b, x[10], 14, 0xffeff47d); /* 55 */
II(b, c, d, a, x[1], 15, 0x85845dd1); /* 56 */
II(a, b, c, d, x[8], 12, 0x6fa87e4f); /* 57 */
II(d, a, b, c, x[15], 13, 0xfe2ce6e0); /* 58 */
II(c, d, a, b, x[6], 14, 0xa3014314); /* 59 */
II(b, c, d, a, x[13], 15, 0x4e0811a1); /* 60 */
II(a, b, c, d, x[4], 12, 0xf7537e82); /* 61 */
II(d, a, b, c, x[11], 13, 0xbd3af235); /* 62 */
II(c, d, a, b, x[2], 14, 0x2ad7d2bb); /* 63 */
II(b, c, d, a, x[9], 15, 0xeb86d391); /* 64 */

54 接下来我们需要做的事是把明文传的23eedd78b2b95ef16b82da4fe2177bdcb1920dd6user/login16751641924oKc,最终MD5Encode的时候压入的字节和下图一样即可

55 怎么操作呢,我直接说结论了,由于传参刚好是512bit,所以只需要把填充和附加消息长度的地方注释即可

56 最终结果也是成功得到了

57 接一下就是改第二次加密的初始化魔数,可以仿照着01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10 按小端字节序排列

58 接下来改updata的字节 

59 这里主要改小端字节序,为什么呢,因为填充的80是直接跟着明文的字节,而小端字节序是有明文的长度决定的,注意这里的长度是整个长度,之前说过了, 

60          00 00 00 00 00 00 02 a8    a8代表的是168bit,21字节,正是0ZztEbNCIcDKL3hoF/A==的字符个数,02代表的是512bit,64字节,也就是前面的那串

61 c++md5中由于只有168字符,所以我们需要手动改消息长度的内容,怎么改呢,很简单 a8 00 00 00 00 00 00 00 改a8 02 00 00 00 00 00 00怎么改?

62 很简单中间改bits的值就好了,加上一句bits[1]=2;

 63 结果也就验证成功了,那么怎么写活呢,结尾我会附上完整python代码

总结:

本次教学干货很多,由于考虑单篇文章的阅读时间,我省略了部分无关紧要的流程,核心流程都在里面了.

说实话写这个sign算法的人水平很高,他对md5算法肯定是有充分了解和把握的,一般改改初始化魔数,改改k值都很少见,他一个算法里连着改那么多算是比较少见了.

提一点,关于那个魔改的md5函数,你可以结合着so层主动调用,不过你需要传3个指针参数,但是不太好构造,我这里采取的是直接修改so层传的第3个参数的值来验证的(本文并未提及),如果没有我上面说的前提,你自己摸索需要不断进行验证推翻再验证的过程,逆向就是这个样子的.

本人写作水平有限,如有讲解不到位或者讲解错误的地方,还请各位大佬在评论区多多指教,共同进步,也可加本人微信lyaoyao__i(两个_)

python代码:

import struct
import base64
from loguru import logger
class sign():def __init__(self):passdef md5_1(self,message):def left_rotate(x, amount):return ((x << amount) | (x >> (32 - amount))) & 0xFFFFFFFFdef F(x, y, z):return (x & y) | (~x & z)def G(x, y, z):return (x & z) | (y & ~z)def H(x, y, z):return x ^ y ^ zdef I(x, y, z):return y ^ (x | ~z)def FF(a, b, c, d, x, s, ac):a = (a + F(b, c, d) + x + ac) & 0xFFFFFFFFreturn left_rotate(a, s) + b & 0xFFFFFFFFdef GG(a, b, c, d, x, s, ac):a = (a + G(b, c, d) + x + ac) & 0xFFFFFFFFreturn left_rotate(a, s) + b & 0xFFFFFFFFdef HH(a, b, c, d, x, s, ac):a = (a + H(b, c, d) + x + ac) & 0xFFFFFFFFreturn left_rotate(a, s) + b & 0xFFFFFFFFdef II(a, b, c, d, x, s, ac):a = (a + I(b, c, d) + x + ac) & 0xFFFFFFFFreturn left_rotate(a, s) + b & 0xFFFFFFFFdef pad_message(message):# original_length_bits = len(message) * 8# message += b'\x80'# while (len(message) + 8) % 64 != 0:#     message += b'\x00'# message += struct.pack('<Q', original_length_bits)    # 填充return messagea0 = 0x67452301b0 = 0xEFCDAB89c0 = 0x98BADCFEd0 = 0x10325476message = pad_message(message)chunks = [message[i:i+64] for i in range(0, len(message), 64)]for chunk in chunks:words = struct.unpack('<16I', chunk)A, B, C, D = a0, b0, c0, d0# Round 1A = FF(A, B, C, D, words[0], 0, 0xD76AA478)D = FF(D, A, B, C, words[1], 1, 0xE8C7B756)C = FF(C, D, A, B, words[2], 2, 0x242070DB)B = FF(B, C, D, A, words[3], 3, 0xC1BDCEEE)A = FF(A, B, C, D, words[4], 0, 0xF57C0FAF)D = FF(D, A, B, C, words[5], 1, 0x4787C62A)C = FF(C, D, A, B, words[6], 2, 0xA8304613)B = FF(B, C, D, A, words[7], 3, 0xFD469501)A = FF(A, B, C, D, words[8], 0, 0x698098D8)D = FF(D, A, B, C, words[9], 1, 0x8B44F7AF)C = FF(C, D, A, B, words[10], 2, 0xFFFF5BB1)B = FF(B, C, D, A, words[11], 3, 0x895CD7BE)A = FF(A, B, C, D, words[12], 0, 0x6B901122)D = FF(D, A, B, C, words[13], 1, 0xFD987193)C = FF(C, D, A, B, words[14], 2, 0xA679438E)B = FF(B, C, D, A, words[15], 3, 0x49B40821)# Round 2A = GG(A, B, C, D, words[1], 4, 0xF61E2562)D = GG(D, A, B, C, words[6], 5, 0xC040B340)C = GG(C, D, A, B, words[11], 6, 0x265E5A51)B = GG(B, C, D, A, words[0], 7, 0xE9B6C7AA)A = GG(A, B, C, D, words[5], 4, 0xD62F105D)D = GG(D, A, B, C, words[10], 5, 0x02441453)C = GG(C, D, A, B, words[15], 6, 0xD8A1E681)B = GG(B, C, D, A, words[4], 7, 0xE7D3FBC8)A = GG(A, B, C, D, words[9], 4, 0x21E1CDE6)D = GG(D, A, B, C, words[14], 5, 0xC33707D6)C = GG(C, D, A, B, words[3], 6, 0xF4D50D87)B = GG(B, C, D, A, words[8], 7, 0x455A14ED)A = GG(A, B, C, D, words[13], 4, 0xA9E3E905)D = GG(D, A, B, C, words[2], 5, 0xFCEFA3F8)C = GG(C, D, A, B, words[7], 6, 0x676F02D9)B = GG(B, C, D, A, words[12], 7, 0x8D2A4C8A)# Round 3A = HH(A, B, C, D, words[5], 8, 0xFFFA3942)D = HH(D, A, B, C, words[8], 9, 0x8771F681)C = HH(C, D, A, B, words[11], 10, 0x6D9D6122)B = HH(B, C, D, A, words[14], 11, 0xFDE5380C)A = HH(A, B, C, D, words[1], 8, 0xA4BEEA44)D = HH(D, A, B, C, words[4], 9, 0x4BDECFA9)C = HH(C, D, A, B, words[7], 10, 0xF6BB4B60)B = HH(B, C, D, A, words[10], 11, 0xBEBFBC70)A = HH(A, B, C, D, words[13], 8, 0x289B7EC6)D = HH(D, A, B, C, words[0], 9, 0xEAA127FA)C = HH(C, D, A, B, words[3], 10, 0xD4EF3085)B = HH(B, C, D, A, words[6], 11, 0x04881D05)A = HH(A, B, C, D, words[9], 8, 0xD9D4D039)D = HH(D, A, B, C, words[12], 9, 0xE6DB99E5)C = HH(C, D, A, B, words[15], 10, 0x1FA27CF8)B = HH(B, C, D, A, words[2], 11, 0xC4AC5665)# Round 4A = II(A, B, C, D, words[0], 12, 0xF4292244)D = II(D, A, B, C, words[7], 13, 0x432AFF97)C = II(C, D, A, B, words[14], 14, 0xAB9423A7)B = II(B, C, D, A, words[5], 15, 0xFC93A039)A = II(A, B, C, D, words[12], 12, 0x655B59C3)D = II(D, A, B, C, words[3], 13, 0x8F0CCC92)C = II(C, D, A, B, words[10], 14, 0xFFEFF47D)B = II(B, C, D, A, words[1], 15, 0x85845DD1)A = II(A, B, C, D, words[8], 12, 0x6FA87E4F)D = II(D, A, B, C, words[15], 13, 0xFE2CE6E0)C = II(C, D, A, B, words[6], 14, 0xA3014314)B = II(B, C, D, A, words[13], 15, 0x4E0811A1)A = II(A, B, C, D, words[4], 12, 0xF7537E82)D = II(D, A, B, C, words[11], 13, 0xBD3AF235)C = II(C, D, A, B, words[2], 14, 0x2AD7D2BB)B = II(B, C, D, A, words[9], 15, 0xEB86D391)a0 = (a0 + A) & 0xFFFFFFFFb0 = (b0 + B) & 0xFFFFFFFFc0 = (c0 + C) & 0xFFFFFFFFd0 = (d0 + D) & 0xFFFFFFFFresult = struct.pack('<4I', a0, b0, c0, d0)return result.hex()def md5_2(self,message,_result,length):def left_rotate(x, amount):return ((x << amount) | (x >> (32 - amount))) & 0xFFFFFFFFdef F(x, y, z):return (x & y) | (~x & z)def G(x, y, z):return (x & z) | (y & ~z)def H(x, y, z):return x ^ y ^ zdef I(x, y, z):return y ^ (x | ~z)def FF(a, b, c, d, x, s, ac):a = (a + F(b, c, d) + x + ac) & 0xFFFFFFFFreturn left_rotate(a, s) + b & 0xFFFFFFFFdef GG(a, b, c, d, x, s, ac):a = (a + G(b, c, d) + x + ac) & 0xFFFFFFFFreturn left_rotate(a, s) + b & 0xFFFFFFFFdef HH(a, b, c, d, x, s, ac):a = (a + H(b, c, d) + x + ac) & 0xFFFFFFFFreturn left_rotate(a, s) + b & 0xFFFFFFFFdef II(a, b, c, d, x, s, ac):a = (a + I(b, c, d) + x + ac) & 0xFFFFFFFFreturn left_rotate(a, s) + b & 0xFFFFFFFFdef pad_message(message):original_length_bits = len(message) * 8message += b'\x80'while (len(message) + 8) % 64 != 0:message += b'\x00'message += struct.pack('<Q', original_length_bits)return messagea0 = int(hex(_result[0]), 16)b0 = int(hex(_result[1]), 16)c0 = int(hex(_result[2]), 16)d0 = int(hex(_result[3]), 16)message = pad_message(message)   #448 255if(length<256):# 1组就一个_hex= hex(length)index_to_replace = message.rindex(bytes.fromhex(_hex[2:]))# 将目标位置替换为 0x02message = message[:index_to_replace + 1] + b'\x02' + message[index_to_replace + 2:]else:_hex = hex(length-256)index_to_replace = message.rindex(bytes.fromhex(_hex[2:]))# 将目标位置替换为 0x03message = message[:index_to_replace + 1] + b'\x03' + message[index_to_replace + 2:]chunks = [message[i:i+64] for i in range(0, len(message), 64)]for chunk in chunks:words = struct.unpack('<16I', chunk)A, B, C, D = a0, b0, c0, d0# Round 1A = FF(A, B, C, D, words[0], 0, 0xD76AA478)D = FF(D, A, B, C, words[1], 1, 0xE8C7B756)C = FF(C, D, A, B, words[2], 2, 0x242070DB)B = FF(B, C, D, A, words[3], 3, 0xC1BDCEEE)A = FF(A, B, C, D, words[4], 0, 0xF57C0FAF)D = FF(D, A, B, C, words[5], 1, 0x4787C62A)C = FF(C, D, A, B, words[6], 2, 0xA8304613)B = FF(B, C, D, A, words[7], 3, 0xFD469501)A = FF(A, B, C, D, words[8], 0, 0x698098D8)D = FF(D, A, B, C, words[9], 1, 0x8B44F7AF)C = FF(C, D, A, B, words[10], 2, 0xFFFF5BB1)B = FF(B, C, D, A, words[11], 3, 0x895CD7BE)A = FF(A, B, C, D, words[12], 0, 0x6B901122)D = FF(D, A, B, C, words[13], 1, 0xFD987193)C = FF(C, D, A, B, words[14], 2, 0xA679438E)B = FF(B, C, D, A, words[15], 3, 0x49B40821)# Round 2A = GG(A, B, C, D, words[1], 4, 0xF61E2562)D = GG(D, A, B, C, words[6], 5, 0xC040B340)C = GG(C, D, A, B, words[11], 6, 0x265E5A51)B = GG(B, C, D, A, words[0], 7, 0xE9B6C7AA)A = GG(A, B, C, D, words[5], 4, 0xD62F105D)D = GG(D, A, B, C, words[10], 5, 0x02441453)C = GG(C, D, A, B, words[15], 6, 0xD8A1E681)B = GG(B, C, D, A, words[4], 7, 0xE7D3FBC8)A = GG(A, B, C, D, words[9], 4, 0x21E1CDE6)D = GG(D, A, B, C, words[14], 5, 0xC33707D6)C = GG(C, D, A, B, words[3], 6, 0xF4D50D87)B = GG(B, C, D, A, words[8], 7, 0x455A14ED)A = GG(A, B, C, D, words[13], 4, 0xA9E3E905)D = GG(D, A, B, C, words[2], 5, 0xFCEFA3F8)C = GG(C, D, A, B, words[7], 6, 0x676F02D9)B = GG(B, C, D, A, words[12], 7, 0x8D2A4C8A)# Round 3A = HH(A, B, C, D, words[5], 8, 0xFFFA3942)D = HH(D, A, B, C, words[8], 9, 0x8771F681)C = HH(C, D, A, B, words[11], 10, 0x6D9D6122)B = HH(B, C, D, A, words[14], 11, 0xFDE5380C)A = HH(A, B, C, D, words[1], 8, 0xA4BEEA44)D = HH(D, A, B, C, words[4], 9, 0x4BDECFA9)C = HH(C, D, A, B, words[7], 10, 0xF6BB4B60)B = HH(B, C, D, A, words[10], 11, 0xBEBFBC70)A = HH(A, B, C, D, words[13], 8, 0x289B7EC6)D = HH(D, A, B, C, words[0], 9, 0xEAA127FA)C = HH(C, D, A, B, words[3], 10, 0xD4EF3085)B = HH(B, C, D, A, words[6], 11, 0x04881D05)A = HH(A, B, C, D, words[9], 8, 0xD9D4D039)D = HH(D, A, B, C, words[12], 9, 0xE6DB99E5)C = HH(C, D, A, B, words[15], 10, 0x1FA27CF8)B = HH(B, C, D, A, words[2], 11, 0xC4AC5665)# Round 4A = II(A, B, C, D, words[0], 12, 0xF4292244)D = II(D, A, B, C, words[7], 13, 0x432AFF97)C = II(C, D, A, B, words[14], 14, 0xAB9423A7)B = II(B, C, D, A, words[5], 15, 0xFC93A039)A = II(A, B, C, D, words[12], 12, 0x655B59C3)D = II(D, A, B, C, words[3], 13, 0x8F0CCC92)C = II(C, D, A, B, words[10], 14, 0xFFEFF47D)B = II(B, C, D, A, words[1], 15, 0x85845DD1)A = II(A, B, C, D, words[8], 12, 0x6FA87E4F)D = II(D, A, B, C, words[15], 13, 0xFE2CE6E0)C = II(C, D, A, B, words[6], 14, 0xA3014314)B = II(B, C, D, A, words[13], 15, 0x4E0811A1)A = II(A, B, C, D, words[4], 12, 0xF7537E82)D = II(D, A, B, C, words[11], 13, 0xBD3AF235)C = II(C, D, A, B, words[2], 14, 0x2AD7D2BB)B = II(B, C, D, A, words[9], 15, 0xEB86D391)a0 = (a0 + A) & 0xFFFFFFFFb0 = (b0 + B) & 0xFFFFFFFFc0 = (c0 + C) & 0xFFFFFFFFd0 = (d0 + D) & 0xFFFFFFFFresult = struct.pack('<4I', a0, b0, c0, d0)return result.hex()def md5_3(self,message):def left_rotate(x, amount):return ((x << amount) | (x >> (32 - amount))) & 0xFFFFFFFFdef F(x, y, z):return (x & y) | (~x & z)def G(x, y, z):return (x & z) | (y & ~z)def H(x, y, z):return x ^ y ^ zdef I(x, y, z):return y ^ (x | ~z)def FF(a, b, c, d, x, s, ac):a = (a + F(b, c, d) + x + ac) & 0xFFFFFFFFreturn left_rotate(a, s) + b & 0xFFFFFFFFdef GG(a, b, c, d, x, s, ac):a = (a + G(b, c, d) + x + ac) & 0xFFFFFFFFreturn left_rotate(a, s) + b & 0xFFFFFFFFdef HH(a, b, c, d, x, s, ac):a = (a + H(b, c, d) + x + ac) & 0xFFFFFFFFreturn left_rotate(a, s) + b & 0xFFFFFFFFdef II(a, b, c, d, x, s, ac):a = (a + I(b, c, d) + x + ac) & 0xFFFFFFFFreturn left_rotate(a, s) + b & 0xFFFFFFFFdef pad_message(message):original_length_bits = len(message) * 8message += b'\x80'while (len(message) + 8) % 64 != 0:message += b'\x00'message += struct.pack('<Q', original_length_bits)return messagea0 = 0x67452301b0 = 0xEFCDAB89c0 = 0x98BADCFEd0 = 0x10325476message = pad_message(message)chunks = [message[i:i+64] for i in range(0, len(message), 64)]for chunk in chunks:words = struct.unpack('<16I', chunk)A, B, C, D = a0, b0, c0, d0# Round 1A = FF(A, B, C, D, words[0], 7, 0xD76AA478)D = FF(D, A, B, C, words[1], 12, 0xE8C7B756)C = FF(C, D, A, B, words[2], 17, 0x242070DB)B = FF(B, C, D, A, words[3], 22, 0xC1BDCEEE)A = FF(A, B, C, D, words[4], 7, 0xF57C0FAF)D = FF(D, A, B, C, words[5], 12, 0x4787C62A)C = FF(C, D, A, B, words[6], 17, 0xA8304613)B = FF(B, C, D, A, words[7], 22, 0xFD469501)A = FF(A, B, C, D, words[8], 7, 0x698098D8)D = FF(D, A, B, C, words[9], 12, 0x8B44F7AF)C = FF(C, D, A, B, words[10], 17, 0xFFFF5BB1)B = FF(B, C, D, A, words[11], 22, 0x895CD7BE)A = FF(A, B, C, D, words[12], 7, 0x6B901122)D = FF(D, A, B, C, words[13], 12, 0xFD987193)C = FF(C, D, A, B, words[14], 17, 0xA679438E)B = FF(B, C, D, A, words[15], 22, 0x49B40821)# Round 2A = GG(A, B, C, D, words[1], 5, 0xF61E2562)D = GG(D, A, B, C, words[6], 9, 0xC040B340)C = GG(C, D, A, B, words[11], 14, 0x265E5A51)B = GG(B, C, D, A, words[0], 20, 0xE9B6C7AA)A = GG(A, B, C, D, words[5], 5, 0xD62F105D)D = GG(D, A, B, C, words[10], 9, 0x02441453)C = GG(C, D, A, B, words[15], 14, 0xD8A1E681)B = GG(B, C, D, A, words[4], 20, 0xE7D3FBC8)A = GG(A, B, C, D, words[9], 5, 0x21E1CDE6)D = GG(D, A, B, C, words[14], 9, 0xC33707D6)C = GG(C, D, A, B, words[3], 14, 0xF4D50D87)B = GG(B, C, D, A, words[8], 20, 0x455A14ED)A = GG(A, B, C, D, words[13], 5, 0xA9E3E905)D = GG(D, A, B, C, words[2], 9, 0xFCEFA3F8)C = GG(C, D, A, B, words[7], 14, 0x676F02D9)B = GG(B, C, D, A, words[12], 20, 0x8D2A4C8A)# Round 3A = HH(A, B, C, D, words[5], 4, 0xFFFA3942)D = HH(D, A, B, C, words[8], 11, 0x8771F681)C = HH(C, D, A, B, words[11], 16, 0x6D9D6122)B = HH(B, C, D, A, words[14], 23, 0xFDE5380C)A = HH(A, B, C, D, words[1], 4, 0xA4BEEA44)D = HH(D, A, B, C, words[4], 11, 0x4BDECFA9)C = HH(C, D, A, B, words[7], 16, 0xF6BB4B60)B = HH(B, C, D, A, words[10], 23, 0xBEBFBC70)A = HH(A, B, C, D, words[13], 4, 0x289B7EC6)D = HH(D, A, B, C, words[0], 11, 0xEAA127FA)C = HH(C, D, A, B, words[3], 16, 0xD4EF3085)B = HH(B, C, D, A, words[6], 23, 0x04881D05)A = HH(A, B, C, D, words[9], 4, 0xD9D4D039)D = HH(D, A, B, C, words[12], 11, 0xE6DB99E5)C = HH(C, D, A, B, words[15], 16, 0x1FA27CF8)B = HH(B, C, D, A, words[2], 23, 0xC4AC5665)# Round 4A = II(A, B, C, D, words[0], 6, 0xF4292244)D = II(D, A, B, C, words[7], 10, 0x432AFF97)C = II(C, D, A, B, words[14], 15, 0xAB9423A7)B = II(B, C, D, A, words[5], 21, 0xFC93A039)A = II(A, B, C, D, words[12], 6, 0x655B59C3)D = II(D, A, B, C, words[3], 10, 0x8F0CCC92)C = II(C, D, A, B, words[10], 15, 0xFFEFF47D)B = II(B, C, D, A, words[1], 21, 0x85845DD1)A = II(A, B, C, D, words[8], 6, 0x6FA87E4F)D = II(D, A, B, C, words[15], 10, 0xFE2CE6E0)C = II(C, D, A, B, words[6], 15, 0xA3014314)B = II(B, C, D, A, words[13], 21, 0x4E0811A1)A = II(A, B, C, D, words[4], 6, 0xF7537E82)D = II(D, A, B, C, words[11], 10, 0xBD3AF235)C = II(C, D, A, B, words[2], 15, 0x2AD7D2BB)B = II(B, C, D, A, words[9], 21, 0xEB86D391)a0 = (a0 + A) & 0xFFFFFFFFb0 = (b0 + B) & 0xFFFFFFFFc0 = (c0 + C) & 0xFFFFFFFFd0 = (d0 + D) & 0xFFFFFFFFresult = struct.pack('<4I', a0, b0, c0, d0)return result.hex()def main(self,_str):str1 = _str[:64]str2 = _str[64:]# 示例用法res1 = self.md5_1(str1.encode('utf-8'))logger.info(f'第一次md5初始化魔数分割前的加密结果==>{res1}')# 将原始哈希字符串转换为字节对象original_bytes = bytes.fromhex(res1)# 使用 struct 模块按照规律解析字节对象并生成新的四组_result = [struct.unpack('<I', original_bytes[i:i + 4])[0] for i in range(0, len(original_bytes), 4)]logger.info(f'初始化魔数==>a1={hex(_result[0])}  a2={hex(_result[1])}  a3={hex(_result[2])}  a4={hex(_result[3])}')res2 = self.md5_2(str2.encode('utf-8'),_result,len(str2)*8)res_2 = base64.b64encode(bytes.fromhex(res2)).decode('utf-8')logger.info(f'第二次md5结果==>{res2},是最终加密结果的明文')sign = self.md5_3(res_2.encode('utf-8'))logger.info(f'第三次md5最终sign结果==>{sign}')obj = sign()
obj.main('23eedd78b2b95ef16b82da4fe2177bdcb1920dd6user/login16751641924oKc0ZztEbNCIcDKL3hoF/A==')

相关文章:

某app c++层3处魔改md5详解

hello everybody,本期是安卓逆向so层魔改md5教学,干货满满,可以细细品味,重点介绍的是so层魔改md5的处理. 常见的魔改md5有: 1:明文加密前处理 2:改初始化魔数 3:改k表中的值 4:改循环左移的次数 本期遇到的是124.且循环左移的次数是动态的,需要前面的加密结果处理生成 目录…...

安装MongoDB

查看MongoDB版本可以执行如下命令 mongod --version 如果是Ubuntu&#xff0c;则直接安装 sudo apt-get install -y mongodb如果是其他&#xff0c;比如Amazon Linux2。 查看Linux系统发行版类型 grep ^NAME /etc/*release 如果是 Amazon Linux 2&#xff0c;则创建一个r…...

C++加持让python程序插上翅膀——利用pybind11进行c++和python联合编程示例

目录 0、前言1、安装 pybind11库c侧python侧 2、C引入bybind11vs增加相关依赖及设置cpp中添加头文件及导出模块cpp中添加numpy相关数据结构的接收和返回编译生成dll后改成导出模块同名文件的.pyd 3、python调用c4、C引入bybind11 0、前言 在当今的计算机视觉和机器学习领域&am…...

ubuntu20.04安装cv2

查看ubuntu的版本 cat /etc/lsb-release DISTRIB_IDUbuntu DISTRIB_RELEASE20.04 DISTRIB_CODENAMEfocal DISTRIB_DESCRIPTION"Ubuntu 20.04.3 LTS"更改镜像源 cp /etc/apt/sources.list /etc/apt/sources.list.bak cat > /etc/apt/sources.listdeb http://mirr…...

Android 13.0 recovery出厂时清理中字体大小的修改

1.前言 在13.0的系统rom定制化开发中,在recovery模块也是系统中比较重要的模块,比如恢复出厂设置,recovery ota升级, 清理缓存等等,在一些1080p的设备,但是density只是240这样的设备,会在恢复出厂设置的时候,显示的字体有点小, 产品要求需要将正在清理的字体调大点,这…...

spring+pom-注意多重依赖时的兼容问题[java.lang.NoSuchMethodError]

背景&#xff1a; 项目中同时引入了依赖A和依赖B&#xff0c;而这两个依赖都依赖于项目C&#xff0c;但它们指定的C版本不一致&#xff0c;导致运行时出现了错误。 报错如&#xff1a; java.lang.NoSuchMethodError 解决方案&#xff1a; 需要在项目pom文件中引入依赖C并指定需…...

Matalab插值详解和源码

转载&#xff1a;Matalab插值详解和源码 - 知乎 (zhihu.com) 插值法 插值法又称“内插法”&#xff0c;是利用函数f (x)在某区间中已知的若干点的函数值&#xff0c;作出适当的特定函数&#xff0c;在区间的其他点上用这特定函数的值作为函数f (x)的近似值&#xff0c;这种方…...

Flask 接口

目录 前言 代码实现 简单接口实现 执行其它程序接口 携带参数访问接口 前言 有时候会想着开个一个接口来访问试试&#xff0c;这里就给出一个基础接口代码示例 代码实现 导入Flask模块&#xff0c;没安装Flask 模块需要进行 安装&#xff1a;pip install flask 使用镜…...

Vue3 toRef函数和toRefs函数

当我们在setup 中的以读取对象属性单独交出去时&#xff0c;我们会发现这样会丢失响应式&#xff1a; setup() {let person reactive({name: "张三",age: 18,job: {type: "前端",salary:10}})return {name: person.name,age: person.age,type: person.jo…...

【论文阅读】(VAE-GAN)Autoencoding beyond pixels using a learned similarity metric

论文地址;[1512.09300] Autoencoding beyond pixels using a learned similarity metric (arxiv.org) / 一、Introduction 主要讲了深度学习中生成模型存在的问题&#xff0c;即常用的相似度度量方式&#xff08;使用元素误差度量&#xff09;对于学习良好的生成模型存在一定…...

verilog之wire vs reg区别

文章目录 一、wire vs reg二、实例一、wire vs reg wire线网: 仅支持组合逻辑建模必须由assign语句赋值不能在always块中驱动用于连接子模块的输出用于定义模块的输入端口reg寄存器: 可支持组合逻辑或时序逻辑建模必须在always块中赋值二、实例 wire [7:0] cnt; assign cnt …...

力扣面试经典150题详细解析

刷题的初心 众所周知&#xff0c;算法题对于面试大厂是必不可缺的一环&#xff0c;而且对于提高逻辑思维能力有着不小的提升。所以&#xff0c;对于程序员来讲&#xff0c;无论刚入行&#xff0c;还是从业多年&#xff0c;保持一个清醒的头脑&#xff0c;具备一个良好的设计思…...

【Java 进阶篇】唤醒好运:JQuery 抽奖案例详解

在现代社交网络和电商平台中&#xff0c;抽奖活动成为吸引用户、提升用户参与度的一种常见手段。通过精心设计的抽奖页面&#xff0c;不仅可以增加用户的互动体验&#xff0c;还能在一定程度上提高品牌的知名度。本篇博客将通过详细解析 JQuery 抽奖案例&#xff0c;带领你走进…...

数据处理生产环境_利用MurmurHash3算法在Spark和Scala中生成随机颜色

需求 根据给定的轨迹编号在这一列后面生成随机颜色_16 输入数据 ("吃饭", "123"), ("吃饭", "宋江"), ("郭靖", "宋江"), ("杨过", "奥特曼"), ("周芷若", "张无忌"),…...

便利工具分享:一个proto文件的便利使用工具

最近在研究序列化&#xff0c;每次的proto文件手敲生成代码指令都很麻烦&#xff0c;干脆自己写一个泛用脚本&#xff0c;这样以后使用时候就方便了。 废话不多说&#xff0c;首先上代码&#xff1a; #!/bin/bash # 检查是否提供了文件名参数 if [ -z "$1" ]; then…...

LeetCode704.二分查找及二分法

每日一题&#xff1a;LeetCode704.二分查找 LeetCode704.二分查找知识点&#xff1a;二分法解题代码 LeetCode704.二分查找 问题描述&#xff1a;给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中…...

2023年R1快开门式压力容器操作证模拟考试题库及R1快开门式压力容器操作理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年R1快开门式压力容器操作证模拟考试题库及R1快开门式压力容器操作理论考试试题是由安全生产模拟考试一点通提供&#xff0c;R1快开门式压力容器操作证模拟考试题库是根据R1快开门式压力容器操作最新版教材&#…...

探索NLP中的核心架构:编码器与解码器的区别

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…...

解决:Error: Missing binding xxxxx\node_modules\node-sass\vendor\win32-x64-83\

一、具体报错 二、报错原因 这个错误是由于缺少 node-sass 模块的绑定文件引起的。 三、导致原因 3.1、环境发生了变化 3.2、安装过程出现问题 四、解决方法步骤&#xff1a; 4.1、重新构建 node-sass 模块 npm rebuild node-sass 4.2、清除缓存并重新安装依赖 npm c…...

科研学习|科研软件——面板数据、截面数据、时间序列数据的区别是什么?

一、数据采集方式不同 面板数据是通过在多个时间点上对同一组体进行观测而获得的数据。面板数据可以是横向面板数据&#xff0c;即对同一时间点上不同个体的观测&#xff0c;也可以是纵向面板数据&#xff0c;即对同一个体在不同时间点上的观测。采集面板数据需要跟踪相同的个体…...

【UE5】物体沿样条线移动

目录 效果 步骤 一、使用样条线创建路径 二、创建沿样条线路径移动的物体 三、定义可移动物体的生成器 效果 步骤 一、使用样条线创建路径 先创建一个Actor蓝图&#xff0c;这里命名为“BP_Line” 该蓝图中只需添加一个样条组件 将“BP_Line”拖入场景中 按住Alt鼠标左键…...

Qt控件按钮大全

​ 按钮 在 Qt 里,最常用使用的控件就是按钮了,有了按钮,我们就可以点击,从而响应事件,达到人机交互的效果。不管是嵌入式或者 PC 端,界面交互,少不了按钮。Qt 按钮部件是一种常用的部件之一,Qt 内置了六种按钮部件如下: (1) QPushButton:下压按钮 (2) QToolBu…...

软件工程--软件过程学习笔记

本篇内容是对学校软件工程课堂内容的记录总结&#xff0c;部分也来源于网上查找的资料 软件过程基础 软件过程是指在软件开发过程中&#xff0c;经过一系列有序的步骤和活动&#xff0c;从问题定义到最终软件产品交付和维护的全过程。这个过程旨在确保软件项目能够按时、按预…...

高校教师资格证备考

高等教育制度 关于人的全面发展和个体发展的关系&#xff0c;说法正确的是&#xff08;ABC&#xff09;。 A.个体发展是在全面发展基础上的选择性发展 B.全面发展是个体发展的前提和基础 C.个体发展又是全面发展的动力 D.个体发展是全面发展的前提和基础...

Git通过rebase合并多个commit

在使用 Git 作为版本控制的时候&#xff0c;我们可能会由于各种各样的原因提交了许多临时的 commit&#xff0c;而这些 commit 拼接起来才是完整的任务。那么我们为了避免太多的 commit 而造成版本控制的混乱&#xff0c;通常我们推荐将这些 commit 合并成一个。 1. 查看提交历…...

ROS 学习应用篇(八)ROS中的坐标变换管理之tf广播与监听的编程实现

偶吼吼胜利在望&#xff0c;冲冲冲 老规矩新建功能包 工作空间目录下/src下开启终端输入 catkin_create_pkg learning_tf roscpp rospy tf turtlesim 如何实现tf广播 引入库 c python …...

计算机算法分析与设计(23)---二分搜索算法(C++)

文章目录 1. 算法介绍2. 代码编写 1. 算法介绍 1. 二分搜索&#xff08;英语&#xff1a;binary search&#xff09;&#xff0c;也称折半搜索&#xff08;英语&#xff1a;half-interval search&#xff09;、对数搜索&#xff08;英语&#xff1a;logarithmic search&#xf…...

前置语音群呼与语音机器人群呼哪个更好

最近通过观察自己接到的营销电话&#xff0c;通过语音机器人外呼的量应该有所下降。同时和客户交流获取到的信息&#xff0c;也是和这个情况类似&#xff0c;很多AI机器人群呼的量转向了OKCC前置语音群呼。询问原因&#xff0c;说是前置语音群呼转化更快&#xff0c;AI机器人群…...

『Element Plus の 百科大全』

Element Plus 官网 点击跳转...

P3879 [TJOI2010] 阅读理解- 字典树

题面 分析 将所有单词存入字典树&#xff0c;重点值怎么判断在哪一行出现过&#xff0c;对于字典树查询的判断字符串是否存在的数组可以开成二维&#xff0c;也就是在查询到某个字符串存在后&#xff0c;再通过循环判断每一层是否存在。 代码 #include <bits/stdc.h>…...

upgrade k8s (by quqi99)

作者&#xff1a;张华 发表于&#xff1a;2023-11-17 版权声明&#xff1a;可以任意转载&#xff0c;转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明(http://blog.csdn.net/quqi99) 本文只是从网上搜索一些升级k8s的理论学习&#xff0c;下面的步骤未实际测…...

CronExpression

CronTrigger配置格式: 格式: [秒] [分] [小时] [日] [月] [周] [年]序号 说明 是否必填 允许填写的值 允许的通配符 1 秒 是 0-59 , - * / 2 分 是 0-59 , - * / 3 小时 是 0-23 , - * / 4 日 是 1-31 , - * ? / L W 5 月 是 1-12 or JA…...

释放机器人潜力,INDEMIND深耕底层技术

市场转暖&#xff0c;但攘外需要同时安内。 市场降温之后&#xff0c;正迎来拐点 疫情之后&#xff0c;经济逐渐下行&#xff0c;服务机器人的“好日子”也随之结束&#xff0c;整个行业都在动荡中经历渡劫。根据TE智库报告显示&#xff0c;从2022年开始&#xff0c;我国服务…...

【ES6标准入门】JavaScript中的模块Module语法的使用细节:export命令和imprt命令详细使用,超级详细!!!

&#x1f601; 作者简介&#xff1a;一名大四的学生&#xff0c;致力学习前端开发技术 ⭐️个人主页&#xff1a;夜宵饽饽的主页 ❔ 系列专栏&#xff1a;JavaScript进阶指南 &#x1f450;学习格言&#xff1a;成功不是终点&#xff0c;失败也并非末日&#xff0c;最重要的是继…...

流量2----2

2...

人工智能发展前景

随着人工智能的快速发展&#xff0c;这个行业对人才的需求也在不断增长。越来越多的有志之士开始关注人工智能&#xff0c;希望通过自学获得相关技能&#xff0c;进而在人工智能领域找到心仪的职业。本文将探讨人工智能职业发展的前景&#xff0c;并为大家提供自学人工智能的途…...

编写程序,要求输入x的值,输出y的值。分别用(1)不嵌套的if语句(2)嵌套的if语句(3)if-else语句(4)switch语句。

编写程序&#xff0c;要求输入x的值&#xff0c;输出y的值。分别用&#xff08;1&#xff09;不嵌套的if语句&#xff08;2&#xff09;嵌套的if语句&#xff08;3&#xff09;if-else语句&#xff08;4&#xff09;switch语句。 选择结构是编程语言中常用的一种控制结构&…...

AcWing 4520:质数 ← BFS

【题目来源】https://www.acwing.com/problem/content/4523/【题目描述】 给定一个正整数 X&#xff0c;请你在 X 后面添加若干位数字&#xff08;至少添加一位数字&#xff1b;添加的数不能有前导0&#xff09;&#xff0c;使得结果为质数&#xff0c;在这个前提下所得的结果应…...

00、计算机视觉入门与调优简介

写在前面 每天更新1篇文章&#xff0c;共更新100篇以上 相关代码会放在gitee上 中间会按进度和反馈安排视频讲解 预计2023-11-11开始推送文章&#xff0c;持续3个月左右 专栏简介 本专栏带你从头开始入门计算机视觉。 内容会比之前写的文章更专业更全面&#xff0c;并且你…...

.L0CK3D来袭:如何保护您的数据免受致命攻击

尊敬的读者&#xff1a; 网络犯罪的威胁日益增长&#xff0c;其中.L0CK3D勒索病毒是一种极具挑战性的数字威胁。为了助您应对这一风险&#xff0c;本文将深入探讨.L0CK3D病毒的狡猾手法、毁灭性影响&#xff0c;提供详实的数据恢复方法&#xff0c;同时为您提供极具实战性的预…...

多媒体ffmpeg学习教程

多媒体ffmpeg 目前比较流行的音视频文件为:MP4 flv m3u8 ffmpeg ffmpeg ffplay ffprobe ffserverffmpeg -i INPUT -vf "split [main][tmp]; [tmp] cropiw:ih/2:0:0, vflip [flip];[main][flip] overlay0:H/2" OUTPUTffmpeg -i 2022.mp4 -vcodec mpeg4 -b:…...

SELinux零知识学习十五、SELinux策略语言之客体类别和许可(9)

接前一篇文章&#xff1a;SELinux零知识学习十四、SELinux策略语言之客体类别和许可&#xff08;8&#xff09; 一、SELinux策略语言之客体类别和许可 4. 客体类别许可实例 &#xff08;3&#xff09;进程客体类别许可 与文件许可不同&#xff0c;许多进程许可没有直接对应到…...

OpenSign:安全可靠的电子签名解决方案 | 开源日报 No.76

microsoft/Web-Dev-For-Beginners Stars: 71.5k License: MIT 这个开源项目是一个为期 12 周的全面课程&#xff0c;由微软云倡导者团队提供。它旨在帮助初学者掌握 JavaScript、CSS 和 HTML 的基础知识。每一节都包括预习和复习测验、详细的书面指南、解决方案、作业等内容。…...

Linux | 进程间通信

目录 前言 一、进程间通信的基本概念 二、管道 1、管道的基本概念 2、匿名管道 &#xff08;1&#xff09;原理 &#xff08;2&#xff09;测试代码 &#xff08;3&#xff09;读写控制相关问题 a、读端关闭 b、写端关闭 c、读快写慢 d、读慢些快 &#xff08;4&a…...

Vue.js正式环境中配置多个请求的URL

在Vue.js中&#xff0c;你可以在正式环境中配置多个请求的URL&#xff0c;通常使用一些配置文件或者环境变量的方式。下面是一种常见的配置方式&#xff1a; 1. 创建配置文件&#xff1a;在项目的根目录下&#xff0c;创建一个配置文件&#xff0c;比如可以是config.js&#x…...

简单的 UDP 网络程序

文章目录&#xff1a; 简单的UDP网络程序服务端创建套接字服务端绑定启动服务器udp客户端本地测试INADDR_ANY 地址转换函数关于 inet_ntoa 简单的UDP网络程序 服务端创建套接字 我们将服务端封装为一个类&#xff0c;当定义一个服务器对象之后&#xff0c;需要立即进行初始化…...

人工智能-深度学习之文本预处理

文本预处理 对于序列数据处理问题&#xff0c; 这样的数据存在许多种形式&#xff0c;文本是最常见例子之一。 例如&#xff0c;一篇文章可以被简单地看作一串单词序列&#xff0c;甚至是一串字符序列。 本节中&#xff0c;我们将解析文本的常见预处理步骤。 这些步骤通常包括…...

【Java 进阶篇】插上翅膀:JQuery 插件机制详解

在前端开发中&#xff0c;JQuery 作为一个广泛应用的 JavaScript 库&#xff0c;为开发者提供了丰富的工具和方法&#xff0c;简化了 DOM 操作、事件处理等繁琐的任务。而在这个庞大的生态系统中&#xff0c;插件机制是 JQuery 的一项重要特性&#xff0c;使得开发者能够轻松地…...

手动编译GDB

手动编译GDB 起因在于使用Clang-14编译C文件并生成调试信息,使用gdb调试时报DWARF相关错误。经检查原因在于虚拟机为Ubuntu 20.04&#xff0c;使用apt下载时官方提供gdb版本为9.2&#xff0c;不支持DWARF5,而Clang-14生成的调试信息是DWARF5版本的。为解决该问题&#xff0c;手…...

竞赛选题 深度学习花卉识别 - python 机器视觉 opencv

文章目录 0 前言1 项目背景2 花卉识别的基本原理3 算法实现3.1 预处理3.2 特征提取和选择3.3 分类器设计和决策3.4 卷积神经网络基本原理 4 算法实现4.1 花卉图像数据4.2 模块组成 5 项目执行结果6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &a…...