JoyChou 发表于 2013-12-16 18:05

【吾爱2013CM大赛解答】-- CrackMe -- 苏紫方璇 详细分析

本帖最后由 JoyChou 于 2013-12-19 14:20 编辑

作者:JoyChou
博客:http://joychou.sinaapp.com
日期:2013年12月16日

这个CM是VC6.0写的MFC程序。这次我就不用MFC按钮入口工具,试试手动来找找。
在Xp下可以这样:
首先用IDA找到CCmdTarget::OnCmdMsg函数的地址,这个CM是00401C6C
OD中,来到00401C6C这个地址,是一个jmpxxxx, enter进入,再向下翻,在push 下断,此时等于0x7DD491F4,
其实这个就是按钮的入口地址,只是有的时候会单步两步才能到处下断。单步两步后,来到入口点00401580

一来就构造了一个SEH的handler,先留意点,下面肯定有异常发生
00401580   .55            push ebp
00401581   .8BEC          mov ebp,esp
00401583   .6A FF         push -0x1
00401585   .68 10344000   push CrackMe.00403410
0040158A   .68 F01D4000   push <jmp.&MSVCRT._except_handler3>      ;SE Hander; SE 处理程序安装
0040158F   .64:A1 0000000>mov eax,dword ptr fs:               ;fs:
00401595   .50            push eax
00401596   .64:8925 00000>mov dword ptr fs:,esp
0040159D   .81C4 A8FEFFFF add esp,-0x158


接着
00401742   > \6A 01         push 0x1
00401744   .8B8D C4FEFFFF mov ecx,dword ptr ss:
0040174A   .E8 43060000   call <jmp.&MFC42.#CWnd::UpdateData_6334>                  ;获取用户名
0040174F   .6A 00         push 0x0
00401751   .8B8D C4FEFFFF mov ecx,dword ptr ss:
00401757   .E8 36060000   call <jmp.&MFC42.#CWnd::UpdateData_6334>                  ;获取密码
0040175C   .8B8D C4FEFFFF mov ecx,dword ptr ss:
00401762   .8B51 60       mov edx,dword ptr ds:
00401765   .8995 CCFEFFFF mov dword ptr ss:,edx
0040176B   .8D85 E4FEFFFF lea eax,dword ptr ss:
00401771   .50            push eax
00401772   .8B8D CCFEFFFF mov ecx,dword ptr ss:
00401778   .51            push ecx
00401779   .E8 92FDFFFF   call CrackMe.00401510                                     ;算法,此时,看堆栈,密文出来了
0040177E   .83C4 08       add esp,0x8


堆栈
0018F650   00362DD0ASCII "JoyChou"
0018F654   0018F6B0ASCII "6FA6B5649CA6AF"


算法很简单,不是重点,就不写keygen了。
做到这其实这题已经差不多算做完了。不过,如果这只是我们想要的结果,那么分析还有什么意思呢?
接着继续看……

重新来一次,输入正确的一组用户名和密码,看看程序的总体流程。
一路单步,看到异常处
0040163C    C745 FC 0000000>mov dword ptr ss:,0x0
00401643    8A15 00000000   mov dl,byte ptr ds:                                    ; 访问0异常
00401649    8815 00000000   mov byte ptr ds:,dl
0040164F    E8 0C020000   call CrackMe.00401860


这个时候在按钮入口的0040158Apush 0x401DF0的0x401DF0处下断
一路单步到7523DD32处F7
7523DD28    33DB            xor ebx,ebx
7523DD2A    33C9            xor ecx,ecx
7523DD2C    33D2            xor edx,edx
7523DD2E    33F6            xor esi,esi
7523DD30    33FF            xor edi,edi
7523DD32    FFD0            call eax                                                ; F7


最后就可以看到成功的样子了,利用SetWindowTextA设置静态文本框为“破解成功”
00401714    50            push eax
00401715    68 EA030000   push 0x3EA
0040171A    8B8D C4FEFFFF   mov ecx,dword ptr ss:
00401720    E8 79060000   call <jmp.&MFC42.#CWnd::GetDlgItem_3092>
00401725    8BC8            mov ecx,eax
00401727    E8 6C060000   call <jmp.&MFC42.#CWnd::SetWindowTextA_6199>
0040172C    C745 FC FFFFFFF>mov dword ptr ss:,-0x1




上面就算基本了解程序流程,不过此CM还有几个地方值得学习。
0x1. 在MFC的OnInitDialog里面检测SetTimer函数的int断点,以及作者自己定义的函数int3 断点
call CrackMe.00401870 这个call就是检测int 3断点
00401870    55            push ebp
00401871    8BEC            mov ebp,esp
00401873    51            push ecx
00401874    57            push edi
00401875    C745 FC 0000000>mov dword ptr ss:,0x0
0040187C    FC            cld
0040187D    8B7D 08         mov edi,dword ptr ss:
00401880    8B4D 0C         mov ecx,dword ptr ss:
00401883    B0 CC         mov al,0xCC
00401885    F2:AE         repne scas byte ptr es:
00401887    75 07         jnz XCrackMe.00401890
00401889    C745 FC 0100000>mov dword ptr ss:,0x1
00401890    8B45 FC         mov eax,dword ptr ss:
00401893    5F            pop edi
00401894    8BE5            mov esp,ebp
00401896    5D            pop ebp
00401897    C3            retn



0x2. 进程退出,都是利用call 00401860退出
分析的时候把这个call retn掉,这样程序就不会退出了。

7C92E510 > 8BD4            mov edx,esp
7C92E512    0F34            sysenter
7C92E514 >C3            retn


0x3. 在SetTimer的回调函数里检测硬件断点,检测到就退出
00401A68    33C0            xor eax,eax
00401A6A    8B50 20         mov edx,dword ptr ds:
00401A6D    8D4C24 18       lea ecx,dword ptr ss:
00401A71    51            push ecx
00401A72    52            push edx
00401A73    FF15 F4314000   call dword ptr ds:[<&USER32.SetWindowTextA>]            ; USER32.SetWindowTextA
00401A79    8D4424 48       lea eax,dword ptr ss:
00401A7D    C74424 48 3F000>mov dword ptr ss:,0x1003F
00401A85    50            push eax
00401A86    FF15 14304000   call dword ptr ds:[<&KERNEL32.GetCurrentThread>]          ; kernel32.GetCurrentThread
00401A8C    50            push eax
00401A8D    FF15 10304000   call dword ptr ds:[<&KERNEL32.GetThreadContext>]          ; kernel32.Wow64GetThreadContext
00401A93    395C24 4C       cmp dword ptr ss:,ebx
00401A97    75 12         jnz XCrackMe.00401AAB
00401A99    395C24 50       cmp dword ptr ss:,ebx
00401A9D    75 0C         jnz XCrackMe.00401AAB
00401A9F    395C24 54       cmp dword ptr ss:,ebx
00401AA3    75 06         jnz XCrackMe.00401AAB
00401AA5    395C24 58       cmp dword ptr ss:,ebx
00401AA9    74 05         je XCrackMe.00401AB0


0x4. 利用QueryPerformanceCounter计算程序执行时间,大于2S就退出,达到反调试。
004018A0   .A1 FC404000   mov eax,dword ptr ds:
004018A5   .56            push esi
004018A6   .8B35 0C304000 mov esi,dword ptr ds:[<&KERNEL32.QueryPe>;kernel32.QueryPerformanceCounter
004018AC   .85C0          test eax,eax
004018AE   .7C 23         jl XCrackMe-.004018D3
004018B0   .7F 09         jg XCrackMe-.004018BB
004018B2   .A1 F8404000   mov eax,dword ptr ds:
004018B7   .85C0          test eax,eax
004018B9   .76 18         jbe XCrackMe-.004018D3
004018BB   >A1 00414000   mov eax,dword ptr ds:
004018C0   .8B0D 04414000 mov ecx,dword ptr ds:
004018C6   .A3 F8404000   mov dword ptr ds:,eax
004018CB   .890D FC404000 mov dword ptr ds:,ecx
004018D1   .EB 12         jmp XCrackMe-.004018E5
004018D3   >68 F0404000   push CrackMe-.004040F0                   ; /pPerformanceFreq = CrackMe-.004040F0
004018D8   .FF15 08304000 call dword ptr ds:[<&KERNEL32.QueryPerfo>; \QueryPerformanceFrequency
004018DE   .68 F8404000   push CrackMe-.004040F8
004018E3   .FFD6          call esi
004018E5   >6A 64         push 0x64                              ; /Timeout = 100. ms
004018E7   .FF15 04304000 call dword ptr ds:[<&KERNEL32.Sleep>]    ; \Sleep
004018ED   .68 00414000   push CrackMe-.00404100
004018F2   .FFD6          call esi
004018F4   .8B15 00414000 mov edx,dword ptr ds:
004018FA   .A1 F8404000   mov eax,dword ptr ds:
004018FF   .8B35 FC404000 mov esi,dword ptr ds:
00401905   .2BD0          sub edx,eax
00401907   .A1 04414000   mov eax,dword ptr ds:
0040190C   .6A 00         push 0x0
0040190E   .1BC6          sbb eax,esi
00401910   .68 E8030000   push 0x3E8
00401915   .50            push eax
00401916   .52            push edx
00401917   .E8 94050000   call CrackMe-.00401EB0
0040191C   .8B0D F4404000 mov ecx,dword ptr ds:
00401922   .51            push ecx
00401923   .8B0D F0404000 mov ecx,dword ptr ds:
00401929   .51            push ecx
0040192A   .52            push edx
0040192B   .50            push eax
0040192C   .E8 CF040000   call CrackMe-.00401E00
00401931   .3D D0070000   cmp eax,0x7D0                            ;判断事件是否小于2秒,大于就退出
00401936   .5E            pop esi
00401937   .7E 05         jle XCrackMe-.0040193E
00401939   .E8 22FFFFFF   call CrackMe-.00401860
0040193E   >C2 1000       retn 0x10

成功截图

JoyChou 发表于 2013-12-16 18:08

写文章好辛苦的说。

阿顺 发表于 2013-12-16 18:14

小人物大智慧 发表于 2013-12-16 18:14

来顶下 大牛的破文
页: [1]
查看完整版本: 【吾爱2013CM大赛解答】-- CrackMe -- 苏紫方璇 详细分析