吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 14678|回复: 41
收起左侧

[原创] 菜鸟对一个有趣的CrackMe的详细分析

[复制链接]
willJ 发表于 2011-11-23 19:25
本帖最后由 xiangshen 于 2011-11-23 19:59 编辑

[文件标题:一个名为CrackMe02CrackMe算法分析
[文章作者]:willjhw
[作者邮箱]:466684954@qq.com
[软件名称]:CrackMe02
[下载地址]:附件
[运行环境]:Windows xp
[使用工具]:OD,PEID
[作者声明]:
只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!

[详细过程]

马上要去实习了,自己也想做逆向方面的东西,所以最近加强的逆向方面的锻炼,最近搞到一个某高校某次比赛的程序,于是拿来分析下,感觉很有收获,在此总结过后与吾爱破解的各位分享下。

老规矩,先用PEID查壳,如下图:
1.jpg
很明显是一个vc++的程序,直接上od吧。
  F9允许后发现是个控制台程序,我们在输入函数后的地方下断,就是40101e吧。
0040101E  |.  8B8424 0C1000 MOV EAX,DWORD PTR SS:[ARG.1]
00401025  |.  83C4 08       ADD ESP,8
00401028  |.  83F8 01       CMP EAX,1
0040102B  |.  75 20         JNE SHORT 0040104D
0040102D  |.  8D4C24 00     LEA ECX,[LOCAL.1023]
00401031  |.  51            PUSH ECX                                 ; /Arg1 => OFFSET LOCAL.1023
00401032  |.  E8 D9000000   CALL 00401110                            ; \CrackMe02.00401110
00401037  |.  83C4 04       ADD ESP,4


关键call就是401032这个call的地方,我们跟进去

00401110  /[        DISCUZ_CODE_31        ]nbsp; 83EC 0C       SUB ESP,0C                               ; CrackMe02.00401110(guessed Arg1)
00401113  |.  A1 A0A14000   MOV EAX,DWORD PTR DS:[40A1A0]            ; ASCII "ADGNWKQU"
00401118  |.  8B0D A4A14000 MOV ECX,DWORD PTR DS:[40A1A4]            ; ASCII "WKQU"
0040111E  |.  53            PUSH EBX
0040111F  |.  55            PUSH EBP
00401120  |.  8B6C24 18     MOV EBP,DWORD PTR SS:[ARG.1]
00401124  |.  56            PUSH ESI
00401125  |.  57            PUSH EDI                                 ; //Arg2 => ARG.EDI
00401126  |.  894424 10     MOV DWORD PTR SS:[LOCAL.2],EAX           ; ||
0040112A  |.  894C24 14     MOV DWORD PTR SS:[LOCAL.1],ECX           ; ||
0040112E  |.  8BFD          MOV EDI,EBP                              ; ||
00401130  |.  83C9 FF       OR ECX,FFFFFFFF                          ; ||
00401133  |.  33C0          XOR EAX,EAX                              ; ||
00401135  |.  F2:AE         REPNE SCAS BYTE PTR ES:[EDI]             ; ||
00401137  |.  8A15 A8A14000 MOV DL,BYTE PTR DS:[40A1A8]              ; ||
0040113D  |.  F7D1          NOT ECX                                  ; ||
0040113F  |.  49            DEC ECX                                  ; ||
00401140  |.  885424 18     MOV BYTE PTR SS:[LOCAL.0],DL             ; ||
00401144  |.  83F9 08       CMP ECX,8                                ; ||
00401147  |.  75 62         JNE SHORT 004011AB                       ; ||


以后的汇编实现的功能就是将关键比较的字符串ADGNWKQU压入,然后在401144处进行判断你输入的长度是否为8,如果不是8则直接跳入失败的地方,所以这里说明输入的注册码的长度为8
00401161  |> /8D741C 10     /LEA ESI,[EBX+ESP+10]                    ; ||
00401165  |. |B9 1A000000   |MOV ECX,1A                              ; ||
0040116A  |. |0FBE042E      |MOVSX EAX,BYTE PTR DS:[EBP+ESI]         ; ||
0040116E  |. |83E8 2F       |SUB EAX,2F                              ; ||
00401171  |. |99            |CDQ                                     ; ||
00401172  |. |F7F9          |IDIV ECX                                ; ||
00401174  |. |52            |PUSH EDX                                ; ||/Arg1
00401175  |. |E8 E6010000   |CALL 00401360                           ; ||\CrackMe02.00401360
0040117A  |. |8A0E          |MOV CL,BYTE PTR DS:[ESI]                ; ||
0040117C  |. |83C4 04       |ADD ESP,4                               ; ||
0040117F  |. |3AC1          |CMP AL,CL                               ; ||
00401181  |. |75 28         |JNE SHORT 004011AB                      ; ||
00401183  |. |8D7C24 10     |LEA EDI,[LOCAL.2]                       ; ||
00401187  |. |83C9 FF       |OR ECX,FFFFFFFF                         ; ||
0040118A  |. |33C0          |XOR EAX,EAX                             ; ||
0040118C  |. |43            |INC EBX                                 ; ||
0040118D  |. |F2:AE         |REPNE SCAS BYTE PTR ES:[EDI]            ; ||
0040118F  |. |F7D1          |NOT ECX                                 ; ||
00401191  |. |49            |DEC ECX                                 ; ||
00401192  |. |3BD9          |CMP EBX,ECX                             ; ||
00401194  |.^\7C CB         \JL SHORT 00401161                       ; ||


这个代码就是关键的算法处,里面有个call我们跟进去如下面:
00401360  /[        DISCUZ_CODE_33        ]nbsp; 8B4424 04     MOV EAX,DWORD PTR SS:[ARG.1]             ; CrackMe02.00401360(guessed Arg1)
00401364  |.  85C0          TEST EAX,EAX                             ; Switch (cases 0..1A, 2 exits)
00401366  |.  7C 08         JL SHORT 00401370
00401368  |.  83F8 1A       CMP EAX,1A
0040136B  |.  7F 03         JG SHORT 00401370
0040136D  |.  83C0 41       ADD EAX,41                               ; Cases 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 1A of switch CrackMe02.401364
00401370  \>  C3            RETN                                     ; Default case of switch CrackMe02.401364


这个call就是对每次计算出来的值进行加‘A’也就是0x41

我们再来看看上面的算法吧,就是一个循环与str=”ADGNWKQU”比较,只要有一个计算出来不等于就跳向错误。算法是:(输入  - 0x2f% 0x1a + 0x41 = str;
于是我们用c语言实现下算法:
#include <stdio.h>
 
int main (void)
 
{
       char str1[8] = "ADGNWKQU";
       char str2[8];
       int i = 0;
       printf ("\n其中一个字符串:\n")
       for (i = 0; i < 8; i++)
       {
              str2[i] = str1[i] - 0x41 + 0x1a + 0x2f;
              printf ("%c",str2[i]);    
       }
       printf ("\n");
       return 0; 
}


因为上面有取余数的操作,所以导致注册码不唯一,我就给出一组吧ILOV_SY]
得到的结果如下图:

2.jpg
我们发现有个问题呀,它的答案是right?说明有问题呀。我们再看看这个程序的提示有个VERYEASY还有在以下汇编我们看看:
0040101E  |.  8B8424 0C1000 MOV EAX,DWORD PTR SS:[ARG.1]
00401025  |.  83C4 08       ADD ESP,8
00401028  |.  83F8 01       CMP EAX,1
0040102B  |.  75 20         JNE SHORT 0040104D
0040102D  |.  8D4C24 00     LEA ECX,[LOCAL.1023]
00401031  |.  51            PUSH ECX                                 ; /Arg1 => OFFSET LOCAL.1023
00401032  |.  E8 D9000000   CALL 00401110                            ; \CrackMe02.00401110
00401037  |.  83C4 04       ADD ESP,4
0040103A  |.  68 30A04000   PUSH OFFSET 0040A030                     ; ASCII "pause"
0040103F  |.  E8 3C030000   CALL 00401380
00401044  |.  33C0          XOR EAX,EAX
00401046  |.  81C4 04100000 ADD ESP,1004
0040104C  |.  C3            RETN
0040104D  |>  83F8 02       CMP EAX,2
00401050  |.  75 18         JNE SHORT 0040106A


如果这个程序不带参数运行,直接就不会跑到下面去,而下面才是真正的注册算法地方,于是我们用到OD的带参数调试,进入程序,发现40101e跳向了下面,参数是VERYEASY哦。关键算法4011c0处。
004011C0  /[        DISCUZ_CODE_36        ]nbsp; 83EC 3C       sub     esp, 3C
004011C3  |.  8B0D F4A14000 mov     ecx, dword ptr [40A1F4]
004011C9  |.  53            push    ebx
004011CA  |.  55            push    ebp
004011CB  |.  56            push    esi
004011CC  |.  57            push    edi
004011CD  |.  894C24 1C     mov     dword ptr [esp+1C], ecx
004011D1  |.  B9 09000000   mov     ecx, 9
004011D6  |.  BE C8A14000   mov     esi, 0040A1C8                    ;  ASCII "X#duh#vr#fohyhu$#Wklv#lv#wkh#Uhdo#Nh|[        DISCUZ_CODE_6        ]quot;
004011DB  |.  8D7C24 24     lea     edi, dword ptr [esp+24]
004011DF  |.  A1 F0A14000   mov     eax, dword ptr [40A1F0]
004011E4  |.  F3:A5         rep     movs dword ptr es:[edi], dword p>
004011E6  |.  66:8B0D C4A14>mov     cx, word ptr [40A1C4]
004011ED  |.  8B6C24 50     mov     ebp, dword ptr [esp+50]
004011F1  |.  66:A5         movs    word ptr es:[edi], word ptr [esi>
004011F3  |.  894424 18     mov     dword ptr [esp+18], eax
004011F7  |.  A1 C0A14000   mov     eax, dword ptr [40A1C0]
004011FC  |.  A4            movs    byte ptr es:[edi], byte ptr [esi>
004011FD  |.  894424 10     mov     dword ptr [esp+10], eax
00401201  |.  66:894C24 14  mov     word ptr [esp+14], cx
00401206  |.  8BFD          mov     edi, ebp
00401208  |.  83C9 FF       or      ecx, FFFFFFFF
0040120B  |.  33C0          xor     eax, eax
0040120D  |.  8A15 F8A14000 mov     dl, byte ptr [40A1F8]
00401213  |.  F2:AE         repne   scas byte ptr es:[edi]
00401215  |.  F7D1          not     ecx
00401217  |.  885424 20     mov     byte ptr [esp+20], dl
0040121B  |.  8A15 C6A14000 mov     dl, byte ptr [40A1C6]
00401221  |.  49            dec     ecx
00401222  |.  885424 16     mov     byte ptr [esp+16], dl
00401226  |.  83F9 08       cmp     ecx, 8
00401229  |.  0F85 D5000000 jnz     00401304



如同上面一样,也是先进行了判断输入的字符长度,上面401229就是个关键跳,如果长度不等于8就会跳向输入错误。
00401289  |> /8B4C24 54     /mov     ecx, dword ptr [esp+54]
0040128D  |. |8D741C 18     |lea     esi, dword ptr [esp+ebx+18]
00401291  |. |0FBE042E      |movsx   eax, byte ptr [esi+ebp]
00401295  |. |0FBE11        |movsx   edx, byte ptr [ecx]
00401298  |. |2BC2          |sub     eax, edx
0040129A  |. |B9 1A000000   |mov     ecx, 1A
0040129F  |. |83C0 1A       |add     eax, 1A
004012A2  |. |99            |cdq
004012A3  |. |F7F9          |idiv    ecx
004012A5  |. |52            |push    edx
004012A6  |. |E8 B5000000   |call    00401360
004012AB  |. |8A0E          |mov     cl, byte ptr [esi]
004012AD  |. |83C4 04       |add     esp, 4
004012B0  |. |3AC1          |cmp     al, cl
004012B2  |. |75 50         |jnz     short 00401304
004012B4  |. |8D7C24 18     |lea     edi, dword ptr [esp+18]
004012B8  |. |83C9 FF       |or      ecx, FFFFFFFF
004012BB  |. |33C0          |xor     eax, eax
004012BD  |. |43            |inc     ebx
004012BE  |. |F2:AE         |repne   scas byte ptr es:[edi]
004012C0  |. |F7D1          |not     ecx
004012C2  |. |49            |dec     ecx
004012C3  |. |3BD9          |cmp     ebx, ecx
004012C5  |.^\7C C2         \jl      short 00401289



关键算法的地方,里面有一个call也很重要,我们跟进去,如下图:
00401360  /[        DISCUZ_CODE_38        ]nbsp; 8B4424 04     mov     eax, dword ptr [esp+4]
00401364  |.  85C0          test    eax, eax
00401366  |.  7C 08         jl      short 00401370
00401368  |.  83F8 1A       cmp     eax, 1A
0040136B  |.  7F 03         jg      short 00401370
0040136D  |.  83C0 41       add     eax, 41
00401370  \>  C3            retn



也就是对结果进行加1

我们继续来看看上面的算法,其实和第一个也差不多,先定义了一个常量字符串str[]= ”ANLJSJWJ”,然后进行对输入的字符串str2进行操作:(str2 – 0x2f) % 0x1a + ‘A’ =str
如果有一个不等于就跳向错误。

下面我简单的使用c写一个算注册码的吧,因为这里是用到了取余,同样结果不唯一
#include <stdio.h>
 
int main (void)
 
{
       char str1[8] = "ANLJSJWJ";
       char str2[8];
       int i = 0;
       printf ("\n其中一个字符串:\n");
       for (i = 0; i < 8; i++)
       {
              str2[i] = str1[i] - 0x41 + 0x56;
              printf ("%c",str2[i]);    
       }
       printf ("\n");
       return 0; 
}


结果是Vca_h_1_(倒数第二个是小写的L)
运行成功的图例:
3.jpg

差不多分析这么多了吧,希望对自己有所提升,也希望和吾爱破解的众位一起学习,一起进步。
附件:
CM.rar (19.99 KB, 下载次数: 55)

免费评分

参与人数 1热心值 +1 收起 理由
KaQqi + 1 我很赞同!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

小败 发表于 2011-11-23 19:30
我承认我是沙发
 楼主| willJ 发表于 2011-11-23 19:31
SoSo. 发表于 2011-11-23 20:17
 楼主| willJ 发表于 2011-11-23 20:35
回复 SoSo. 的帖子

其实不难吧,可以玩玩嘛,互相学习
alonesky 发表于 2011-11-23 23:18
菜鸟默默地路过
SoSo. 发表于 2011-11-24 08:44
回复 xiangshen 的帖子

其实是一些汇编的语言还不是太熟练。一个人很难摸索,比方说DWORD PTR DS:[40A1A4]、DWORD PTR SS:[ARG.1]这样的指令是什么意思?
 楼主| willJ 发表于 2011-11-24 08:51
回复 SoSo. 的帖子

一个是内存数,一个是堆栈数呀,那看看王爽老师的书吧,或者那本intel汇编,都不错
 楼主| willJ 发表于 2011-11-24 08:52
回复 alonesky 的帖子

互相学习
SoSo. 发表于 2011-11-24 08:59
回复 xiangshen 的帖子

王爽老师的那本是叫《汇编语言》吧?
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-15 10:43

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表