1、MD5是业界非常成熟的hash算法了,原理不再赘述,这里介绍一下可以魔改的地方!
(1)MD5默认输出是128bit,怎么改变这个长度了?MD5的结果是由4个32bit的ABCD组成的,原始取值如下:
unsigned int A = 0x67452301; unsigned int B = 0xEFCDAB89; unsigned int C = 0x98BADCFE; unsigned int D = 0x10325476;
大家有没有发现啥规律了?16进制数从0开始分别是0123456789abcdef,直接按照4byte的长度截取使用了(注意MD5用的是小端,顺序刚好是反过来的),这不也是很明显的特征数么?所以这里完全可以换成其他没规律的数字;如果要想改变结果的长度,分别改变ABCD长度就行了;由此同样要改变明文Mi的分组长度和Ki的长度!
(2)上图只有Mi是明文,F和Ki出现的目的就是为了尽可能混淆或扩散明文和hash值,让明文和hash值之间找不到任何规律!所以F函数和Ki也是可以魔改的!原F函数如下:
round 1: F(x,y,z) = (x & y) | (~x & z) //X为真就是Y;X为假就是Z round 2: G(x,y,z) = (x & z) | (y & ~z) : round 3: H(x,y,z) = x ^ y ^ z round 4: I(x,y,z) = y ^ ( x | ~z)
完全可以替换成其他的函数,也可以调换顺序!同理,Ki原始值的计算方式是2^32 * |sin i |,而后取其整数部分, 原始的取值如下:
const unsigned int k[] = { 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391};
这么多固定值的数,不是很容易被找到么?所以这里的三角函数sin完全可以换成cos、tg、ctg等其他函数。经过这些魔改后,特征数完全改变,想要查找就不那么容易了!
2、之前用findcrypt在x音的libmetasec.so中找到了base64的码表,进而找到了X-Tyhon、X-Ladon、X-Argus生成代码的附近,但是还有X-Gorgon了,看着很像MD5类的算法,但是一直没找到,今天换个新插件试试:signsrch!居然找到了部分特征数,结果如下:
(1)先看第一个,使用的地方在偏移0x6A5D4这里,来到代码这里后直接F5看看,还真有新发现:
这不就是MD5的ABCD四个数么?继续进入里面的函数,在0x69D9C函数里面开始大量计算hash值了, 这里明显用到K表:
注意,原始值是10进制表示的,按H后转成16进制,但是F5识别成了补码,需要在数字上点击右键->invert sign才能看到正确的数字;
继续往下扒,在0x6A4F4偏移处开始用0x80填充了,如下:
3、至此,可以明确x音肯定用了MD5算法,具体传入了哪些参数了?这个只能动态调试看看了! MD5的ABCD四个数都放栈上了,并且函数传入的是一串疑似URL内容的字符串!
经过一系列骚操作后,栈上的ABCD变成这样了:这个结果后续会被用于X-Gorgon的构造(当然肯定不是简单粗暴地直接拿过来用)!
同样的代码位置,还处理过这类“密文”数据:
处理完的结果还是放栈上原ABCD的位置:
其他遇到过计算MD5的字符串:
这里把cronet、quic协议的版本都拿来求hash值了:
堆内存居然偶遇了X-Gorgon,难道是malloc申请的内存使用后忘记free了?
这里的1128后续会被用来生成X-Ladon字段:
总结:
1、算法模块特征:
- 进行大量的循环运算
- 依赖运算相关的汇编指令,诸如XOR、AND、OR、NOT等(70%)
- 加解密中信息熵的变化
2、MD5的ABCD、K表内部的数据都是明文存储,很容易被找到,为啥对这些数据加密?为啥不通过某些公式计算出来,而是直接放明文了?我个人猜测:这类使用频率非常高的hash算法,如果把ABCD或K表加密,或用公式现场计算,效率肯定受影响,会降低用户体验的!其他某些地方加了OLLVM和VMP,已经导致client端计算效率降低了,如果再在这里加固,效率怕是直接跌倒地板,用户都跑光了,要安全有啥用了?
3、MD5除了F函数,在和明文运算的时候为啥不用异或了?
(1)如果用异或,需要IV或key,接收端验证的时候也要这个,该怎么得到这两个了?除非提前通过其他方式获取,比如DH算法交换双方的公钥后生成key,然后HMAC算法使用key和明文一起生成hash值,所以HMAC的本质相当于用key加盐了!
(2)异或有个特性,满足“交换律”:如果A^B=C,那么A^C=B或则B^C=A;一旦key泄漏,结合得到的hash值,可能反推出明文,就不安全了!
参考:
1、https://cloud.tencent.com/developer/article/1806329 MD5 C源码