[CTF]ISCC2011-Qual-Writeup

By Le4F - 2011-07-05

0x00 前言

补:人生中玩的第一个类CTF游戏,感谢Tm3yshell7

朋友曾告诉我ISCLAB竞赛里有几道破解题可以看一下,共四道Cracking题目,只下载了前三关。

0x01 第一关

第一关相对简单,只需要填写注册码验证即可,如图1。

img

脱壳部分:

用Peid查壳,Microsoft Visual C++ 6.0 [Overlay],与程序标识的“易语言程序”不同,这里不需在意,总之是没有加壳。

动态调试部分:

将CrackMe载入Ollyice,右键选择查找--所有参考字符串,如图2。

img

进入文本字串参考,向上滚动,寻找比较敏感的字符串,看到图3的地方。

img

双击“加油”,回到反汇编窗口。向上滚动一点,看到图4的位置

img

可以看出跳转向成功或失败的关键部分如下:

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。

img

0x02 第二关

分析第二关会是一个比较有意思的过程。第二关是个注册机,界面如图6,题目要求是以2011为用户名得带正确的注册码。

img

脱壳部分:

同样是个没有加壳的程序Microsoft Visual C++ 6.0 [Overlay],这里就不截图了。

动态调试部分:

还是载入Ollyice查找字符串参考,同样能达到目的,这是分析到后来发现的,crackme1和crackme2竟然可以用同种方法破解,囧了。有图为证,如图7。

img

这里简介一下我最初分析时用的另一种方法:函数断点法。利用的是Windows常用的一个的API:MessageBoxA。也是比较简单的。程序载入到Ollyice后,在左下角命令行输入 BP MessageBoxA,或者右键--查找--当前模块中的名称(标签),如图8。

img

找到MessageBoxA,右键选择在每个参考上设置断点,如图9。

img

这时按下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。

img

这样就进入如图11的窗口。

img

上面两个关于00401460 的调用相距较近,没什么区别,我就双击第一个。进入图12的代码区域

img

关键代码如下:

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。

img

脱壳部分:

PEID查壳,汗颜,一个CM加了壳ASPack 2.x (without poly) -> Alexey Solodovnikov [Overlay]。也就是说,第三关是一个检验脱壳能力的一关。至于这个壳ASPack 2.x (without poly) -> Alexey Solodovnikov [Overlay],我试过几次,普通单步试图不脱壳破解最终只会陷入死循环里,一跳出死循环就直接运行。这也就是问题所说,其实与第一关可不太一样。当然,这并不意味这不脱壳破解就是不可能的。只是我还没达到那层次。

这里我是以先脱壳后破解的思路来破解的。首先载入Ollyice,出现图14所示提示:

img

按下SHIFT+F9忽略所有异常进入程序。弹出图15所示的对话框。

img

说明这个壳有对程序代码进行压缩。这里还是选择否。终于进入程序的汇编窗口,如图16。

img

没别的好方法,只好单步走了,单步走几下会有一个返回,代码如下:

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。

img

按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的地方。

img

单步走几下,经验告诉我们,快到OEP了,单步跟踪这里

0047F001    60              pushad

仍然没有到,要有耐心,嗯,再按几下,终于到了这里,如图19。

img

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。

img

脱壳后再用PEID查一下壳,如图21,Borland C++ 1999。

img

这样再运行一下,正常,脱壳完毕。至此,第三关的难点已经过去了。

动态调试部分:

脱壳后的程序载入Ollyice,经典的查找字符串如图22

img

很容易发现注册码就是a4d6sdsf3。想来出题者不想在这里为难参赛者吧。注册一下,成功,如图23。

img

From Le4F'Blog