solly 发表于 2019-7-24 01:43

160 CrackMe 之 098 - woody 玩一个警察与小偷的猜迷游戏

本帖最后由 solly 于 2019-7-25 16:22 编辑

160 个 CrackMe 之 098 - woody 是一个比较特殊的CrackMe,有点猜迷类游戏的意思,启动后如下图所示:

显示一套黑黝黝房子,下面有説明:
K ... You're a thief, and the taget is to get into the house, and to the computer .. and download the very secret file ;)

The easiest thing to do is just go through the door ... but try it the "real" way first.

There are several ways to get into the house.

The real way would be:

1) Find the tool to open the window.
2) Then find the tool to open the door.
3) Then crack the keyhole with the tool
4) Now you should be in the house ...
5) Crack the password on the computer
6) Download the file

that's it ..

The wrong way ... kick the door in, and download the file.

But remember .. the police is right behind the corner, so be quiet :)

Here's a hint .. the texts isn't what it should be :) heh

意思就是要偷偷溜进房子,打开电脑,下载一个加密文件。。。
还告诉我们破解步骤就是:
1)找到工具打开窗户;
2)然后用工具打开门;
3)再用工具撬开门锁;
4)现在你进入房子。。。
5)破解电脑密码;
6)下载文件。
既然是 CrackMe,我认为其説的工具就是破解工具,下面就综合使用各类工具来完成这个迷题。
工具包括:exeInfo PE,DeDeDark,ExeScope,IDA,OD,Delphi 等。

首先看看文件信息,如下图所示:

显示这是一个 Delphi 编译的 CrackMe,拿出 DeDeDark 来查看控件和事件,如下图所示:

CrackMe 一共有 3 个表单(TForm),其中表单 1 事件较多,如上图所示,有 5 个 Click 事件、1 个定时器事件和 1 个 FormCreate 事件(表单创建时执行的事件)。
再看 Form2,如下图:

只有一个 Button 的 Click 事件。
再看看 Form3 的,如下图:

也只有一个事件,一个时间定时器事件 Timer1Timer。

下面看看控件信息,看看 From1 的 Timer 控件,属性 Enabled = False,默认没有启动,看来是通过代码来启动的。

再看看 Form3 的 Timer 控件,也一样默认没有启动,同样是通过代码启动的。


下面打开 DeDeDark 的 DFM Inspector 查看Form1 其它控件信息,如下图所示:

通过它可以看到哪些控件有事件处理,哪些没有,没有事件处理的基本就是显示用的。
整理一下,我们得到如下信息:
一、标签:
1. Label1~ Label4没有内容也没有事件。
2. Label5和Label12有显示内容,没有事件。
3. Label6、Label9和Label13没有显示内容,拥有同一个Click事件:Label6Click。
4. Lable7 没有显示内容,有事件:Label7Click。
5. Lable8 没有显示内容,也没有事件。
6. Label10 没有显示内容,有事件:Label10Click。
7. Label11 没有内容,有事件:Lable11Click。

二、按钮
只有一个按钮,事件为:Button1Click。

三、定时器
只有一个定时器,事件为:Timer1Timer。


另外,我们把事件的地址也整理出来:
一、Form1
FormCreate:    0x00459270
Button1Click:0x0045D67C
Timer1Timer:   0x0045D614

Label6Click:   0x00459134
Lable7Click:   0x0045D574
Label10Click:0x0045D694
Label11Click:0x00459158

二、Form2
Button1Click:0x00458CD4

三、Form3:
Timer1Timer:   0x00458A7C
这些入口地址,是等下在OD中下断点的地方。

控件找出来了,但好多 Label 没有显示文字内容,只有事件,那它们在哪里呢,DeDe也没显示或不明显(DFM预览功能)。

下面,我们用 eXeScope 打开 CrackMe,在左边资源树中,展开 RCData 项,选中 TForm1,如下图所示:

然后,导出为 Unit1.DFM。

我们用 Delphi7 创建一个 Delphi 项目,其Form代码保存为 Unit1.pas(表单资源会自动保存为 Unit1.DFM),关闭并保存该项目。将前面在 eXeScope 中导出的 Unit1.DFM 拷贝到这个项目目录中,覆盖掉原来的 Unit1.DFM。再重新用 Delphi 打开项目,就可以观看各个控件的位置了,如下图所示:


最后,我们定位了所有不可见控件,如下图所示:



标红框的都是标签(Label)控件,红框大小与标签大小基本相同。数字代表标签名序号,如1代表 Label1,6代表 Label6,A 代表 Label10,B 代表 Label11,D 代表 Label13,等等。

根据上面的事件表,我们知道哪些Label 控件有事件处理过程。

我们先用 IDA7 打开 CrackMe,根据上面的事件表,跳转到各个事件看看,了解一下 Delphi 内部函数调用的情况,等一下在 OD 中就不用 F7 到一些内部函数中去参观了。

下图是 _start() ,Delphi 程序的入口,创建了三个表单,具体如下图所示:



Form1.Button1Click() 事件代码,如下图所示,时间控件启停函数解析有误(即 Timer1.Enabled = True/False),在 DeDeDark中也可看到,不过 DeDeDark 将几个可能的函数名都列举出来了:



再看 Label11Click()的事件,有两次文件是否存在的检查(FileExists()),如下图所示:


下面还有写文件的过程,都是调用的 Delphi 函数,在 OD 中就不用进入这些函数去跟踪了,如下图:



其它过程就不细説了,根据需要可以全部查看一遍,了解 Delphi 内部函数的调用情况。参观完各个事件代码后,现在我们进行动态跟踪尝试破解迷题。

用 OD 载入 CrackMe,根据前面 DeDe 的信息,如下图:


我们先看看一些事件代码:

上图是 CrackMe 入口代码,创建了三个表单。

我们用OD的“转到”功能,输入 Button1Click 入口地址 0x0045D67C,如上图,点“确定”,来到其事件代码处:

具体代码如下:
0045D67C   .C605 67084600 01   mov   byte ptr , 1             ;开始游戏
0045D683   .B2 01            mov   dl, 1                            ;dl == 1, Enabled
0045D685   .8B80 F4020000      mov   eax, dword ptr
0045D68B   .E8 505BFEFF      call    004431E0                         ;启动 Timer1
0045D690   .C3               retn

这段代码很短,完成两个功能:
1、将一个全局变量设置为1,应该是游戏开始标志。
2、启动定时器,进行倒计时。

然后看看 FormCreate 事件,如下图:

选中部分是初始化一些全局变量。后面还初始化了一些字符串,并解密一些字符串,这些字符串是用来做提示的,后面都会用到。本方法的代码很长,不需多看,主要是以下几个变量关注一下:
00459290|.C605 64084600 00   mov   byte ptr , 0
00459297|.C605 65084600 00   mov   byte ptr , 0
0045929E|.C605 66084600 00   mov   byte ptr , 0
004592A5|.C605 6D084600 1E   mov   byte ptr , 1E                     ;30, 30 秒?
004592AC|.C605 67084600 00   mov   byte ptr , 0                      ;置 1, 在 Button.Click() 中
004592B3|.C605 68084600 00   mov   byte ptr , 0


前面 Button1Click 启动了定时器,我们看看定时器事件代码:
;;------------------------- Form1.Timer1Timer() ------------------------------------------------------------------------
0045D614   .53               push    ebx                         ;Form1.Timer()
0045D615   .8BD8               mov   ebx, eax                  ;ebx == Sender
0045D617   .FE0D 6D084600      dec   byte ptr          ;计时(计次: 30 次),正是 FormCreate 中初始化的
0045D61D   .33D2               xor   edx, edx
0045D61F   .8A15 6D084600      mov   dl, byte ptr
0045D625   .8B83 10030000      mov   eax, dword ptr
0045D62B   .E8 74B1FFFF      call    004587A4                  ;SetPosition()
0045D630   .803D 6D084600 00   cmp   byte ptr , 0      ;等于 0 就结束,表示游戏结束
0045D637   .77 3D            ja      short 0045D676
0045D639   .6A 00            push    0
0045D63B   .66:8B0D 78D64500   mov   cx, word ptr
0045D642   .B2 03            mov   dl, 3
0045D644   .A1 3C0A4600      mov   eax, dword ptr    ;游戏结束提示,eax ===> "Sorry .. the police caught you :)   "
0045D649   .E8 E26AFEFF      call    00444130                  ;MessageDlg()
0045D64E   .A1 94F54500      mov   eax, dword ptr    ;Form3
0045D653   .8B00               mov   eax, dword ptr
0045D655   .8078 47 01         cmp   byte ptr , 1      ;Form3.Timer1 是否 enabled,即是否正在下载
0045D659   .75 14            jnz   short 0045D66F
0045D65B   .A1 94F54500      mov   eax, dword ptr    ;Form3
0045D660   .8B00               mov   eax, dword ptr
0045D662   .8B80 CC020000      mov   eax, dword ptr
0045D668   .33D2               xor   edx, edx                  ;dl == 0, Disabled
0045D66A   .E8 715BFEFF      call    004431E0                  ;Form3.Timer1.SetEnabled(false),停止 Form3.Timer1,即停止模拟下载
0045D66F   >8BC3               mov   eax, ebx
0045D671   .E8 5600FEFF      call    0043D6CC                  ;Form1.Close() //Termelate()
0045D676   >5B               pop   ebx
0045D677   .C3               retn
就是一个倒计时,30次(秒)后弹出一个消息后,结束 CrackMe。



按 F9 直接运行 CrackMe,来到主界面:

按照按钮标题提示,要点按钮(Button1)开始游戏,我们点击按钮,可以看到,下面的进度条变短,应该定时器启动了,正在倒计时了,如下图:

等这个进度条走完,弹出一个消息框,表示游戏失败(“被警察抓住了”),如下图所示:

点“OK”后,CrackMe 退出了,只有重新来了,再次加载 CrackMe,F9运行,点击“开始”,这次,我们先在那三个有 Label6Click 事件的标签位置点点鼠标,弹出下面消息:

説位置太高,不行,看来不是这里,再点一下门(Label7),又弹出:

再点一下窗户(Label10),没有反应,看来也不对。只剩下 Label11没有点了,那个位置最小,点击后,弹出:

噫,卡住了,要 Patch?立马在这个事件中下断点,看看patch哪里,如下图所示:


上面图中显示下了一个断点,Label11Click 事件的具体代码如下:
00459158/.55                push    ebp                     ;Label11Click(),寻找工具
00459159|.8BEC            mov   ebp, esp
0045915B|.6A 00             push    0
0045915D|.33C0            xor   eax, eax
0045915F|.55                push    ebp
00459160|.68 53924500       push    00459253
00459165|.64:FF30         push    dword ptr fs:
00459168|.64:8920         mov   dword ptr fs:, esp
0045916B|.803D 67084600 01cmp   byte ptr , 1      ;是否已开始游戏
00459172|.0F85 C5000000   jnz   0045923D
00459178      803D 6E084600 01cmp   byte ptr , 1      ;前题条件1, 为0, patch 成与0比较: cmp byte ptr , 0
0045917F|.75 5F             jnz   short 004591E0            ;跳转去提示需要 patch,并生成文件 annoy.txt
00459181|.A1 580A4600       mov   eax, dword ptr
00459186|.E8 91E7FAFF       call    0040791C                  ;FileExists(), 文件检查,是否存在文件 "annoy.txt"
0045918B|.84C0            test    al, al
0045918D|.75 51             jnz   short 004591E0            ;不能跳转,因此如果当前目录下有这个文件,必须先删除
0045918F|.6A 00             push    0                         ; MessageDlg()参数4
00459191|.FF35 4C0A4600   push    dword ptr       ; "Yer .. that looks like a tool to break a window :)"
00459197|.68 68924500       push    00459268                  ; '\n'
0045919C|.FF35 500A4600   push    dword ptr       ; "You picked it up"
004591A2|.8D45 FC         lea   eax, dword ptr     ; result
004591A5|.BA 03000000       mov   edx, 3                  ; n = 3, 3 个字符串连接
004591AA|.E8 8DA9FAFF       call    00403B3C                  ; LStrCatN(),字符串连接
004591AF|.8B45 FC         mov   eax, dword ptr     ;string
004591B2|.66:8B0D 6C924500mov   cx, word ptr    ;
004591B9|.B2 03             mov   dl, 3                     ;,
004591BB|.E8 70AFFEFF       call    00444130                  ;MessageDlg(),显示可以进行下一步的提示
004591C0|.A1 580A4600       mov   eax, dword ptr
004591C5|.E8 52E7FAFF       call    0040791C                  ;FileExists(), 文件检查,是否存在文件 "annoy.txt"
004591CA|.84C0            test    al, al                  ;al == 0 表示文件不存在,非0表示存在
004591CC|.75 12             jnz   short 004591E0            ;存在文件则跳转去报错!!!
004591CE|.803D 6E084600 00cmp   byte ptr , 0      ; 不能大于 0
004591D5|.77 09             ja      short 004591E0
004591D7|.C605 64084600 01mov   byte ptr , 1      ; 设置标志,已完成任务1,表示找到工具
004591DE|.EB 15             jmp   short 004591F5            ;跳转去生成文件:annoy.txt,不生成文件改成 jmp 0045923D,就没有文件干拢了
004591E0|>6A 00             push    0                         ;MessageDlg()参数4
004591E2|.66:8B0D 6C924500mov   cx, word ptr    ;cx == 0x0004, mtConfirmation
004591E9|.B2 03             mov   dl, 3                     ;
004591EB|.A1 480A4600       mov   eax, dword ptr    ; ===> "Dammit ... it's stuck, maybe it needs a patch?"
004591F0|.E8 3BAFFEFF       call    00444130                  ;MessageDlg,显示错误信息
004591F5|>8B15 580A4600   mov   edx, dword ptr    ;edx ===> "annoy.txt",文件名
004591FB|.B8 70084600       mov   eax, 00460870
00459200|.E8 A5BFFAFF       call    004051AA                  ;Assign(),文件操作
00459205|.B8 70084600       mov   eax, 00460870
0045920A|.E8 BBC0FAFF       call    004052CA                  ;ReWriteText(),创建文件 annoy.txt
0045920F|.E8 6895FAFF       call    0040277C                  ;_IOTest(void)
00459214|.8B15 540A4600   mov   edx, dword ptr    ;edx ===> "heh...", 文件内容
0045921A|.B8 70084600       mov   eax, 00460870
0045921F|.E8 90ABFAFF       call    00403DB4                  ;写入文件
00459224|.E8 FCBFFAFF       call    00405225                  ;Flush(),生成磁盘文件并写入内容到磁盘
00459229|.E8 4E95FAFF       call    0040277C                  ;_IOTest(void)
0045922E|.B8 70084600       mov   eax, 00460870
00459233|.E8 14C0FAFF       call    0040524C                  ;Close()
00459238|.E8 3F95FAFF       call    0040277C                  ;_IOTest(void)
0045923D|>33C0            xor   eax, eax
0045923F|.5A                pop   edx
00459240|.59                pop   ecx
00459241|.59                pop   ecx
00459242|.64:8910         mov   dword ptr fs:, edx
00459245|.68 5A924500       push    0045925A
0045924A|>8D45 FC         lea   eax, dword ptr
0045924D|.E8 AEA5FAFF       call    00403800                  ;释放字符串资源
00459252\.C3                retn
00459253   .^ E9 68A0FAFF       jmp   004032C0
00459258   .^ EB F0             jmp   short 0045924A
0045925A   .59                pop   ecx
0045925B   .5D                pop   ebp
0045925C   .C3                retn
上面代码中,有一个文件检查,如果当前目录中存在文件 annoy.txt 的话,也会弹出这条消息,然后退出。
所以,我运行CrackMe 前,需要删除这个文件,不然也会一直无法往下走。
每次启动前删除 annoy.txt,就不会有提示了:

回到 patch 问题,继续执行,当执行到以下位置时,会有一个跳转:

就跳转到显示我们前面説的那个消息框了,所以这一个比对需要处理,我们先看 的引用情况,在 IDA 中查看引用情况如下:

没有看到有赋值的指令,全部是比较,并且分别与 0,1,2 比较,OD 中显示 当前值为 0,所以这里要将
cmp   byte ptr , 1
改成
cmp   byte ptr , 0

如下图所示:


就可顺利执行下一个逻辑了。继续执行,会弹出:

弹出消息说找到开窗工具,好了,那就去点窗户了(Label10),点后,弹出一消息框:

噫,patch不正确,还要patch,找到Lable10Click 查看,如下图:

具体代码如下:
0045D694/.55                push    ebp                         ;Label10Click(),打开窗户
0045D695|.8BEC            mov   ebp, esp
0045D697|.6A 00             push    0
0045D699|.33C0            xor   eax, eax
0045D69B|.55                push    ebp
0045D69C|.68 52D74500       push    0045D752
0045D6A1|.64:FF30         push    dword ptr fs:
0045D6A4|.64:8920         mov   dword ptr fs:, esp
0045D6A7|.803D 67084600 01cmp   byte ptr , 1      ;是否开始游戏
0045D6AE|.0F85 88000000   jnz   0045D73C
0045D6B4|.803D 64084600 01cmp   byte ptr , 1      ;是否已完成任务1,即是否 Lable11Click() 已通过验证
0045D6BB|.75 7F             jnz   short 0045D73C
0045D6BD      803D 6E084600 02cmp   byte ptr , 2      ;前题条件2, 为0, patch 成与0比较: cmp byte ptr , 0
0045D6C4|.75 45             jnz   short 0045D70B            ;跳转去提示没有正确 patch,需要 patch 后才可继续
0045D6C6|.6A 00             push    0                         ;   MessageDlg() 参数4
0045D6C8|.FF35 680A4600   push    dword ptr       ;"You through the thing in the window, and it broke :))"
0045D6CE|.68 64D74500       push    0045D764                  ;'\n'
0045D6D3|.FF35 6C0A4600   push    dword ptr       ;"You're in the house .. what's that on the floor??"
0045D6D9|.68 64D74500       push    0045D764                  ;'\n'
0045D6DE|.FF35 700A4600   push    dword ptr       ;"It's erhm something to open a do or with ... and you picked it up"
0045D6E4|.8D45 FC         lea   eax, dword ptr
0045D6E7|.BA 05000000       mov   edx, 5                  ;字符串个数,5个
0045D6EC|.E8 4B64FAFF       call    00403B3C                  ;LStrCatN(),连接字符串
0045D6F1|.8B45 FC         mov   eax, dword ptr     ;string
0045D6F4|.66:8B0D 68D74500mov   cx, word ptr    ;cx == 0x0004, mtConfirmation
0045D6FB|.B2 03             mov   dl, 3                     ;
0045D6FD|.E8 2E6AFEFF       call    00444130                  ;MessageDlg(),显示成功提示
0045D702|.C605 69084600 01mov   byte ptr , 1      ;设置已完成任务2,打开窗口
0045D709|.EB 31             jmp   short 0045D73C
0045D70B|>6A 00             push    0                         ;MessageDlg() 参数4
0045D70D|.FF35 740A4600   push    dword ptr       ;"You through the thing in the window, but it pansered"
0045D713|.68 64D74500       push    0045D764                  ;'\n'
0045D718|.FF35 780A4600   push    dword ptr       ;"maybe it needs a fix? yer that's right patch it :)"
0045D71E|.8D45 FC         lea   eax, dword ptr
0045D721|.BA 03000000       mov   edx, 3                  ;字符串个数,3个
0045D726|.E8 1164FAFF       call    00403B3C                  ;LStrCatN(),连接字符串
0045D72B|.8B45 FC         mov   eax, dword ptr     ;string
0045D72E|.66:8B0D 68D74500mov   cx, word ptr    ;,
0045D735|.B2 03             mov   dl, 3
0045D737|.E8 F469FEFF       call    00444130                  ;MessageDlg(),显示失败提示
0045D73C|>33C0            xor   eax, eax
0045D73E|.5A                pop   edx
0045D73F|.59                pop   ecx
0045D740|.59                pop   ecx
0045D741|.64:8910         mov   dword ptr fs:, edx
0045D744|.68 59D74500       push    0045D759
0045D749|>8D45 FC         lea   eax, dword ptr
0045D74C|.E8 AF60FAFF       call    00403800
0045D751\.C3                retn
0045D752   .^ E9 695BFAFF       jmp   004032C0
0045D757   .^ EB F0             jmp   short 0045D749
0045D759   .59                pop   ecx
0045D75A   .5D                pop   ebp
0045D75B   .C3                retn

看到没有,在IDA中出现的 cmp ds:byte_4608E, 2 就在这个事件里,与 2 比较,就预示着这是第二个需要 patch 的地方了,因为不 patch 就会跳转去弹出前面那个消息框,于是将:
cmp   byte ptr , 2
改成
cmp   byte ptr , 0
如下图所示:


重新点击 Label10,激发 Click 事件,这次显示消息框如下:

说是你爬窗而入了,到房子里了。。。地板上有啥?好象是开门用的。。。(密码),捡起来吧。于是再去点门(Label7),这次没有弹出消息框,弹出 Form2 了:

果然,要输入进门密码了。

先看看 Label7Click事件代码,如下图所示:


具体代码如下:
;;; =========================================================== Form1.Label7Click(), Door =====================================
0045D574   .803D 67084600 01   cmp   byte ptr , 1            ;是否开始游戏
0045D57B   .0F85 8C000000      jnz   0045D60D
0045D581   .803D 69084600 01   cmp   byte ptr , 1            ;是否已完成任务2
0045D588   .75 65            jnz   short 0045D5EF
0045D58A   .A1 C8F64500      mov   eax, dword ptr          ;Form2
0045D58F   .8B00               mov   eax, dword ptr
0045D591   .B2 01            mov   dl, 1                           ;dl == 0x01,显示
0045D593   .E8 F8D1FDFF      call    0043A790                        ;Form2.Show(),显示 Form2,用于输入密码
0045D598   .A1 C8F64500      mov   eax, dword ptr          ;Form2
0045D59D   .8B00               mov   eax, dword ptr
0045D59F   .8B80 C4020000      mov   eax, dword ptr       ;文本框
0045D5A5   .33D2               xor   edx, edx                        ;edx ===> null string,清空文本框
0045D5A7   .E8 6475FCFF      call    00424B10                        ;TControl.SetText()
0045D5AC   .A1 C8F64500      mov   eax, dword ptr          ;Form2
0045D5B1   .8B00               mov   eax, dword ptr
0045D5B3   .8B80 C8020000      mov   eax, dword ptr       ;文本框提示
0045D5B9   .8B15 840A4600      mov   edx, dword ptr          ;edx ===> "Enter the correct code"
0045D5BF   .E8 4C75FCFF      call    00424B10                        ;TControl.SetText()
0045D5C4   .803D 6B084600 00   cmp   byte ptr , 0            ;进入次数,Form2,Button1Click() 修改
0045D5CB   .75 40            jnz   short 0045D60D
0045D5CD   .803D 6C084600 01   cmp   byte ptr , 1            ;提示次数,Form2,Button1Click() 修改
0045D5D4   .75 37            jnz   short 0045D60D
0045D5D6   .A1 C8F64500      mov   eax, dword ptr          ;Form2
0045D5DB   .8B00               mov   eax, dword ptr
0045D5DD   .8B80 C8020000      mov   eax, dword ptr       ;文本框提示
0045D5E3   .8B15 900A4600      mov   edx, dword ptr          ;edx ===> "What's the code for the computer ??"
0045D5E9   .E8 2275FCFF      call    00424B10                        ;TControl.SetText(), 第1次正确后,修改 Form2 提示信息
0045D5EE   .C3               retn
0045D5EF   >803D 66084600 00   cmp   byte ptr , 0            ;Form1Create()中初始化为 0
0045D5F6   .75 15            jnz   short 0045D60D
0045D5F8   .6A 00            push    0
0045D5FA   .66:8B0D 10D64500   mov   cx, word ptr          ;ex == 0x0004,mtConfirmation
0045D601   .B2 03            mov   dl, 3
0045D603   .A1 400A4600      mov   eax, dword ptr          ;eax ===> "kicking the door in?? Uhhh that's gotta hurt .. without boots damn .. :)"
0045D608   .E8 236BFEFF      call    00444130                        ;显示失败提示信息,先要完成任务2
0045D60D   >C3               retn

主要就是满足条件后,显示 Form2,不然就提示失败(不能踹门而入,要撬锁而入的意思)。

为了便于跟踪,我们先保存刚才修改好的两处 Patch,不然超时退出后,每次都要去改代码,利用 OD 保存 patch 功能:

选择“所有修改”,并确认后,如下,再右键保存:

选择”保存文件“,取一个新文件名,就可以了,然后用 OD 加载新的 CrackMe 程序。


我们先进入Form2 的 Button1Click()事件看看,先找到其入口:


在 OD 中 Ctrl + G,输入上面找到的入口地址:

直接来到其事件代码入口,如下图所示:


在其事件代码中下一断点,便于动态跟踪分析。

再次 F9 直接运行程序,这次我们很快就可以弹出 Form2 了(按 Label11Click()-->Label10Click()-->Label7Click() 的顺序点击,不会再有patch的提醒了,如果还有的话,老老实实的去删除文件 annoy.txt 吧),Form2 中只有一个 Button1Click 事件,其代码如下:
;;;;=========================================================== Form2. Button1Click() =========================================
00458CD4/.55                  push    ebp                               ;Form2.Button1Click()
00458CD5|.8BEC                mov   ebp, esp
00458CD7|.6A 00               push    0
00458CD9|.53                  push    ebx
00458CDA|.8BD8                mov   ebx, eax
00458CDC|.33C0                xor   eax, eax
00458CDE|.55                  push    ebp
00458CDF|.68 F88D4500         push    00458DF8
00458CE4|.64:FF30             push    dword ptr fs:
00458CE7|.64:8920             mov   dword ptr fs:, esp
00458CEA|.8D55 FC             lea   edx, dword ptr             ;返回地址缓冲区
00458CED|.8B83 C4020000       mov   eax, dword ptr
00458CF3|.E8 E8BDFCFF         call    00424AE0                        ;TControl.GetText(), 取假码 "78787878",eax 返回长度
00458CF8|.8B45 FC             mov   eax, dword ptr             ;eax ===> "78787878"
00458CFB|.8B15 C8F54500       mov   edx, dword ptr          ;CRACKME_.00460A88
00458D01|.8B12                mov   edx, dword ptr             ;edx ===> "123-456-789-000",第1次点门输入这个密码
00458D03|.E8 84AEFAFF         call    00403B8C                        ;LStrCmp(), 字符比较
00458D08|.75 08               jnz   short 00458D12                  ;不相等跳转
00458D0A|.A1 88F54500         mov   eax, dword ptr
00458D0F|.C600 01             mov   byte ptr , 1               ;设置标志1
00458D12|>8D55 FC             lea   edx, dword ptr
00458D15|.8B83 C4020000       mov   eax, dword ptr
00458D1B|.E8 C0BDFCFF         call    00424AE0                        ;TControl.GetText(),再次取假码 "78787878"
00458D20|.8B45 FC             mov   eax, dword ptr             ;eax ===> "78787878"
00458D23|.8B15 8CF34500       mov   edx, dword ptr          ;CRACKME_.00460A8C
00458D29|.8B12                mov   edx, dword ptr             ;edx ===> "456-678",第2次点门输入这个密码
00458D2B|.E8 5CAEFAFF         call    00403B8C                        ;LStrCmp(), 字符比较
00458D30|.75 08               jnz   short 00458D3A                  ;不相等跳转
00458D32|.A1 00F54500         mov   eax, dword ptr
00458D37|.C600 01             mov   byte ptr , 1               ;设置标志2
00458D3A|>A1 88F54500         mov   eax, dword ptr
00458D3F|.8038 01             cmp   byte ptr , 1               ;检查标志1
00458D42|.75 7B               jnz   short 00458DBF
00458D44|.A1 00F54500         mov   eax, dword ptr
00458D49|.8038 00             cmp   byte ptr , 0               ;检查标志2
00458D4C|.75 29               jnz   short 00458D77
00458D4E|.A1 94F44500         mov   eax, dword ptr
00458D53|.8038 00             cmp   byte ptr , 0               ;检查标志3
00458D56|.75 1F               jnz   short 00458D77
00458D58|.6A 00               push    0
00458D5A|.A1 9CF34500         mov   eax, dword ptr          ; ===> "and the door opens! :)"
00458D5F|.8B00                mov   eax, dword ptr
00458D61|.66:8B0D 048E4500    mov   cx, word ptr              ;mtConfirmation
00458D68|.B2 03               mov   dl, 3
00458D6A|.E8 C1B3FEFF         call    00444130                        ;MessageDlg(),提示进门密码正确
00458D6F|.A1 94F44500         mov   eax, dword ptr
00458D74|.C600 01             mov   byte ptr , 1               ;设置标志3
00458D77|>A1 00F54500         mov   eax, dword ptr
00458D7C|.8038 01             cmp   byte ptr , 1               ;检查标志2
00458D7F|.75 55               jnz   short 00458DD6                  ;第1次检查门密码,从这里退出
00458D81|.A1 94F54500         mov   eax, dword ptr          ;Form3
00458D86|.8B00                mov   eax, dword ptr
00458D88|.B2 01               mov   dl, 1                           ;dl == 1,显示
00458D8A|.E8 011AFEFF         call    0043A790                        ;Form.Show(),显示 Form3
00458D8F|.A1 94F54500         mov   eax, dword ptr          ;Form3
00458D94|.8B00                mov   eax, dword ptr
00458D96|.8B80 CC020000       mov   eax, dword ptr
00458D9C|.B2 01               mov   dl, 1                           ;dl == 1, enabled
00458D9E|.E8 3DA4FEFF         call    004431E0                        ;启动 Form3 的 Timer,显示下载进度
00458DA3|.8B15 00F74500       mov   edx, dword ptr          ;CRACKME_.00460A98
00458DA9|.8B12                mov   edx, dword ptr             ; ===> "Downloading file ...."
00458DAB|.A1 94F54500         mov   eax, dword ptr          ; Form3
00458DB0|.8B00                mov   eax, dword ptr
00458DB2|.8B80 C4020000       mov   eax, dword ptr
00458DB8|.E8 53BDFCFF         call    00424B10                        ; TControl.SetText()
00458DBD|.EB 17               jmp   short 00458DD6
00458DBF|>6A 00               push    0
00458DC1|.A1 44F44500         mov   eax, dword ptr
00458DC6|.8B00                mov   eax, dword ptr             ;eax ===> "nope the code isn't correct :`"
00458DC8|.66:8B0D 048E4500    mov   cx, word ptr              ;cx == 0x0004, mtConfirmation
00458DCF|.B2 03               mov   dl, 3
00458DD1|.E8 5AB3FEFF         call    00444130                        ;MessageDlg(),提示输入的密码不正确
00458DD6|>33D2                xor   edx, edx                        ;dl == 0, 隐藏
00458DD8|.A1 58084600         mov   eax, dword ptr
00458DDD|.E8 AE19FEFF         call    0043A790                        ;Form.Hide(),关闭(隐藏) Form2
00458DE2|.33C0                xor   eax, eax
00458DE4|.5A                  pop   edx
00458DE5|.59                  pop   ecx
00458DE6|.59                  pop   ecx
00458DE7|.64:8910             mov   dword ptr fs:, edx
00458DEA|.68 FF8D4500         push    00458DFF
00458DEF|>8D45 FC             lea   eax, dword ptr
00458DF2|.E8 09AAFAFF         call    00403800
00458DF7\.C3                  retn
00458DF8   .^ E9 C3A4FAFF         jmp   004032C0
00458DFD   .^ EB F0               jmp   short 00458DEF
00458DFF   .5B                  pop   ebx
00458E00   .59                  pop   ecx
00458E01   .5D                  pop   ebp
00458E02   .C3                  retn
代码比较简单,就是两次明文密码比较,第一次为 "123-456-789-000",如下所示:


如果密码不正确,比如输入下面的假码:


则会提示:


输入正确的密码(123-456-789-000)后,会弹出一个消息:

显示门已开,点确定后,回到主界面。我们再次点门(Label7),这次又弹出如下界面:

需要输入电脑密码,我们输入前面发现的第二个明文密码”456-678”,如下图所示:

点“okay" 后,弹出一个带进度条的下载界面(Form3),模拟一个下载过程,如下图所示:

这个进度条也是由定时器来处理的,代码如下:
00458A7C   .53                  push    ebx                              ;Fotm3.Timer1Timer()
00458A7D   .56                  push    esi
00458A7E   .8BD8                mov   ebx, eax                         ;Sender, Form3
00458A80   .8BB3 C8020000       mov   esi, dword ptr
00458A86   .8BC6                mov   eax, esi
00458A88   .E8 67FBFFFF         call    004585F4                         ;GetPosition()
00458A8D   .8BD0                mov   edx, eax
00458A8F   .42                  inc   edx
00458A90   .8BC6                mov   eax, esi
00458A92   .E8 0DFDFFFF         call    004587A4                         ;SetPosition()
00458A97   .8B83 C8020000       mov   eax, dword ptr
00458A9D   .E8 52FBFFFF         call    004585F4                         ;GetPosition()
00458AA2   .83F8 64             cmp   eax, 64                        ;100,循环100次,模拟下载过程
00458AA5   .7C 53               jl      short 00458AFA
00458AA7   .33D2                xor   edx, edx                         ;dl == 0
00458AA9   .8B83 CC020000       mov   eax, dword ptr
00458AAF   .E8 2CA7FEFF         call    004431E0                         ;停止 Form3 的 Timer
00458AB4   .A1 A8F64500         mov   eax, dword ptr           ;Form1
00458AB9   .8B00                mov   eax, dword ptr
00458ABB   .8B80 F4020000       mov   eax, dword ptr
00458AC1   .33D2                xor   edx, edx                         ;dl == 0, disabled
00458AC3   .E8 18A7FEFF         call    004431E0                         ;停止 Form1 的 Timer
00458AC8   .6A 00               push    0
00458ACA   .A1 30F44500         mov   eax, dword ptr
00458ACF   .8B00                mov   eax, dword ptr              ; ===> "You've succeded this crackme .. cool :) now write to woody@post9.tele.dk and tell me all about it"
00458AD1   .66:8B0D 008B4500    mov   cx, word ptr             ;cx == 0x0004, mtConfirmation
00458AD8   .B2 03               mov   dl, 3
00458ADA   .E8 51B6FEFF         call    00444130                         ;MessageDlg(),显示成功破解的提示
00458ADF   .48                  dec   eax
00458AE0   .75 18               jnz   short 00458AFA
00458AE2   .33D2                xor   edx, edx                         ;dl == 0,隐藏
00458AE4   .A1 50084600         mov   eax, dword ptr
00458AE9   .E8 A21CFEFF         call    0043A790                         ;Form.Hide(),关闭 Form3
00458AEE   .A1 A8F64500         mov   eax, dword ptr           ;Form1
00458AF3   .8B00                mov   eax, dword ptr
00458AF5   .E8 D24BFEFF         call    0043D6CC                         ;Form1.Close(),结束 CrackMe
00458AFA   >5E                  pop   esi
00458AFB   .5B                  pop   ebx
00458AFC   .C3                  retn


如果下载结束还没有超时,就会将 Form1 的倒计时定时器停止,不再倒计时。
并且,等进度条走完后,就会弹出下面的消息框:

显示成功了!!!只有点”OK“后,才会退出 CrackMe 了,不会再由Form1 的定时器强行退出了。


下面附加分析一下。

因为主界面上按”开始“后,有一个30秒计时,30秒一到,没有解开游戏就会结束,所以,我们只要把那个定时器不启动,就可以成”无敌“状态了,Button1Click()事件改动如下:
0045D67C   .C605 67084600 01   mov   byte ptr , 1             ;开始游戏
0045D683   .B2 00            mov   dl, 0                            ;dl == 1, Enabled, 当 dl == 0 时,禁用定时器,变成无敌状态
0045D685   .8B80 F4020000      mov   eax, dword ptr
0045D68B   .E8 505BFEFF      call    004431E0                         ;启动 Timer1,或禁用 Timer1
0045D690   .C3               retn
按上面改动后,就无敌了。

还有就是那个文件的问题,当CrackMe启动时会检测文件是否存在,如果存在也会报需要 patch 而无法往下走,我们也把这个问题 patch 一下,让 CrackMe 无法生成这个 annoy.txt 文件,我们修改 Label11Click() 事件的代码,具体修改如下:
;; Label11Click() 部分代码
;
004591CE|.803D 6E084600 00cmp   byte ptr , 0      ; 不能大于 0
004591D5|.77 09             ja      short 004591E0
004591D7|.C605 64084600 01mov   byte ptr , 1      ; 设置标志,已完成任务1,表示找到工具
004591DE|.EB 15             jmp   short 004591F5            ;跳转去生成文件:annoy.txt
; 最后的jmp 改成如下代码:
004591DE|.EB 5D             jmp   short 0045923D            ; 不生成文件改成 jmp 0045923D,就没有文件干拢了



上面两处代码改好后,同样用 OD 保存 Patch 的功能,保存到一个新文件即可。


分析完毕!!!






feob 发表于 2019-7-24 07:20


感谢分享

fanluc 发表于 2019-7-24 07:34

很有意思的游戏

bm5381 发表于 2019-7-24 08:32

感觉不错 先看看 感谢分享

丶Supreme 发表于 2019-7-24 10:12

膜拜大神。

hutopower 发表于 2019-7-24 11:48

厉害厉害/:strong /:strong/:strong/:strong

左耳近情 发表于 2019-7-24 13:45

这是大神,好屌的样子

璐璐诺 发表于 2019-7-24 13:59

这个有点东西啊。。。

liushan 发表于 2019-7-24 14:20

这么长,感觉没有玩的欲望了。。

范闲不闲 发表于 2019-7-24 15:22

厉害厉害
页: [1] 2 3
查看完整版本: 160 CrackMe 之 098 - woody 玩一个警察与小偷的猜迷游戏