系统 : Windows xp

程序 : crackme1

程序下载地址 :http://pan.baidu.com/s/1gdY4wMJ

要求 : 分析算法

使用工具 :OD

可在“PEDIY CrackMe 2007”中查找关于此程序的讨论,标题为“muckis's crakcme #1破解(检测OD)”。

 

OD载入程序,键入命令:bp GetWindowTextA,成功断下,并返回程序领空:

004014A0  |.  68 EA030000   push    3EA                                         ; /ControlID = 3EA (1002.)
004014A5  |.  8B45 08       mov     eax, dword ptr [ebp+8]                      ; |
004014A8  |.  50            push    eax                                         ; |hWnd
004014A9  |.  FF15 CC024300 call    dword ptr [<&USER32.GetDlgItem>]            ; \GetDlgItem
004014AF  |.  3BF4          cmp     esi, esp
004014B1  |.  E8 0A1E0000   call    004032C0
004014B6  |.  8945 9C       mov     dword ptr [ebp-64], eax
004014B9  |.  8BF4          mov     esi, esp
004014BB  |.  6A 14         push    14                                          ; /Count = 14 (20.)
004014BD  |.  8D4D C0       lea     ecx, dword ptr [ebp-40]                     ; |
004014C0  |.  51            push    ecx                                         ; |Buffer
004014C1  |.  8B55 9C       mov     edx, dword ptr [ebp-64]                     ; |
004014C4  |.  52            push    edx                                         ; |hWnd
004014C5  |.  FF15 D0024300 call    dword ptr [<&USER32.GetWindowTextA>]        ; \GetWindowTextA
004014CB  |.  3BF4          cmp     esi, esp
004014CD  |.  E8 EE1D0000   call    004032C0
004014D2  |.  8BF4          mov     esi, esp
004014D4  |.  68 EB030000   push    3EB                                         ; /ControlID = 3EB (1003.)
004014D9  |.  8B45 08       mov     eax, dword ptr [ebp+8]                      ; |
004014DC  |.  50            push    eax                                         ; |hWnd
004014DD  |.  FF15 CC024300 call    dword ptr [<&USER32.GetDlgItem>]            ; \GetDlgItem
004014E3  |.  3BF4          cmp     esi, esp
004014E5  |.  E8 D61D0000   call    004032C0
004014EA  |.  8945 9C       mov     dword ptr [ebp-64], eax
004014ED  |.  8BF4          mov     esi, esp
004014EF  |.  6A 14         push    14                                          ; /Count = 14 (20.)
004014F1  |.  8D4D A0       lea     ecx, dword ptr [ebp-60]                     ; |
004014F4  |.  51            push    ecx                                         ; |Buffer
004014F5  |.  8B55 9C       mov     edx, dword ptr [ebp-64]                     ; |
004014F8  |.  52            push    edx                                         ; |hWnd
004014F9  |.  FF15 D0024300 call    dword ptr [<&USER32.GetWindowTextA>]        ; \GetWindowTextA
004014FF  |.  3BF4          cmp     esi, esp                                    ;  ↑获取字串
00401501  |.  E8 BA1D0000   call    004032C0
00401506  |.  E8 FFFAFFFF   call    0040100A                                    
0040150B  |.  85C0          test    eax, eax                                    
0040150D  |.  74 4D         je      short 0040155C                              

40150B处的判断指令根据上一条指令call的结果来决定是否跳转,有些cracker喜欢直接根据call执行之后的状态来猜测子程序的作用。此处,不跟入子程序,40150D处不跳转:

0040150F  |.  6A 0A         push    0A
00401511  |.  8D45 E0       lea     eax, dword ptr [ebp-20]                     ;  取一段地址
00401514  |.  50            push    eax                                         ;  入栈
00401515  |.  8D4D C0       lea     ecx, dword ptr [ebp-40]                     ;  取用户名
00401518  |.  51            push    ecx                                         ;  入栈
00401519  |.  E8 0AFBFFFF   call    00401028
0040151E  |.  83C4 04       add     esp, 4
00401521  |.  50            push    eax
00401522  |.  E8 49A00000   call    0040B570
00401527  |.  83C4 0C       add     esp, 0C
0040152A  |.  50            push    eax
0040152B  |.  8D55 A0       lea     edx, dword ptr [ebp-60]
0040152E  |.  52            push    edx
0040152F  |.  E8 6C1F0000   call    004034A0
00401534  |.  83C4 08       add     esp, 8
00401537  |.  85C0          test    eax, eax
00401539  |.  75 1F         jnz     short 0040155A
0040153B  |.  8BF4          mov     esi, esp
0040153D  |.  6A 00         push    0                                           ; /Style = MB_OK|MB_APPLMODAL
0040153F  |.  68 4CA04200   push    0042A04C                                    ; |lolmuckis crackme #1\ncoded 2006 by mucki
00401544  |.  68 34A04200   push    0042A034                                    ; |make a keygen ;-)
00401549  |.  8B45 08       mov     eax, dword ptr [ebp+8]                      ; |
0040154C  |.  50            push    eax                                         ; |hOwner
0040154D  |.  FF15 D4024300 call    dword ptr [<&USER32.MessageBoxA>]           ; \MessageBoxA

看上去很正常,有一段F(用户名)函数,有一段指令判断是否注册成功,还有MessageBox提示。似乎就是正确的流程了。

然后,当你分析该算法并写出注册机,高高兴兴地想要测试时就会发现,注册机根本不起作用。

没错,就像你想的那样,正是之前看似人畜无害的call引发了一连串的“蝴蝶效应”。

 

跟入call:

0040100A   $ /E9 01060000   jmp     00401610

继续跟:

00401610  /> \55            push    ebp
00401611  |.  8BEC          mov     ebp, esp
00401613  |.  83EC 40       sub     esp, 40
00401616  |.  53            push    ebx
00401617  |.  56            push    esi
00401618  |.  57            push    edi
00401619  |.  8D7D C0       lea     edi, dword ptr [ebp-40]                     ;  取一段内存
0040161C  |.  B9 10000000   mov     ecx, 10
00401621  |.  B8 CCCCCCCC   mov     eax, CCCCCCCC
00401626  |.  F3:AB         rep     stos dword ptr es:[edi]                     ;  用CCCCCCCC填充16个DWORD内存
00401628  |.  64:A1 1800000>mov     eax, dword ptr fs:[18]                      ;  找到TEB地址
0040162E  |.  3E:8B40 30    mov     eax, dword ptr [eax+30]                     ;  在TEB偏移30H处获得PEB地址
00401632  |.  3E:0FB640 02  movzx   eax, byte ptr [eax+2]                       ;  BeingDebugged标志
00401637  |.  83F8 01       cmp     eax, 1
0040163A  |.  74 04         je      short 00401640
0040163C  |.  33C0          xor     eax, eax
0040163E  |.  EB 05         jmp     short 00401645
00401640  |>  B8 01000000   mov     eax, 1
00401645  |>  5F            pop     edi
00401646  |.  5E            pop     esi
00401647  |.  5B            pop     ebx
00401648  |.  83C4 40       add     esp, 40                                     ;  平衡堆栈
0040164B  |.  3BEC          cmp     ebp, esp
0040164D  |.  E8 6E1C0000   call    004032C0
00401652  |.  8BE5          mov     esp, ebp
00401654  |.  5D            pop     ebp
00401655  \.  C3            retn

Win32 Api为程序提供了IsDebuggerPresent判断自己是否处于调试状态,这个函数读取了当前进程PEB中的BeingDebugged标志。通过判断这个标志,可知程序是否被别人调试。

这里,利用OD的插件HideOD对抗反调试。打开HideOD->设置,选择HideNtDebugBit,单击OK,再单击Hide。这样,程序就跳转进入正常的流程:

0040155C  |> \6A 0A         push    0A
0040155E  |.  8D4D E0       lea     ecx, dword ptr [ebp-20]                     ;  取一段地址
00401561  |.  51            push    ecx                                         ;  入栈
00401562  |.  8D55 C0       lea     edx, dword ptr [ebp-40]                     ;  取用户名
00401565  |.  52            push    edx                                         ;  入栈
00401566  |.  E8 B3FAFFFF   call    0040101E                                    ;  根据用户名算出一个值
0040156B  |.  83C4 04       add     esp, 4
0040156E  |.  50            push    eax
0040156F  |.  E8 FC9F0000   call    0040B570                                    ;  根据这个值算出密钥
00401574  |.  83C4 0C       add     esp, 0C                                     ;  平衡堆栈
00401577  |.  50            push    eax                                         ;  密钥入栈
00401578  |.  8D45 A0       lea     eax, dword ptr [ebp-60]                     ;  取出序列号
0040157B  |.  50            push    eax                                         ;  序列号入栈
0040157C  |.  E8 1F1F0000   call    004034A0                                    ;  是否相等?
00401581  |.  83C4 08       add     esp, 8                                      ;  平衡堆栈
00401584  |.  85C0          test    eax, eax                                    ;  相等?
00401586  |.  75 18         jnz     short 004015A0                              ;  不相等则跳转
00401588  |.  8BF4          mov     esi, esp
0040158A  |.  68 1CA04200   push    0042A01C                                    ; /now make a keygen!
0040158F  |.  8B4D 9C       mov     ecx, dword ptr [ebp-64]                     ; |
00401592  |.  51            push    ecx                                         ; |hWnd
00401593  |.  FF15 D8024300 call    dword ptr [<&USER32.SetWindowTextA>]        ; \SetWindowTextA

如果之前粗心大意没有发现反调试就开始分析算法写出注册机的话,那么你只能重新开始。没想到,一条简单的call指令,却能增加Cracker这么多的工作量!

跟入40101E:

0040101E   $ /E9 9D010000   jmp     004011C0

继续跟:

004011C0  /> \55            push    ebp
004011C1  |.  8BEC          mov     ebp, esp
004011C3  |.  83EC 50       sub     esp, 50                                     ;  开辟空间
004011C6  |.  53            push    ebx
004011C7  |.  56            push    esi
004011C8  |.  57            push    edi
004011C9  |.  8D7D B0       lea     edi, dword ptr [ebp-50]                     ;  取一段内存空间
004011CC  |.  B9 14000000   mov     ecx, 14
004011D1  |.  B8 CCCCCCCC   mov     eax, CCCCCCCC
004011D6  |.  F3:AB         rep     stos dword ptr es:[edi]                     ;  用CC填充内存空间
004011D8  |.  C745 FC 00000>mov     dword ptr [ebp-4], 0
004011DF  |.  C745 F8 00000>mov     dword ptr [ebp-8], 0
004011E6  |.  C745 F4 00000>mov     dword ptr [ebp-C], 0
004011ED  |.  8B45 08       mov     eax, dword ptr [ebp+8]                      ;  取用户名字串
004011F0  |.  50            push    eax                                         ;  入栈
004011F1  |.  E8 2A220000   call    00403420                                    ;  算出长度
004011F6  |.  83C4 04       add     esp, 4                                      ;  平衡堆栈
004011F9  |.  8945 F0       mov     dword ptr [ebp-10], eax                     ;  保存长度
004011FC  |.  8B4D 08       mov     ecx, dword ptr [ebp+8]
004011FF  |.  51            push    ecx                                         ;  用户名入栈
00401200  |.  E8 1B210000   call    00403320                                    ;  转化大小写
00401205  |.  83C4 04       add     esp, 4                                      ;  平衡堆栈
00401208  |.  C745 FC 00000>mov     dword ptr [ebp-4], 0
0040120F  |.  EB 09         jmp     short 0040121A
00401211  |>  8B55 FC       /mov     edx, dword ptr [ebp-4]
00401214  |.  83C2 01       |add     edx, 1                                     ;  循环变量自增
00401217  |.  8955 FC       |mov     dword ptr [ebp-4], edx
0040121A  |>  8B45 FC        mov     eax, dword ptr [ebp-4]                     ;  取一段内存空间
0040121D  |.  3B45 F0       |cmp     eax, dword ptr [ebp-10]                    ;  是否迭代完毕?
00401220  |.  7D 3C         |jge     short 0040125E
00401222  |.  8B4D 08       |mov     ecx, dword ptr [ebp+8]                     ;  取用户名字串
00401225  |.  034D FC       |add     ecx, dword ptr [ebp-4]                     ;  加上循环变量
00401228  |.  33D2          |xor     edx, edx
0040122A  |.  8A11          |mov     dl, byte ptr [ecx]                         ;  迭代用户名字串
0040122C  |.  83FA 20       |cmp     edx, 20                                    ;  是空格?
0040122F  |.  74 2B         |je      short 0040125C                             ;  则continue
00401231  |.  8B45 08       |mov     eax, dword ptr [ebp+8]                     ;  取用户名字串
00401234  |.  0345 FC       |add     eax, dword ptr [ebp-4]                     ;  加上循环变量
00401237  |.  33C9          |xor     ecx, ecx
00401239  |.  8A08          |mov     cl, byte ptr [eax]                         ;  迭代用户名字串
0040123B  |.  894D F4       |mov     dword ptr [ebp-C], ecx                     ;  保存字符
0040123E  |.  8B55 F4       |mov     edx, dword ptr [ebp-C]
00401241  |.  69D2 7A150000 |imul    edx, edx, 157A                             ;  字符 乘以 157A
00401247  |.  8955 F4       |mov     dword ptr [ebp-C], edx                     ;  保存结果
0040124A  |.  8B45 F4       |mov     eax, dword ptr [ebp-C]                     ;  取结果
0040124D  |.  83E8 01       |sub     eax, 1                                     ;  减去1
00401250  |.  8945 F4       |mov     dword ptr [ebp-C], eax                     ;  并保存
00401253  |.  8B4D F8       |mov     ecx, dword ptr [ebp-8]                     ;  取一段内存
00401256  |.  034D F4       |add     ecx, dword ptr [ebp-C]                     ;  累加结果
00401259  |.  894D F8       |mov     dword ptr [ebp-8], ecx                     ;  保存累加结果
0040125C  |>^ EB B3         \jmp     short 00401211
0040125E  |>  8B75 F8       mov     esi, dword ptr [ebp-8]
00401261  |.  6BF6 0A       imul    esi, esi, 0A                                ;  累加结果乘以0A
00401264  |.  8B55 F8       mov     edx, dword ptr [ebp-8]                      ;  取累加结果
00401267  |.  52            push    edx                                         ;  入栈
00401268  |.  E8 98FDFFFF   call    00401005                                    ;  浮点运算call
0040126D  |.  83C4 04       add     esp, 4
00401270  |.  03C6          add     eax, esi                                    ;  累加结果加上 浮点运算call的结果
00401272  |.  5F            pop     edi
00401273  |.  5E            pop     esi
00401274  |.  5B            pop     ebx
00401275  |.  83C4 50       add     esp, 50
00401278  |.  3BEC          cmp     ebp, esp
0040127A  |.  E8 41200000   call    004032C0
0040127F  |.  8BE5          mov     esp, ebp
00401281  |.  5D            pop     ebp
00401282  \.  C3            retn

跟入浮点运算call:

00401005   $ /E9 D6000000   jmp     004010E0

继续跟:

004010E0  /> \55            push    ebp
004010E1  |.  8BEC          mov     ebp, esp
004010E3  |.  83EC 58       sub     esp, 58
004010E6  |.  53            push    ebx
004010E7  |.  56            push    esi
004010E8  |.  57            push    edi
004010E9  |.  8D7D A8       lea     edi, dword ptr [ebp-58]
004010EC  |.  B9 16000000   mov     ecx, 16
004010F1  |.  B8 CCCCCCCC   mov     eax, CCCCCCCC
004010F6  |.  F3:AB         rep     stos dword ptr es:[edi]                     ;  用CC填充一段内存
004010F8  |.  C745 FC 00000>mov     dword ptr [ebp-4], 0
004010FF  |.  C745 F8 01000>mov     dword ptr [ebp-8], 1
00401106  |.  C745 F4 00000>mov     dword ptr [ebp-C], 0
0040110D  |.  C745 FC 0A000>mov     dword ptr [ebp-4], 0A
00401114  |.  EB 09         jmp     short 0040111F
00401116  |>  8B45 FC       /mov     eax, dword ptr [ebp-4]
00401119  |.  83E8 01       |sub     eax, 1
0040111C  |.  8945 FC       |mov     dword ptr [ebp-4], eax
0040111F  |>  837D FC 00     cmp     dword ptr [ebp-4], 0                       ;  小于0?
00401123  |.  7C 4F         |jl      short 00401174                             ;  则退出循环
00401125  |.  DB45 08       |fild    dword ptr [ebp+8]                          ;  将累加结果转化为real80对象,并压栈
00401128  |.  DD5D E8       |fstp    qword ptr [ebp-18]                         ;  保存转化成浮点数的累加结果
0040112B  |.  DB45 FC       |fild    dword ptr [ebp-4]                          ;  将0A转化为real80对象,并压栈
0040112E  |.  83EC 08       |sub     esp, 8                                     ;  开辟8个字节的内存空间
00401131  |.  DD1C24        |fstp    qword ptr [esp]                            ;  保存转化成浮点数的0A
00401134  |.  68 00002440   |push    40240000                                   ;  esp + 4入栈
00401139  |.  6A 00         |push    0
0040113B  |.  E8 C91E0000   |call    00403009
00401140  |.  83C4 10       |add     esp, 10
00401143  |.  DC7D E8       |fdivr   qword ptr [ebp-18]                         ;  浮点反除
00401146  |.  E8 AD210000   |call    004032F8
0040114B  |.  8945 F0       |mov     dword ptr [ebp-10], eax
0040114E  |.  837D F0 00    |cmp     dword ptr [ebp-10], 0
00401152  |.  7E 0F         |jle     short 00401163
00401154  |.  8B4D F8       |mov     ecx, dword ptr [ebp-8]
00401157  |.  51            |push    ecx
00401158  |.  E8 DAFEFFFF   |call    00401037
0040115D  |.  83C4 04       |add     esp, 4
00401160  |.  8945 F8       |mov     dword ptr [ebp-8], eax
00401163  |>  8B55 F0       |mov     edx, dword ptr [ebp-10]
00401166  |.  0FAF55 F8     |imul    edx, dword ptr [ebp-8]
0040116A  |.  8B45 F4       |mov     eax, dword ptr [ebp-C]
0040116D  |.  03C2          |add     eax, edx
0040116F  |.  8945 F4       |mov     dword ptr [ebp-C], eax
00401172  |.^ EB A2         \jmp     short 00401116
00401174  |>  8B45 F4       mov     eax, dword ptr [ebp-C]                      ;  算出一个值
00401177  |.  99            cdq                                                 ;  把EDX的所有位都设成EAX最高位的值
00401178  |.  B9 0A000000   mov     ecx, 0A
0040117D  |.  F7F9          idiv    ecx                                         ;  除以0A
0040117F  |.  8BC2          mov     eax, edx                                    ;  余数放入eax
00401181  |.  5F            pop     edi
00401182  |.  5E            pop     esi
00401183  |.  5B            pop     ebx
00401184  |.  83C4 58       add     esp, 58
00401187  |.  3BEC          cmp     ebp, esp
00401189  |.  E8 32210000   call    004032C0
0040118E  |.  8BE5          mov     esp, ebp
00401190  |.  5D            pop     ebp
00401191  \.  C3            retn

这个浮点运算call中包含了大量的浮点运算和子程序,我还要进一步了解浮点运算的汇编指令才能完整分析算法。这里,只能了解到密钥是累加的结果 加上 浮点运算call算出的余数。

一路retn,回到主函数,继续跟入40B570:

0040B570  /$  55            push    ebp
0040B571  |.  8BEC          mov     ebp, esp
0040B573  |.  837D 10 0A    cmp     dword ptr [ebp+10], 0A
0040B577  |.  75 1E         jnz     short 0040B597
0040B579  |.  837D 08 00    cmp     dword ptr [ebp+8], 0
0040B57D  |.  7D 18         jge     short 0040B597
0040B57F  |.  6A 01         push    1
0040B581  |.  8B45 10       mov     eax, dword ptr [ebp+10]
0040B584  |.  50            push    eax
0040B585  |.  8B4D 0C       mov     ecx, dword ptr [ebp+C]
0040B588  |.  51            push    ecx
0040B589  |.  8B55 08       mov     edx, dword ptr [ebp+8]
0040B58C  |.  52            push    edx
0040B58D  |.  E8 2E000000   call    0040B5C0
0040B592  |.  83C4 10       add     esp, 10
0040B595  |.  EB 16         jmp     short 0040B5AD
0040B597  |>  6A 00         push    0
0040B599  |.  8B45 10       mov     eax, dword ptr [ebp+10]
0040B59C  |.  50            push    eax
0040B59D  |.  8B4D 0C       mov     ecx, dword ptr [ebp+C]
0040B5A0  |.  51            push    ecx
0040B5A1  |.  8B55 08       mov     edx, dword ptr [ebp+8]
0040B5A4  |.  52            push    edx
0040B5A5  |.  E8 16000000   call    0040B5C0                                    ;  累加结果转化为十进制
0040B5AA  |.  83C4 10       add     esp, 10
0040B5AD  |>  8B45 0C       mov     eax, dword ptr [ebp+C]
0040B5B0  |.  5D            pop     ebp
0040B5B1  \.  C3            retn

至此,该程序就分析完毕了。除了反调试,程序中还运用了大量的浮点运算。这让我非常头疼,这两天准备去补下浮点运算相关的汇编指令,把这个程序的注册机写出来。

给出一个可用的用户名-序列号组合:

用户名:pediy

序列号:20837376