首页
社区
课程
招聘
[原创]diablo2oo2's Crackme 1 分析 v1.2
发表于: 2005-8-20 18:21 9751

[原创]diablo2oo2's Crackme 1 分析 v1.2

2005-8-20 18:21
9751

【破文标题】diablo2oo2's Crackme 1 分析 v1.2
【对  象】和我一样菜的新手 :)
【破解工具】flyODBG + PEiD
【保护方式】序列号
【任  务】分析算法 + 写出注册机
【作    者】David
【破解声明】初学破解,发现入门的破文很少,所以写此篇与大家分享.
【邮    箱】DavidNes [AT] GMail.com
【Blog网址】http://www.5DBlog.com/user1/Davidz
【破解过程】

在网上找呀找,终于找到个给我点自信心的Crackme.它是dUP的作者写的,总共有8个,今天这个是最简单的1. ^-^

1.检查文件

打开PEiD检查文件,结果显示MASM32 / TASM32.说明文件未加壳,且用汇编语言编写.  :)

2.载入到flyODBG

打开flyODBG,加载后,我们停在了这里:

00401000 >  6A 00           push 0  <-----------  HoHo,Here,Here
00401002    E8 35040000     call <jmp.&KERNEL32.GetModuleHandleA>
00401007    A3 30314000     mov dword ptr ds:[403130],eax
0040100C    6A 0A           push 0A
0040100E    6A 00           push 0
00401010    6A 00           push 0
..............................

是不是看不出什么呢? 没关系,现在我们通过下断来获取我们所需的东西.点击"插件"菜单,选择进入"命令行"插件.如果是英文则是Plugin -->
Commandline.由于我们的目的是分析算法,所以这里设断点: bp GetDlgItemTextA,此函数的作用是获取文本框的内容.

现在,我们运行文件(F9),随便输入Name和Serial.(注:之前如出现暂停,可用Shift + F9略过,不影响结果).按下"Try"键,程序遇到断点,停在了
77D3274F这个地址.看看flyODBG的窗体标题,得知我们处在USER32的领空.点击"调试"-->"执行到用户代码",然后我们回到了这里:

00401246    33C0            xor eax,eax                           //eax=0
00401248    6A 28           push 28
0040124A    68 8C314000     push d2k2_cra.0040318C
0040124F    6A 02           push 2
00401251    FF75 08         push dword ptr ss:[ebp+8]
00401254    E8 8F010000     call <jmp.&USER32.GetDlgItemTextA>    //调用GetDlgItemTextA函数,获取输入的Name
00401259    84C0            test al,al <---- 我们在这儿呢 :)      //al为Name的长度,单位Byte
0040125B    0F84 06010000   je d2k2_cra.00401367                  //为0则跳,MessageBoxA --> "Enter Name!"
00401261    3C 20           cmp al,20
00401263    0F8F 13010000   jg d2k2_cra.0040137C                  //大于20H则跳,MessageBoxA --> "Name can be max 32 Chars long!"
00401269    3C 05           cmp al,5
0040126B    0F8C 20010000   jl d2k2_cra.00401391                  //小于5H则跳,MessageBoxA --> "Name must be min 5 Chars long!"
..............................

看看我们所停地址的上面,是一个完整的GetDlgItemTextA调用. 分析0040124A这一行我们知道,我们输入的Name被保存在了0040318C
这个地址.后面的几行代码请看相关的注释,均为判断Name是否合法的语句.我们继续往下看:

00401271    8D1D 8C314000   lea ebx,dword ptr ds:[40318C]         //ebx=40318C,这个地址就是储存Name的地址
00401277    33C9            xor ecx,ecx                           //ecx=0
00401279    B0 05           mov al,5                              //al=5
0040127B    33D2            xor edx,edx                           //edx=0
0040127D    8A0C1A          mov cl,byte ptr ds:[edx+ebx]          //依次取Name的前5位至cl,5位之后不参与计算
00401280    80F1 29         xor cl,29                             //cl=cl xor 29
00401283    02C8            add cl,al                             //cl=cl+al
00401285    80F9 41         cmp cl,41
00401288    7C 1C           jl short d2k2_cra.004012A6            //cl小于41则跳到004012A6
0040128A    80F9 5A         cmp cl,5A
0040128D    7F 17           jg short d2k2_cra.004012A6            //cl大于5A则跳到004012A6 (If cl < 41 or cl > 5A Then jmp short d2k2_cra.004012A6)
0040128F    888A 3C314000   mov byte ptr ds:[edx+40313C],cl       //byte ptr ds:[edx+40313C]=cl 注:这里依次将运算后的注册码存入40313C-403140
00401295    C682 3D314000   mov byte ptr ds:[edx+40313D],0        //byte ptr ds:[edx+40313D]=0     的空间中
0040129C    FEC2            inc dl                                //dl=dl+1
0040129E    FEC8            dec al                                //al=al-1
004012A0    3C 00           cmp al,0
004012A2    74 08           je short d2k2_cra.004012AC            //al等于0则跳到004012AC
004012A4  ^ EB D7           jmp short d2k2_cra.0040127D           //跳回0040127D
004012A6    B1 52           mov cl,52                             //cl=52
004012A8    02C8            add cl,al                             //cl=cl+al
004012AA  ^ EB E3           jmp short d2k2_cra.0040128F           //跳回0040128F
.............................

上面这段代码我们可以看出程序算出了前5位注册码,并将其存入40313C-403140这部分空间中.还可以发现注册码只与Name的前5位有关(PS:怪不得最小要求5位).
用VB语言表达上面的算法如下:

//Name(0 To 4)表示Name的前5位;Serial()表示计算出的注册码
For al = 5 To 1 Step -1
    cl = Name(5 - al)   //依次取Name的前5位至cl
    cl = cl Xor &H29
    cl = cl + al

    If (cl < &H41) Or (cl > &H5A) Then
       cl = &H52
       cl = cl + al
    End If
   
    Serial(5 - al) = cl
Next al

继续跟下去:

004012AC    33D2            xor edx,edx                            //edx=0
004012AE    B8 05000000     mov eax,5                              //eax=5
004012B3    8A0C1A          mov cl,byte ptr ds:[edx+ebx]           //依次取Name的前5位至cl,5位之后不参与计算
004012B6    80F1 27         xor cl,27                              //cl=cl xor 27
004012B9    02C8            add cl,al                              //cl=cl+al
004012BB    80C1 01         add cl,1                               //cl=cl+1
004012BE    80F9 41         cmp cl,41
004012C1    7C 1C           jl short d2k2_cra.004012DF             //cl小于41则跳到004012DF
004012C3    80F9 5A         cmp cl,5A
004012C6    7F 17           jg short d2k2_cra.004012DF             //cl大于5A则跳到004012DF (If cl < 41H or cl > 5AH then jmp short d2k2_cra.004012DF)
004012C8    888A 41314000   mov byte ptr ds:[edx+403141],cl        //byte ptr ds:[edx+403141]=cl 注:这里依次将运算后的注册码存入403141-403145
004012CE    C682 42314000   mov byte ptr ds:[edx+403142],0         //byte ptr ds:[edx+403142]=0     的空间中
004012D5    FEC2            inc dl                                 //dl=dl+1
004012D7    FEC8            dec al                                 //al=al-1
004012D9    3C 00           cmp al,0
004012DB    74 08           je short d2k2_cra.004012E5             //al等于0则跳到004012E5
004012DD  ^ EB D4           jmp short d2k2_cra.004012B3            //跳回004012B3
004012DF    B1 4D           mov cl,4D                              //cl=4D
004012E1    02C8            add cl,al                              //cl=cl+al
004012E3  ^ EB E3           jmp short d2k2_cra.004012C8            //跳回004012C8
.............................

上面这段代码是程序根据Name的前5位经不同的运算又算出了后5位的注册码,并存入了403141-403145这部分空间中.
用VB语言表达上面的算法如下:

//Name(0 To 4)表示Name前5位;Serial(0 To 9)表示计算出的注册码
For al = 5 To 1 Step -1
    cl = Name(5 - al)
    cl = cl Xor &H27
    cl = cl + al + 1
   
    If (cl < &H41) Or (cl > &H5A) Then
       cl = &H4D
       cl = cl + al
    End If
   
    Serial(5+(5 - al)) = cl
Next al

让我们继续往下看:

004012E5    33C0            xor eax,eax                            //eax=0
004012E7    6A 28           push 28
004012E9    68 B4314000     push d2k2_cra.004031B4                 //这里可以看出程序把输入的Serial存入004031B4这里的空间中
004012EE    6A 04           push 4
004012F0    FF75 08         push dword ptr ss:[ebp+8]
004012F3    E8 F0000000     call <jmp.&USER32.GetDlgItemTextA>     //调用GetDlgItemTextA函数,获得输入的Serial
004012F8    66:85C0         test ax,ax                             //ax为Serial长度,单位Byte
004012FB    74 55           je short d2k2_cra.00401352             //ax为零则跳,MessageBoxA --> "Wrong Code!Try Again!"
004012FD    66:83F8 0A      cmp ax,0A
00401301    7F 4F           jg short d2k2_cra.00401352             //ax不为0A则跳,MessageBoxA --> "Wrong Code!Try Again!".说明Serial必须是10位.
00401303    7C 4D           jl short d2k2_cra.00401352             //(If ax <> 0AH Then jmp short d2k2_cra.00401352)
00401305    33C0            xor eax,eax                            //eax=0
00401307    33DB            xor ebx,ebx                            //ebx=0
00401309    33C9            xor ecx,ecx                            //ecx=0
0040130B    33D2            xor edx,edx                            //edx=0
0040130D    8D05 B4314000   lea eax,dword ptr ds:[4031B4]          //eax=4013B4
00401313    8A1C01          mov bl,byte ptr ds:[ecx+eax]           //依次取Serial到bl
00401316    8A91 3C314000   mov dl,byte ptr ds:[ecx+40313C]        //依次取byte ptr ds:[ecx+40313C]到dl,即刚才算出来的10位Serial(注:这里循环取10次)
0040131C    80FB 00         cmp bl,0
0040131F    0F84 81000000   je d2k2_cra.004013A6                   //bl为0则跳,MessageBoxA --> "Serial is correct!..."
00401325    80C2 05         add dl,5                               //dl=dl+5
00401328    80FA 5A         cmp dl,5A
0040132B    7F 14           jg short d2k2_cra.00401341             //dl大于5A则跳到00401341
0040132D    80F2 0C         xor dl,0C                              //dl=dl XOR 0CH
00401330    80FA 41         cmp dl,41
00401333    7C 11           jl short d2k2_cra.00401346             //dl小于41则跳到00401346
00401335    80FA 5A         cmp dl,5A
00401338    7F 12           jg short d2k2_cra.0040134C             //dl大于5A则跳到0040134C
0040133A    41              inc ecx                                //ecx=ecx + 1
0040133B    38DA            cmp dl,bl
0040133D  ^ 74 D4           je short d2k2_cra.00401313             //若dl=bl,则比较下一位
0040133F    EB 11           jmp short d2k2_cra.00401352            //不相等则跳,MessageBoxA --> "Wrong Code!Try Again!"
00401341    80EA 0D         sub dl,0D                              //dl=dl-0D
00401344  ^ EB E7           jmp short d2k2_cra.0040132D            //跳回0040132D
00401346    B2 4B           mov dl,4B                              //dl=4B
00401348    02D1            add dl,cl                              //dl=dl+cl
0040134A  ^ EB EE           jmp short d2k2_cra.0040133A            //跳回0040133A
0040134C    B2 4B           mov dl,4B                              //dl=4B
0040134E    2AD1            sub dl,cl                              //dl=dl-cl
00401350  ^ EB E8           jmp short d2k2_cra.0040133A            //跳回0040133A
..............................

这段代码相当于对上面算出来的Serial做一番修正后,与输入的Serial进行比较.可以看到0040133B这条是比较语句,因此这里的dl就相当于正确的Serial了,相关的计算也到此结束.它的计算用VB代码表示就是下面这样:

//Name(0 To 4)表示Name前5位;Serial(0 To 9)表示计算出的注册码
For ecx = 0 To 9
    dl = Serial(ecx)  //依次取出已算出的Serial
    dl = dl + 5
   
    If dl > &H5A Then dl = dl  - &HD
   
    dl = dl  Xor &HC
   
    If dl < &H41 Then
       dl = &H4B
       dl = dl + ecx
    Else
       If dl > &H5A Then
          dl = &H4B
          dl = dl - ecx
       End If
    End If
   
    Serial(ecx) = dl  //一番计算后重新赋值
Next ecx

经过这3步,Serial就计算出来了.至于写注册机,那么只要把上面的3段VB代码结合起来就可以写出来啦.   ^-^

【F. A. Q.】
问:可以看出第一段00401271-004012AA中al控制了循环次数,但在0040127D mov cl,byte ptr ds:[edx+ebx]处,循环体内没有改变edx或ebx值的
   代码,即每次都取Name[0].那edx或ebx值是何时发生了改变?

答:ebx的值未改变,一直为40318C.
   edx的值改变注意这里:0040129C FEC2 inc dl   //dl=dl+1
   dl的改变(8位) ---> dx的改变(16位) ---> edx的改变(32位).

【更    新】
2005-08-20:第一版发布,同时也是第一次发表破文 :)
2005-09-10:v1.1发布,更新了注释.
2005-10-01:v1.2发布,修改了部分文字,增加了FAQ.

【下    载】

大家可以在这里下载到相关的资源(diablo2oo2's Crackme 1 + 注册机及源代码 + 这篇文章):
http://free.ys168.com/?davidz 里的"Crackme相关"栏目

【小    结】
第一次写这样的文章,还请大家多多指教! 继续偶的diablo2oo2's Crackme之路....


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

收藏
免费 7
支持
分享
最新回复 (7)
雪    币: 1852
活跃值: (504)
能力值: (RANK:1010 )
在线值:
发帖
回帖
粉丝
2
不错,写的很详细
支持!!
2005-8-20 21:21
0
雪    币: 442
活跃值: (1241)
能力值: ( LV12,RANK:1130 )
在线值:
发帖
回帖
粉丝
3
后面的几个可没有这么简单,要有生理和心理准备,继续……
2005-8-20 21:36
0
雪    币: 234
活跃值: (370)
能力值: ( LV9,RANK:530 )
在线值:
发帖
回帖
粉丝
4
支持!不知是那为牛人的东东,好多人想破它
2005-8-21 13:18
0
雪    币: 214
活跃值: (15)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
5
支持一下楼主
2005-8-22 00:52
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
我是新手,请问:
可以很明显的看出第一段00401271 - 004012AA 中al 控制了循环次数 ,
但在0040127D处 mov cl,byte ptr ds:[edx+ebx],循环体内没有改变
edx 或者 ebx 值的代码啊,那按照我的理解就是每次都取Name[0],

那edx或ebx都底是何时改变了值?
2005-8-22 02:58
0
雪    币: 207
活跃值: (40)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
7
ebx的值未改变,一直为40318C.
edx的值注意这里:0040129C FEC2 inc dl //dl=dl+1
dl的改变(8位) ---> dx的改变(16位) ---> edx的改变(32位).
呵呵,我一开始也卡在了这里,建立looklook查下有关的资料,看看这三个数的关系
2005-8-23 00:18
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
感谢楼主点拨, 这下果然明白了.
2005-8-25 01:37
0
游客
登录 | 注册 方可回帖
返回
//