160 个 CrackMe 之 041 -- defiler.1 的菜单Patch过程及分析

本帖最后由 solly 于 2019-6-18 17:33 编辑

160 个 CrackMe 之 041 - defiler.1 是一个 Delphi 编制的 CrackMe,论坛中至少已有3贴説明了,pk8900也有收集,我这里再说明一下,主要是觉得:
1、原有几种方式操作有些复杂;
2、没有充分利用 Delphi 的特性;
3、修改程序的代码量有点多。


既然是 Delphi 程序,当然先用 DeDeDark 打开看看吧:



按 rules.txt 的要求,要做一个 Exit 菜单项的事件处理。但在 DeDeDark中可以看到,“窗体”代码中,Exit 菜单项没有 OnClick 事件属性,再看看过程:



可以看到,事件过程也只有一个:About2Click,这个就是 About 的事件处理过程,因此,可以断定,CrackMe 中没的 Exit 菜单的对应事件处理过程。
我们先看看 About2Click() 事件的代码,双击上图的事件名即可打开代码查看器,如下图:



可以看到 About2Click() 函数的代码,具体内容如下:[Delphi] 纯文本查看 复制代码

0043E270   6A40                   push    $40

* Possible String Reference to: 'bleh'
|
0043E272   B98CE24300             mov     ecx, $0043E28C

* Possible String Reference to: 'See rules.txt, mail your solution t
|                                o [url=mailto:defiler@immortaldescendants.org]defiler@immortaldescendants.org[/url]'
|
0043E277   BA94E24300             mov     edx, $0043E294
0043E27C   A1D0FB4300             mov     eax, dword ptr [$0043FBD0]
0043E281   8B00                   mov     eax, [eax]

* Reference to: forms.TApplication.MessageBox(TApplication;PChar;PChar;Longint):Integer;
|
0043E283   E88CE9FFFF             call    0043CC14
0043E288   C3                     ret

在 OD 中也可以看到这段代码及其资源:
[Asm] 纯文本查看 复制代码

0043E270   .  6A 40         push    40
0043E272   .  B9 8CE24300   mov     ecx, 0043E28C             ;  ASCII "bleh"
0043E277   .  BA 94E24300   mov     edx, 0043E294             ;  ASCII "See rules.txt, mail your solution to [url=mailto:defiler@immortaldescendants.org]defiler@immortaldescendants.org[/url]"
0043E27C   .  A1 D0FB4300   mov     eax, dword ptr [43FBD0]
0043E281   .  8B00          mov     eax, dword ptr [eax]
0043E283   .  E8 8CE9FFFF   call    0043CC14                  ;  call forms.TApplication.MessageBox()
0043E288   .  C3            retn
0043E289      00            db      00
0043E28A      00            db      00
0043E28B      00            db      00
0043E28C   .  62 6C 65 68 0>ascii   "bleh",0
0043E291      00            db      00
0043E292      00            db      00
0043E293      00            db      00
0043E294   .  53 65 65 20 7>ascii   "See rules.txt, m"
0043E2A4   .  61 69 6C 20 7>ascii   "ail your solutio"
0043E2B4   .  6E 20 74 6F 2>ascii   "n to defiler@imm"
0043E2C4   .  6F 72 74 61 6>ascii   "ortaldescendants"
0043E2D4   .  2E 6F 72 67 0>ascii   ".org",0
0043E2D9      00            db      00
0043E2DA      00            db      00

编过 Delphi 程序的人应该知道,Delphi 的事件是可以重用的,也就是説 Exit 菜单也可以使用这个事件处理过程,我们使用另一个工具来完成这个修改:eXeScope。我们用 eXeScope 打开 CrackMe 来修改 Delphi 程序的 RCData 资源,如下图:



在左侧的资源树中,选中“TFORM1”,然后在右侧的编辑区,在 Exit1 菜单对象中,增加一行 OnClick = About2Click,如下:
[Delphi] 纯文本查看 复制代码

  object MainMenu1: TMainMenu
    Left = 120
    Top = 80
    object About1: TMenuItem
      Caption = '&Ficken'
      object About2: TMenuItem
        Caption = '&About'
        OnClick = About2Click
      end
      object Exit1: TMenuItem
        Caption = '&Exit'
        OnClick = About2Click
      end
    end
  end

可以从上面的  About2 菜单项中复制,改好后保存,如下图所示:



先择“OK”就可以了。
这样修改后,点 Exit 菜单,也会执行 About2Click() 函数,这样,我们只要修改 0x0043E270 处的 About2Click()就可以了。
用 OD 载入修改了资源的 CrackMe 程序,按 Ctrl+G,输入 0043E270,如下图所示:



我们来到了 Exit 和 About 的事件处理过程:



先在函数中的 0x0043E27C 处,下一个断点,如上图所示,再按 F9 运行 CrackMe,然后我们点击一个菜单项(About 或 Exit 均可),就会来到上面的断点。然后几个 F8 后,来到下图所示位置:



这里就是菜单处理事件回调处,如果[ebx+0x82]处为0,则表示没有指定 OnClick 事件,不用回调用户代码。如果不为0,则在 0x0042F428 处的 call 指令回调用户编写的代码。
再按多次 F8 返回到下图代码范围,往上翻,就可以看到Windows消息处理的代码,其中[esi]中保存的是消息代码,我们需要处理两个消息:WM_COMMAND 和 WM_CLOSE。我们在 0x00420285 处下一个条件断点,如下图所示:

为什么要拦截 WM_CLOSE 消息呢,因为我们要先找到 WM_CLOSE  消息的处理过程,然后才能改造 Exit 菜单的代码,用来退出 CrackMe。
经过几个来回的分析,我们确定,下图处就是 WM_COMMAND 和 WM_CLOSE 消息处理的分发处,从这里开始,进入不同的事件处理过程(jmp ecx):



上图ecx == 0x00438B68,是菜单事件处理,以及下图:

这里 ecx == 0x00438CEC,这是点击窗口右上角的关闭图标(即 WM_CLOSE)时的处理过程。

也就是 WM_COMMAND 和 WM_CLOSE 消息处理的分发,是通过一个 jmp ecx 跳转到不同的事件处理来完成的,具体代码如下:
[Asm] 纯文本查看 复制代码

00402E64   .  53            push    ebx
00402E65   .  66:8B1A       mov     bx, word ptr [edx]
00402E68   .  66:09DB       or      bx, bx
00402E6B   .  74 17         je      short 00402E84
00402E6D   .  66:81FB 00C0  cmp     bx, 0C000
00402E72   .  73 10         jnb     short 00402E84
00402E74   .  50            push    eax
00402E75   .  8B00          mov     eax, dword ptr [eax]
00402E77   .  E8 74FFFFFF   call    00402DF0
00402E7C   .  58            pop     eax
00402E7D   .  74 05         je      short 00402E84
00402E7F   .  89D9          mov     ecx, ebx
00402E81   .  5B            pop     ebx
00402E82   .  FFE1          jmp     ecx                       ;  跳转到不同的事件处理过程
00402E84   >  5B            pop     ebx
00402E85   .  8B08          mov     ecx, dword ptr [eax]
00402E87   .  FF61 F0       jmp     dword ptr [ecx-10]
00402E8A   .  C3            retn

其中,处理 WM_CLOSE 的事件处理代码如下:
[Asm] 纯文本查看 复制代码

00438CEC   .  E8 DF0B0000   call    004398D0
00438CF1   .  C3            retn

这里看不出什么,我们用 IDA 打开 CrackMe ,通过地址找到上面代码,如下:
[Asm] 纯文本查看 复制代码

CODE:00438CEC sub_438CEC      proc near               ; DATA XREF: CODE:00432EBE↑o
CODE:00438CEC                 call    @Forms@TCustomForm@Close$qqrv ; Forms::TCustomForm::Close(void)
CODE:00438CF1                 retn
CODE:00438CF1 sub_438CEC      endp

IDA中指明了我们调用的函数名是 Forms::TCustomForm::Close,这个就是关闭表单的过程,我们在后面要修改 Exit 菜单的事件代码,调用这里的代码退出 CrackMe。


另外,按 Delphi 事件处理过程的规则,每次调用事件时,至少都会传入一个 Sender 参数,所以我们手动调用 Form.Close()时,也要传入 Form 对象指针,这个指针 Delphi 会存于 ebx 中,所以我们可以根据 ebx 的值来区分是哪个组件在调用事件处理过程。通过几个观察,可以得到
[Asm] 纯文本查看 复制代码

;============= Sender ===============
Menu.Exit  ===> EBX = 021D357C
Menu.About ===> EBX = 021D344C
Form.Close ===> EBX = 021D1738

上面就是每次调用时传入的 Sender 参数并会存于 ebx 中,并且 ebx 的高 16 bits 是变化的,而低 16 bits 不变,我们只要判断低 16 bits (即bx)就可以了。


下面,我们开始构建一个新的事件过程,用于处理菜单消息,我们来到前面找到的About 事件处理过程(0x0043E270处),往下拖动滚动条,寻找用来填充代码的空白区域,到 0x0043E4C0 处,可以找到一大片空白区域,我们在这里填充我们的事件处理代码和数据,如下图所示:



上图已输入了所需代码(上图的第2行的je指令还没修正偏移量,下图是修正了的),正在填充字符串数据,数据填充完后:



具体代码如下:
[Asm] 纯文本查看 复制代码

;======================================================================================
0043E4C0      66:81FB 7C35   cmp     bx, 357C                  ;  Sender 是否为 Exit 菜单项
0043E4C5      74 1B          je      short 0043E4E2            ;  是则跳转去执行 Exit 操作
0043E4C7      90             nop                               ;  下面是原有 About 事件处理代码
0043E4C8      6A 40          push    40                        ;  MB_OK | MB_ICONINFORMATION
0043E4CA      B9 8CE24300    mov     ecx, 0043E28C             ;  ASCII "bleh"
0043E4CF      BA 94E24300    mov     edx, 0043E294             ;  ASCII "See rules.txt, mail your solution to [url=mailto:defiler@immortaldescendants.org]defiler@immortaldescendants.org[/url]"
0043E4D4      A1 D0FB4300    mov     eax, dword ptr [43FBD0]
0043E4D9      8B00           mov     eax, dword ptr [eax]
0043E4DB      E8 34E7FFFF    call    0043CC14                  ;  call forms.TApplication.MessageBox()
0043E4E0      C3             retn                              ;  eax == IDOK == 1
0043E4E1      90             nop                               ;  下面是新加的 Exit 事件处理代码
0043E4E2      6A 44          push    44                        ;  MB_YESNO | MB_ICONINFORMATION
0043E4E4      B9 8CE24300    mov     ecx, 0043E28C             ;  ASCII "bleh"
0043E4E9      BA 10E54300    mov     edx, 0043E510             ;  ASCII "Do you fickbirne really want to quit?"
0043E4EE      A1 D0FB4300    mov     eax, dword ptr [43FBD0]
0043E4F3      8B00           mov     eax, dword ptr [eax]
0043E4F5      E8 1AE7FFFF    call    0043CC14                  ;  call forms.TApplication.MessageBox()
0043E4FA      83F8 06        cmp     eax, 6                    ;  IDOK  = 1, IDYES = 6, IDNO = 7 (这里为6表示选择了“YES”)
0043E4FD     /75 0C          jnz     short 0043E50B            ;  不为IDYES则跳转并返回,否则调用 CustomForm.Close(Sender)退出程序
0043E4FF     |8BC3           mov     eax, ebx                  ;  eax为Sender参数,从ebx取得 Sender 对象高16位
0043E501     |66:B8 3817     mov     ax, 1738                  ;  修改Sender对象的低 16 位,修改成 CustomForm 对象。
0043E505    ^|E9 E2A7FFFF    jmp     00438CEC                  ;  调用 CustomForm.Close(Sender)
0043E50A     |90             nop
0043E50B     \C3             retn                              ;  如果选择“NO”,则 eax == IDNO,在这里返回

数据如下:
[Asm] 纯文本查看 复制代码

;---------------------------------------------------------------------------------------
0043E510  44 6F 20 79 6F 75 20 66 69 63 6B 62 69 72 6E 65  Do you fickbirne
0043E520  20 72 65 61 6C 6C 79 20 77 61 6E 74 20 74 6F 20   really want to
0043E530  71 75 69 74 3F 00 00 00 00 00 00 00 00 00 00 00  quit?...........

以上事件处理过程和数据录入完成后,就修改(0043E270)处的原事件代码,指向新的事件处理代码:



具体代码改动后,如下所示:
[Asm] 纯文本查看 复制代码

;=======================================================================================
0043E270     /E9 4B020000    jmp     0043E4C0                  ;  直接跳转到新的事件处理代码
0043E275     |90             nop
0043E276     |90             nop
0043E277   . |BA 94E24300    mov     edx, 0043E294             ;  ASCII "See rules.txt, mail your solution to [url=mailto:defiler@immortaldescendants.org]defiler@immortaldescendants.org[/url]"
0043E27C   . |A1 D0FB4300    mov     eax, dword ptr [43FBD0]
0043E281   . |8B00           mov     eax, dword ptr [eax]
0043E283   . |E8 8CE9FFFF    call    0043CC14
0043E288   . |C3             retn

搞完这些操作后,需要把这些变动保存起来,先把我们设置的所有断点禁用。
在改动了的代码上按右键,如下:



选择“复制到可执行文件==>所有修改”。会有一个确认提示:



选择“复制”,一共进行3次确认后,如下图:



再点右键,如下图:



选择”保存文件“,然后输入一个新的文件名保存即可。

我们运行刚才保存的新文件程序,击”Exit“菜单项,可以看到下面的提示:

按”是“就退出 CrackMe, 按”否“则不会退出。

下面是直接修改文件(eXsScope修改后的文件)时的地方,新事件和资源:
[Asm] 纯文本查看 复制代码

;==== File =======
0003d8c0h: 66 81 FB 7C 35 74 1B 90 6A 40 B9 8C E2 43 00 BA ; f侞|5t.恓@箤釩.?
0003d8d0h: 94 E2 43 00 A1 D0 FB 43 00 8B 00 E8 34 E7 FF FF ; 斺C.⌒鸆.????
0003d8e0h: C3 90 6A 44 B9 8C E2 43 00 BA 10 E5 43 00 A1 D0 ; 脨jD箤釩.?錍.⌒
0003d8f0h: FB 43 00 8B 00 E8 1A E7 FF FF 83 F8 06 75 0C 8B ; 鸆.????凐.u.?
0003d900h: C3 66 B8 38 17 E9 E2 A7 FF FF 90 C3 00 00 00 00 ; 胒?.殁??惷....
0003d910h: 44 6F 20 79 6F 75 20 66 69 63 6B 62 69 72 6E 65 ; Do you fickbirne
0003d920h: 20 72 65 61 6C 6C 79 20 77 61 6E 74 20 74 6F 20 ;  really want to 
0003d930h: 71 75 69 74 3F 00 00 00 00 00 00 00 00 00 00 00 ; quit?...........

原事件处理代码的修改:
[Asm] 纯文本查看 复制代码

;----------------------------------------------------------------------------
0003d670h: E9 4B 02 00 00 90 90 BA 94 E2 43 00 A1 D0 FB 43 ; 镵...悙簲釩.⌒鸆

分析完毕!!!

THE END
喜欢就支持以下吧
点赞0
分享
评论 抢沙发
管埋员的头像-小北的自留地

昵称

取消
昵称