• 一条汇编指令引发的 蝴蝶效应


    系统 : 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
    coded 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

    我们一路奋战,不是为了改变世界,而是不让世界改变我们 ——《熔炉》
  • 相关阅读:
    同余方程
    倒酒
    机器翻译
    vue 锚点定位
    解决vuex刷新页面数据丢失
    h5 input失去焦点软键盘把页面顶起
    js 监听ios手机键盘弹起和收起的事件
    js 将数组中的每一项安装奇偶重新组合成一个数组对象
    moment.js获取本周本月本年的开始日期和结束日期
    vue 所有的路由跳转加一个统一参数
  • 原文地址:https://www.cnblogs.com/ZRBYYXDM/p/5209786.html
Copyright © 2020-2023  润新知