首页
社区
课程
招聘
[原创]小菜分析的第一个CrackMe
发表于: 2007-12-5 09:05 8129

[原创]小菜分析的第一个CrackMe

petnt 活跃值
12
2007-12-5 09:05
8129

【文章标题】: 小菜分析的第一个CrackMe
【文章作者】: petnt
【作者邮箱】: petnt@sohu.com
【软件名称】: TheBigMan's CrackMe #6
【软件大小】: 8K
【下载地址】: 见附件
【使用工具】: OLLYDBG MASM32
【操作平台】: XP SP2
【作者声明】: 如果你和我一样也是刚刚入门,第一次接触CrackMe,就进来看看交流一下。大侠请略过!
--------------------------------------------------------------------------------
【详细过程】
  前两天下了PEDIY CrackME 2007精华集(上网时间不多,所以好多事情都慢人一步),按照kanxue老大的要求,一切从头学起。看完简介,第一篇为4nil大侠2005-02-17完成的大作。(汗!马上08年了,差距太大了,只能用那句话鼓励自己:从下一秒开始,一切都不会晚!)看了他的软件简介,看来是个不错的CrackMe,就从这个开始吧。
  同样按照老大的要求,没有继续看他的破解过程。直接下了附件,正式开战!

  为了便于总结和以后复习以及小菜们更容易看清整个过程,下面将整个过程分为三部分:下断、分析 和编写注册机。

  第一部分  下断

  打开CrackMe,随便输入用户名、序列号,点击Check,没有反应。好了,不管这么多,右键请出我的OLLYDBG,程序顺利地停在了入口处。
  不管3721,Command: bpx GetWindowTextA。晕,No references。右键,查找,当前模块中的名称。再晕,只看到3个api,GetModuleHandleA,GetProcAddress,LoadLibraryA。看来我们遇到麻烦了,OllyDBG并没有提示我有壳,难道是作者把所有API都自己读入?还是在故意在隐藏什么?不管他,当程序运行以后,总该能让我们看到什么吧,F9。界面出来了,好,Alt+W,在Check上设LEFTBUTTONUP的消息断点。Alt+M,在代码段设内存访问断点。设置好之后,准备输入用户名,鼠标刚到窗口,程序就被断了下来。

004015A1  /.  55            push    ebp                         ;断在了这里
004015A2  |.  89E5          mov     ebp, esp
004015A4  |.  83EC 3C       sub     esp, 3C
004015A7  |.  53            push    ebx
004015A8  |.  56            push    esi
004015A9  |.  57            push    edi
004015AA  |.  8B45 0C       mov     eax, [ebp+C]
004015AD  |.  83F8 10       cmp     eax, 10                 ;  Switch (cases 10..111)
004015B0  |.  0F84 BB000000 je      00401671
004015B6  |.  0F8C C4000000 jl      00401680
004015BC  |.  3D 10010000   cmp     eax, 110
004015C1  |.  74 0C         je      short 004015CF
004015C3  |.  3D 11010000   cmp     eax, 111
004015C8  |.  74 1E         je      short 004015E8
004015CA  |.  E9 B1000000   jmp     00401680
004015CF  |>  FF75 14       push    dword ptr [ebp+14]      ;  Case 110 (WM_INITDIALOG) of switch 004015AD
004015D2  |.  FF75 10       push    dword ptr [ebp+10]
004015D5  |.  FF75 08       push    dword ptr [ebp+8]
004015D8  |.  E8 C0FFFFFF   call    0040159D
004015DD  |.  83C4 0C       add     esp, 0C
004015E0  |.  31C0          xor     eax, eax
004015E2  |.  40            inc     eax
004015E3  |.  E9 9A000000   jmp     00401682
004015E8  |>  0FB745 10     movzx   eax, word ptr [ebp+10]  ;  Case 111 (WM_COMMAND) of switch 004015AD
004015EC  |.  25 FFFF0000   and     eax, 0FFFF
004015F1  |.  83F8 01       cmp     eax, 1                  ;  Switch (cases 1..3)   Check按钮
004015F4  |.  74 0C         je      short 00401602
004015F6  |.  83F8 02       cmp     eax, 2                  ;                        Exit按钮
004015F9  |.  74 6A         je      short 00401665
004015FB  |.  83F8 03       cmp     eax, 3                  ;                        About按钮
004015FE  |.  74 43         je      short 00401643
00401600  |.  EB 7E         jmp     short 00401680
00401602  |>  8D7D D3       lea     edi, [ebp-2D]           ;  Case 1 of switch 004015F1
00401605  |.  8D35 5E254000 lea     esi, [40255E]
0040160B  |.  B9 29000000   mov     ecx, 29
00401610  |.  F3:A4         rep     movs byte ptr es:[edi],>
00401612  |.  8D7D C7       lea     edi, [ebp-39]
00401615  |.  8D35 87254000 lea     esi, [402587]
0040161B  |.  B9 03000000   mov     ecx, 3
00401620  |.  F3:A5         rep     movs dword ptr es:[edi]>
00401622  |.  FF75 08       push    dword ptr [ebp+8]
00401625  |.  E8 DFFEFFFF   call    00401509                ; 关键函数
0040162A  |.  59            pop     ecx
0040162B  |.  09C0          or      eax, eax
0040162D  |.  74 53         je      short 00401682          ; 关键点
0040162F  |.  6A 40         push    40                      ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
00401631  |.  8D45 C7       lea     eax, [ebp-39]           ; |
00401634  |.  50            push    eax                     ; |Title
00401635  |.  8D45 D3       lea     eax, [ebp-2D]           ; |
00401638  |.  50            push    eax                     ; |Text
00401639  |.  FF75 08       push    dword ptr [ebp+8]       ; |hOwner
0040163C  |.  E8 1B010000   call    0040175C                ; \MessageBoxA
00401641  |.  EB 3D         jmp     short 00401680
00401643  |>  8D05 0E264000 lea     eax, [40260E]           ;  Case 3 of switch 004015F1
00401649  |.  8945 F8       mov     [ebp-8], eax
0040164C  |.  8D05 93254000 lea     eax, [402593]
00401652  |.  8945 F4       mov     [ebp-C], eax
00401655  |.  6A 40         push    40                      ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
00401657  |.  FF75 F8       push    dword ptr [ebp-8]       ; |Title
0040165A  |.  50            push    eax                     ; |Text => "You have to make an own working keygen!",LF,"Send the solutions to: t.h.e.b.i.g.m.a.n@gmx.net",LF,"Patching is not allowed!",LF,LF,"Enjoy !"
0040165B  |.  FF75 08       push    dword ptr [ebp+8]       ; |hOwner
0040165E  |.  E8 F9000000   call    0040175C                ; \MessageBoxA
00401663  |.  EB 1B         jmp     short 00401680
00401665  |>  6A 01         push    1                       ; /Result = 1; Case 2 of switch 004015F1
00401667  |.  FF75 08       push    dword ptr [ebp+8]       ; |hWnd
0040166A  |.  E8 B1000000   call    00401720                ; \EndDialog
0040166F  |.  EB 0F         jmp     short 00401680
00401671  |>  6A 00         push    0                       ; /Result = 0; Case 10 (WM_CLOSE) of switch 004015AD
00401673  |.  FF75 08       push    dword ptr [ebp+8]       ; |hWnd
00401676  |.  E8 A5000000   call    00401720                ; \EndDialog
0040167B  |.  31C0          xor     eax, eax
0040167D  |.  40            inc     eax
0040167E  |.  EB 02         jmp     short 00401682
00401680  |>  31C0          xor     eax, eax                ;  Default case of switch 004015F1
00401682  |>  5F            pop     edi
00401683  |.  5E            pop     esi
00401684  |.  5B            pop     ebx
00401685  |.  C9            leave
00401686  \.  C2 1000       retn    10

  看来上面就是消息处理函数了,OLLY注释的已经很清楚了。我们很轻易的可以找到按钮的消息处理过程,界面上共有3个按钮,WM_COMMAND下共有3个分支。根据跳转的位置我们可以分析出第一分支就是我们要找的Check的处理过程,第2、3分别为 Exit 和 About。我们关心的分支中只有一个自定义Call,紧跟着这个Call就是一个判断跳转,在这个Call上设断点。更改je 为 jne ,F9,我们期待的对话框就出来了。看来我们的那个Call就是关键了。删除其他断点,输入用户名、注册码,check。

  第二部分  分析
  
  正如我们期待的那样,程序断在了我们下断的Call上。F7,跟进。

00401509  /$  55            push    ebp                   ;  important Call
0040150A  |.  89E5          mov     ebp, esp
0040150C  |.  81EC 00010000 sub     esp, 100
00401512  |.  53            push    ebx
00401513  |.  56            push    esi
00401514  |.  57            push    edi
00401515  |.  8DBD 00FFFFFF lea     edi, [ebp-100]
0040151B  |.  8D35 5E244000 lea     esi, [40245E]
00401521  |.  B9 40000000   mov     ecx, 40
00401526  |.  F3:A5         rep     movs dword ptr es:[ed>
00401528  |.  68 00010000   push    100                   ; /Count = 100 (256.)
0040152D  |.  8D85 00FFFFFF lea     eax, [ebp-100]        ; |
00401533  |.  50            push    eax                   ; |Buffer
00401534  |.  6A 65         push    65                    ; |ControlID = 65 (101.)
00401536  |.  FF75 08       push    dword ptr [ebp+8]     ; |hWnd
00401539  |.  E8 FA010000   call    00401738              ; \GetDlgItemTextA
0040153E  |.  89C3          mov     ebx, eax              ;  获取用户名,EAX中为用户名字符数
00401540  |.  09DB          or      ebx, ebx
00401542  |.  75 04         jnz     short 00401548        ;  用户名字符数不为0则跳下计算
00401544  |.  31C0          xor     eax, eax
00401546  |.  EB 50         jmp     short 00401598        ;  用户名为0跳走
00401548  |>  BF BC020000   mov     edi, 2BC              ;  700d
0040154D  |.  BE 30000000   mov     esi, 30               ;  48d
00401552  |.  B8 48000000   mov     eax, 48               ;  72d
00401557  |.  99            cdq                           ;  Eax符号扩展 符号位扩展到Edx中
00401558  |.  F7FB          idiv    ebx                   ;  eax/ebx 商在eax 中  余数在edx
0040155A  |.  29C6          sub     esi, eax              ;  esi=固定数30h-(固定数 48h/用户名字符数)
0040155C  |.  8D34B6        lea     esi, [esi+esi*4]      ;  esi=esi+esi*4
0040155F  |.  29F7          sub     edi, esi              ;  edi=edi-esi
00401561  |.  6BFF 6B       imul    edi, edi, 6B          ;  edi=edi*6bh
00401564  |.  81EF 6CCF0000 sub     edi, 0CF6C            ;  edi=edi-0cf6ch
0040156A  |.  81FF 00230000 cmp     edi, 2300             ;  edi=2300h?(由此可向上反推用户名字符数=3)
00401570  |.  7F 08         jg      short 0040157A        ;  用户名字符数<3 则跳出
00401572  |.  81FF 90010000 cmp     edi, 190              ;  反推用户名字符数为9
00401578  |.  7D 04         jge     short 0040157E        ;  用户名字符数>9则跳出
0040157A  |>  31C0          xor     eax, eax
0040157C  |.  EB 1A         jmp     short 00401598
0040157E  |>  8D85 00FFFFFF lea     eax, [ebp-100]        ;  eax=用户名地址
00401584  |.  50            push    eax                   ;  用户名地址
00401585  |.  53            push    ebx                   ;  用户名字符数
00401586  |.  FF75 08       push    dword ptr [ebp+8]     ;  对话框HWND
00401589  |.  E8 77FDFFFF   call    00401305              ;  关键 用户名变换与注册码比较函数
0040158E  |.  83C4 0C       add     esp, 0C
00401591  |.  09C0          or      eax, eax
00401593  |.  74 03         je      short 00401598
00401595  |.  31C0          xor     eax, eax
00401597  |.  40            inc     eax
00401598  |>  5F            pop     edi
00401599  |.  5E            pop     esi
0040159A  |.  5B            pop     ebx
0040159B  |.  C9            leave
0040159C  \.  C3            retn
  
  分析此函数可看出,这个函数在读取了用户名后,对用户名长度进行了变换和比较,用户名长度符合作者要求之后,程序进入了下一个关键的Call。这个函数中用户名长度变换比较过程分析整理如下:
  设 n=用户名长度,则n必须满足:2300H<{2bcH-[30H-int(48H/n)]*5}*6bH-0cfbcH<190H。
  晕,还是一道比较复杂的数学题。还好学过数学,由上式可得符合条件的n:3<=n<=9。
  分析完毕,F7,进入下一个Call。
  
00401305  /$  55            push    ebp
00401306  |.  89E5          mov     ebp, esp
00401308  |.  81EC 2C040000 sub     esp, 42C
0040130E  |.  53            push    ebx
0040130F  |.  56            push    esi
00401310  |.  57            push    edi
00401311  |.  8DBD FCFEFFFF lea     edi, [ebp-104]                ;  目的操作数地址 ebp-104
00401317  |.  8D35 38204000 lea     esi, [402038]                 ;  源操作数地址 [402038]
0040131D  |.  B9 40000000   mov     ecx, 40                       ;  循环次数 40h
00401322  |.  F3:A5         rep     movs dword ptr es:[edi], dwor>;  一次操作大小DWORD
00401324  |.  8DBD E1FBFFFF lea     edi, [ebp-41F]
0040132A  |.  8D35 38214000 lea     esi, [402138]                 ;  源操作数地址[402138]
00401330  |.  B9 40000000   mov     ecx, 40                       ;  40h
00401335  |.  F3:A5         rep     movs dword ptr es:[edi], dwor>;  DWORD
00401337  |.  8DBD E1FDFFFF lea     edi, [ebp-21F]                ;  后面要用到
0040133D  |.  8D35 38224000 lea     esi, [402238]                 ;  [402238]
00401343  |.  B9 40000000   mov     ecx, 40                       ;  40h
00401348  |.  F3:A5         rep     movs dword ptr es:[edi], dwor>;  DWORD
0040134A  |.  8DBD E1FCFFFF lea     edi, [ebp-31F]
00401350  |.  8D35 38234000 lea     esi, [402338]                 ;  [402338]
00401356  |.  B9 40000000   mov     ecx, 40                       ;  40h
0040135B  |.  F3:A5         rep     movs dword ptr es:[edi], dwor>;  DWORD
0040135D  |.  8DBD DCFBFFFF lea     edi, [ebp-424]
00401363  |.  8D35 38244000 lea     esi, [402438]                 ;  [402438] 内容为“%c%s”
00401369  |.  B9 05000000   mov     ecx, 5                        ;  5h
0040136E  |.  F3:A4         rep     movs byte ptr es:[edi], byte >;  Byte
00401370  |.  8DBD D6FBFFFF lea     edi, [ebp-42A]
00401376  |.  8D35 3D244000 lea     esi, [40243D]                 ;  [40243D] 内容为“%s-%d”
0040137C  |.  B9 03000000   mov     ecx, 3                        ;  3h
00401381  |.  F3:66:A5      rep     movs word ptr es:[edi], word >;  Word
00401384  |.  8DBD E1FEFFFF lea     edi, [ebp-11F]
0040138A  |.  8D35 43244000 lea     esi, [402443]                 ;  [402443] 内容为“A……Z”
00401390  |.  B9 1B000000   mov     ecx, 1B                       ;  1bh
00401395  |.  F3:A4         rep     movs byte ptr es:[edi], byte >;  Byte
00401397  |.  C745 FC 00000>mov     dword ptr [ebp-4], 0          ;  [ebp-4]=0 以备后用
0040139E  |.  68 00010000   push    100                           ; /Count = 100 (256.)
004013A3  |.  8D85 E1FCFFFF lea     eax, [ebp-31F]                ; |
004013A9  |.  50            push    eax                           ; |Buffer
004013AA  |.  6A 66         push    66                            ; |ControlID = 66 (102.)
004013AC  |.  FF75 08       push    dword ptr [ebp+8]             ; |hWnd
004013AF  |.  E8 84030000   call    00401738                      ; \GetDlgItemTextA
004013B4  |.  09C0          or      eax, eax                      ;  获取注册码 eax中为注册码字符数
004013B6  |.  0F84 48010000 je      00401504                      ;  注册码字符数=0则跳走
004013BC  |.  B8 CF110000   mov     eax, 11CF                     ;  eax=11cfh
004013C1  |.  0FB68D E1FCFF>movzx   ecx, byte ptr [ebp-31F]       ;  ecx=注册码第一位
004013C8  |.  99            cdq
004013C9  |.  F7F9          idiv    ecx
004013CB  |.  83FA 17       cmp     edx, 17
004013CE  |.  74 07         je      short 004013D7                ;  11cfh/s0 余数不等17则跳走
004013D0  |.  31C0          xor     eax, eax
004013D2  |.  E9 2D010000   jmp     00401504
004013D7  |>  31DB          xor     ebx, ebx                      ;  ebx=0 准备循环
004013D9  |.  EB 0B         jmp     short 004013E6
004013DB  |>  8B45 10       /mov     eax, [ebp+10]                ;  这个循环为计算
004013DE  |.  0FBE0418      |movsx   eax, byte ptr [eax+ebx]      ;  用户名所有字符ASCII码相加之和
004013E2  |.  0145 FC       |add     [ebp-4], eax                 ;  将这个计算值保存于[EBP-4]处
004013E5  |.  43            |inc     ebx                          ;  以备后用
004013E6  |>  3B5D 0C        cmp     ebx, [ebp+C]
004013E9  |.^ 7C F0         \jl      short 004013DB               ;  循环结束
004013EB  |.  31DB          xor     ebx, ebx                      ;  ebx=0 准备下一个循环
004013ED  |.  E9 83000000   jmp     00401475
004013F2  |>  8B55 10       /mov     edx, [ebp+10]                ;  edx = addr 用户名
004013F5  |.  0FBE3C1A      |movsx   edi, byte ptr [edx+ebx]      ;  edi=取用户名中的一位
004013F9  |.  8B75 FC       |mov     esi, [ebp-4]                 ;  esi=上面计算的和值
004013FC  |.  89D9          |mov     ecx, ebx                     ;  ecx=ebx(循环数)
004013FE  |.  C1E1 02       |shl     ecx, 2                       ;  ecx 逻辑左移2位
00401401  |.  89DA          |mov     edx, ebx                     ;  edx=ebx(循环数)
00401403  |.  42            |inc     edx                          ;  edx=edx+1
00401404  |.  29D1          |sub     ecx, edx                     ;  ecx=ecx-edx(第一次循环ecx=-1)
00401406  |.  0FB68C0D E1FE>|movzx   ecx, byte ptr [ebp+ecx-11F]  ;  ecx= 表中值(位置和Ecx相关)
0040140E  |.  89FA          |mov     edx, edi                     ;  edx=用户名中的一位
00401410  |.  31CA          |xor     edx, ecx                     ;  edx=edx Xor ecx
00401412  |.  89F1          |mov     ecx, esi                     ;  ecx=esi(和值)
00401414  |.  0FAFCB        |imul    ecx, ebx                     ;  ecx=ecx(和值) * ebx (循环数)
00401417  |.  29F1          |sub     ecx, esi                     ;  ecx=ecx - esi (和值)
00401419  |.  89CE          |mov     esi, ecx                     ;  esi=ecx(和值*循环数-和值)
0040141B  |.  83F6 FF       |xor     esi, FFFFFFFF                ;  esi=esi Xor FFFFFFFF
0040141E  |.  8DB432 4D0100>|lea     esi, [edx+esi+14D]           ;  esi = edx+esi+14dh(得到值1)
00401425  |.  8B4D 0C       |mov     ecx, [ebp+C]                 ;  ecx=用户名字符数
00401428  |.  89DA          |mov     edx, ebx                     ;  edx=循环数
0040142A  |.  83C2 03       |add     edx, 3                       ;  edx=edx+3
0040142D  |.  0FAFCA        |imul    ecx, edx                     ;  ecx=ecx(用户名字符数)*edx(循环数+3)
00401430  |.  0FAFCF        |imul    ecx, edi                     ;  ecx=ecx*edi(用户名中的第循环数+1位)值2
00401433  |.  89F0          |mov     eax, esi
00401435  |.  01C8          |add     eax, ecx                     ;  eax=值1+值2(得到值3)
00401437  |.  B9 0A000000   |mov     ecx, 0A                      ;  ecx=0ah
0040143C  |.  31D2          |xor     edx, edx                     ;  edx=0
0040143E  |.  F7F1          |div     ecx                          ;  eax=eax/ecx
00401440  |.  83C2 30       |add     edx, 30                      ;  edx=值3%0ah+30h
00401443  |.  88941D FCFEFF>|mov     [ebp+ebx-104], dl
0040144A  |.  0FB6BC1D FCFE>|movzx   edi, byte ptr [ebp+ebx-104]  ;  edi=dl
00401452  |.  81F7 ACAD0000 |xor     edi, 0ADAC                   ;  edi=edi Xor 0adach(得到值4)
00401458  |.  89DE          |mov     esi, ebx                     ;  esi=循环数
0040145A  |.  83C6 02       |add     esi, 2                       ;  esi =循环数+2
0040145D  |.  89F8          |mov     eax, edi
0040145F  |.  0FAFC6        |imul    eax, esi                     ;  eax=值4 * (循环数+2)
00401462  |.  B9 0A000000   |mov     ecx, 0A                      ;  ecx=0ah
00401467  |.  99            |cdq
00401468  |.  F7F9          |idiv    ecx                          ;  eax=eax/ecx
0040146A  |.  83C2 30       |add     edx, 30                      ;  edx=eax%ecx+30
0040146D  |.  88941D FCFEFF>|mov     [ebp+ebx-104], dl            ;  dl 就是变换码 之一
00401474  |.  43            |inc     ebx
00401475  |>  3B5D 0C        cmp     ebx, [ebp+C]
00401478  |.^ 0F8C 74FFFFFF \jl      004013F2
0040147E  |.  8D85 FCFEFFFF lea     eax, [ebp-104]                ; eax=addr 所有变换码 n位 
00401484  |.  50            push    eax
00401485  |.  6A 54         push    54                            ; 字符 T
00401487  |.  8D85 DCFBFFFF lea     eax, [ebp-424]
0040148D  |.  50            push    eax                           ; |Format      "%c%s"
0040148E  |.  8D85 E1FBFFFF lea     eax, [ebp-41F]                ; |
00401494  |.  50            push    eax                           ; |s
00401495  |.  E8 CE020000   call    00401768                      ; \wsprintfA 变换成TXXXXX的格式 n个X
0040149A  |.  8B7D 0C       mov     edi, [ebp+C]                  ;  edi=用户名字符数
0040149D  |.  89F8          mov     eax, edi
0040149F  |.  0FAF45 FC     imul    eax, [ebp-4]                  ;  eax=字符数*和值
004014A3  |.  B9 64000000   mov     ecx, 64                       ;  ecx=64h
004014A8  |.  99            cdq
004014A9  |.  F7F9          idiv    ecx                           ;  eax=eax/ecx
004014AB  |.  89D7          mov     edi, edx                      ;  edi=eax%ecx
004014AD  |.  83C7 30       add     edi, 30                       ;  edi= (字符数 * 和值)%64h +30h
004014B0  |.  57            push    edi
004014B1  |.  8DBD E1FBFFFF lea     edi, [ebp-41F]
004014B7  |.  57            push    edi
004014B8  |.  8DBD D6FBFFFF lea     edi, [ebp-42A]
004014BE  |.  57            push    edi                           ; |Format       "%s-%d"
004014BF  |.  8DBD E1FDFFFF lea     edi, [ebp-21F]                ; |
004014C5  |.  57            push    edi                           ; |s
004014C6  |.  E8 9D020000   call    00401768                      ; \wsprintfA  变换成 TXXXXX-XXX的形式
004014CB  |.  83C4 20       add     esp, 20
004014CE  |.  8D8D E1FDFFFF lea     ecx, [ebp-21F]                ;  ecx=addr 用户名变换码
004014D4  |.  83C8 FF       or      eax, FFFFFFFF
004014D7  |>  40            /inc     eax
004014D8  |.  803C01 00     |cmp     byte ptr [ecx+eax], 0
004014DC  |.^ 75 F9         \jnz     short 004014D7               ;  循环得到变换码长度
004014DE  |.  50            push    eax                           ; /Arg3         变换码长度
004014DF  |.  8D85 E1FCFFFF lea     eax, [ebp-31F]                ; |
004014E5  |.  50            push    eax                           ; |Arg2    addr 输入的注册码
004014E6  |.  8D85 E1FDFFFF lea     eax, [ebp-21F]                ; |
004014EC  |.  50            push    eax                           ; |Arg1   addr 变换码
004014ED  |.  E8 D0FDFFFF   call    004012C2                      ; \crackme6.004012C2
004014F2  |.  83C4 0C       add     esp, 0C
004014F5  |.  83F8 00       cmp     eax, 0
004014F8  |.  75 07         jnz     short 00401501
004014FA  |.  B8 00000000   mov     eax, 0
004014FF  |.  EB 03         jmp     short 00401504
00401501  |>  31C0          xor     eax, eax
00401503  |.  40            inc     eax
00401504  |>  5F            pop     edi
00401505  |.  5E            pop     esi
00401506  |.  5B            pop     ebx
00401507  |.  C9            leave
00401508  \.  C3            retn
  
  好长,分析下来还真的需要点耐心。这个函数首先为程序作了一些准备,读入了一些固定值作为表,以备后面查询;然后读入我们输入的注册码,取出第一位进行变换比较,符合条件后继续;利用一个循环获得用户名ASCII码和值;利用另一个循环获得变换码第一部分,并将其格式化为TXXXXX的形式,其中X位数同用户名位数;计算变化码第二部分,并整合第一部分成TXXXXX-XXX形式;将变化码长度,假注册码及变换码入栈作为参数,进入下一个关键Call。
  注册码第一位变化比较算法:设 n = 注册码第一位的ASCII值,则n必须符合  11cfH%n=17H,这个不难,我们可以穷举。
  变换码第一部分算法比较复杂(对于我来说,:)),用我极其不熟练的C+ASM语言进行表达如下:
  设:n=用户名长度,U[i]=用户名ASCII数组,Hez=用户名ASCII和值,T[i]=表A....Z,S[i]=第一部分变换码数组
  for(i=0;i++;i<n)
  { 
     值1=T[3*i-1] Xor U[i] + Hez*(i-1) Xor FFFFFFFF + 14dH
     值2=n*(i+3)*U[i]
     值3=值1+值2
     edx=值3%0aH+30H
     值4=dl Xor 0adacH
     edx=值4*(i+2)%0aH+30H
     S[i]=dl
  }
  希望上面的表达大家能理解。这里值得注意的是当i=0时,将访问T[-1],查看函数的准备部分,我们可以得到T[-1]=00H。
  变换码第二部分算法比较简单:借用上面假设,取 (n*Hez)%64H+30H 的十进制字符串形式,如 结果=7bH,则第二部分变换码为 123。
  好了,总算分析完毕。我们进入下一个Call。

004012C2  /$  55            push    ebp
004012C3  |.  89E5          mov     ebp, esp
004012C5  |.  53            push    ebx
004012C6  |.  56            push    esi
004012C7  |.  57            push    edi
004012C8  |.  8B5D 10       mov     ebx, [ebp+10]             ;  ebx=变换码长度
004012CB  |.  31F6          xor     esi, esi
004012CD  |.  46            inc     esi                       ;  esi 作为循环变量 次数 为变换码长度
004012CE  |.  EB 29         jmp     short 004012F9
004012D0  |>  8B55 08       /mov     edx, [ebp+8]             ;  edx=addr 变换码
004012D3  |.  0FBE3C32      |movsx   edi, byte ptr [edx+esi]  ;  edi=变换码第n+1位
004012D7  |.  89F8          |mov     eax, edi                 ;  eax=edi
004012D9  |.  83F0 20       |xor     eax, 20                  ;  eax=eax Xor 20h
004012DC  |.  B9 0A000000   |mov     ecx, 0A                  ;  ecx=0ah
004012E1  |.  99            |cdq
004012E2  |.  F7F9          |idiv    ecx
004012E4  |.  89D7          |mov     edi, edx                 ;  edi=eax%ecx
004012E6  |.  83C7 30       |add     edi, 30                  ;  edi=edi+30h
004012E9  |.  8B55 0C       |mov     edx, [ebp+C]
004012EC  |.  0FBE1432      |movsx   edx, byte ptr [edx+esi]  ;  edx=注册码第n+1位
004012F0  |.  39D7          |cmp     edi, edx
004012F2      74 04         je      short 004012F8            ;  等则比较下一位
004012F4  |.  31C0          |xor     eax, eax
004012F6  |.  EB 08         |jmp     short 00401300
004012F8  |>  46            |inc     esi
004012F9  |>  39DE           cmp     esi, ebx
004012FB  |.^ 7C D3         \jl      short 004012D0
004012FD  |.  31C0          xor     eax, eax
004012FF  |.  40            inc     eax
00401300  |>  5F            pop     edi
00401301  |.  5E            pop     esi
00401302  |.  5B            pop     ebx
00401303  |.  5D            pop     ebp
00401304  \.  C3            retn
  终于看到了曙光,这里再也没有下一个call了。这个函数过程比较明了,将得到的变换码进行再次变换,然后逐位与我们输入的注册码进行比较,这里舍弃了第一位,其余各位均等则函数设置Eax=1 后返回。变换比较算法如下:
  设Z[i]=我们输入的注册码数组 , S[i]=变换码数组 , n=变换码长度
  则必须满足: Z[i]= (S[i] Xor 20H)%0aH+30H (其中 i From 1 to n)
  至此,整个算法分析完毕。

  第三部分,编写注册机

  我正在学习汇编语言,就用汇编写个注册机吧。这样我还可以把大部分代码搬到我的程序里。序列号产生程序如下:

GenKey proc uses edi, lpUserName:DWORD,nU:DWORD 
  ;生成序列号函数,参数分别为:指向用户名的指针,用户名字符数,返回值为 注册码 指针
  local lpBuffer[128]:BYTE
  local szBuffer[128]:BYTE
  local hezhi:DWORD
  local zcm1[32]:Byte
  
  .if (nU>2) && (nU<10)
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;计算注册码第一位字符
    mov ecx,20h
    xor edi,edi
    .while ecx<129
      
      mov eax,11cfh
      cdq
      idiv ecx
      .if edx==17h
        mov byte ptr [edi+lpBuffer],cl
        inc edi
      .endif
      inc ecx
    .endw
    mov byte ptr [edi+lpBuffer],0
    invoke wsprintf,addr szBuffer,addr szFormat1,addr lpBuffer
    
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;计算用户名和值 save hezhi
    mov eax,0
    mov hezhi,eax
    xor ebx,ebx
    .while ebx<nU
      
      mov eax,lpUserName
      movsx edx,byte ptr [eax+ebx]
      add hezhi,edx
      inc ebx
      
    .endw
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 计算第一部分中间码 save szBuffer
    lea eax,zcm1
    mov byte ptr [eax-1],0
    xor ebx,ebx
    .while ebx<nU
      mov edx,lpUserName
      movsx edi,byte ptr [edx+ebx]
      mov esi,hezhi
      mov ecx,ebx
      shl ecx,2h
      mov edx,ebx
      inc edx
      sub ecx,edx
      movzx ecx,byte ptr[ecx+offset table]
      mov edx,edi
      xor edx,ecx
      mov ecx,esi
      imul ecx,ebx
      sub ecx,esi
      mov esi,ecx
      xor esi,0ffffffffh
      lea esi,[edx+esi+14dh]
      mov ecx,nU
      mov edx,ebx
      add edx,3h
      imul ecx,edx
      imul ecx,edi
      mov eax,esi
      add eax,ecx
      mov ecx,0ah
      xor edx,edx
      div ecx
      add edx,30h
      lea eax,zcm1
      mov [ebx+eax],dl
      movzx edi,byte ptr [ebx+eax]
      xor edi,0adach
      mov esi,ebx
      add esi,2h
      mov eax,edi
      imul eax,esi
      mov ecx,0ah
      cdq
      idiv ecx
      add edx,30h
      lea eax,zcm1
      mov [ebx+eax],dl
      inc ebx
    .endw
    lea eax,zcm1
    mov byte ptr [ebx+eax],0
    invoke wsprintf,addr szBuffer ,addr szFormat2,addr zcm1
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;计算中间码2 save edi
    mov edi,nU
    mov eax,edi
    imul eax,hezhi
    mov ecx,64h
    cdq
    idiv ecx
    mov edi,edx
    add edi,30h
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;计算完整中间码 save szlpBuffer
    invoke wsprintf,addr lpBuffer,addr szFormat3,addr szBuffer,edi
    mov ebx,eax
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;计算注册码 save szBuffer
    xor esi,esi
    inc esi
    .while esi<ebx
      lea edx,lpBuffer
      movsx edi,byte ptr [edx+esi]
      mov eax,edi
      xor eax,20h
      mov ecx,0ah
      cdq
      idiv ecx
      add edx,30h
      lea eax,szBuffer
      mov byte ptr[eax+esi],dl
      inc esi
    .endw
    lea eax,szBuffer
    mov byte ptr[eax],38h
    mov byte ptr[eax+ebx],0
    invoke StrCpyNW,addr TestString,addr szBuffer,ebx
    ret
    
  .else
    invoke  MessageBox,NULL,offset szErrUsername,offset szCaption,MB_OK or MB_SYSTEMMODAL
    mov eax,0
    ret
  .endif

GenKey endp

  感谢您一直等我啰嗦到这里,等我一切作完,我看了4nil的过程。我在重新载入这个CrackMe时,就发现我下断的地方数据变了,我怀疑加了壳,可不但OLLYDBG没提示我有壳,就是我请出PEID,也没有查出什么。带壳分析完了整个程序,上述问题仍然迷惑不解。4nil分析的简单明了,因为我是第一次如此分析CrackMe,所以把整个过程都罗嗦了上来,再次感谢您读到这里。
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2007年12月03日 23:20:18


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 7
支持
分享
最新回复 (12)
雪    币: 47147
活跃值: (20450)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
2
恭喜你又进步了
2007-12-5 09:30
0
雪    币: 207
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
不错啊,强!
2007-12-5 09:38
0
雪    币: 485
活跃值: (12)
能力值: ( LV9,RANK:490 )
在线值:
发帖
回帖
粉丝
4
谢谢老大鼓励!
2007-12-5 10:00
0
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
跟上你的腳步。。。
2007-12-5 12:29
0
雪    币: 212
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
6
分析的很好啊!
2007-12-5 17:17
0
雪    币: 405
活跃值: (10)
能力值: ( LV9,RANK:1130 )
在线值:
发帖
回帖
粉丝
7
真好啊~~努力努力
2007-12-7 08:47
0
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
高人啊!向你学习!
2007-12-7 16:57
0
雪    币: 234
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
9
我们就需要这样的,适合我们初学者.
2007-12-18 17:04
0
雪    币: 557
活跃值: (10)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
10
  不用去理壳啊
2008-1-12 23:58
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
这样也叫小菜  那我 叫什么
2008-1-13 03:56
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
楼主文章中没有提高壳,是带壳破解吗?
2008-1-17 14:57
0
雪    币: 82
活跃值: (10)
能力值: (RANK:210 )
在线值:
发帖
回帖
粉丝
13
不是带壳 是程序动态导入API
2008-1-17 15:04
0
游客
登录 | 注册 方可回帖
返回
//