<<加密与解密第二版>>光盘中的一个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
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!