Please Crack Me
闲着无聊,从以前的程序堆随便找了个程序,“破解”一下,很简单,供大家把玩。
工具:windbg
破解方法:找出加密方法,算出注册码。
https://files.cnblogs.com/diggingdeeply/crackme.rar
要破解的程序界面如图:
打开注册时出现:
输入name和serial正确时:
输入错误时:
好,下面我们开始解密。打开windbg,load程序,一路F5.
程序界面出现,打开注册窗口,这时候kb,看一下callstack:
工具: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
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
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+4] ss: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
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
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分析完了。下面接着是serial,F10进入:
先是5行送个0ah到AL,然后将serial送入BL,9行减去30h,然后edi×eax+bl,依次循环。
一般减30h是将数字字符ascii码转为十进制数字,所以上面实际上就是
pop eax
cmp eax,ebx
则就是比较两个值,如果相等就显示正确的;反之就是错误的
我们name的值输入的是BBB,则name加密后的值是56BE;再则异或有交换的作用,
serial^1234h=name^5678h=56BE
则56BE^1234h=serial=448A,十进制是17546。
这时候输入BBB和17546,就能得到正确的消息了。
好了,这个程序分析完了。很简单吧?
则至此,name 的加密规则解密完毕,其伪代码如下:
循环name字符串
{
if(字符<'A'或是字符>'Z') return;
累加字符的和,返回。
}
之后和5678h异或
{
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
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
最后回到最最上面的代码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,就能得到正确的消息了。
好了,这个程序分析完了。很简单吧?