密码学学习记录|hash md5 算法练习样本三 Shield MD5

密码学学习记录 4 / 18

前沿

样本 app 小黄书,版本 6.87.0,shield 加密参数的 md5 部分
小黄书是 HMAC-MD5 算法,本章只是拿其中的 MD5 算法,来当作练习样本

总结

可以参考下之前的分析文章(各位巨巨巨佬轻喷)
https://www.qinless.com/633

  • 文案来自龙哥 csdn 文章

网上也有不少 Shield 的算法还原文章,一些是IDA F5扣下来伪代码,所以我们有必要再说说。算法用到了现代密码学算法(AES+HMAC MD5)来保证强度,以及古典加密(查表替换,类似于凯撒密码之类的)来保证独特性。其中 AES 和 HMAC MD5 都经过了魔改,代码本身没有经过混淆,这极大的降低了难度,但开发者对密码学显然有一定了解,算法魔改的很好。MD5主要修改了IV(ABCD颠倒)、运算中循环左移的位数、K值、运算的顺序,在我见过的样本里,是是对MD5的魔改程度很彻底的了,粒度也很细。

分析样本 md5 算法

  • 1、四个常量(大家通过 findhash 等 ida 插件,或者自己分析都可以)

函数地址 0x4E2D6,四个常量的顺序看起来是非标准算法

  • 2、T常量数组(正弦函数表)

这个可以尝试着去 md5 transform(函数地址 0x4D108) 函数开始往上跟踪

这里的 v205 就是 T常量数组,来自函数的参数一

在往上跟踪,来到了调用侧,v12 又是传进来的,但是这里面有修改逻辑,在往上也没啥结果了,咱们直接使用 unidbg 看看

transform 函数处下断点 0x4D108

成功断下来,查看 mr0 400 的数据,前十六字节是四个常量,中间的就是 T常量数组 了,需要注意大小端序

  • 3、循环移位数

回到 transform 函数,这里可以直接看到

  • 4、ABCD 顺序,这个如果没啥好的技巧,就自己人工肉眼观察吧

Tips: 样本算法还原之前,需要先获取输入输出的数据,还是借用 unidbg, 这个样本因为是 hmac-md5 所以会有多次 update transform,在第三次调用 transform 函数时,就是对明文进行运算了,在获取明文常量等数据

样本 md5 算法还原

  • 1、四个常量,T常量数组,获取

获取这里的常量(注意:输入不同,这里的 ABCDT,也不同)

A = 0x0da64109
B = 0x64275f40
C = 0x4d9c37cc
D = 0xa695c6c0

T = [
    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, 0x8f0c192, 0xffeff47d, 0x85845DD1,
    0x6FA87E4F, 0xFE2CE6E0, 0xA3014314, 0x4E0811A1, 0xF7537E82, 0xBD3AF235, 0x2AD7D2BB, 0xEB86D391
]
  • 2、循环移位数
s1 = [26, 19, 15, 11, 25, 20, 15, 12, 25, 20, 16, 10, 25, 19, 15, 10]
s2 = [27, 23, 18, 12] * 4
s3 = [28, 21, 16, 9] * 4
s4 = [26, 22, 17, 11] * 4
S = s1 + s2 + s3 + s4
  • 3、运算前的数据处理
def msg_handler(msg_list):
    return msg_list[0] | (msg_list[1] << 0x8) | (msg_list[2] << 0x10) | (msg_list[3] << 0x18)

a_1 = msg_handler(new_msg[0:4])
d_1 = msg_handler(new_msg[4:8])
c_1 = msg_handler(new_msg[8:12])
b_1 = msg_handler(new_msg[12:16])
a_2 = msg_handler(new_msg[16:20])
d_2 = msg_handler(new_msg[20:24])
c_2 = msg_handler(new_msg[24:28])
b_2 = msg_handler(new_msg[28:32])
a_3 = msg_handler(new_msg[32:36])
d_3 = msg_handler(new_msg[36:40])
c_3 = msg_handler(new_msg[40:44])
b_3 = msg_handler(new_msg[44:48])
a_4 = msg_handler(new_msg[48:52])
d_4 = msg_handler(new_msg[52:56])
c_4 = msg_handler(new_msg[56:60])
b_4 = msg_handler(new_msg[60:64])
  • 4、abcd 循序(这是前 16 步的运算细节,后面的不太一样,大家自行还原即可)
a = b + r0_r4(a + (((c ^ d) & b) ^ d) + a_1 + T[0], S[0])
d = a + r0_r4(d + (((b ^ c) & a) ^ c) + d_1 + T[1], S[1])
c = d + r0_r4(c + (((a ^ b) & d) ^ b) + c_1 + T[2], S[2])
b = c + r0_r4(b + (((d ^ a) & c) ^ a) + b_1 + T[3], S[3])
a = b + r0_r4(a + (((c ^ d) & b) ^ d) + a_2 + T[4], S[4])
d = a + r0_r4(d + (((b ^ c) & a) ^ c) + d_2 + T[5], S[5])
c = d + r0_r4(c + (((a ^ b) & d) ^ b) + c_2 + T[6], S[6])
b = c + r0_r4(b + (((d ^ a) & c) ^ a) + b_2 + T[7], S[7])
a = b + r0_r4(a + (((c ^ d) & b) ^ d) + a_3 + T[8], S[8])
d = a + r0_r4(d + (((b ^ c) & a) ^ c) + d_3 + T[9], S[9])
c = d + r0_r4(c + (((a ^ b) & d) ^ b) + c_3 + T[10], S[10])
b = c + r0_r4(b + (((d ^ a) & c) ^ a) + b_3 + T[11], S[11])
a = b + r0_r4(a + (((c ^ d) & b) ^ d) + a_4 + T[12], S[12])
d = a + r0_r4(d + (((b ^ c) & a) ^ c) + d_4 + T[13], S[13])
c = d + r0_r4(c + (((a ^ b) & d) ^ b) + c_4 + T[14], S[14])
b = c + r0_r4(b + (((d ^ a) & c) ^ a) + b_4 + T[15], S[15])

数据验证

结束执行 transform 函数,再次查看参数一,内存地址的值,前十六个字节就是结果

在使用 python 跑一下,结果相同

暂无评论
本文作者:
本文链接: https://www.qinless.com/?p=1287
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 qinless 的博客!
100

发表评论

返回顶部