首页
社区
课程
招聘
[分享]haunte's Crackme #1 ,新手破解+注册算法
发表于: 2007-11-5 21:38 8387

[分享]haunte's Crackme #1 ,新手破解+注册算法

2007-11-5 21:38
8387

在看雪潜水很长时间,今天吐个泡,发一篇自己写的CrackMe破解,难度不高,高手就不用看了,感谢看雪论坛和所有朋友对我的帮助。

【文章标题】: haunte's Crackme #1 破解+注册算法
【文章作者】: megadeath
【作者邮箱】: massacre@163.com
【作者QQ号】: 84227716
【软件名称】: haunte's Crackme #1
【软件大小】: 14,336
【下载地址】: http://www.crackmes.de/users/haunte/crachme_1_by_haunted/
【加壳方式】: 无
【保护方式】: 无
【编写语言】: ASM
【使用工具】: OllyICE
【操作平台】: WinXPsp2
【软件介绍】: 用户名+密码 验证
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
  MD5:39e1b194a26009aa91f6dd42e326453f   Crackme.exe

        首先拿到这个CrackMe,初次执行竟然没有反映,将在XP中设置为兼容win95模式后可以启动,程序很小,只有14k,但结构比我想象中的复杂,有不少干扰代码,花了一些时间读懂,破解过程如下。

        程序是老套,输入用户名和密码,点击确认,但是错误注册码不会弹出对话框,用OD加载,在串式参考中找不到注册失败或成功的注册码,但是刚才在输入错误注册信息时弹出的对话框的标题是“crackme by haunted”,所以直接从这里找,在程序段往上一点点可以找到注册成功或失败的字样(幸运),可以断定注册判注册在这附近,再往上翻看,可以查到从004010D0 处开始进行注册码判断,我们从这里开始逐步分析,重新下断点在004010D0 处,然后往下走

004010CB   > \B9 1E000000   mov     ecx, 1E
004010D0   .  31C0          xor     eax, eax                         ;  这里是开始点
004010D2   .  BF B8204000   mov     edi, 004020B8                    ;  这里是最后放入真正注册码的
004010D7   .  F3:AA         rep     stos byte ptr es:[edi]
004010D9   .  31FF          xor     edi, edi
004010DB   .  47            inc     edi
004010DC   .  C1E7 0B       shl     edi, 0B
004010DF   .  6A 2D         push    2D                               ;  用户名最长不能超过0x2d
004010E1   .  68 4F204000   push    0040204F                         ;  这个指针用于存放用户名
004010E6   .  57            push    edi
004010E7   .  56            push    esi
004010E8   .  FF15 90214000 call    dword ptr [402190]               ;  USER32.GetDlgItemTextA
004010EE   .  09C0          or      eax, eax                         ;  判断用户名长度
004010F0   .  0F85 01000000 jnz     004010F7                         ;  如果用户名长度不为0则跳转
004010F6   .  C3            retn                                     ;  否则就结束
004010F7   >  D1EF          shr     edi, 1
004010F9   .  6A 1E         push    1E                               ;  输入的注册码最长不能超过0x1E
004010FB   .  68 7C204000   push    0040207C                         ;  这个指针用于存放注册码
00401100   .  57            push    edi
00401101   .  56            push    esi
00401102   .  FF15 90214000 call    dword ptr [402190]               ;  USER32.GetDlgItemTextA
00401108   .  09C0          or      eax, eax
0040110A   .  0F85 01000000 jnz     00401111                         ;  判断注册码长度
00401110   .  C3            retn                                     ;  长度如果为0就Over
00401111   >  B8 4F204000   mov     eax, 0040204F                    ;  这里放的是输入的用户名
00401116   .  E8 1D020000   call    00401338                         ;  进到里面看,这是计算字符串长度的
0040111B   .  A3 A0214000   mov     dword ptr [4021A0], eax          ;  字符串长度放到[4021A0],从后面来看,这步操作似乎没有太多作用,只是暂存了字符串长度
00401120   .  BB 4F204000   mov     ebx, 0040204F                    ;  输入的用户名字符串
00401125   .  0FB613        movzx   edx, byte ptr [ebx]              ;  取用户名的第一个字符放到edx中
00401128   .  0FB64C03 FF   movzx   ecx, byte ptr [ebx+eax-1]        ;  取用户名的最后一个字符到ecx中
0040112D   .  0FAFD1        imul    edx, ecx                         ;  edx = edx * ecx,即第一个字和最后一个字的乘积
00401130   .  50            push    eax
00401131   .  B9 02000000   mov     ecx, 2
00401136   .  52            push    edx
00401137   .  31D2          xor     edx, edx                         ;  edx清零
00401139   .  F7F9          idiv    ecx                              ;  eax = 用户名长度 / ecx
0040113B   .  5A            pop     edx                              ;  edx是刚才的乘积
0040113C   .  0FB60C03      movzx   ecx, byte ptr [ebx+eax]          ;  取用户名[用户名长度/2]的字符
00401140   .  0FAFD1        imul    edx, ecx                         ;  刚才的乘积再乘以上面的字符
00401143   .  BB B8204000   mov     ebx, 004020B8                    ;  这个地址是放真正注册码的,现在是空的
00401148   .  C703 484E542D mov     dword ptr [ebx], 2D544E48        ;  将 2D544E48 放到 数据区 004020B8 处,即字符串“HNT-”
0040114E   .  89D0          mov     eax, edx                         ;  将刚才的乘积放到eax
00401150   .  83C3 04       add     ebx, 4                           ;  这里ebx是放注册码的新位置,就是在 HNT- 这几个字符的后面
00401153   .  E8 F7010000   call    0040134F                         ;  对eax进行一系列运算,算出四个值,添加到注册码尾部
00401158   .  C705 00204000>mov     dword ptr [402000], 1E           ;  这步的确不知道是做什么用的,可能是迷惑代码
00401162   .  68 00204000   push    00402000                         ; /pBufferSize = Crackme.00402000
00401167   .  68 9A204000   push    0040209A                         ; |Buffer = Crackme.0040209A
0040116C   .  E8 B34E0000   call    <jmp.&KERNEL32.GetComputerNameA> ; \GetComputerNameA
00401171   .  B8 9A204000   mov     eax, 0040209A                    ;  这里eax中放的是计算机的名称
00401176   .  E8 F2010000   call    0040136D                         ;  对计算机名称每个字符进行累加,结果返回eax
0040117B   .  BB 4F204000   mov     ebx, 0040204F                    ;  这里是用户名,地址传给ebx
00401180   .  E8 00020000   call    00401385                         ;  对字符串一系列运算
00401185   .  50            push    eax                              ;  对刚才的计算结果压栈,后面还有用到这个值
00401186   .  31C0          xor     eax, eax                         ;  eax清零
00401188   .  0FA2          cpuid                                    ;  取得CPUID
0040118A   .  58            pop     eax                              ;  eax是刚才计算后在 00401185 处压栈的结果
0040118B   .  51            push    ecx
0040118C   .  52            push    edx
0040118D   .  21D8          and     eax, ebx                         ;  eax 的值更新为 eax 和CPUID后ebx的与结果
0040118F   .  BB B8204000   mov     ebx, 004020B8                    ;  这是放注册码的地方
00401194   .  89DF          mov     edi, ebx                         ;  取得注册码首地址位置放到edi中
00401196   .  50            push    eax                              ;  将刚才eax的计算结果保存起来
00401197   .  66:31C0       xor     ax, ax                           ;  ax清零
0040119A   .  F2:AE         repne   scas byte ptr es:[edi]           ;  统计现在注册码的长度,edi步进到字符串的末尾
0040119C   .  89FB          mov     ebx, edi                         ;  字符串末尾位置赋值给ebx
0040119E   .  58            pop     eax                              ;  回复eax的值
0040119F   .  4B            dec     ebx                              ;  注意这里的ebx自减1
004011A0   .  C603 2D       mov     byte ptr [ebx], 2D               ;  在注册码中增加 - 这个分割符号
004011A3   .  43            inc     ebx                              ;  步进新的位置填充注册码
004011A4   .  E8 A6010000   call    0040134F                         ;  eax的值是0040118D时的eax值,计算后增加注册码
004011A9   .  B8 4F204000   mov     eax, 0040204F                    ;  这里是输入的用户名
004011AE   .  E8 BA010000   call    0040136D                         ;  对输入的用户名的每个字符进行累加,结果返回eax
004011B3   .  59            pop     ecx                              ;  ecx中是刚才CPUID调用时取得的edx返回的值
004011B4   .  31C8          xor     eax, ecx                         ;  eax 异或 ecx
004011B6   .  59            pop     ecx                              ;  这个返回的是刚才CPUID调用时ecx的值
004011B7   .  09C8          or      eax, ecx                         ;  eax 或 ecx
004011B9   .  50            push    eax                              ;  保存eax
004011BA   .  BB 4F204000   mov     ebx, 0040204F                    ;  这是放输入用户名的地方
004011BF   .  0FB603        movzx   eax, byte ptr [ebx]              ;  注册码的第一个字符
004011C2   .  0FB64B 01     movzx   ecx, byte ptr [ebx+1]            ;  注册码的第二个字符
004011C6   .  0FAFC1        imul    eax, ecx                         ;  两者相乘结果放入到eax
004011C9   .  59            pop     ecx                              ;  ecx 是刚才上面计算的结果
004011CA   .  0FAFC1        imul    eax, ecx
004011CD   .  BF B8204000   mov     edi, 004020B8                    ;  放注册码的地方
004011D2   .  50            push    eax
004011D3   .  30C0          xor     al, al
004011D5   .  F2:AE         repne   scas byte ptr es:[edi]           ;  扫描注册码字符串
004011D7   .  58            pop     eax
004011D8   .  89FB          mov     ebx, edi
004011DA   .  4B            dec     ebx
004011DB   .  C603 2D       mov     byte ptr [ebx], 2D               ;  再次增加 - 分隔符
004011DE   .  43            inc     ebx
004011DF   .  E8 6B010000   call    0040134F                         ;  对eax进行运算得到 - 后的新注册码
004011E4   .  B8 4F204000   mov     eax, 0040204F                    ;  这里存放的是用户名
004011E9   .  E8 7F010000   call    0040136D                         ;  累加用户名值
004011EE   .  B9 1A000000   mov     ecx, 1A
004011F3   .  31D2          xor     edx, edx                         ;  edx清零
004011F5   .  F7F9          idiv    ecx                              ;  累加值除以1a
004011F7   .  B8 41000000   mov     eax, 41                          ;  eax 放入 41
004011FC   .  01D0          add     eax, edx                         ;  再和刚才的余数相加
004011FE   .  89C7          mov     edi, eax                         ;  将结果存入到edi,一会儿要用到
00401200   .  BB 4F204000   mov     ebx, 0040204F                    ;  这里存放的是用户名
00401205   .  E8 7B010000   call    00401385                         ;  对用户名进行一系列计算
0040120A   .  31D2          xor     edx, edx                         ;  edx清零
0040120C   .  F7F9          idiv    ecx                              ;  得到的结果除以1A
0040120E   .  83C2 41       add     edx, 41                          ;  将余数加0x41
00401211   .  BB B8204000   mov     ebx, 004020B8                    ;  这是存放注册码
00401216   .  50            push    eax
00401217   .  31C0          xor     eax, eax
00401219   .  57            push    edi
0040121A   .  89DF          mov     edi, ebx
0040121C   .  F2:AE         repne   scas byte ptr es:[edi]           ;  到注册码的末尾处
0040121E   .  58            pop     eax
0040121F   .  89FB          mov     ebx, edi
00401221   .  5F            pop     edi
00401222   .  4B            dec     ebx
00401223   .  C603 2D       mov     byte ptr [ebx], 2D               ;  注册码增加短线分隔符
00401226   .  8843 01       mov     byte ptr [ebx+1], al             ;  把al作为字符增加
00401229   .  8853 02       mov     byte ptr [ebx+2], dl             ;  把dl作为字符增加
0040122C   .  C643 03 00    mov     byte ptr [ebx+3], 0              ;  最后添加结束符,这时注册码已经完整
00401230   .  58            pop     eax
00401231   .  56            push    esi
00401232   .  B8 B8204000   mov     eax, 004020B8                    ;  真正注册码
00401237   .  E8 FC000000   call    00401338                         ;  统计真正注册码长度
0040123C   .  89C2          mov     edx, eax                         ;  将长度放到edx中
0040123E   .  B8 7C204000   mov     eax, 0040207C                    ;  输入的伪注册码
00401243   .  E8 F0000000   call    00401338                         ;  统计输入注册码长度,将注册码长度放到eax
00401248   .  39D0          cmp     eax, edx                         ;  比较一下
0040124A   .  0F85 5F000000 jnz     004012AF                         ;  长度不相等就跳转到失败处
00401250   .  BE B8204000   mov     esi, 004020B8                    ;  真正注册码
00401255   .  BF 7C204000   mov     edi, 0040207C                    ;  输入的伪注册码
0040125A   .  89C1          mov     ecx, eax
0040125C   >  8A06          mov     al, byte ptr [esi]
0040125E   .  8A27          mov     ah, byte ptr [edi]
00401260   .  46            inc     esi
00401261   .  47            inc     edi
00401262   .  30C4          xor     ah, al                           ;  两个注册码逐个比较
00401264   .  0F85 45000000 jnz     004012AF                         ;  如果不相等则跳到失败处
0040126A   .  49            dec     ecx
0040126B   .^ 75 EF         jnz     short 0040125C                   ;  两个注册码逐个字符比较,循环
0040126D   .  5E            pop     esi                              ;  后面就是显示正确注册的提示信息了
0040126E   .  B9 C8000000   mov     ecx, 0C8
00401273   .  B8 DC000000   mov     eax, 0DC
00401278   .  BF 23204000   mov     edi, 00402023                    ;  ASCII "Right Code , Well Done",CR,LF,"    -hari code eka-?
0040127D   .  F2:AE         repne   scas byte ptr es:[edi]
0040127F   .  4F            dec     edi
00401280   .  8827          mov     byte ptr [edi], ah
00401282   .  B8 DD204000   mov     eax, 004020DD
00401287   .  83C0 64       add     eax, 64
0040128A   .  6A 40         push    40
0040128C   .  50            push    eax
0040128D   .  68 23204000   push    00402023                         ;  ASCII "Right Code , Well Done",CR,LF,"    -hari code eka-?
00401292   .  56            push    esi
00401293   .  FF15 08204000 call    dword ptr [402008]               ;  USER32.MessageBoxA
00401299   .  B9 C8000000   mov     ecx, 0C8
0040129E   .  B8 00000000   mov     eax, 0
004012A3   .  BF 23204000   mov     edi, 00402023                    ;  ASCII "Right Code , Well Done",CR,LF,"    -hari code eka-?
004012A8   .  F2:AE         repne   scas byte ptr es:[edi]
004012AA   .  4F            dec     edi
004012AB   .  C607 DC       mov     byte ptr [edi], 0DC
004012AE   .  C3            retn
004012AF   >  B9 C8000000   mov     ecx, 0C8
004012B4   .  B8 DC000000   mov     eax, 0DC
004012B9   .  BF 0C204000   mov     edi, 0040200C                    ;  ASCII "Wrong Code",CR,LF,"-weradiyi-躌ight Code , Well Done",CR,LF,"    -hari code eka-?
004012BE   .  F2:AE         repne   scas byte ptr es:[edi]
004012C0   .  4F            dec     edi
004012C1   .  8827          mov     byte ptr [edi], ah
004012C3   .  B8 DD204000   mov     eax, 004020DD
004012C8   .  83C0 64       add     eax, 64
004012CB   .  6A 30         push    30
004012CD   .  50            push    eax
004012CE   .  68 0C204000   push    0040200C                         ;  ASCII "Wrong Code",CR,LF,"-weradiyi-躌ight Code , Well Done",CR,LF,"    -hari code eka-?
004012D3   .  56            push    esi
004012D4   .  FF15 08204000 call    dword ptr [402008]               ;  USER32.MessageBoxA
004012DA   .  B9 C8000000   mov     ecx, 0C8
004012DF   .  B8 00000000   mov     eax, 0
004012E4   .  BF 0C204000   mov     edi, 0040200C                    ;  ASCII "Wrong Code",CR,LF,"-weradiyi-躌ight Code , Well Done",CR,LF,"    -hari code eka-?
004012E9   .  F2:AE         repne   scas byte ptr es:[edi]
004012EB   .  4F            dec     edi
004012EC   .  C607 DC       mov     byte ptr [edi], 0DC
004012EF   .  5E            pop     esi
004012F0   .  C3            retn
004012F1   >  6A 30         push    30
004012F3   .  68 41214000   push    00402141                         ;  ASCII "Crackme By Haunted"
004012F8   .  68 06214000   push    00402106                         ;  ASCII "Crackme",CR,CR,"Rules :",CR,"Find a serial(Write a keygen if you want)"
004012FD   .  56            push    esi
004012FE   .  FF15 04204000 call    dword ptr [402004]               ;  USER32.MessageBoxA
00401304   .  C3            retn

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

几点说明:

1.在00401188 处调用的CPUID指令,在AMD的CPU上也有这个指令,但求得的结果和Intel的不同,这里按照Intel的来写
如果eax初始值为0x00,调用CPUID后会往ebx,ecx和edx中写入一些值,查Intel手册的话可以了解到是寄存器中放的是一些字符串,ebx写的是“Genu”,ecx是“ntel”,edx中是“ineI”,也就是说如果是Intel的CPU的话必然是ebx=756E6547h,ecx=6c65746eh,edx=49656e69h。

2.说明一下几个call的调用,这几个call基本上都是靠eax和ebx传递参数的,刚开始看的时候觉得很混乱,多看几次就能理解了,不是很难

call 00401338
00401338  /$  51            push    ecx
00401339  |.  57            push    edi
0040133A  |.  B9 64000000   mov     ecx, 64                          ;  最多扫描64个字符
0040133F  |.  89C7          mov     edi, eax                                                 ;  eax中放的是字符串,赋值给edi,为后面的扫描
00401341  |.  31C0          xor     eax, eax                                                 ;  eax 清零,al 也是0
00401343  |.  F2:AE         repne   scas byte ptr es:[edi]           ;  对注册码扫描,碰到al就结束
00401345  |.  F7D1          not     ecx                              ;  反转ecx,ecx是减少的次数
00401347  |.  83C1 64       add     ecx, 64                          ;  ecx 再加上64,ok,这样ecx中存放的是字符串的长度
0040134A  |.  89C8          mov     eax, ecx                         ;  结果就是用户名长度,放到eax中
0040134C  |.  5F            pop     edi
0040134D  |.  59            pop     ecx
0040134E  \.  C3            retn                                     ;  返回

这个是个很简单的函数,目的是统计输入字符串的长度,我们只要记得 00401338 是统计字符串长度的函数就可以了

call 0040134F
0040134F  /$  51            push    ecx
00401350  |.  56            push    esi
00401351  |.  4B            dec     ebx
00401352  |.  B9 04000000   mov     ecx, 4                           ;  ecx赋值4,要计算4个新值
00401357  |.  BE 0A000000   mov     esi, 0A                          ;  esi赋值0xA,就是10进制的10
0040135C  |.  52            push    edx
0040135D  |>  31D2          xor     edx, edx                         ;  edx清零
0040135F  |.  F7FE          idiv    esi                              ;  eax = eax / esi,等于除以10
00401361  |.  80C2 30       add     dl, 30                           ;  余数加30
00401364  |.  88140B        mov     byte ptr [ebx+ecx], dl           ;  放到一个数据区中
00401367  |.^ E2 F4         loopd   short 0040135D
00401369  |.  5A            pop     edx
0040136A  |.  5E            pop     esi
0040136B  |.  59            pop     ecx
0040136C  \.  C3            retn

这段是要计算四个值,将刚才的eax传入后不停除以0xA,每次得到的余数转换成数字字符,然后在刚才的注册码尾部增加上去,但要注意的是增加数字字符是倒着着加进去的,也就是从后往前加的

call 0040136D
0040136D  /$  56            push    esi
0040136E  |.  51            push    ecx
0040136F  |.  89C6          mov     esi, eax                                                 ;  将字符串传给esi
00401371  |.  31C9          xor     ecx, ecx
00401373  |.  31C0          xor     eax, eax
00401375  |>  8A06          /mov     al, byte ptr [esi]              ;  取得字符串的每个字符
00401377  |.  84C0          |test    al, al                                                         ;  看看是否有值
00401379  |.  74 05         |je      short 00401380
0040137B  |.  46            |inc     esi
0040137C  |.  01C1          |add     ecx, eax                        ;  然后进行累加
0040137E  |.^ EB F5         \jmp     short 00401375
00401380  |>  89C8          mov     eax, ecx                         ;  将结果返回到eax返回
00401382  |.  59            pop     ecx
00401383  |.  5E            pop     esi
00401384  \.  C3            retn

直接就是对计算机名称进行累加计算,结果放到eax后返回

call 00401385
00401385  /$  51            push    ecx                              ;  
00401386  |.  52            push    edx
00401387  |.  89D8          mov     eax, ebx                                                 ;  这里把eax清除掉了
00401389  |.  E8 AAFFFFFF   call    00401338                         ;  计算字符串长度的函数
0040138E  |.  89C1          mov     ecx, eax                         ;  字符串长度放到ecx
00401390  |.  4B            dec     ebx
00401391  |.  31D2          xor     edx, edx                         ;  edx清零
00401393  |>  8A140B        /mov     dl, byte ptr [ebx+ecx]          ;  取得字符串每个字符,倒序
00401396  |.  0FAFD1        |imul    edx, ecx                        ;  edx = edx * ecx
00401399  |.  01D0          |add     eax, edx                                                 ;  eax = edx + eax
0040139B  |.  49            |dec     ecx
0040139C  |.^ 75 F5         \jnz     short 00401393
0040139E  |.  5A            pop     edx
0040139F  |.  59            pop     ecx
004013A0  \.  C3            retn

这段代码就比较有意思,这里是把用户名传入,然后先计算长度用来做循环次数,循环是倒序的,也是倒序取得用户名字符,然后将用户名字符乘以循环循环值,和eax累积,eax中初始值为用户名长度,最终返回eax的值,但有意思的是每次取得用户名的一个字符时是要放到edx中的,edx初始值为0x00,但每次循环都是将取得的字符是放在edx的低8位上的,其余位不变,这个要注意

        最后到00401232 处的时候可以直接看内存中004020B8 ,这时注册码已经被计算出来了,爆破就从这边下手就可以了。

        到这里我们把重新把思路整理一下,在计算注册码的时候总共有4个关键的call,00401338、0040134F、0040136D和00401385,其中00401338是统计字符串长度的,0040134F是将eax的值进行运算求得4个0-9的数字字符并增加到注册码末尾的,0040136D是对字符串的每个字符进行累加求和,00401385是对字符串每个字符求一个特殊的累积值。知道这四个函数的功能,我们把注册机写出来:

#include <iostream>
#include <string>
using namespace std;

//将字符串转换为4个数字字符并增加到注册码末尾,注意是倒序放入的
void Func0040134F(string & strCode, unsigned iNumber)
{
        strCode.resize(4 + strCode.length());
        for (int ii = 0; ii < 4; ++ii)
        {
                strCode[strCode.length() - ii - 1] = (char)((iNumber % 0x0A) + 0x30);
                iNumber /= 0xA;
        }
        return;
}

//对字符串的每个字符进行一系列特殊的计算,返回一个特殊的乘积结果
unsigned Func00401385(const string & strString)
{
        unsigned iResult = 0;
        unsigned iStringLength = strString.length();
        unsigned iAccumulate = iStringLength;
       
        for (int ii = iStringLength - 1; ii >= 0; --ii)
        {
                iResult = iResult & 0xFFFFFF00;
                iResult = iResult + (((int)strString[ii]) & 0xFF);
                iResult = iResult * (ii + 1);
                iAccumulate = iResult + iAccumulate;
        }

        return iAccumulate;
}

//累加字符串操作
unsigned Func0040136D(const string & strString)
{
        unsigned iSum = 0;

        for (int ii = 0; ii < strString.length(); ++ ii)
        {
                iSum += (int)strString[ii];
        }
        return iSum;
}

int main(int,char **)
{
        string strName;
        string strSn;
        strSn = "HNT-";//注册码的第一部分
        unsigned iNameLength = 0;
        unsigned iResult = 0;
        unsigned iEax, iEbx, iEcx, iEdx;
        iEax = iEbx = iEcx = iEdx = 0;

        do
        {
                cout << "Please input your name:" << endl;
                cin >> strName;

                if((0 != (iNameLength = strName.length())) && (0x2D >= iNameLength))
                {
                        goto KeyGen;
                }
               
        } while(1);

KeyGen:
        //增加注册码的第二部分
        iResult = strName[0] * strName[iNameLength - 1];
        iResult *= strName[iNameLength/2];
        Func0040134F(strSn, iResult);

        //增加注册码的第三部分
        iResult = Func00401385(strName);
        __asm
        {
                pushad
                xor eax, eax
                cpuid
                mov iEax, eax
                mov iEbx, ebx
                mov iEcx, ecx
                mov iEdx, edx
                popad
        }
        iResult = iResult & iEbx;
        strSn.push_back('-');
        Func0040134F(strSn, iResult);

        //增加注册码的第四部分
        iResult = Func0040136D(strName);
        iResult ^= iEdx;
        iResult |= iEcx;
        iResult *= (strName[0] * strName[1]);
        strSn.push_back('-');
        Func0040134F(strSn, iResult);

        //增加注册码的第五部分
        strSn.push_back('-');
        iResult = Func0040136D(strName);
        iResult = (iResult % 0x1A) + 0x41;
        strSn.push_back((char)iResult);

        iResult = (Func00401385(strName) % 0x1A) + 0x41;
        strSn.push_back((char)iResult);

        cout << strSn <<endl;

        cout << "all right!" << endl;
        cin.get();
        return 0;
}
  
--------------------------------------------------------------------------------
【经验总结】
        其中在找注册码的过程中,有一些迷惑代码,比如GetComputerNameAPI的调用,还有在 00401158 处存放0x1E,这个到最终也没有用上,在对CPUID调用后压栈后再重新取值进行计算也要小心,需要记下压栈的顺序以便后面运算的,否则很容易被搞乱计算步骤。在函数调用的时候也不是一般的压栈传参数,而是通过eax和ebx来传值,这个在开始的时候被弄得很迷惑,但多看几次就能明白怎么回事了。

        另外对于明码比较的CrackMe还是比较好破解的,用爆破是最简单的办法,而且注册码也比较容易得到,今后将多练习看看非明码比对的CrackMe来学习学习。
  
--------------------------------------------------------------------------------
【版权声明】: 转载请注明作者并保持文章的完整, 谢谢!

                                                       2007年11月04日 22:50:15

------------
上传附件到本地了,方便大家下载和以后整理。


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

收藏
免费 7
支持
分享
最新回复 (13)
雪    币: 6075
活跃值: (2236)
能力值: (RANK:1060 )
在线值:
发帖
回帖
粉丝
2
metallica
2007-11-5 21:50
0
雪    币: 29235
活跃值: (7759)
能力值: ( LV15,RANK:3306 )
在线值:
发帖
回帖
粉丝
3
学习,支持~
2007-11-5 22:22
0
雪    币: 1844
活跃值: (35)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
为你的耐心而顶贴
2007-11-5 23:33
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
支持,学习~  
2007-11-7 15:32
0
雪    币: 209
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
好详细哦,顶~
2007-11-7 18:44
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
每一步都很清晰,我来慢慢学习
2007-11-7 18:50
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
写的好详细啊。。高人。。学习中。。
2007-11-7 19:01
0
雪    币: 297
活跃值: (21)
能力值: ( LV9,RANK:330 )
在线值:
发帖
回帖
粉丝
9
厉害,学习 ,学习.......
2007-11-7 20:52
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
学习一下,谢谢
2007-11-7 22:42
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
先回复,再学习~~
2007-11-9 10:18
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ltr
12
下载学习。。
2007-11-14 16:09
0
雪    币: 6075
活跃值: (2236)
能力值: (RANK:1060 )
在线值:
发帖
回帖
粉丝
13
对于明码比较的keygen其实没什么意义
2007-11-14 17:57
0
雪    币: 209
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
初级就这么复杂 望而却步啊
2007-11-15 15:13
0
游客
登录 | 注册 方可回帖
返回
//