0x00 前言
补:人生中玩的第一个类CTF游戏,感谢Tm3yshell7
朋友曾告诉我ISCLAB竞赛里有几道破解题可以看一下,共四道Cracking题目,只下载了前三关。
0x01 第一关
第一关相对简单,只需要填写注册码验证即可,如图1。
脱壳部分:
用Peid查壳,Microsoft Visual C++ 6.0 [Overlay],与程序标识的“易语言程序”不同,这里不需在意,总之是没有加壳。
动态调试部分:
将CrackMe载入Ollyice,右键选择查找--所有参考字符串,如图2。
进入文本字串参考,向上滚动,寻找比较敏感的字符串,看到图3的地方。
双击“加油”,回到反汇编窗口。向上滚动一点,看到图4的位置
可以看出跳转向成功或失败的关键部分如下:
00401064 . 3945 F8 cmp dword ptr [ebp-8], eax
00401067 . 0F85 40000000 jnz 004010AD
如果dword ptr [ebp-8]与 eax相等,则ZF标志位为1,就转向成功,否则为失败。
注意,对于CM程序通常需要单步调试一次,这样会对程序有较好的把握,另外利用OD的插件才会找到字符串。刚入程序单步时会进入死循环,按F4跳过,下面的就好说了,多试几次就好。
在00401064处按F2下断点。重新载入程序。直接运行,输入注册码,单击确定,程序会停在下断点处即cmp比较的地方,如图四。注意此时寄存器的内容。
EAX=000007DB,而堆栈 ss:[0012F6FC]即dword ptr [ebp-8]=0000007B。这里我们知道7B是十进制123,就是我输入的注册码。那么7DB就应该是真正的注册码。转换一下,图五,真正的注册码是2011。
0x02 第二关
分析第二关会是一个比较有意思的过程。第二关是个注册机,界面如图6,题目要求是以2011为用户名得带正确的注册码。
脱壳部分:
同样是个没有加壳的程序Microsoft Visual C++ 6.0 [Overlay],这里就不截图了。
动态调试部分:
还是载入Ollyice查找字符串参考,同样能达到目的,这是分析到后来发现的,crackme1和crackme2竟然可以用同种方法破解,囧了。有图为证,如图7。
这里简介一下我最初分析时用的另一种方法:函数断点法。利用的是Windows常用的一个的API:MessageBoxA。也是比较简单的。程序载入到Ollyice后,在左下角命令行输入 BP MessageBoxA,或者右键--查找--当前模块中的名称(标签),如图8。
找到MessageBoxA,右键选择在每个参考上设置断点,如图9。
这时按下Ctrl+F2重新载入程序 ,按F9运行,输入2011和错误的注册码1234,程序自动停在断点处。断点这里是马上就调用MessageBoxA了,表明程序已将用户名和注册码比较完毕,向上翻一番,会发现下面区域(中间部分省略):
00401460 . 83EC 64 sub esp, 64
00401463 . 56 push esi
00401464 . 8B7424 74 mov esi, dword ptr [esp+74]
00401468 . 57 push edi
00401469 . 8B7E 08 mov edi, dword ptr [esi+8]
0040146C . 57 push edi
0040146D . E8 7EC00000 call 0040D4F0
00401472 . 83C4 04 add esp, 4
00401475 . 85C0 test eax, eax
00401477 . 74 10 je short 00401489
00401479 . 8D4424 08 lea eax, dword ptr [esp+8]
......
004014E4 . 85C0 test eax, eax
004014E6 . 74 03 je short 004014EB
004014E8 . 8B56 18 mov edx, dword ptr [esi+18]
004014EB > 8B46 0C mov eax, dword ptr [esi+C]
004014EE . 8BF0 mov esi, eax
004014F0 . F7D6 not esi
004014F2 . 81E6 00100000 and esi, 1000
004014F8 . 8D0470 lea eax, dword ptr [eax+esi*2]
004014FB . 50 push eax ; /Style
004014FC . 52 push edx ; |Title
004014FD . 51 push ecx ; |Text
004014FE . 6A 00 push 0 ; |hOwner = NULL
00401500 . FF15 A0834600 call near dword ptr [<&USER32.Message>; \MessageBoxA
00401460 是该部分的头部,那就在此处按F2下断点。接下来的思路很好想,就是找到哪里用到或说调用了00401460这里 。右键选择转到--没有发现什么调用。那就换个思路,右键选择查找参考--选定命令,如图10。
这样就进入如图11的窗口。
上面两个关于00401460 的调用相距较近,没什么区别,我就双击第一个。进入图12的代码区域
关键代码如下:
00401064 . 3945 F8 cmp dword ptr [ebp-8], eax
00401067 . 0F85 40000000 jnz 004010AD
0040106D . 68 04000080 push 80000004
00401072 . 6A 00 push 0
00401074 . 68 519B4600 push 00469B51
00401079 . 68 01030080 push 80000301
0040107E . 6A 00 push 0
00401080 . 68 40000000 push 40
00401085 . 68 04000080 push 80000004
0040108A . 6A 00 push 0
0040108C . 68 569B4600 push 00469B56
00401091 . 68 03000000 push 3
00401096 . BB 60144000 mov ebx, 00401460
0040109B . E8 51010000 call 004011F1
004010A0 . 83C4 28 add esp, 28
004010A3 . E9 40000000 jmp 004010E8
004010A8 .^ E9 60FFFFFF jmp 0040100D
004010AD > 68 04000080 push 80000004
004010B2 . 6A 00 push 0
004010B4 . 68 5F9B4600 push 00469B5F ; ASCII "加油"
此部分与CrackMe1部分是极相似的,也是在00401064处通过cmp比较dword ptr [ebp-8]与eax。下面思路就明了,和第一关一样00401064按F2下断点。运行即可。这个CRACKME2的算法分析可以找一下,就在上方的一个CALL调用里,这里我就不多说了,得靠大家自己分析了。
0x03 第三关
第三关题目是这样讲的:这道题看起来和第一关很像,其实可不太一样。第三关的CrackMe运行如图13。
脱壳部分:
PEID查壳,汗颜,一个CM加了壳ASPack 2.x (without poly) -> Alexey Solodovnikov [Overlay]。也就是说,第三关是一个检验脱壳能力的一关。至于这个壳ASPack 2.x (without poly) -> Alexey Solodovnikov [Overlay],我试过几次,普通单步试图不脱壳破解最终只会陷入死循环里,一跳出死循环就直接运行。这也就是问题所说,其实与第一关可不太一样。当然,这并不意味这不脱壳破解就是不可能的。只是我还没达到那层次。
这里我是以先脱壳后破解的思路来破解的。首先载入Ollyice,出现图14所示提示:
按下SHIFT+F9忽略所有异常进入程序。弹出图15所示的对话框。
说明这个壳有对程序代码进行压缩。这里还是选择否。终于进入程序的汇编窗口,如图16。
没别的好方法,只好单步走了,单步走几下会有一个返回,代码如下:
00485010 5E pop esi
00485011 FF3432 push dword ptr [edx+esi]
00485014 310424 xor dword ptr [esp], eax
00485017 8F0432 pop dword ptr [edx+esi]
0048501A 4E dec esi
0048501B 83EE 03 sub esi, 3
0048501E ^ 75 F1 jnz short 00485011
00485020 16 push ss
在00485020 按F4跳过,否则是走不完的死循环。跳过后代码立即变了
00485020 E8 7D010000 call 004851A2
00485025 0000 add byte ptr [eax], al
00485027 0000 add byte ptr [eax], al
00485029 0040 00 add byte ptr [eax], al
00485020处按F7跟进。(如果不跟进程序就会运行),来到了这片代码区域:
004851A2 55 push ebp
004851A3 8BEC mov ebp, esp
004851A5 81C4 B4FEFFFF add esp, -14C
004851AB C645 F7 00 mov byte ptr [ebp-9], 0
004851AF 8BC5 mov eax, ebp
004851B1 83C0 04 add eax, 4
004851B4 8B10 mov edx, dword ptr [eax]
004851B6 83EA 05 sub edx, 5
004851B9 8955 FC mov dword ptr [ebp-4], edx
004851BC 8B4D FC mov ecx, dword ptr [ebp-4]
004851BF 81C1 84000000 add ecx, 84
004851C5 894D F8 mov dword ptr [ebp-8], ecx
004851C8 8B45 FC mov eax, dword ptr [ebp-4]
004851CB 8B50 0C mov edx, dword ptr [eax+C]
004851CE 8B4D FC mov ecx, dword ptr [ebp-4]
004851D1 0351 08 add edx, dword ptr [ecx+8]
004851D4 8BC5 mov eax, ebp
乍一看004851A2处很像是DELPHI的特征码。但事实是这个壳不会这么容易就可以脱掉的(不相信可以试一下)。现在ESP寄存器已经变化了。这时用ESP定律,在命令窗口输入hr 0012FFC0,并回车。如图17。
按F9运行,第一次断点停在
004851B6 83EA 05 sub edx, 5
很明显,这里不是。继续按一次F9。来到这里:
004851DB FF75 F8 push dword ptr [ebp-8] ; CrackMeP.004850A4
这里也不是,继续到达这里,这里有点眉目了,看此处的代码
00482001 60 pushad
00482002 E8 03000000 call 0048200A
00482007 - E9 EB045D45 jmp 45A524F7
0048200C 55 push ebp
0048200D C3 retn
0048200E E8 01000000 call 00482014
看起来很像经典的ASPack,但事实是这里还没完呢(可以跳出来试一试)。继续F9到达如图18的地方。
单步走几下,经验告诉我们,快到OEP了,单步跟踪这里
0047F001 60 pushad
仍然没有到,要有耐心,嗯,再按几下,终于到了这里,如图19。
004012FC /EB 10 jmp short 0040130E
......
00401308 |90 nop
00401309 -|E9 98504600 jmp 008663A6
0040130E \A1 8B504600 mov eax, dword ptr [46508B]
00401313 C1E0 02 shl eax, 2
00401316 A3 8F504600 mov dword ptr [46508F], eax
004012FC这里就是OEP了,我想各位可能会问怎么知道这里是入口点。其实我也不确定,只是凭感觉。即使不是也没关系,我们可以继续嘛。从这里DUMP出来,如图20。
脱壳后再用PEID查一下壳,如图21,Borland C++ 1999。
这样再运行一下,正常,脱壳完毕。至此,第三关的难点已经过去了。
动态调试部分:
脱壳后的程序载入Ollyice,经典的查找字符串如图22
很容易发现注册码就是a4d6sdsf3。想来出题者不想在这里为难参赛者吧。注册一下,成功,如图23。






















