【文章标题】: 密码学CrackMe之MD5算法CM分析
【文章作者】: coolstar14
【下载地址】: http://bbs.pediy.com/attachment.php?attachmentid=6580&d=1183561716
【使用工具】: Ida, windbg
【作者声明】: 感谢windrand, 同时希望他可以快些出RSA的破文和源码.失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
程序很简单, 因为已经讲明是MD5变换的, 所以输入用户名, 找个MD5计算工具算一下用户名的md5, 串做为序列号输入就可以看到 成功的提示. 由此也可确定, MD5后的结果串并没有再逆序啊之类的操作.
ida反汇编, 查看它提供的Strings参考, 很容易看到 恭喜你, 注册码正确! 查看引用这个串的地址:
.text:004028EB lea eax, [esp+30Ch+var_100]
.text:004028F2 push 0
.text:004028F4 lea ecx, [esp+310h+String]
.text:004028FB push eax
.text:004028FC push ecx
.text:004028FD call sub_402600 ; 关键调用, 算MD5并转换结果为串表示
.text:004028FD
.text:00402902 lea edx, [esp+318h+var_100]
.text:00402909 lea eax, [esp+318h+String2]
.text:0040290D push edx ; int
.text:0040290E push eax ; lpString2
.text:0040290F call sub_4026E0 ;比较两个串, 一致eax为1, 否则为0xFFFFFFFF
.text:0040290F
.text:00402914 add esp, 14h
.text:00402917 cmp eax, 1
.text:0040291A push 40h ; uType
.text:0040291C push offset Caption ; "注册提示"
.text:00402921 jnz short loc_40293B
.text:00402921
.text:00402923 push offset s_ZUgmVSI ; "恭喜你,注册码正确!"
.text:00402928 push esi ; hWnd
.text:00402929 call ds:MessageBoxA
.text:0040292F pop edi
.text:00402930 pop esi
.text:00402931 xor eax, eax
.text:00402933 pop ebp
.text:00402934 add esp, 300h
.text:0040293A retn ; lpCaption
.text:0040293A
.text:0040293B ; ---------------------------------------------------------------------------
.text:0040293B
.text:0040293B loc_40293B: ; CODE XREF: DialogFunc+171j
.text:0040293B push offset s_VSIAGm ; "注册码错误,继续加油!"
.text:00402940 push esi ; hWnd
.text:00402941 call ds:MessageBoxA
看过windrand提供的crc32加密算法的破文, 猜测sub_4026E0为比较两个串, 先找简单的验证一下.
Windbg 截入程序运行, bp 4026e0 下断, F5运行, 随便输入用户名, 序列号, 这儿输入 coolstar / 1234567890, 点注册, 中断.
dds esp L4
显示:
0012f760 00402914 image00400000+0x2914, 返回地址, 不去管它
0012f764 0012f784 第一个参数,
0012f768 0012f984 第二个参数.
alt+5打开内存窗口把两个参数分别做为地址输入, 可以看到一个不认识的16位的字符串和我们输入的序列号. 因为CM写明是MD5, 所以验证输入用户名的md5串, 恰好与此一致. 至此可断定 sub_4026E0作用.
关键函数sub_402600
这个是算MD5的了, 跟进, 因为算法不熟, 所以花了些时间还有不明白的, 列出我的分析, 大家帮忙找下问题:
.text:00402600 sub_402600 proc near ; CODE XREF: DialogFunc+14Dp
.text:00402600
.text:00402600 var_140 = dword ptr -140h
.text:00402600 var_13C = dword ptr -13Ch
.text:00402600 var_138 = dword ptr -138h
.text:00402600 var_134 = byte ptr -134h
.text:00402600 var_133 = dword ptr -133h
.text:00402600 String2 = byte ptr -0FCh
.text:00402600 var_6C = dword ptr -6Ch
.text:00402600 var_18 = dword ptr -18h
.text:00402600 lpString1 = dword ptr -4
.text:00402600 arg_0 = dword ptr 4
.text:00402600 arg_8 = dword ptr 0Ch
.text:00402600
.text:00402600 push 0FFFFFFFFh
.text:00402602 push offset loc_40A1A8
.text:00402607 mov eax, large fs:0
.text:0040260D push eax
.text:0040260E mov large fs:0, esp
.text:00402615 sub esp, 12Ch
.text:0040261B push ebx
.text:0040261C push ebp
.text:0040261D push esi
.text:0040261E push edi
.text:0040261F lea ecx, [esp+148h+var_6C] ; 这儿应该是要用到一个类
.text:00402626 call sub_401840 ; 初始化了一下
.text:00402626
.text:0040262B mov ebp, [esp+148h+arg_8]
.text:00402632 xor eax, eax
.text:00402634 cmp ebp, eax
.text:00402636 mov [esp+148h+lpString1], eax
.text:0040263D lea esi, [esp+148h+var_6C]
.text:00402644 jz short loc_40264A
.text:00402644
.text:00402646 mov esi, [esp+148h+var_138]
.text:00402646
.text:0040264A
.text:0040264A loc_40264A: ; CODE XREF: sub_402600+44j
.text:0040264A mov [esp+148h+var_134], al
.text:0040264E mov ecx, 10h
.text:00402653 xor eax, eax
.text:00402655 lea edi, [esp+148h+var_133]
.text:00402659 rep stosd
.text:0040265B mov eax, [esi]
.text:0040265D mov ecx, esi ;esi 有前面怀疑的结构的地址, 传给了ecx, 好像类的调用喜欢把类指定传给ecx
.text:0040265F call dword ptr [eax+0Ch] ; Md5Init, 初始化content结构
.text:00402662 mov edx, [esp+148h+arg_0]
.text:00402669 or ecx, 0FFFFFFFFh
.text:0040266C mov edi, edx
.text:0040266E xor eax, eax
.text:00402670 repne scasb
.text:00402672 mov ebx, [esi]
.text:00402674 not ecx
.text:00402676 dec ecx
.text:00402677 push ecx
.text:00402678 push edx
.text:00402679 mov ecx, esi
.text:0040267B call dword ptr [ebx+4] ;Md5Update, 添加数据
.text:0040267E mov edx, [esi]
.text:00402680 lea eax, [esp+150h+var_13C]
.text:00402684 push eax
.text:00402685 mov ecx, esi
.text:00402687 call dword ptr [edx+8] ;Md5Final, 结束
.text:0040268A mov ecx, 20h
.text:0040268F xor eax, eax
.text:00402691 lea edi, [esp+59h]
.text:00402695 mov [esp+154h+String2], 0
.text:0040269A rep stosd
.text:0040269C pop edi
.text:0040269D pop esi
.text:0040269E test ebp, ebp
.text:004026A0 pop ebp
.text:004026A1 pop ebx
.text:004026A2 jnz short loc_4026B8
.text:004026A2
.text:004026A4 lea ecx, [esp+144h+String2]
.text:004026A8 lea edx, [esp+144h+var_140]
.text:004026AC push ecx
.text:004026AD push 10h
.text:004026AF push edx
.text:004026B0 call sub_402590 ;将Md5计算出来的16字节转换为字符串, 三个参数, 节MD5散列值地址, 长度, 目标缓冲区地址
.text:004026B0
.text:004026B5 add esp, 0Ch
.text:004026B5
.text:004026B8
.text:004026B8 loc_4026B8: ; CODE XREF: sub_402600+A2j
.text:004026B8 mov ecx, [esp+144h+lpString1]
.text:004026BF lea eax, [esp+144h+String2]
.text:004026C3 push eax ; lpString2
.text:004026C4 push ecx ; lpString1
.text:004026C5 call ds:lstrcpyA
.text:004026CB mov ecx, [esp+144h+var_18]
.text:004026D2 mov large fs:0, ecx
.text:004026D9 add esp, 138h
.text:004026DF retn
.text:004026DF
.text:004026DF sub_402600 endp ; sp = -0Ch
关于 call dword ptr [ebx+4] 怎么确定是什么功能, 我承认我是猜的, 不过可以调试到这个位置, 然后f11跟进, 可以看到明显的提示, 像CMD5::FinalDigest(), CMD5::AddData()等等这种.
我们可以看到在调用类的成员函数时都是把类的地址传给ecx的, 这可能是个惯例的吧.
OK, 就这样了, 第一次写这种东西.
感谢 windrand 大侠提供的这一系列CM, 不过他更新破文的速度好像并不快, 也许是有意留下时间让我等菜鸟学习的吧, 毕竟自己分析一下印象会更深刻一下.
题外, 最近在学 密码学 的东西, 要求不高, 只希望可以看到一段代码知道是用的算法加密的, 加密的关键函数和关键变量就可以了, 本来想做那个RSA256的来着, 结果弄下来看了半天, 只能猜测什么有把握的东西也没得到, 怀疑有个串是公钥对(n, e)中的n也不能确定. 唉, 功力太浅, 这儿请求如果哪位要做windrand 密码学系列的破文, 能不能先处理RSA系列的啊, 谢谢.
注册机就算了, 就是算个MD5, 网上算MD5的工具是很多的.
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2007年09月06日 17:22:04
[培训]科锐逆向工程师培训第53期2025年7月8日开班!