Please Crack Me

闲着无聊,从以前的程序堆随便找了个程序,“破解”一下,很简单,供大家把玩。
工具:windbg
破解方法:找出加密方法,算出注册码。
https://files.cnblogs.com/diggingdeeply/crackme.rar
要破解的程序界面如图:

打开注册时出现:

输入name和serial正确时:

输入错误时:


好,下面我们开始解密。打开windbg,load程序,一路F5.
程序界面出现,打开注册窗口,这时候kb,看一下callstack:
0:000> kb
ChildEBP RetAddr  Args to Child              
0012fd94 7756073f 77573c9f 001c0d68 00000001 ntdll!KiFastSystemCallRet
0012fd98 77573c9f 001c0d68 00000001 00000000 USER32!NtUserWaitMessage+0xc
0012fdcc 77572dc0 00080dbe 001c0d68 00000010 USER32!DialogBox2+0x202
0012fdf4 77572eec 00400000 004070dc 001c0d68 USER32!InternalDialogBox+0xd0
0012fe14 7758819e 00400000 004070dc 001c0d68 USER32!DialogBoxIndirectParamAorW+0x37
*** 
WARNING: Unable to verify checksum for crackme.EXE
*** 
ERROR: Symbol file could not be found.  Defaulted to export symbols for crackme.EXE - 
0012fe40 00401223 00400000 00402115 001c0d68 USER32!DialogBoxParamA+0x4c
WARNING: Stack unwind information not available. Following frames may be wrong.
0012fe68 7755fd72 001c0d68 00000111 00000066 crackme!WndProc+0xfb
0012fe94 7755fe4a 00401128 001c0d68 00000111 USER32!InternalCallWinProc+0x23
0012ff0c 7756018d 00000000 00401128 001c0d68 USER32!UserCallWinProcCheckWow+0x14b
0012ff70 77558b7c 00401128 00000001 0012ff94 USER32!DispatchMessageWorker+0x322
0012ff80 0040111b 00402048 777ad0e9 7ffdc000 USER32!DispatchMessageA+0xf
0012ff94 77c019bb 7ffdc000 75ec3dbf 00000000 crackme+0x111b
0012ffd4 77c0198e 00401000 7ffdc000 00000000 ntdll!__RtlUserThreadStart+0x23
0012ffec 00000000 00401000 7ffdc000 00000000 ntdll!_RtlUserThreadStart+0x1b

其中发现USER32!DialogBoxParamA比较可疑,下一个断点:
bp USER32!DialogBoxParamA,继续F5.
这时候cancle注册窗口,在打开就能击中断点了。
一路F10,打开汇编代码窗口(Alt+7),出现注册窗口,输入测试数据(aaa和bbb),这时候因为不知道加密规则,所以是随便输入的。
之后OK,断在了如下代码处:
 1 00401223 83f800          cmp     eax,0
 2 00401226 74be            je      crackme!WndProc+0xbe (004011e6)         [br=0]
 3 00401228 688e214000      push    offset crackme!WndProc+0x1066 (0040218e)
 4 0040122d e84c010000      call    crackme!WndProc+0x256 (0040137e)
 5 00401232 50              push    eax
 6 00401233 687e214000      push    offset crackme!WndProc+0x1056 (0040217e)
 7 00401238 e89b010000      call    crackme!WndProc+0x2b0 (004013d8)
 8 0040123d 83c404          add     esp,4
 9 00401240 58              pop     eax
10 00401241 3bc3            cmp     eax,ebx
11 00401243 7407            je      crackme!WndProc+0x124 (0040124c)
12 00401245 e818010000      call    crackme!WndProc+0x23a (00401362)
13 0040124a eb9a            jmp     crackme!WndProc+0xbe (004011e6)
14 0040124c e8fc000000      call    crackme!WndProc+0x225 (0040134d)
15 

因为14行call之后直接出现了错误提示窗口,所以12行应该是正确提示窗口。
那么3和4行,6行和7行则分别是两次数据判断的函数所在,则10行就是破解的关键,暴力破解的话就可以从这句入手。
从4行进入,代码如下:
 1 0040137e 8b742404        mov     esi,dword ptr [esp+4ss:0023:0012fe58=0040218e
 2 00401382 56              push    esi
 3 00401383 8a06            mov     al,byte ptr [esi]
 4 00401385 84c0            test    al,al
 5 00401387 7413            je      crackme!WndProc+0x274 (0040139c)
 6 00401389 3c41            cmp     al,41h
 7 0040138b 721f            jb      crackme!WndProc+0x284 (004013ac)
 8 0040138d 3c5a            cmp     al,5Ah
 9 0040138f 7303            jae     crackme!WndProc+0x26c (00401394)
10 00401391 46              inc     esi
11 00401392 ebef            jmp     crackme!WndProc+0x25b (00401383)
12 00401394 e839000000      call    crackme!WndProc+0x2aa (004013d2)
13 00401399 46              inc     esi
14 0040139a ebe7            jmp     crackme!WndProc+0x25b (00401383)
15 0040139c 5e              pop     esi
16 0040139d e820000000      call    crackme!WndProc+0x29a (004013c2)
17 004013a2 81f778560000    xor     edi,5678h
18 004013a8 8bc7            mov     eax,edi
19 004013aa eb15            jmp     crackme!WndProc+0x299 (004013c1)
20 004013ac 5e              pop     esi
21 004013ad 6a30            push    30h
22 004013af 6860214000      push    offset crackme!WndProc+0x1038 (00402160)
23 004013b4 6869214000      push    offset crackme!WndProc+0x1041 (00402169)
24 004013b9 ff7508          push    dword ptr [ebp+8]
25 004013bc e879000000      call    crackme!WndProc+0x312 (0040143a)
26 004013c1 c3              ret

刚开始就是将ESI的地址内容送入AL,看看ESI的内容是什么?打开寄存器窗口(Alt+4),看到ESI的值是40218e,
dd 40218e,数据为:
00616161 00000000 00000000 00000000
对照ascii表,知道61h是字符a,则就是刚才输入的name。可以看到将a送入AL后,分别和41h('A')和5Ah('Z')比较,
根据代码跟踪可以发现要求name的字符在A~Z之间, 不然就直接跳到错误的地方去了。
则变换数据,输入BBB,在继续跟踪将name 的地址pop到esi,在16行进入到另外一个地方:
1 04013c2 33ff            xor     edi,edi
2 004013c4 33db            xor     ebx,ebx
3 004013c6 8a1e            mov     bl,byte ptr [esi]
4 004013c8 84db            test    bl,bl
5 004013ca 7405            je      crackme!WndProc+0x2a9 (004013d1)
6 004013cc 03fb            add     edi,ebx
7 004013ce 46              inc     esi
8 004013cf ebf5            jmp     crackme!WndProc+0x29e (004013c6)
9 004013d1 c3              ret
这段代码比较简单,就是将name的值相加,结果由edi传出,继续上一段代码,发现函数返回之后则和5678h进行了异或,结果放入了eax传回
则至此,name 的加密规则解密完毕,其伪代码如下:
循环name字符串
{
      if(字符<
'A'或是字符>'Z') return;

      累加字符的和,返回。
}
之后和5678h异或

好了,name分析完了。下面接着是serial,F10进入:
 1 004013d8 33c0            xor     eax,eax
 2 004013da 33ff            xor     edi,edi
 3 004013dc 33db            xor     ebx,ebx
 4 004013de 8b742404        mov     esi,dword ptr [esp+4]
 5 004013e2 b00a            mov     al,0Ah
 6 004013e4 8a1e            mov     bl,byte ptr [esi]
 7 004013e6 84db            test    bl,bl
 8 004013e8 740b            je      crackme!WndProc+0x2cd (004013f5)
 9 004013ea 80eb30          sub     bl,30h
10 004013ed 0faff8          imul    edi,eax
11 004013f0 03fb            add     edi,ebx
12 004013f2 46              inc     esi
13 004013f3 ebed            jmp     crackme!WndProc+0x2ba (004013e2)
14 004013f5 81f734120000    xor     edi,1234h
15 004013fb 8bdf            mov     ebx,edi
16 004013fd c3              ret

先是5行送个0ah到AL,然后将serial送入BL,9行减去30h,然后edi×eax+bl,依次循环。
一般减30h是将数字字符ascii码转为十进制数字,所以上面实际上就是
1 循环serial字符串
2 {
3     int i=strtoint(字符);
4      sum=sum×10+i;
5     return sum;
6 }//其实就是inttostr(serial)
然后和1234h异或,结果由ebx
最后回到最最上面的代码
pop     eax
cmp     eax,ebx
则就是比较两个值,如果相等就显示正确的;反之就是错误的

我们name的值输入的是BBB,则name加密后的值是56BE;再则异或有交换的作用,
serial^1234h=name^5678h=56BE
则56BE^1234h=serial=448A,十进制是17546。
这时候输入BBB和17546,就能得到正确的消息了。


好了,这个程序分析完了。很简单吧?
posted @ 2009-09-16 23:06  DiggingDeeply  阅读(2383)  评论(9编辑  收藏  举报