关灯
开启左侧

160个CrackMe之89 -- PhrekTech (16位NE)的详细跟踪和追码过程

[复制链接]
哥不帅但很坏 发表于 2019-5-5 17:26:31 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
 
160个CrackMe之89--PhrekTech是一个16位的NE格式的win16执行程序,这个程序只能在Win3.x和Win9x系统下运行,需要装一个Win98SE来跟踪。
我是在VMWare中装了一个Win98SE的虚拟机来跟踪这个程序的,并且是通过Win9x下经典的调试工具 TRW2000 来完成跟踪和追码。
为了在虚拟机中调试该CrackMe,需要进行以下设置或操作,不然无法调出TRW2k的调试界面,但这样设置后就无法使用鼠标了,只能通过键盘操作。





1、修改虚拟机vmx配置文件:
  vmmouse.present = "FALSE"
  svga.maxFullscreenRefreshTick = "5"
2、将TRW2000的所有文件及子目录放置到C:\盘的根目录下。如下图所示:
由于只能键盘操作,有几个快捷键要用到:
1、ALT+SpaceBar:调用出系统菜单,可以用方向键调整窗口大小,以及移动窗口位置;
2、ALT+F4:关闭窗口;
3、ALT+TAB:切换窗口;
4、TAB键:在窗口内各个控件中移动焦点。
5、CTRL + ALT:从虚拟机中切回到Window10主机;
6、TRW2000加载后,CTRL+N和CTRL+M,调出TRW2000的调试界面。

下面简单介绍在TRW中需要用到了几个调试命令:
1、s 0,FFFFFFFF ’solly‘  在内存中搜索字符串”solly"
2、bpm address 内存下断点,内存地址格式:segmentffset,如 es:0528
3、bl 查看断点
4、bd 编号  禁用某个编号的断点,如 bd 04 禁用04断点,编号可以通过上面的bl查到
5、be 编号  启用某个编号的断点,如 be 04 启用04断点,编号可以通过前面的bl查到
6、bpx 代码下断点,如 bpx cs:0208 ,在代码段中偏移0208处下断点。
7、g 运行,退出调试界面
8、按F8键是跟入,可以进入函数,F10是单步跟踪(不进入函数)
注意,有时从TRW2000退回Win98后,键盘不响应,按任何键虚拟机都是发出“嘀”声时,可以先按"CTRL+ALT"返回Window10,再点击虚拟机的桌面进去,就可以再次使用键盘了。

16位的NE程序与DOS程序一样,是分段的,所有的代码和数据的访问是通过 segmentffset 的地址格式来访问的,如 cs:0208 是访问代码,ds:0528、ss:sp、es:si、es:di 是访问数据等


CrackMe程序是Delphi 1.x编写的,通过IDA反汇编后,可以看到其资源和内部函数,我们可以通过IDA找到内部函数,在TRW2000中就不需要进入这些内部函数跟踪了。

启动TRW2000的Loader程序 trw2000.exe:
点击“Browse”找到我们要跟踪的CrackMe程序。

然后再点击“Load"加载程序,TRW加载程序后,会弹出调试界面,停留在 INITTASK 位置。


不管它,输入 g, 加回车,返回桌面:

继续运行程序,如下:

TRW2000的 Message Output 内显示加载成功,并且CrackMe也正常进入界面,如下:

  
按钮上面的标签显示”Not tested“,表示还没有进行过注册码验证。
输入假码,如下图:


然后按CTRL+N调出TRW2000调试界面,如果没有出来,则多按几次。


输入” S 0, ffffffff 'solly'   “,搜索刚才输入的用户名,如果搜到,则会在后面显示地址,同时,数据窗口会显示搜索到的数据,如上图所示。
搜到地址,可以下内存断点:bpm 80386d68,这样下完断点后,只要程序读取这个用户名,就会断下来。
如果没有断下来,説明这个数据在内存中有多个,如上图,我们可以重新搜索,如 S 80386d69,ffffffff 'solly' 来重新指定搜索范围,搜索刚才没有搜索过的地址空间,直到搜索到能够断下来的地址,如果搜索结果太多,一直断不下来,则可以下g关闭调试窗口,重新输入一个没有使用过的用户名再来重新搜索。如下图,我就把用户用重新改成了”username9977",再重新搜索。

下完新的断点,再g回到windows,按CrackMe的 Test 按钮。这回断了下来,如上图,TRW2000显示“Break on BP1",代码区显示,我们断在了 KERNEL.DLL中的 HMEMCPY 函数中,这是一个内存拷贝系统函数,这里 es:si指向源字符串,为系统空间,es:di为目的字符串,指向了应用程序的空间,如下图:

在指令区下 d es:di-4,就可以看到,系统正向程序传送用户名数据,如下图:

目的地址为: es:5128,这是应用程序保存用户名的缓冲区。
这个时候为了我们可以下命令 bd 01,禁用刚才的内存中断,也可以下 bc * ,禁用所有的断点,并重新下一个新的断点:bpx HMEMCPY, 这样,等一下读取序列号时就可以断下来了。
一路按F10,返回多个 retf 后,我们来到了CrackMe的指令空间,如下图:

这里就是CrackMe进行序列号验证的地方。同时,我们用IDA反编译程序,按地址2907:0237在IDA找到相应代码位置,另外,段地址2907不用管,只要在IDA搜索偏移地址0237就可以,然后跟据TRW2000中显示的汇编代码就可以在IDA中找到相应的汇编代码范围。
这样,我们可以在IDA中看到Delphi的内部函数,如下所示,是上图对应的汇编代码:
[Asm] 纯文本查看 复制代码
[color=white !important]
[color=white !important]?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

cseg01:0237                 call    @TControl@GetText$qv ; 读取用户名:username9977

cseg01:023C                 call    @Concat$qm6Stringt1 ; 连接字符串:"g3df" + "username9977"

cseg01:0241                 lea     di, [bp+var_100]

cseg01:0245                 push    ss

cseg01:0246                 push    di              ; es:di 输出结果缓冲区

cseg01:0247                 push    0FFh

cseg01:024A                 call    @$basg$qm6Stringt14Byte ; 生成Delphi字符串:"g3dfusername9977"

cseg01:024F                 lea     di, [bp+var_300] ; es:di ===> 用户名:username9977

cseg01:0253                 push    ss

cseg01:0254                 push    di

cseg01:0255                 lea     di, [bp+var_100] ; es:di ===>连接后的字符串:"g3dfusername9977"

cseg01:0259                 push    ss

cseg01:025A                 push    di

cseg01:025B                 call    @$basg$qm6Stringt1 ; 生成字符串:"g3dfusername9977"

cseg01:0260                 mov     di, offset aH9cf8 ; "h9cf8"

cseg01:0263                 push    cs






可以看到刚才执行了Delphi 控件的 GetText 函数,取得了用户名。
一路往下跟踪执行,来到了 3907:02D9 处,执行完这条指令,就生成了一个序列号,如下图所示:

使用 d es:4F28 就会在数据区显示出来,这个地址是前面push到栈中的[sp] = 0x4F28,在TRW2000中的Stack窗口可以看到。
同时在IDA中可以看到,马上要执行一个字符比较函数: bsub(),这是一个delphi的字符串比较函数,如果相等则返回0,不相等则返回非0,函数据内部比较字符串的细节如下图所示:


先比较长度,再比较字符串。
执行到 0FA7:2DCD LODSB 时,可以通过 d es:si 和 d es:di 来显示进行比较的两个字符串,如下图:



到这里,真正的序列号已经出来了,其生成规则是:
1、输入的用户名不能为空;
2、在用户名"username9977"前面加上"g3df",形成字符串1:"g3dfusername9977";
3、在前面生成的字符串1的后面加上"h9cf8",形成字符串2:"g3dfusername9977h9cf8";
4、再把前面生成的两个字符串连接起来,形成序列号:"g3dfusername9977g3dfusername9977h9cf8";
这样,只要我们返回CrackMe,输入以上序列号就可以注册通过了。
先禁用断点:


禁用断点后,输入 g 返回应用。输入正确的序列号,再按“Test”:


这时,按钮上面的标签显示“YEAH,Good work!”,表示注册成功!
下面是完整的汇编代码的验证过程,我加了注释:
[Asm] 纯文本查看 复制代码
[color=white !important]
[color=white !important]?

001

002

003

004

005

006

007

008

009

010

011

012

013

014

015

016

017

018

019

020

021

022

023

024

025

026

027

028

029

030

031

032

033

034

035

036

037

038

039

040

041

042

043

044

045

046

047

048

049

050

051

052

053

054

055

056

057

058

059

060

061

062

063

064

065

066

067

068

069

070

071

072

073

074

075

076

077

078

079

080

081

082

083

084

085

086

087

088

089

090

091

092

093

094

095

096

097

098

099

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

cseg01:0208 sub_208         proc far                ; DATA XREF: cseg01:010E↑o

cseg01:0208

cseg01:0208 var_500         = byte ptr -500h

cseg01:0208 var_400         = byte ptr -400h

cseg01:0208 var_300         = byte ptr -300h

cseg01:0208 var_200         = byte ptr -200h

cseg01:0208 var_100         = byte ptr -100h

cseg01:0208 arg_0           = dword ptr  6

cseg01:0208

cseg01:0208                 push    bp

cseg01:0209                 mov     bp, sp

cseg01:020B                 mov     ax, 500h

cseg01:020E                 call    @__StackCheck$q4Word               ; __StackCheck(Word)

cseg01:0213                 sub     sp, 500h

cseg01:0217                 lea     di, [bp+var_400]

cseg01:021B                 push    ss

cseg01:021C                 push    di

cseg01:021D                 mov     di, offset aG3df                   ; "g3df"

cseg01:0220                 push    cs

cseg01:0221                 push    di

cseg01:0222                 call    @$basg$qm6Stringt1                 ; 生成Delphi字符串:"g3df"

cseg01:0227                 lea     di, [bp+var_300]                   ; es:di 保存用户名的缓冲区

cseg01:022B                 push    ss

cseg01:022C                 push    di

cseg01:022D                 les     di, [bp+arg_0]

cseg01:0230                 les     di, es:[di+18Ch]

cseg01:0235                 push    es

cseg01:0236                 push    di                                 ; this

cseg01:0237                 call    @TControl@GetText$qv               ; 读取用户名:username9977

cseg01:023C                 call    @Concat$qm6Stringt1                ; 连接字符串:"g3df" + "username9977"

cseg01:0241                 lea     di, [bp+var_100]

cseg01:0245                 push    ss

cseg01:0246                 push    di                                 ; es:di 输出结果缓冲区

cseg01:0247                 push    0FFh

cseg01:024A                 call    @$basg$qm6Stringt14Byte            ; 生成Delphi字符串:"g3dfusername9977"

cseg01:024F                 lea     di, [bp+var_300]                   ; es:di ===> 用户名:username9977

cseg01:0253                 push    ss

cseg01:0254                 push    di

cseg01:0255                 lea     di, [bp+var_100]                   ; es:di ===>连接后的字符串:"g3dfusername9977"

cseg01:0259                 push    ss

cseg01:025A                 push    di

cseg01:025B                 call    @$basg$qm6Stringt1                 ; 生成字符串:"g3dfusername9977"

cseg01:0260                 mov     di, offset aH9cf8                  ; "h9cf8"

cseg01:0263                 push    cs

cseg01:0264                 push    di

cseg01:0265                 call    @Concat$qm6Stringt1                ; 连接字符串:"g3dfusername9977" + "h9cf8"

cseg01:026A                 lea     di, [bp+var_200]                   ; es:di ===> 字符串缓冲区

cseg01:026E                 push    ss

cseg01:026F                 push    di

cseg01:0270                 push    0FFh

cseg01:0273                 call    @$basg$qm6Stringt14Byte            ; 生成Delphi字符串:"g3dfusername9977h9cf8"

cseg01:0278                 lea     di, [bp+var_300]                   ; es:di ==> delphi字符串数据区

cseg01:027C                 push    ss

cseg01:027D                 push    di

cseg01:027E                 les     di, [bp+arg_0]

cseg01:0281                 les     di, es:[di+18Ch]

cseg01:0286                 push    es

cseg01:0287                 push    di                                 ; this

cseg01:0288                 call    @TControl@GetText$qv               ; 再次取用户名

cseg01:028D                 add     sp, 4

cseg01:0290                 cmp     [bp+var_300], 0                    ; 字符串长度不等于0?

cseg01:0295                 jnz     short loc_2AD

cseg01:0297                 mov     di, offset aNaahWrong              ; "Naah! Wrong!"

cseg01:029A                 push    cs

cseg01:029B                 push    di                                 ; __int32

cseg01:029C                 les     di, [bp+arg_0]

cseg01:029F                 les     di, es:[di+184h]

cseg01:02A4                 push    es                                 ; int

cseg01:02A5                 push    di                                 ; TControl *

cseg01:02A6                 call    @TControl@SetText$q8TCaption       ; TControl::SetText(TCaption)

cseg01:02AB                 jmp     short locret_30F

cseg01:02AD ; ---------------------------------------------------------------------------

cseg01:02AD

cseg01:02AD loc_2AD:                                                   ; CODE XREF: sub_208+8D↑j

cseg01:02AD                 lea     di, [bp+var_400]                   ; es:di ==> delphi字符串数据区,准备保存序列号

cseg01:02B1                 push    ss

cseg01:02B2                 push    di

cseg01:02B3                 les     di, [bp+arg_0]

cseg01:02B6                 les     di, es:[di+17Ch]

cseg01:02BB                 push    es

cseg01:02BC                 push    di                                 ; this

cseg01:02BD                 call    @TControl@GetText$qv               ; 读取序列号

cseg01:02C2                 lea     di, [bp+var_500]

cseg01:02C6                 push    ss

cseg01:02C7                 push    di

cseg01:02C8                 lea     di, [bp+var_100]                   ; es:di ===> "g3dfusername9977"

cseg01:02CC                 push    ss

cseg01:02CD                 push    di

cseg01:02CE                 call    @$basg$qm6Stringt1                 ; 生成字符串:"g3dfusername9977"

cseg01:02D3                 lea     di, [bp+var_200]                   ; es:di ===> "g3dfusername9977h9cf8"

cseg01:02D7                 push    ss

cseg01:02D8                 push    di

cseg01:02D9                 call    @Concat$qm6Stringt1                ; 连接字符:"g3dfusername9977" + "g3dfusername9977h9cf8"

cseg01:02DE                 call    @$bsub$qm6Stringt1                 ; 比较上面连接的字符串是否与输入的序列号相等,不相等返回非0,相等返回0

cseg01:02E3                 jnz     short loc_2FB

cseg01:02E5                 mov     di, offset aYeahGoodWork           ; "YEAH! Good work!"

cseg01:02E8                 push    cs

cseg01:02E9                 push    di                                 ; __int32

cseg01:02EA                 les     di, [bp+arg_0]

cseg01:02ED                 les     di, es:[di+184h]

cseg01:02F2                 push    es                                 ; int

cseg01:02F3                 push    di                                 ; TControl *

cseg01:02F4                 call    @TControl@SetText$q8TCaption       ; TControl::SetText(TCaption)

cseg01:02F9                 jmp     short locret_30F

cseg01:02FB ; ---------------------------------------------------------------------------

cseg01:02FB

cseg01:02FB loc_2FB:                                                   ; CODE XREF: sub_208+DB↑j

cseg01:02FB                 mov     di, offset aNaahWrong              ; "Naah! Wrong!"

cseg01:02FE                 push    cs

cseg01:02FF                 push    di                                 ; __int32

cseg01:0300                 les     di, [bp+arg_0]

cseg01:0303                 les     di, es:[di+184h]

cseg01:0308                 push    es                                 ; int

cseg01:0309                 push    di                                 ; TControl *

cseg01:030A                 call    @TControl@SetText$q8TCaption       ; TControl::SetText(TCaption)

cseg01:030F

cseg01:030F locret_30F:                                                ; CODE XREF: sub_208+A3↑j

cseg01:030F                                                            ; sub_208+F1↑j

cseg01:030F                 leave

cseg01:0310                 retf    8

cseg01:0310 sub_208         endp






分析完华!




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

 
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


排行榜

关注我们:QQ交流群

官方微信

APP下载

全国服务热线:

4000-888-888

公司地址:上海市嘉定区

运营中心:上海市嘉定区百达国际大厦25楼

邮编:200000 Email:admin@mr-technos.com

Copyright   ©2015-2018  先森科技Powered by©Discuz!技术支持:先森科技     ( 浙ICP备18046157号-1 )|网站地图