首页
社区
课程
招聘
[原创][原创]一个CrackMe的算法分析
发表于: 2011-4-9 01:47 4099

[原创][原创]一个CrackMe的算法分析

2011-4-9 01:47
4099
标 题: 【原创】一个CrackMe的算法分析
作 者: zhaodyun
时 间: 2010-4-9 1:06
工 具:OD
链 接: http://bbs.pediy.com/showthread.php?p=945780&posted=1#post945780
说 明: 看到论坛上看到求助贴,好奇就分析了下。原文链接http://bbs.pediy.com/showthread.php?p=944869#post944869感谢s大的提醒,让我找到分析的思路,便将对此CrackMe的算法分析给像我一样的菜鸟分享一下。(第一次发贴,不中之处,还请见谅)

        刚开始的时候运行程序,查找字符串,来到如下界面



选择wrong!跟随F2下断,输入验证码zhaodyun,程序断在
004011AB  |>  68 90A14000   push CrackMe0.0040A190                   ;  wrong!\n
F8跟踪返回到主验证Call
00401031  |.  51            push ecx
00401032  |.  E8 D9000000   call CrackMe0.00401110                   ;  在此验证
00401037  |.  83C4 04       add esp,4
0040103A  |.  68 30A04000   push CrackMe0.0040A030                   ;  pause

F8单步跟踪,此时验证函数及算法分析

00401161  |> /8D741C 10 /lea esi,dword ptr ss:[esp+ebx+10]
00401165  |. |B9 1A000000  |mov ecx,1A                                                  ;  ecx=1A
0040116A  |. |0FBE042E  |movsx eax,byte ptr ds:[esi+ebp]          ;  取输入注册码
0040116E  |. |83E8 2F|sub eax,2F                                                          ;  注册码字符ASCII-2F
00401171  |. |99  |cdq
00401172  |. |F7F9|idiv ecx ;  eax/1A
00401174  |. |52  |push edx
00401175  |. |E8 E6010000  |call CrackMe0.00401360                  ;  将余数据转换成 在‘a-z‘范围内的字符
0040117A  |. |8A0E|mov cl,byte ptr ds:[esi]                                        ;  取“ADGNWKQU”中字符
0040117C  |. |83C4 04|add esp,4
0040117F  |. |3AC1|cmp al,cl                                                                ;  字符比较
00401181  |. |75 28  |jnz short CrackMe0.004011AB
00401183  |. |8D7C24 10 |lea edi,dword ptr ss:[esp+10]
00401187  |. |83C9 FF|or ecx,FFFFFFFF
0040118A  |. |33C0|xor eax,eax
0040118C  |. |43  |inc ebx                                                                  ;  循环计数+1
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 CrackMe0.00401161
00401196  |.  68 98A14000  push CrackMe0.0040A198;  right?\n
0040119B  |.  E8 8D040000  call CrackMe0.0040162D
        总结:并写了简单注册机见原贴(才发现掉陷阱里了)出现Right?,没有破解成功!看到昨天看到sessiondiy大大的提醒,今天又分析了下.

发现在这里有对输入参数有无的比较有的话eax在下面的值为2没有为1
00401025  |.  83C4 08       add esp,8
00401028  |.  83F8 01       cmp eax,1;在此验证输入有无参数,没的话为1
0040102B  |.  75 20         jnz short CrackMe0.0040104D
0040102D  |.  8D4C24 00     lea ecx,dword ptr ss:[esp]
00401031  |.  51            push ecx
00401032  |.  E8 D9000000   call CrackMe0.00401110                   ;  在此验证
00401037  |.  83C4 04       add esp,4
0040103A  |.  68 30A04000   push CrackMe0.0040A030                   ;  pause
0040103F  |.  E8 3C030000   call CrackMe0.00401380                   ;  (初始化 cpu 选择状态)
00401044  |.  33C0          xor eax,eax
00401046  |.  81C4 04100000 add esp,1004
0040104C  |.  C3            retn
0040104D  |>  83F8 02       cmp eax,2;在此验证有无参数输入有的话为2       
00401050  |.  75 18         jnz short CrackMe0.0040106A
00401052  |.  8B9424 081000>mov edx,dword ptr ss:[esp+1008]
00401059  |.  8D4C24 00     lea ecx,dword ptr ss:[esp]
0040105D  |.  8B42 04       mov eax,dword ptr ds:[edx+4]
00401060  |.  50            push eax
00401061  |.  51            push ecx
        F8单步跟踪来到这里,发现有对命令行参数验证

00401226  |.  83F9 08cmp ecx,8
00401229  |.  0F85 D5000000jnz CrackMe0.00401304                         ;  调了就OVER
0040122F  |.  8B4424 54 mov eax,dword ptr ss:[esp+54]                  ;  字符串VEREASY
00401233  |.  BE B4A14000  mov esi,CrackMe0.0040A1B4;                  veryeasy
00401238  |>  8A10/mov dl,byte ptr ds:[eax];                          取命令行参数 字符
0040123A  |.  8A1E|mov bl,byte ptr ds:[esi];                          取 VERYEASY 每个符
0040123C  |.  8ACA|mov cl,dl;                                          参数字符 给Cl(奇怪这个有什么用)
0040123E  |.  3AD3|cmp dl,bl
00401240  |.  75 1E  |jnz short CrackMe0.00401260;          如果不相等刚跳
00401242  |.  84C9|test cl,cl
00401244  |.  74 16  |je short CrackMe0.0040125C
00401246  |.  8A50 01|mov dl,byte ptr ds:[eax+1]
00401249  |.  8A5E 01|mov bl,byte ptr ds:[esi+1]
0040124C  |.  8ACA|mov cl,dl
0040124E  |.  3AD3|cmp dl,bl                                ;  同上 取第二个字符接着比较
00401250  |.  75 0E  |jnz short CrackMe0.00401260
00401252  |.  83C0 02|add eax,2
00401255  |.  83C6 02|add esi,2
00401258  |.  84C9|test cl,cl
0040125A  |.^ 75 DC  \jnz short CrackMe0.00401238;  每次取两个字符,对输入的参数进行验证
                总结:由上以参数验证算法可知,如果输入的命令行参数不是字符串VERYEASY程序直接调转向Wrong

        将输入参数改为VERYEASY继续搞。。。
        来到对验证码的验证处:
00401289|> /8B4C24 54 /mov ecx,dword ptr ss:[esp+54]         ;ECX=“VERYEASY”
0040128D|. |8D741C 18 |lea esi,dword ptr ss:[esp+ebx+18];ESI=“ANLJSJWJ”
00401291|. |0FBE042E|movsx eax,byte ptr ds:[esi+ebp]         ;逐个 取 输入验证码字符
00401295|. |0FBE11 |movsx edx,byte ptr ds:[ecx]                        ; 取“VERYEASY"字符第一个字符
00401298|. |2BC2 |sub eax,edx                                                        ;相减eax-=edx
0040129A|. |B9 1A000000 |mov ecx,1A
0040129F|. |83C0 1A |add eax,1A                                                        ;eax+=0x1A
004012A2|. |99|cdq
004012A3|. |F7F9|idiv ecx                                                                 ;eax/=0x1A
004012A5|. |52|push edx
004012A6|. |E8 B5000000 |call CrackMe0.00401360;                函数作用:把edx转换到A-Z范围内字符
004012AB|. |8A0E|mov cl,byte ptr ds:[esi]
004012AD|. |83C4 04 |add esp,4                                                         ;取“ANLJSJWJ”字符
004012B0|. |3AC1|cmp al,cl
004012B2|. |75 50 |jnz short CrackMe0.00401304                         ;跳走就 OVER
004012B4|. |8D7C24 18 |lea edi,dword ptr ss:[esp+18]
004012B8|. |83C9 FF |or ecx,FFFFFFFF
004012BB|. |33C0|xor eax,eax
004012BD|. |43|inc ebx                                                                         ;计数+1
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 CrackMe0.00401289                        ;循环
        总结:程序 取输入的验证码的每个字符与字符V相减后加上0x1A再对0x1A取模,得到的结果再调用call 00401360将基转换成A-Z范围内的字符串

        编写简单注册机如下:
#include <stdio.h>
main()
{
        char password[]="ANLJSJWJ";       
        int len=0;
        int i=0;
        len=strlen(password);   

        for(;i<len;i++)
        {
                password[i]=password[i]-'A'+'V';       
        }
        printf(password);
        printf("\n");
}
进入CMD下测试运行结果如图:


分析文档 2011-4-9.doc
Over~~~~

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 0
支持
分享
最新回复 (2)
雪    币: 51
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
自己来坐sf~
2011-4-9 01:53
0
雪    币: 193
活跃值: (1225)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
学的不错,学习一下~~
2011-5-9 22:57
0
游客
登录 | 注册 方可回帖
返回
//