• [反汇编练习] 160个CrackMe之006


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

    本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将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,选择第6个aLoNg3x,保存下来。运行程序,程序界面如下:

    image

    这是一个典型的Name/Serial(Delphi)程序,但是,因为是Delphi的我恨死它了!

    随意输入Nome和Codice,我们发现OK没法点。好吧,我们看看About-Help,'The purpose of this CrackMe v. 1.00 by aLoNg3x is to MAKE INVISIBLE the buttons "OK" and "Cancella" in order to see the Ringzer0 logo. So you must insert the correct codes'。大概意思就是将两个按钮直接隐藏掉就算是破解了。

    看到这里我有一种不祥的预感:难道又是一个游戏?事实证明我的预感是很准的….

    讨厌也没办法,使用PEID查看:没有壳,delphi 4.0 - 5.0, 随意一个Dede或者IDR什么的都能反编译它。这里我还是选择昨天才找到的IDR。

    3、思路分析和破解流程

    遇到这种游戏类型的,根本就不可能有啥思路,直接反编译,大概地看看:

    image

    双击_CrackMe100模块,我们看到只有4个函数,codiceChange/Okclick/NomeChange/CancellaClick/AboutClick事件。除了About之外,其他的似乎我们都要跟踪。

    由于OK按钮按时不可用,我们先从codiceChange开始:

    在IDR中双击codiceChange事件,在反汇编区域找到开头地址:00442AF4,使用OD打开程序,Ctrl+G,输入这个地址,根据IDR反汇编的提示,F8调试,记录重要数据:

    00442C78  /.  55            push ebp                                 ;  //  _CrackMe100::TPrincipale.CodiceChange
    00442C79  |.  8BEC          mov ebp,esp
    00442C7B  |.  33C9          xor ecx,ecx
    00442C7D  |.  51            push ecx
    00442C7E  |.  51            push ecx
    00442C7F  |.  51            push ecx
    00442C80  |.  51            push ecx
    00442C81  |.  53            push ebx
    00442C82  |.  56            push esi
    00442C83  |.  8BD8          mov ebx,eax
    00442C85  |.  33C0          xor eax,eax
    00442C87  |.  55            push ebp
    00442C88  |.  68 562D4400   push 00442D56
    00442C8D  |.  64:FF30       push dword ptr fs:[eax]
    00442C90  |.  64:8920       mov dword ptr fs:[eax],esp
    00442C93  |.  8D55 F8       lea edx,[local.2]
    00442C96  |.  8B83 E0020000 mov eax,dword ptr ds:[ebx+0x2E0]         ;  TPrincipale.Codice:TEdit
    00442C9C  |.  E8 1F06FEFF   call 004232C0                            ;  TControl.GetText
    00442CA1  |.  8B45 F8       mov eax,[local.2]                        ;  // eax=11223
    00442CA4  |.  8D55 FC       lea edx,[local.1]
    00442CA7  |.  E8 ACFCFBFF   call 00402958                            ;  @ValLong
    00442CAC  |.  8BF0          mov esi,eax                              ;  // eax=0x2BD7=11223
    00442CAE  |.  837D FC 00    cmp [local.1],0x0
    00442CB2  |.  74 18         je short 00442CCC
    00442CB4  |.  8D55 F4       lea edx,[local.3]
    00442CB7  |.  8BC6          mov eax,esi
    00442CB9  |.  E8 8249FCFF   call 00407640                            ;  IntToStr
    00442CBE  |.  8B55 F4       mov edx,[local.3]
    00442CC1  |.  8B83 E0020000 mov eax,dword ptr ds:[ebx+0x2E0]         ;  TPrincipale.Codice:TEdit
    00442CC7  |.  E8 2406FEFF   call 004232F0
    00442CCC  |>  8B83 D0020000 mov eax,dword ptr ds:[ebx+0x2D0]         ;  TPrincipale.Cancella:TButton
    00442CD2  |.  8078 47 00    cmp byte ptr ds:[eax+0x47],0x0           ;  TButton.FVisible:Boolean
    00442CD6  |.  75 0F         jnz short 00442CE7
    00442CD8  |.  B2 01         mov dl,0x1
    00442CDA  |.  8B83 CC020000 mov eax,dword ptr ds:[ebx+0x2CC]         ;  Principale.Ok:TButton
    00442CE0  |.  8B08          mov ecx,dword ptr ds:[eax]
    00442CE2  |.  FF51 60       call dword ptr ds:[ecx+0x60]             ;  TControl.SetEnabled
    00442CE5  |.  EB 49         jmp short 00442D30
    00442CE7  |>  8D55 F8       lea edx,[local.2]
    00442CEA  |.  8B83 E0020000 mov eax,dword ptr ds:[ebx+0x2E0]         ;  TPrincipale.Codice:TEdit
    00442CF0  |.  E8 CB05FEFF   call 004232C0                            ;  TControl.GetText
    00442CF5  |.  8B45 F8       mov eax,[local.2]
    00442CF8  |.  50            push eax
    00442CF9  |.  8D55 F0       lea edx,[local.4]
    00442CFC  |.  8B83 DC020000 mov eax,dword ptr ds:[ebx+0x2DC]         ;  TPrincipale.Nome:TEdit
    00442D02  |.  E8 B905FEFF   call 004232C0                            ;  TControl.GetText
    00442D07  |.  8B45 F0       mov eax,[local.4]                        ;  eax=bbdxf
    00442D0A  |.  5A            pop edx                                  ;  11223
    00442D0B  |.  E8 2CFDFFFF   call 00442A3C                            ;  // 验证的CALL
    00442D10  |.  84C0          test al,al                               ;  al=0
    00442D12  |.  74 0F         je short 00442D23
    00442D14  |.  B2 01         mov dl,0x1
    00442D16  |.  8B83 CC020000 mov eax,dword ptr ds:[ebx+0x2CC]         ;  TPrincipale.Ok:TButton
    00442D1C  |.  8B08          mov ecx,dword ptr ds:[eax]
    00442D1E  |.  FF51 60       call dword ptr ds:[ecx+0x60]             ;  TControl.SetEnabled
    00442D21  |.  EB 0D         jmp short 00442D30
    00442D23  |>  33D2          xor edx,edx
    00442D25  |.  8B83 CC020000 mov eax,dword ptr ds:[ebx+0x2CC]         ;  TPrincipale.Ok:TButton
    00442D2B  |.  8B08          mov ecx,dword ptr ds:[eax]
    00442D2D  |.  FF51 60       call dword ptr ds:[ecx+0x60]             ;  TControl.SetEnabled
    00442D30  |>  33C0          xor eax,eax
    00442D32  |.  5A            pop edx
    00442D33  |.  59            pop ecx
    00442D34  |.  59            pop ecx
    00442D35  |.  64:8910       mov dword ptr fs:[eax],edx
    00442D38  |.  68 5D2D4400   push 00442D5D
    00442D3D  |>  8D45 F0       lea eax,[local.4]
    00442D40  |.  E8 730AFCFF   call 004037B8                            ;  @LStrClr
    00442D45  |.  8D45 F4       lea eax,[local.3]
    00442D48  |.  E8 6B0AFCFF   call 004037B8                            ;  @LStrClr
    00442D4D  |.  8D45 F8       lea eax,[local.2]
    00442D50  |.  E8 630AFCFF   call 004037B8                            ;  @LStrClr
    00442D55  .  C3            retn
    00442D56   .^ E9 1D05FCFF   jmp 00403278
    00442D5B   .^ EB E0         jmp short 00442D3D
    00442D5D   .  5E            pop esi
    00442D5E   .  5B            pop ebx
    00442D5F   .  8BE5          mov esp,ebp
    00442D61   .  5D            pop ebp
    00442D62   .  C3            retn

    发现除了Call 00442A3C  其它的都有具体含义,并且当这个call的返回值不为0时,OK按钮会被设置为Enable,看来关键Call就是它了!F7跟进去:

    00442A3C  /$  55            push ebp                                 ;  // 一个子函数
    00442A3D  |.  8BEC          mov ebp,esp
    00442A3F  |.  83C4 F8       add esp,-0x8
    00442A42  |.  53            push ebx
    00442A43  |.  56            push esi
    00442A44  |.  8955 F8       mov [local.2],edx
    00442A47  |.  8945 FC       mov [local.1],eax
    00442A4A  |.  8B45 FC       mov eax,[local.1]
    00442A4D  |.  E8 9611FCFF   call 00403BE8                            ;  // 引用计数CALL
    00442A52  |.  8B45 F8       mov eax,[local.2]
    00442A55  |.  E8 8E11FCFF   call 00403BE8
    00442A5A  |.  33C0          xor eax,eax
    00442A5C  |.  55            push ebp
    00442A5D  |.  68 E52A4400   push 00442AE5
    00442A62  |.  64:FF30       push dword ptr fs:[eax]
    00442A65  |.  64:8920       mov dword ptr fs:[eax],esp
    00442A68  |.  8B45 FC       mov eax,[local.1]                        ;  bbdxf
    00442A6B  |.  E8 C40FFCFF   call 00403A34                            ;  @LStrLen
    00442A70  |.  83F8 05       cmp eax,0x5                              ;  // len  > 5
    00442A73  |.  7E 53         jle short 00442AC8
    00442A75  |.  8B45 FC       mov eax,[local.1]
    00442A78  |.  E8 B70FFCFF   call 00403A34
    00442A7D  |.  8BD8          mov ebx,eax                              ;  // eax=6
    00442A7F  |.  8B45 FC       mov eax,[local.1]                        ;  // eax = bbdxf6
    00442A82  |.  E8 AD0FFCFF   call 00403A34
    00442A87  |.  8BD0          mov edx,eax                              ;  edx=len
    00442A89  |.  4A            dec edx                                  ;  edx--
    00442A8A  |.  85D2          test edx,edx
    00442A8C  |.  7E 20         jle short 00442AAE
    00442A8E  |.  B8 01000000   mov eax,0x1                              ;  // eax==1,序号
    00442A93  |>  8B4D FC       /mov ecx,[local.1]                       ;  // bbdxf6
    00442A96  |.  0FB64C01 FF   |movzx ecx,byte ptr ds:[ecx+eax-0x1]     ;  // 取一个字符,现在是第一个
    00442A9B  |.  8B75 FC       |mov esi,[local.1]
    00442A9E  |.  0FB63406      |movzx esi,byte ptr ds:[esi+eax]         ;  // 取第二个字符
    00442AA2  |.  0FAFCE        |imul ecx,esi                            ;  // esi=62,ecx=62,乘法
    00442AA5  |.  0FAFC8        |imul ecx,eax                            ;  // ecx*eax=62*62*1
    00442AA8  |.  03D9          |add ebx,ecx                             ;  // ebx=len; ebx+=ecx
    00442AAA  |.  40            |inc eax                                 ;  // eax++
    00442AAB  |.  4A            |dec edx                                 ;  // edx--
    00442AAC  |.^ 75 E5         jnz short 00442A93
    00442AAE  |>  8B45 F8       mov eax,[local.2]                        ;  // eax= 6, ebx=0002298E
    00442AB1  |.  E8 BA4BFCFF   call 00407670                            ;  StrToInt
    00442AB6  |.  2BD8          sub ebx,eax                              ;  // eax=000419C4=268740,ebx-eax
    00442AB8  |.  81FB 9A020000 cmp ebx,0x29A                            ;  // 差==0x29A
    00442ABE      75 04         jnz short 00442AC4
    00442AC0  |.  B3 01         mov bl,0x1                               ;  // 可见
    00442AC2  |.  EB 06         jmp short 00442ACA
    00442AC4  |>  33DB          xor ebx,ebx                              ;  // 不可见
    00442AC6  |.  EB 02         jmp short 00442ACA
    00442AC8  |>  33DB          xor ebx,ebx

    这一块的算法类似于:

    char Nome[] = "bbdxf6" // eax
    char code[] = "112233"
    int nLen = strlen(Nome); // esi
    int nRet = nLen;  // ebx
    for( int i=1;i<nLen;i++)
    {
    	nRet += Nome[i-1]*Nome[i]*i;
    }
    nRet -= atoi(code);
    if( nRet == 0x29A )
    {
    	// 返回0x01,OK按钮可以使用
    }else{
    	// 返回0,OK按钮禁止使用
    }

    当然,爆破可以直接在这个关键CALL之后将JE使用NOP替代。

    下面同样方法进行OK按钮的事件处理:

    00442D64  /.  55            push ebp                                 ;   //_CrackMe100::TPrincipale.OkClick
    00442D65  |.  8BEC          mov ebp,esp
    00442D67  |.  6A 00         push 0x0
    00442D69  |.  53            push ebx
    00442D6A  |.  8BD8          mov ebx,eax
    00442D6C  |.  33C0          xor eax,eax
    00442D6E  |.  55            push ebp
    00442D6F  |.  68 ED2D4400   push 00442DED
    00442D74  |.  64:FF30       push dword ptr fs:[eax]
    00442D77  |.  64:8920       mov dword ptr fs:[eax],esp
    00442D7A  |.  8B83 D0020000 mov eax,dword ptr ds:[ebx+0x2D0]         ;  TPrincipale.Cancella:TButton
    00442D80  |.  8078 47 01    cmp byte ptr ds:[eax+0x47],0x1           ;  TButton.FVisible:Boolean
    00442D84  |.  75 12         jnz short 00442D98                       ;  // 判断cancle按钮是否被隐藏了
    00442D86  |.  BA 002E4400   mov edx,00442E00                         ;  UNICODE "0"
    00442D8B  |.  8B83 E0020000 mov eax,dword ptr ds:[ebx+0x2E0]         ;  TPrincipale.Codice:TEdit
    00442D91      E8 5A05FEFF   call 004232F0                            ;  TControl.SetText
    00442D96      EB 3F         jmp short 00442DD7
    00442D98  |>  8D55 FC       lea edx,[local.1]
    00442D9B  |.  8B83 E0020000 mov eax,dword ptr ds:[ebx+0x2E0]         ;  TPrincipale.Codice:TEdit
    00442DA1  |.  E8 1A05FEFF   call 004232C0                            ;  TControl.GetText
    00442DA6  |.  8B45 FC       mov eax,[local.1]
    00442DA9  |.  E8 C248FCFF   call 00407670                            ;  StrToInt
    00442DAE  |.  50            push eax
    00442DAF  |.  8D55 FC       lea edx,[local.1]
    00442DB2  |.  8B83 DC020000 mov eax,dword ptr ds:[ebx+0x2DC]         ;  TPrincipale.Nome:TEdit
    00442DB8  |.  E8 0305FEFF   call 004232C0                            ;  TControl.GetText
    00442DBD  |.  8B45 FC       mov eax,[local.1]
    00442DC0  |.  5A            pop edx
    00442DC1  |.  E8 DAFDFFFF   call 00442BA0                            ;  // 关键检测call
    00442DC6  |.  84C0          test al,al
    00442DC8  |.  74 0D         je short 00442DD7
    00442DCA  |.  33D2          xor edx,edx
    00442DCC  |.  8B83 CC020000 mov eax,dword ptr ds:[ebx+0x2CC]         ;  TPrincipale.Ok:TButton
    00442DD2  |.  E8 D903FEFF   call 004231B0                            ;  TControl.SetVisible
    00442DD7  |>  33C0          xor eax,eax
    00442DD9  |.  5A            pop edx
    00442DDA  |.  59            pop ecx
    00442DDB  |.  59            pop ecx
    00442DDC  |.  64:8910       mov dword ptr fs:[eax],edx
    00442DDF  |.  68 F42D4400   push 00442DF4
    00442DE4  |>  8D45 FC       lea eax,[local.1]
    00442DE7  |.  E8 CC09FCFF   call 004037B8                            ;  @LStrClr
    00442DEC  .  C3            retn
    00442DED   .^ E9 8604FCFF   jmp 00403278
    00442DF2   .^ EB F0         jmp short 00442DE4
    00442DF4   .  5B            pop ebx
    00442DF5   .  59            pop ecx
    00442DF6   .  5D            pop ebp
    00442DF7   .  C3            retn

    关键CALL的分析:

    00442BE8  |. /7E 60         jle short 00442C4A
    00442BEA  |. |8B45 F8       mov eax,[local.2]                        ;  141044
    00442BED  |. |E8 420EFCFF   call 00403A34                            ;  StrLen
    00442BF2  |. |8BF0          mov esi,eax
    00442BF4  |. |83FE 01       cmp esi,0x1
    00442BF7  |. |7C 2F         jl short 00442C28
    00442BF9  |> |8D45 F4       /lea eax,[local.3]
    00442BFC  |. |E8 0310FCFF   |call 00403C04                           ;  // 检查string引用
    00442C01  |. |8D4430 FF     |lea eax,dword ptr ds:[eax+esi-0x1]      ;  // esi=len
    00442C05  |. |50            |push eax
    00442C06  |. |8B45 F8       |mov eax,[local.2]
    00442C09  |. |0FB64430 FF   |movzx eax,byte ptr ds:[eax+esi-0x1]     ;  // 最后一个
    00442C0E  |. |F7E8          |imul eax                                ;  eax=eax*eax
    00442C10  |. |0FBFC0        |movsx eax,ax                            ;  // eax=a90; 只要低16位
    00442C13  |. |F7EE          |imul esi                                ;  // eax*len--
    00442C15  |. |B9 19000000   |mov ecx,0x19                            ;  // ecx=0x19
    00442C1A  |. |99            |cdq
    00442C1B  |. |F7F9          |idiv ecx                                ;  // 除以ecx,eax=整除值,edx=Mod值
    00442C1D  |. |83C2 41       |add edx,0x41                            ;  // edx=mod之后+0x14
    00442C20  |. |58            |pop eax
    00442C21  |. |8810          |mov byte ptr ds:[eax],dl
    00442C23  |. |4E            |dec esi
    00442C24  |. |85F6          |test esi,esi
    00442C26  |.^|75 D1         jnz short 00442BF9
    00442C28  |> |8B45 F4       mov eax,[local.3]                        ;  BIDQUY
    00442C2B  |. |8B55 FC       mov edx,[local.1]                        ;  bbdxf6
    00442C2E  |. |E8 110FFCFF   call 00403B44                            ;  strcmp
    00442C33     |75 17         jnz short 00442C4C
    00442C35  |. |8B45 FC       mov eax,[local.1]
    00442C38  |. |8B55 F4       mov edx,[local.3]
    00442C3B  |. |E8 040FFCFF   call 00403B44
    00442C40  |. |75 04         jnz short 00442C46
    00442C42  |. |B3 01         mov bl,0x1
    00442C44  |. |EB 06         jmp short 00442C4C
    00442C46  |> |33DB          xor ebx,ebx
    00442C48  |. |EB 02         jmp short 00442C4C

    这一块的算法类似于:

    char Nome[] = "bbdxf6" // eax
    char code[] = "112233"
    int nLen = strlen(Nome); // esi
    int nRet = 0;  // eax
    for( int i=0;i<nLen;i++)
    {
    	int nTmp = Nome[nLen-1-i]*Nome[nLen-1-i]*(nLen-i);
    	nRet = nTmp%0x19 + 0x41; // 转换为大写字母
    	Nome[nLen-1-i] = nRet;
    }
    int nrt = strCmp("bbdxf6",Nome); //x2,两次比较原始字符串和生成后的字符串是否相同
    
    if( nrt == 0 )
    {
    	// 返回0x01,OK按钮隐藏
    }else{
    	// 返回0,OK按钮显示
    }
    

    到这里我就停下来了。为什么?因为有一种被戏耍的感觉。他这个游戏大概应该是这样的:

    1、先根据Nome和Codice的值满足第一个算法,则OK按钮变为可以点击。-- 算法1

    2、再根据Nome和Codice满足第二个算法,则OK会被隐藏。-- 算法2

    3、Nome满足第三种算法时,点击Cancella按钮,Cancella按钮会隐藏。-- 算法3

    这样,才会实现作者说的把两个按钮都隐藏了的效果。这都不是关键!关键是不借助任何东西找到同时满足这三种算法的Nome和Codice的几率和买体彩中头奖的概率差不多了!

    次篇文章就到这里了!感兴趣的可继续跟踪其他的2个事件,结构和关键CAll都和这两个结构差不多(为什么我知道,因为我已经看过了!哈哈)。

    4、注册机的探索

    见3,那里已经分析了。

    PS:我讨厌反汇编Delphi,特别讨厌它们以游戏方式写的CrackMe。

    BY  笨笨D幸福

  • 相关阅读:
    cocoapods使用遇到的一些问题
    so
    UITextField的各种属性方法介绍
    <<第1章 初识JAVA>>
    《第16章 复习》
    《第17章 图书管理系统》
    《第15章 字符串》
    《第13章 猜拳游戏》
    《第14章 带参数的方法》
    《第12章 类的无参方法》
  • 原文地址:https://www.cnblogs.com/bbdxf/p/3788289.html
Copyright © 2020-2023  润新知