willJ 发表于 2011-11-23 19:25

菜鸟对一个有趣的CrackMe的详细分析

本帖最后由 xiangshen 于 2011-11-23 19:59 编辑

[文件标题:一个名为CrackMe02的CrackMe算法分析[文章作者]:willjhw[作者邮箱]:466684954@qq.com[软件名称]:CrackMe02[下载地址]:附件[运行环境]:Windows xp[使用工具]:OD,PEID[作者声明]:
只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
[详细过程]:
马上要去实习了,自己也想做逆向方面的东西,所以最近加强的逆向方面的锻炼,最近搞到一个某高校某次比赛的程序,于是拿来分析下,感觉很有收获,在此总结过后与吾爱破解的各位分享下。
老规矩,先用PEID查壳,如下图:
很明显是一个vc++的程序,直接上od吧。F9允许后发现是个控制台程序,我们在输入函数后的地方下断,就是40101e吧。
0040101E|.8B8424 0C1000 MOV EAX,DWORD PTR SS:
00401025|.83C4 08       ADD ESP,8
00401028|.83F8 01       CMP EAX,1
0040102B|.75 20         JNE SHORT 0040104D
0040102D|.8D4C24 00   LEA ECX,
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:            ; ASCII "ADGNWKQU"
00401118|.8B0D A4A14000 MOV ECX,DWORD PTR DS:            ; ASCII "WKQU"
0040111E|.53            PUSH EBX
0040111F|.55            PUSH EBP
00401120|.8B6C24 18   MOV EBP,DWORD PTR SS:
00401124|.56            PUSH ESI
00401125|.57            PUSH EDI                                 ; //Arg2 => ARG.EDI
00401126|.894424 10   MOV DWORD PTR SS:,EAX         ; ||
0040112A|.894C24 14   MOV DWORD PTR SS:,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:             ; ||
00401137|.8A15 A8A14000 MOV DL,BYTE PTR DS:            ; ||
0040113D|.F7D1          NOT ECX                                  ; ||
0040113F|.49            DEC ECX                                  ; ||
00401140|.885424 18   MOV BYTE PTR SS:,DL             ; ||
00401144|.83F9 08       CMP ECX,8                              ; ||
00401147|.75 62         JNE SHORT 004011AB                     ; ||


以后的汇编实现的功能就是将关键比较的字符串ADGNWKQU压入,然后在401144处进行判断你输入的长度是否为8,如果不是8则直接跳入失败的地方,所以这里说明输入的注册码的长度为8。
00401161|> /8D741C 10   /LEA ESI,                  ; ||
00401165|. |B9 1A000000   |MOV ECX,1A                              ; ||
0040116A|. |0FBE042E      |MOVSX EAX,BYTE PTR DS:         ; ||
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:                ; ||
0040117C|. |83C4 04       |ADD ESP,4                               ; ||
0040117F|. |3AC1          |CMP AL,CL                               ; ||
00401181|. |75 28         |JNE SHORT 004011AB                      ; ||
00401183|. |8D7C24 10   |LEA EDI,                     ; ||
00401187|. |83C9 FF       |OR ECX,FFFFFFFF                         ; ||
0040118A|. |33C0          |XOR EAX,EAX                           ; ||
0040118C|. |43            |INC EBX                                 ; ||
0040118D|. |F2:AE         |REPNE SCAS BYTE PTR ES:            ; ||
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:             ; 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 = "ADGNWKQU";
       char str2;
       int i = 0;
       printf ("\n其中一个字符串:\n")
       for (i = 0; i < 8; i++)
       {
            str2 = str1 - 0x41 + 0x1a + 0x2f;
            printf ("%c",str2);   
       }
       printf ("\n");
       return 0;
}


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

我们发现有个问题呀,它的答案是right?说明有问题呀。我们再看看这个程序的提示有个VERYEASY还有在以下汇编我们看看:
0040101E|.8B8424 0C1000 MOV EAX,DWORD PTR SS:
00401025|.83C4 08       ADD ESP,8
00401028|.83F8 01       CMP EAX,1
0040102B|.75 20         JNE SHORT 0040104D
0040102D|.8D4C24 00   LEA ECX,
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
004011C9|.53            push    ebx
004011CA|.55            push    ebp
004011CB|.56            push    esi
004011CC|.57            push    edi
004011CD|.894C24 1C   mov   dword ptr , 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
004011DF|.A1 F0A14000   mov   eax, dword ptr
004011E4|.F3:A5         rep   movs dword ptr es:, dword p>
004011E6|.66:8B0D C4A14>mov   cx, word ptr
004011ED|.8B6C24 50   mov   ebp, dword ptr
004011F1|.66:A5         movs    word ptr es:, word ptr [esi>
004011F3|.894424 18   mov   dword ptr , eax
004011F7|.A1 C0A14000   mov   eax, dword ptr
004011FC|.A4            movs    byte ptr es:, byte ptr [esi>
004011FD|.894424 10   mov   dword ptr , eax
00401201|.66:894C24 14mov   word ptr , cx
00401206|.8BFD          mov   edi, ebp
00401208|.83C9 FF       or      ecx, FFFFFFFF
0040120B|.33C0          xor   eax, eax
0040120D|.8A15 F8A14000 mov   dl, byte ptr
00401213|.F2:AE         repne   scas byte ptr es:
00401215|.F7D1          not   ecx
00401217|.885424 20   mov   byte ptr , dl
0040121B|.8A15 C6A14000 mov   dl, byte ptr
00401221|.49            dec   ecx
00401222|.885424 16   mov   byte ptr , dl
00401226|.83F9 08       cmp   ecx, 8
00401229|.0F85 D5000000 jnz   00401304



如同上面一样,也是先进行了判断输入的字符长度,上面401229就是个关键跳,如果长度不等于8就会跳向输入错误。
00401289|> /8B4C24 54   /mov   ecx, dword ptr
0040128D|. |8D741C 18   |lea   esi, dword ptr
00401291|. |0FBE042E      |movsx   eax, byte ptr
00401295|. |0FBE11      |movsx   edx, byte ptr
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
004012AD|. |83C4 04       |add   esp, 4
004012B0|. |3AC1          |cmp   al, cl
004012B2|. |75 50         |jnz   short 00401304
004012B4|. |8D7C24 18   |lea   edi, dword ptr
004012B8|. |83C9 FF       |or      ecx, FFFFFFFF
004012BB|. |33C0          |xor   eax, eax
004012BD|. |43            |inc   ebx
004012BE|. |F2:AE         |repne   scas byte ptr es:
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
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 = "ANLJSJWJ";
       char str2;
       int i = 0;
       printf ("\n其中一个字符串:\n");
       for (i = 0; i < 8; i++)
       {
            str2 = str1 - 0x41 + 0x56;
            printf ("%c",str2);   
       }
       printf ("\n");
       return 0;
}


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

差不多分析这么多了吧,希望对自己有所提升,也希望和吾爱破解的众位一起学习,一起进步。附件:

小败 发表于 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

{:1_937:}菜鸟默默地路过

SoSo. 发表于 2011-11-24 08:44

回复 xiangshen 的帖子

其实是一些汇编的语言还不是太熟练。一个人很难摸索,比方说DWORD PTR DS:、DWORD PTR SS:这样的指令是什么意思?

willJ 发表于 2011-11-24 08:51

回复 SoSo. 的帖子

一个是内存数,一个是堆栈数呀,那看看王爽老师的书吧,或者那本intel汇编,都不错

willJ 发表于 2011-11-24 08:52

回复 alonesky 的帖子

互相学习:loveliness:

SoSo. 发表于 2011-11-24 08:59

回复 xiangshen 的帖子

王爽老师的那本是叫《汇编语言》吧?
页: [1] 2 3 4 5
查看完整版本: 菜鸟对一个有趣的CrackMe的详细分析