首页 > 代码库 > [反汇编练习] 160个CrackMe之007

[反汇编练习] 160个CrackMe之007

[反汇编练习] 160个CrackMe之007.

本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注册机的东西。

其中,文章中按照如下逻辑编排(解决如下问题):

1、使用什么环境和工具

2、程序分析

3、思路分析和破解流程

4、注册机的探索

----------------------------------

提醒各位看客: 如果文章中的逻辑看不明白,那你一定是没有亲手操刀!OD中的跳转提示很强大,只要你跟踪了,不用怎么看代码就理解了!

----------------------------------

1、工具和环境:

WinXP SP3 + 52Pojie六周年纪念版OD + PEID + 汇编金手指。

160个CrackMe的打包文件。

下载地址: http://pan.baidu.com/s/1xUWOY  密码: jbnq

注:

1、Win7系统对于模块和程序开启了随机初始地址的功能,会给分析带来很大的负担,所以不建议使用Win7进行分析。

2、以上工具都是在52PoJie论坛下的原版程序,NOD32不报毒,个人承诺绝对不会进行任何和木马病毒相关内容。

wps_clip_image-142827

 

2、程序分析:

想要破解一个程序,必须先了解这个程序。所以,在破解过程中,对最初程序的分析很重要,他可以帮助我们理解作者的目的和意图,特别是对于注册码的处理细节,从而方便我们反向跟踪和推导。

和上一节一样,打开CHM,选择第7个aLoNg3x.2,保存下来。运行程序,程序界面如下:

image

使用PEID查一下,Delphi 4.0 - 5.0。点一下About-Help,看完之后和上一个要求一样。不用想了,直接上IDR分析。

 

3、思路分析和破解流程

IDR打开后如图:

3

 

我们先看一下窗口信息(F5):

1

 

我们发现,除了第一个register按钮之后,还有一个again按钮。看来这个程序意思很明确点击完Reg之后还需要通过again按钮的验证。我们在树列表中查看下按钮对应事件的关系。

首先,分析Register的事件:

双击IDR最下面的列表中的RegisterClick.event,右上角会显示对应的反汇编。

根据上一个程序的经验,大概地分析一下:

Delphi字符串函数反汇编参考:http://www.cnblogs.com/bbdxf/p/3787684.html

 _CrackMe200::TPrincipale.RegisterzClick 00442F28    push       ebp 00442F29    mov        ebp,esp 00442F2B    add        esp,0FFFFFFF8 00442F2E    push       ebx 00442F2F    push       esi 00442F30    xor        ecx,ecx 00442F32    mov        dword ptr [ebp-8],ecx 00442F35    mov        ebx,eax 00442F37    xor        eax,eax 00442F39    push       ebp 00442F3A    push       443022 00442F3F    push       dword ptr fs:[eax] 00442F42    mov        dword ptr fs:[eax],esp 00442F45    lea        edx,[ebp-8] 00442F48    mov        eax,dword ptr [ebx+2DC]; TPrincipale.Codice:TEdit 00442F4E    call       TControl.GetText 00442F53    mov        eax,dword ptr [ebp-8] 00442F56    lea        edx,[ebp-4] 00442F59    call       @ValLong 00442F5E    mov        esi,eax 00442F60    cmp        dword ptr [ebp-4],0>00442F64    je         00442F9D 00442F66    mov        eax,443038; ‘You MUST insert a valid Long Integer Value in the Code Editor... Thank you :)‘ 00442F6B    call       ShowMessage 00442F70    lea        edx,[ebp-8] 00442F73    mov        eax,dword ptr [ebx+2DC]; TPrincipale.Codice:TEdit 00442F79    call       TControl.GetText 00442F7E    mov        eax,dword ptr [ebp-8] 00442F81    call       00442A8C 00442F86    mov        [00445830],eax; gvar_00445830 00442F8B    mov        edx,443090; ‘0‘ 00442F90    mov        eax,dword ptr [ebx+2DC]; TPrincipale.Codice:TEdit 00442F96    call       TControl.SetText>00442F9B    jmp        0044300C 00442F9D    test       esi,esi>00442F9F    jle        00442FFB 00442FA1    lea        edx,[ebp-8] 00442FA4    mov        eax,dword ptr [ebx+2D8]; TPrincipale.Nome:TEdit 00442FAA    call       TControl.GetText 00442FAF    mov        ecx,dword ptr [ebp-8] 00442FB2    mov        edx,esi 00442FB4    mov        eax,[00445830]; 0x0 gvar_00445830 00442FB9    call       004429A8	; // 关键CALL 00442FBE    test       al,al>00442FC0    je         00442FF2	; // 关键跳转 00442FC2    xor        edx,edx		;// 将注册按钮隐藏,然后显示出来那个again按钮 00442FC4    mov        eax,dword ptr [ebx+2CC]; TPrincipale.Registerz:TButton 00442FCA    call       TControl.SetVisible 00442FCF    mov        dl,1 00442FD1    mov        eax,dword ptr [ebx+2E8]; TPrincipale.Again:TButton 00442FD7    call       TControl.SetVisible 00442FDC    xor        edx,edx 00442FDE    mov        eax,dword ptr [ebx+2D8]; TPrincipale.Nome:TEdit 00442FE4    mov        ecx,dword ptr [eax] 00442FE6    call       dword ptr [ecx+60]; TControl.SetEnabled 00442FE9    xor        eax,eax 00442FEB    mov        [00445830],eax; gvar_00445830>00442FF0    jmp        0044300C 00442FF2    xor        eax,eax 00442FF4    mov        [00445830],eax; gvar_00445830>00442FF9    jmp        0044300C 00442FFB    mov        eax,44309C; ‘Please... The Code Must be > 0‘ 00443000    call       ShowMessage 00443005    xor        eax,eax 00443007    mov        [00445830],eax; gvar_00445830 0044300C    xor        eax,eax 0044300E    pop        edx 0044300F    pop        ecx 00443010    pop        ecx 00443011    mov        dword ptr fs:[eax],edx 00443014    push       443029 00443019    lea        eax,[ebp-8] 0044301C    call       @LStrClr 00443021    ret<00443022    jmp        @HandleFinally<00443027    jmp        00443019 00443029    pop        esi 0044302A    pop        ebx 0044302B    pop        ecx 0044302C    pop        ecx 0044302D    pop        ebp 0044302E    ret

根据函数的名称,我们很容易分析出了关键Call 004429A8, 在CALL下面的JE就是爆破的关键跳转。

将exe程序拖到OD中打开,根据IDR中的地址,转到(Ctrl+G)开头地址:00442F28。在程序中输入伪码,参照IDR中的汇编,修改关键的跳转JE 00442FF2,选中JE->右键->Binary->Fill with NOPs。在程序中随意输入,点击Register按钮,发现注册按钮不见了,again按钮出来了。

我们继续在IDR中找到againClick.event,双击进去,继续分析一下:

 _CrackMe200::TPrincipale.AgainClick 004430BC    push       ebp 004430BD    mov        ebp,esp 004430BF    push       0 004430C1    push       0 004430C3    push       0 004430C5    push       ebx 004430C6    push       esi 004430C7    mov        ebx,eax 004430C9    xor        eax,eax 004430CB    push       ebp 004430CC    push       44322D 004430D1    push       dword ptr fs:[eax] 004430D4    mov        dword ptr fs:[eax],esp 004430D7    lea        edx,[ebp-0C] 004430DA    mov        eax,dword ptr [ebx+2DC]; TPrincipale.Codice:TEdit 004430E0    call       TControl.GetText 004430E5    mov        eax,dword ptr [ebp-0C] 004430E8    lea        edx,[ebp-4] 004430EB    call       @ValLong 004430F0    mov        esi,eax 004430F2    cmp        dword ptr [ebp-4],0>004430F6    je         00443132 004430F8    mov        eax,443244; ‘You MUST insert a valid Long Integer Value in the Code Editor... Thank you :)‘ 004430FD    call       ShowMessage 00443102    lea        edx,[ebp-0C] 00443105    mov        eax,dword ptr [ebx+2DC]; TPrincipale.Codice:TEdit 0044310B    call       TControl.GetText 00443110    mov        eax,dword ptr [ebp-0C] 00443113    call       00442A8C 00443118    mov        [00445830],eax; gvar_00445830 0044311D    mov        edx,44329C; ‘0‘ 00443122    mov        eax,dword ptr [ebx+2DC]; TPrincipale.Codice:TEdit 00443128    call       TControl.SetText>0044312D    jmp        0044320F 00443132    test       esi,esi>00443134    jle        004431FE 0044313A    lea        edx,[ebp-0C] 0044313D    mov        eax,dword ptr [ebx+2D8]; TPrincipale.Nome:TEdit 00443143    call       TControl.GetText 00443148    mov        ecx,dword ptr [ebp-0C] 0044314B    mov        edx,esi 0044314D    mov        eax,[00445830]; 0x0 gvar_00445830 00443152    call       004429A8 00443157    test       al,al>00443159    je         004431CE 0044315B    xor        edx,edx 0044315D    mov        eax,dword ptr [ebx+2E8]; TPrincipale.Again:TButton 00443163    call       TControl.SetVisible 00443168    lea        edx,[ebp-8] 0044316B    mov        eax,[0044582C]; 0x0 gvar_0044582C:TPrincipale 00443170    call       TControl.GetText 00443175    lea        eax,[ebp-8] 00443178    call       UniqueString 0044317D    mov        byte ptr [eax+5],65 00443181    lea        eax,[ebp-8] 00443184    call       UniqueString 00443189    mov        byte ptr [eax+6],64 0044318D    lea        eax,[ebp-8] 00443190    mov        ecx,13 00443195    mov        edx,0C 0044319A    call       @LStrDelete 0044319F    lea        edx,[ebp-0C] 004431A2    mov        eax,dword ptr [ebx+2D8]; TPrincipale.Nome:TEdit 004431A8    call       TControl.GetText 004431AD    mov        edx,dword ptr [ebp-0C] 004431B0    lea        eax,[ebp-8] 004431B3    call       @LStrCat 004431B8    mov        edx,dword ptr [ebp-8] 004431BB    mov        eax,[0044582C]; 0x0 gvar_0044582C:TPrincipale 004431C0    call       TControl.SetText 004431C5    xor        eax,eax 004431C7    mov        [00445830],eax; gvar_00445830>004431CC    jmp        0044320F 004431CE    xor        eax,eax 004431D0    mov        [00445830],eax; gvar_00445830 004431D5    xor        edx,edx 004431D7    mov        eax,dword ptr [ebx+2E8]; TPrincipale.Again:TButton 004431DD    call       TControl.SetVisible 004431E2    mov        dl,1 004431E4    mov        eax,dword ptr [ebx+2CC]; TPrincipale.Registerz:TButton 004431EA    call       TControl.SetVisible 004431EF    mov        dl,1 004431F1    mov        eax,dword ptr [ebx+2D8]; TPrincipale.Nome:TEdit 004431F7    mov        ecx,dword ptr [eax] 004431F9    call       dword ptr [ecx+60]; TControl.SetEnabled>004431FC    jmp        0044320F 004431FE    mov        eax,4432A8; ‘Please... The Code Must be > 0‘ 00443203    call       ShowMessage 00443208    xor        eax,eax 0044320A    mov        [00445830],eax; gvar_00445830 0044320F    xor        eax,eax 00443211    pop        edx 00443212    pop        ecx 00443213    pop        ecx 00443214    mov        dword ptr fs:[eax],edx 00443217    push       443234 0044321C    lea        eax,[ebp-0C] 0044321F    call       @LStrClr 00443224    lea        eax,[ebp-8] 00443227    call       @LStrClr 0044322C    ret<0044322D    jmp        @HandleFinally<00443232    jmp        0044321C 00443234    pop        esi 00443235    pop        ebx 00443236    mov        esp,ebp 00443238    pop        ebp 00443239    ret

大概地一看,是不是发现他们的逻辑基本和Register的差不多?关键Call也一样。没关系,我们继续在JE 004431CE右键,Binary->Fill with NOPs。这时,回到程序,继续点击Again,是不是两个按钮都被隐藏了?!!哈哈哈!

(多试几次,会发现第一个编辑框还是有字数限制的,需要大于4个)

小结:两个按钮调用了相同的关键CALL,即使用了同一个算法函数对注册码进行验证,这要爆破这一个函数或它的跳转就行。

 

4、注册机尝试

由于两个按钮的关键Call一样,所以这个算法就很省事了,直接在 OD中跳转到CALL 004429A8的地方,F8单步分析。

慢着,是不是很多CALL还不知道什么意思?是啊,先用IDR看一下嘛!

在IDR中也是用Ctrl+G,输入地址 004429A8,确定:

 _CrackMe200::sub_004429A8 004429A8    push       ebp 004429A9    mov        ebp,esp 004429AB    add        esp,0FFFFFFF4 004429AE    push       ebx 004429AF    push       esi 004429B0    push       edi 004429B1    mov        dword ptr [ebp-8],ecx 004429B4    mov        dword ptr [ebp-4],edx 004429B7    mov        edi,eax 004429B9    mov        eax,dword ptr [ebp-8] 004429BC    call       @LStrAddRef 004429C1    xor        eax,eax 004429C3    push       ebp 004429C4    push       442A7A 004429C9    push       dword ptr fs:[eax] 004429CC    mov        dword ptr fs:[eax],esp 004429CF    mov        eax,dword ptr [ebp-8] 004429D2    call       @LStrLen 004429D7    cmp        eax,4>004429DA    jle        00442A62 004429E0    xor        ebx,ebx 004429E2    mov        eax,dword ptr [ebp-8] 004429E5    call       @LStrLen 004429EA    test       eax,eax>004429EC    jle        00442A26 004429EE    mov        dword ptr [ebp-0C],eax 004429F1    mov        esi,1 004429F6    mov        eax,dword ptr [ebp-8] 004429F9    call       @LStrLen 004429FE    cmp        eax,1>00442A01    jl         00442A20 00442A03    mov        edx,dword ptr [ebp-8] 00442A06    movzx      edx,byte ptr [edx+esi-1] 00442A0B    mov        ecx,dword ptr [ebp-8] 00442A0E    movzx      ecx,byte ptr [ecx+eax-1] 00442A13    imul       edx,ecx 00442A16    imul       edx,edi 00442A19    add        ebx,edx 00442A1B    dec        eax 00442A1C    test       eax,eax<00442A1E    jne        00442A03 00442A20    inc        esi 00442A21    dec        dword ptr [ebp-0C]<00442A24    jne        004429F6 00442A26    mov        eax,ebx 00442A28    cdq 00442A29    xor        eax,edx 00442A2B    sub        eax,edx 00442A2D    mov        ecx,0A2C2A 00442A32    cdq 00442A33    idiv       eax,ecx 00442A35    mov        ebx,edx 00442A37    mov        eax,dword ptr [ebp-4] 00442A3A    mov        ecx,59 00442A3F    cdq 00442A40    idiv       eax,ecx 00442A42    mov        ecx,eax 00442A44    mov        eax,dword ptr [ebp-4] 00442A47    mov        esi,50 00442A4C    cdq 00442A4D    idiv       eax,esi 00442A4F    add        ecx,edx 00442A51    inc        ecx 00442A52    mov        dword ptr [ebp-4],ecx 00442A55    cmp        ebx,dword ptr [ebp-4]>00442A58    jne        00442A5E 00442A5A    mov        bl,1>00442A5C    jmp        00442A64 00442A5E    xor        ebx,ebx>00442A60    jmp        00442A64 00442A62    xor        ebx,ebx 00442A64    xor        eax,eax 00442A66    pop        edx 00442A67    pop        ecx 00442A68    pop        ecx 00442A69    mov        dword ptr fs:[eax],edx 00442A6C    push       442A81 00442A71    lea        eax,[ebp-8] 00442A74    call       @LStrClr 00442A79    ret<00442A7A    jmp        @HandleFinally<00442A7F    jmp        00442A71 00442A81    mov        eax,ebx 00442A83    pop        edi 00442A84    pop        esi 00442A85    pop        ebx 00442A86    mov        esp,ebp 00442A88    pop        ebp 00442A89    ret

然后在OD中F8单步调试详细分析:

004429A8  /$  55            push ebp                                 ;  // reg和again 关键Call004429A9  |.  8BEC          mov ebp,esp004429AB  |.  83C4 F4       add esp,-0xC004429AE  |.  53            push ebx004429AF  |.  56            push esi004429B0  |.  57            push edi004429B1  |.  894D F8       mov [local.2],ecx004429B4  |.  8955 FC       mov [local.1],edx                        ;  // edx=123321转整数004429B7  |.  8BF8          mov edi,eax                              ;  // edi=eax=0004429B9  |.  8B45 F8       mov eax,[local.2]004429BC  |.  E8 2712FCFF   call 00403BE8                            ;  LStrAddRef004429C1  |.  33C0          xor eax,eax004429C3  |.  55            push ebp004429C4  |.  68 7A2A4400   push 00442A7A004429C9  |.  64:FF30       push dword ptr fs:[eax]004429CC  |.  64:8920       mov dword ptr fs:[eax],esp004429CF  |.  8B45 F8       mov eax,[local.2]                        ;  bbdxf004429D2  |.  E8 5D10FCFF   call 00403A34                            ;  @LStrLen004429D7  |.  83F8 04       cmp eax,0x4004429DA  |.  0F8E 82000000 jle 00442A62                             ;  必须 > 4004429E0  |.  33DB          xor ebx,ebx                              ;  // ebx=0004429E2  |.  8B45 F8       mov eax,[local.2]004429E5  |.  E8 4A10FCFF   call 00403A34                            ;  @LStrLen004429EA  |.  85C0          test eax,eax004429EC  |.  7E 38         jle short 00442A26004429EE  |.  8945 F4       mov [local.3],eax004429F1  |.  BE 01000000   mov esi,0x1004429F6  |>  8B45 F8       /mov eax,[local.2]004429F9  |.  E8 3610FCFF   |call 00403A34                           ;  @LStrLen004429FE  |.  83F8 01       |cmp eax,0x100442A01  |.  7C 1D         |jl short 00442A2000442A03  |>  8B55 F8       |/mov edx,[local.2]00442A06  |.  0FB65432 FF   ||movzx edx,byte ptr ds:[edx+esi-0x1]    ;  // 从第一个字符开始00442A0B  |.  8B4D F8       ||mov ecx,[local.2]00442A0E  |.  0FB64C01 FF   ||movzx ecx,byte ptr ds:[ecx+eax-0x1]    ;  // 最后一个字符00442A13  |.  0FAFD1        ||imul edx,ecx                           ;  // 第一个字符乘上最后一个--00442A16  |.  0FAFD7        ||imul edx,edi                           ;  // edi=0, 所以结果一直为000442A19  |.  03DA          ||add ebx,edx                            ;  // ebx=0, 所以结果一直为000442A1B  |.  48            ||dec eax                                ;  // len--00442A1C  |.  85C0          ||test eax,eax00442A1E  |.^ 75 E3         |\jnz short 00442A0300442A20  |>  46            |inc esi00442A21  |.  FF4D F4       |dec [local.3]                           ;  // len--00442A24  |.^ 75 D0         \jnz short 004429F6                      ;  // 整个循环结束,edx=0,ebx=000442A26  |>  8BC3          mov eax,ebx00442A28  |.  99            cdq00442A29  |.  33C2          xor eax,edx                              ;  // eax=0,edx=000442A2B  |.  2BC2          sub eax,edx00442A2D  |.  B9 2A2C0A00   mov ecx,0xA2C2A00442A32  |.  99            cdq00442A33  |.  F7F9          idiv ecx                                 ;  // eax/ecx00442A35  |.  8BDA          mov ebx,edx                              ;  // 这里以上的计算结果都一定是000442A37  |.  8B45 FC       mov eax,[local.1]                        ;  // 序列号转整数,从这里开始才是有意义的计算00442A3A  |.  B9 59000000   mov ecx,0x5900442A3F  |.  99            cdq                                      ;  // edx=000442A40  |.  F7F9          idiv ecx                                 ;  // eax=eax/0x5900442A42  |.  8BC8          mov ecx,eax                              ;  // 存储结果到ecx00442A44  |.  8B45 FC       mov eax,[local.1]00442A47  |.  BE 50000000   mov esi,0x5000442A4C  |.  99            cdq00442A4D  |.  F7FE          idiv esi                                 ;  // eax=eax/0x50, edx=eax % 0x5000442A4F  |.  03CA          add ecx,edx                              ;  // ecx=ecx+edx00442A51  |.  41            inc ecx                                  ;  // ecx++00442A52  |.  894D FC       mov [local.1],ecx00442A55  |.  3B5D FC       cmp ebx,[local.1]00442A58  |.  75 04         jnz short 00442A5E                       ;  // ebx等于返回值,应该为100442A5A  |.  B3 01         mov bl,0x100442A5C  |.  EB 06         jmp short 00442A6400442A5E  |>  33DB          xor ebx,ebx00442A60  |.  EB 02         jmp short 00442A6400442A62  |>  33DB          xor ebx,ebx00442A64  |>  33C0          xor eax,eax                              ;  // 都调到这里00442A66  |.  5A            pop edx00442A67  |.  59            pop ecx00442A68  |.  59            pop ecx00442A69  |.  64:8910       mov dword ptr fs:[eax],edx00442A6C  |.  68 812A4400   push 00442A8100442A71  |>  8D45 F8       lea eax,[local.2]00442A74  |.  E8 3F0DFCFF   call 004037B8                            ;  @LStrClr00442A79  \.  C3            retn00442A7A   .^ E9 F907FCFF   jmp 0040327800442A7F   .^ EB F0         jmp short 00442A7100442A81   .  8BC3          mov eax,ebx                              ;  // 返回到这里00442A83   .  5F            pop edi00442A84   .  5E            pop esi00442A85   .  5B            pop ebx00442A86   .  8BE5          mov esp,ebp00442A88   .  5D            pop ebp00442A89   .  C3            retn

请详细看上面的汇编代码的注释在地址00442A35以上部分的代码最终的结果一直为0,这个地址下面的代码才真正的有实际意义。

其中,有意义这一块的C/CPP代码大概如下:

int nCode=123321; // 用户输入的注册码,必须是4位以上,转换为整数int n1 = nCode/0x59;int n2 = nCode%0x50;if( n1+n2+1 == 0 ){    // 第一次隐藏Register按钮,显示again按钮,第二次隐藏again按钮}else{    //显示register按钮,隐藏again按钮 }

为什么我没有写出一个注册机呢?

算法原理大概是一个数除以0x59的结果加上它对于0x50取模,然后结果加上1等于0。不加1还好理解,加上1就顿时感觉蛋疼了,我实在无法找到这样一个数。(当然也不排除我理解错了,求大牛指导!!)

 

007结束。

-----------

PS: 有人说,帖子内容很难看懂,问我能否做成视频?

我想说:

首先,我的贴子都是按照我分析的流程写的,相关的工具、参考资料、代码分析、关键算法分析流程 全部都已经很详细地写下来了。只要你拿着OD和有限的几个工具,除非你真的连F7、F8分析代码都不会,否则对照我的文章肯定能看到一些有价值的东西,至少我是这么认为的。

其次,【无论多么简单的事情,想要做好,都是不容易的!】经常混论坛的都知道,爆破虽易,算法不易!确实自己水平有限,无法做到举重若轻,几分钟分析出一个算法。这种水平我真达不到!此系列文章的重头戏不在于爆破,而在于算法部分。每天破解的80%以上的时间都是在分析算法的部分,还有10%是用来整理排版帖子,虽然做的不是很好,但我问心无愧地做到了自己的承诺,尽自己所能。帖子尚且不易,视频何其远乎!我只能说声抱歉了!

最后,谢谢大家的捧场!

 

BY  笨笨D幸福