首页
社区
课程
招聘
<<加密与解密第二版>>光盘中的一个CrackMe破解
2006-2-21 17:34 11724

<<加密与解密第二版>>光盘中的一个CrackMe破解

2006-2-21 17:34
11724
<<加密与解密第二版>>光盘中的一个CrackMe破解

    本人是新手,最近下决心努力学习破解技术.在<<加密与解密第二版>>的练习题中发现了这个CrackMe,做完觉得挺有意思.书中也有答案,不过是实验出来的,我是算出来的:)
    我把破解的过程,包括走的弯路总结了一下,写下这篇破破文,一来和大家一起分享,二来为了以后自己复习,OK,LET'S GO!
    CrackMe文件名为echap511.exe,无壳.(带壳的我都不做,等学完脱壳再说^_^)
    运行后,只有一个文本框让输入注册码,看来注册码是固定的了.乱输了一个,显示"Bad Serial.Sorry!",嗯,有门.
    打开W32DSM,找到该字串位置,往上看看,还发现一个字串"Good Work Cracker",嗯,这是我的目标.那再往上就应该是计算注册码的过程了.我把这段汇编代码粘下来,虽然我自己也不喜欢看这玩意,不过只要耐着性子看,还是能看懂的(不爱看主要就是因为菜).另外我喜欢用OLLYDBG看汇编代码,因为它加的很多注释对理解汇编代码非常有帮助,建议你看此文的时候也用OLLYDBG打开这个CrackMe.
    下面就是我输入1234后,中断下来的汇编代码:
   
004010C9  /$  56            PUSH ESI                                 ;  echap511.00401041
004010CA  |.  57            PUSH EDI
004010CB  |.  51            PUSH ECX
004010CC  |.  33F6          XOR ESI,ESI
004010CE  |.  33FF          XOR EDI,EDI
004010D0  |.  B9 08000000   MOV ECX,8
004010D5  |.  BE 44304000   MOV ESI,echap511.00403044                ;  ASCII "1234"
004010DA  |>  8036 32       /XOR BYTE PTR DS:[ESI],32
004010DD  |.  46            |INC ESI
004010DE  |.^ E2 FA         \LOOPD SHORT echap511.004010DA
004010E0  |.  BE 44304000   MOV ESI,echap511.00403044                ;  ASCII "1234"
004010E5  |.  B9 04000000   MOV ECX,4
004010EA  |>  8A06          /MOV AL,BYTE PTR DS:[ESI]
004010EC  |.  8A5E 01       |MOV BL,BYTE PTR DS:[ESI+1]
004010EF  |.  32C3          |XOR AL,BL
004010F1  |.  8887 4C304000 |MOV BYTE PTR DS:[EDI+40304C],AL
004010F7  |.  83C6 02       |ADD ESI,2
004010FA  |.  47            |INC EDI
004010FB  |.^ E2 ED         \LOOPD SHORT echap511.004010EA
004010FD  |.  BE 4C304000   MOV ESI,echap511.0040304C
00401102  |.  8A06          MOV AL,BYTE PTR DS:[ESI]
00401104  |.  8A5E 01       MOV BL,BYTE PTR DS:[ESI+1]
00401107  |.  32C3          XOR AL,BL
00401109  |.  8A5E 02       MOV BL,BYTE PTR DS:[ESI+2]
0040110C  |.  8A4E 03       MOV CL,BYTE PTR DS:[ESI+3]
0040110F  |.  32D9          XOR BL,CL
00401111  |.  32C3          XOR AL,BL
00401113  |.  B9 08000000   MOV ECX,8
00401118  |.  BE 44304000   MOV ESI,echap511.00403044                ;  ASCII "1234"
0040111D  |>  3006          /XOR BYTE PTR DS:[ESI],AL
0040111F  |.  46            |INC ESI
00401120  |.^ E2 FB         \LOOPD SHORT echap511.0040111D
00401122  |.  B9 08000000   MOV ECX,8
00401127  |.  BE 44304000   MOV ESI,echap511.00403044                ;  ASCII "1234"
0040112C  |.  BF 08304000   MOV EDI,echap511.00403008
00401131  |>  8A06          /MOV AL,BYTE PTR DS:[ESI]
00401133  |.  3A07          |CMP AL,BYTE PTR DS:[EDI]
00401135  |.  75 1D         |JNZ SHORT echap511.00401154
00401137  |.  46            |INC ESI
00401138  |.  47            |INC EDI
00401139  |.^ E2 F6         \LOOPD SHORT echap511.00401131
0040113B  |.  6A 40         PUSH 40                                  ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
0040113D  |.  68 35304000   PUSH echap511.00403035                   ; |crackme 1.0
00401142  |.  68 10304000   PUSH echap511.00403010                   ; |good work cracker
00401147  |.  FF35 54304000 PUSH DWORD PTR DS:[403054]               ; |hOwner = 006D06F6 ('Pusillus Crackme 1.0',class='#32770')
0040114D  |.  E8 3C000000   CALL <JMP.&USER32.MessageBoxA>           ; \MessageBoxA
00401152  |.  EB 17         JMP SHORT echap511.0040116B
00401154  |>  6A 30         PUSH 30                                  ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
00401156  |.  68 35304000   PUSH echap511.00403035                   ; |crackme 1.0
0040115B  |.  68 22304000   PUSH echap511.00403022                   ; |bad serial, sorry!
00401160  |.  FF35 54304000 PUSH DWORD PTR DS:[403054]               ; |hOwner = 006D06F6 ('Pusillus Crackme 1.0',class='#32770')
00401166  |.  E8 23000000   CALL <JMP.&USER32.MessageBoxA>           ; \MessageBoxA
0040116B  |>  5F            POP EDI
0040116C  |.  5E            POP ESI
0040116D  |.  59            POP ECX

    如果你和我一样菜,现在应该头痛了.我已经头痛过了,现在来帮助你减少一下痛苦,我一点点来解释这段代码,以下出现的代码全是节选上面的,不同的是加入了我自己的注释:

第一段:
004010C9  /$  56            PUSH ESI                                ;  echap511.00401041
004010CA  |.  57            PUSH EDI
004010CB  |.  51            PUSH ECX                                                                ; 以上三句和函数调用有关,不管
004010CC  |.  33F6          XOR ESI,ESI       
004010CE  |.  33FF          XOR EDI,EDI                                                                ; ESI和EDI就归0了,算是初始化
004010D0  |.  B9 08000000   MOV ECX,8                                                                ; ECX = 8,这是干什么呢?往下看
004010D5  |.  BE 44304000   MOV ESI,echap511.00403044               ; ASCII "1234" ,把你输入的注册码地址放到ESI里
004010DA  |>  8036 32       /XOR BYTE PTR DS:[ESI],32                               
004010DD  |.  46            |INC ESI                                                                ; 指向注册码的下一位
004010DE  |.^ E2 FA         \LOOPD SHORT echap511.004010DA                       
    上面的代码主要是一个循环,以ECX为循环变量,也就是要循环8次,第N次循环把注册码的第N位和32异或.由此可见,注册码是8位长.开局不错,往下来

第二段:
004010E0  |.  BE 44304000   MOV ESI,echap511.00403044               ; ASCII "1234"
004010E5  |.  B9 04000000   MOV ECX,4                                                                ; 又要循环了吧,这次是4次       
004010EA  |>  8A06          /MOV AL,BYTE PTR DS:[ESI]                                ; AL依次指向注册码的1,3,5,7位
004010EC  |.  8A5E 01       |MOV BL,BYTE PTR DS:[ESI+1]                                ; BL依次指向注册码的2,4,6,8位
004010EF  |.  32C3          |XOR AL,BL
004010F1  |.  8887 4C304000 |MOV BYTE PTR DS:[EDI+40304C],AL                ; 把做完异或运算的AL放到一个地方存起来.会有4个AL放到连续的空间里
004010F7  |.  83C6 02       |ADD ESI,2
004010FA  |.  47            |INC EDI
004010FB  |.^ E2 ED         \LOOPD SHORT echap511.004010EA
    上段代码也挺简单,注意的是,虽然注释中我使用的是注册码,不过这个注册码已经是在第一段代码中和0X32做完异或运算的了,只不过地址一样.
   
第三段:  
004010FD  |.  BE 4C304000   MOV ESI,echap511.0040304C                                ; 0040304C这个地址就是刚才存放那4个AL的位置
00401102  |.  8A06          MOV AL,BYTE PTR DS:[ESI]                                ; AL取该地址的第1个值
00401104  |.  8A5E 01       MOV BL,BYTE PTR DS:[ESI+1]                                ; BL取第2个值
00401107  |.  32C3          XOR AL,BL                                                                ; AL和BL做异或
00401109  |.  8A5E 02       MOV BL,BYTE PTR DS:[ESI+2]                                ; BL取第3个值
0040110C  |.  8A4E 03       MOV CL,BYTE PTR DS:[ESI+3]                                ; CL取第4个值
0040110F  |.  32D9          XOR BL,CL                                                                ; BL和CL做异或
00401111  |.  32C3          XOR AL,BL                                                                ; AL再和新的BL异或(咋这么多异或呢...)
    这段代码最后求出一个AL,而这个AL是这段代码中最主要的,可以管它叫"算子"

第四段:
00401113  |.  B9 08000000   MOV ECX,8                                                                ; 还是循环
00401118  |.  BE 44304000   MOV ESI,echap511.00403044               ; ASCII "1234"   
0040111D  |>  3006          /XOR BYTE PTR DS:[ESI],AL
0040111F  |.  46            |INC ESI
00401120  |.^ E2 FB         \LOOPD SHORT echap511.0040111D                        ; 把注册码和算子AL做异或(我保证是最后的异或了...)
    现在注册码又发生了变化,我们理一下:输入的注册码和0X32做了一次异或,然后又和算出的AL做了一次异或,得出的是什么东西?往下看
   

第五段:
00401122  |.  B9 08000000   MOV ECX,8
00401127  |.  BE 44304000   MOV ESI,echap511.00403044                ;  ASCII "1234"
0040112C  |.  BF 08304000   MOV EDI,echap511.00403008
00401131  |>  8A06          /MOV AL,BYTE PTR DS:[ESI]
00401133  |.  3A07          |CMP AL,BYTE PTR DS:[EDI]
00401135  |.  75 1D         |JNZ SHORT echap511.00401154
00401137  |.  46            |INC ESI
00401138  |.  47            |INC EDI
00401139  |.^ E2 F6         \LOOPD SHORT echap511.00401131

        00403044就是存放注册码的地址,这段代码中有一个循环,让00403044开始的8个值和00403008开始的8个值比较,有一位不同就会弹出Bad Serial....的字串.我看了一下00403088处的值是71  18  59  1B  79  42  45  4C,从程序开始就没变化过,ASCII码是一堆乱码,看来是把输入的注册码经过一顿运算,算出乱码后和目标码比较,相同就注册成功.这样就避免了明码比较,加强了安全性.
        我们的目标就是输入一个8位长的字串,经过上面的"各种异或"运算后,得到71  18  59  1B  79  42  45  4C这8个值就成功了.我试过把求这段代码的逆运算,后来求迷糊了就放弃了,还试过写个程序穷举注册码,结果程序陷入了长长的计算过程中....
        还是清醒一下,好好看看计算过程吧:
        我们把注册码假设为abcdefgh,正好8位:)
        然后a xor 0x32, b xor 0x32, .......又算出了8个值,假设为a'b'c'd'e'f'g'h'
        然后a' xor AL, b' xor AL, .....算出的值要等于71  18  59  1B  79  42  45  4C才行
        即
        a xor 0x32 xor AL = 0x71  因为a xor 0x32 = a',所以该式等价于 a' xor AL = 0x71
        b xor 0x32 xor AL = 0x18  同上等价于b' xor AL = 0x18
        .....
        .....
        异或运算有个特点,就是如果 A XOR B = C,那么 A = C XOR B
        那么可得a', b'....的表达形式:
        a' = 0x71 xor AL        (1)
        b' = 0x18 xor AL        (2)
        .....
        .....
        h' = 0x4C xor AL    (8)
        那么那个AL是怎么算的呢?看一下第三段代码可得
        AL = (a' xor b') xor (c' xor d') xor (e' xor f') xor (g' xor h')
        把(1),(2)....(8)代入可得
        AL =         (0x71 xor AL xor 0x18 xor AL ) xor (0x59 xor AL xor 0x1B xor AL) xor
                        (0x79 xor AL xor 0x42 xor AL ) xor (0x45 xor AL xor 0x4C xor AL)
        由于异或运算满足交换律,结合律,且一个数异或本身结果为0,任一个数异或0值不变(这点类似减法)
        上式中有8个AL,根据性质它们可以消掉,即
        AL = 0x71 xor 0x18 xor 0x59 xor 0x1B xor 0x79 xor 0x42 xor 0x45 xor 0x4C
        原来就是目标码异或的值!
        知道了AL,原注册码就好办了
        a = a' xor 0x32 = 0x71 xor AL xor 0x32
        .....
        .....
        最后得到注册码Z3r0Ring

[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

上传的附件:
收藏
点赞7
打赏
分享
最新回复 (16)
雪    币: 424
活跃值: (2618)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
gdszmai 2 2006-2-21 19:27
2
0
 支持!学习!
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
viviann 2006-2-21 20:50
3
0
支持楼主,此等正是我学习之教材!
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
peterwang 2006-2-21 21:03
4
0
我比你还菜,居然还有地方不明白。虽然经常上来看,可是迷糊的地方多。
对初学者来说,着就是精华!
最佳新人奖,应该奖励给你!!

雪    币: 32410
活跃值: (18730)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 8 2006-2-21 21:13
5
0
文章不错,建议刚入门的新人都从CrackMe入门,这样进步很快的,这个版块主要也是为新人设立的。
如果找外面的软件练习,可能会伤自信心的,因为现在的软件保护都比较强。
雪    币: 2256
活跃值: (941)
能力值: (RANK:2210 )
在线值:
发帖
回帖
粉丝
逍遥风 55 2006-2-21 21:49
6
0
深有同感,只是开学了没时间搞CRACKME了.哎...
雪    币: 50
活跃值: (145)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
zhaoocn 7 2006-2-22 00:16
7
0
老大说的对,以后照着做
雪    币: 214
活跃值: (15)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
ljy3282393 1 2006-2-22 01:27
8
0
支持并学习
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Eller 2006-2-22 10:37
9
0
我想试一下,多谢了!!
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
晓宇小雨 2006-2-22 13:17
10
0
侬也try一下,thanks!
雪    币: 179
活跃值: (131)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
WAKU 7 2006-2-22 16:39
11
0
得到老大的肯定,POWER MAX!
和大家一起努力学习
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yujinjianx 2006-2-22 20:24
12
0
支持楼主,
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
arron 2006-2-22 22:03
13
0
详细,支持楼主。
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
WildCat 2006-2-23 00:29
14
0
最初由 kanxue 发布
文章不错,建议刚入门的新人都从CrackMe入门,这样进步很快的,这个版块主要也是为新人设立的。
如果找外面的软件练习,可能会伤自信心的,因为现在的软件保护都比较强。


听老大的话。。。一切从零开始!
雪    币: 214
活跃值: (70)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
小Ding 2006-2-24 21:48
15
0
我第一次写的注册码算法,呵呵,谢谢楼主!
main()
{        int A,B,C,a[16]={0x71,0x18,0x59,0x1B,0x79,0x42,0x45,0x4C};
        int i,j=0;
        for(i=0;i<8;i++)
        {        a[i]=a[i]^0x32;
        }
        for(i=0;i<4;i++)
        {        A=a[j];
                B=a[j+1];
                A=A^B;
                a[i+8]=A;
                j=j+2;
        }
        A=a[8];
        B=a[9];
        A=A^B;
        B=a[10];
        C=a[11];
        B=B^C;
        A=A^B;
        for(i=0;i<8;i++)
        {        a[i]=a[i]^A;
                printf("%x ",a[i]);
        }

}
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
TAOTAO 2006-2-26 16:22
16
0
最初由 viviann 发布
支持楼主,此等正是我学习之教材!
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lanzo 2006-2-27 09:54
17
0
我是菜鸟,反复地看还有许多地方不明白,迷糊的东西挺多的,对初学者来说,就是支持和鼓励!谢谢楼主!!
游客
登录 | 注册 方可回帖
返回