| 网站首页 | 绿色软件 | 安全中心 | 屏保中心 | 源码中心 | 电子书库 | 教程库 | 图片库 | 资料库 | 论坛 | 笑话 | 手机 | 算命 | 绿站旧版 | 返回总部 | 
您现在的位置: 绿色软件站 >> 教程库 >> 绿化室 >> 绿化相关 >> 加密解密 >> 文章正文
看雪解密:第3章 动态分析技术         
看雪解密:第3章 动态分析技术
作者:看雪 文章来源:Internet 点击数: 更新时间:2006-5-3 12:13:21

第一节 SoftICE与TRW2000安装安装与配制

SOFTICE有几个平台的版本,DOS,WINDOWS 3.0,Windows 95/98,WINDOWS NT,等。 由于现在最普及的操作系统是 Windows 95/98、Windows NT、Windows Millennium、Windows2000因此就讲讲SOFTICE在这几个平台安装时的一些注意事项。

一、SOFTICE for win9x安装与配制

  1、显卡安装
  2、鼠标安装
  3、Autoexec.bat和config.sys配制
  4、Symbol Loader
  5、winice.dat配制
二、SOFTICE for Windows Millennium
三、SOFTICE for NT/2K安装与配制
四、TRW2000安装

 SOFTICE的安装与配制

一、SOFTICE for win9x安装与配制

㈠、SOFTICE安装 

1、SOFTICE目前最新版本是4.05,如你的系统是win9x,就请下载for win9x版本的SOFTICE,建议下载SOFTICE的最新版本,这样稳定性好些。运行setup.exe开始安装,出现(图一):

(图一)

2、然后点击下一步,输入安装序列号(图二)(序列号一般在安装软件的readme.txt或其它说明文件里)

(图二)

3、然后下面几个画面是要求选定路径和安装组件,不久你会来到显卡配制对话框(图三):

(图三)

在显卡配制里两种方法:

①这种配制使SOFTICE激活状态时类似DOS全屏状态一样(也就是字符模式状态),在显卡列表选择你的显卡类型,Universal Vidoe Driver和Use monochrome card/monitor这两项不要选,然后点击Test按钮,在测试过程中你能看到各种颜色的字符,说明显卡测试通过,就可点击下一步了。

② 这种配制使SOFTICE在激活状态下类似windows应用程序的一个窗口那样,这样在调试时可避免显示器不停地在图形和字符模式转换,对提高显示器寿命大有好处。配制时,显卡列表一栏忽略,不用配制,只要把Universal Vidoe Driver这一项选上,然后test,如跳出如(图四)对话框,测试通过。(本人强烈推荐这种方式)



(图四)

4、再下一步是鼠标的配制(图五):

(图五)

现在鼠标常见的一般是串行口或ps/2接口,你跟据自己的鼠标接口类型或位置选上合适的就可。如碰到鼠标在SOFTICE调试画面不能用或一用死机,可能是没选好正确的选项,你可在SOFTICE菜单里的,运行mosue setup这个菜单项重新配制鼠标。

5、最后一步是询问以何种方式装载SOFTICE的主文件winice.exe(图六):

(图六)

首先要了解SOFTICE for 9x版本是如何装载的,在SOFTICE的安装目录下有winice.exe这个文件,windows启动到纯DOS环境下,运行winice.exe这个文件,将装载SOFTICE。
安装时默认将C:\PROGRA~1\NUMEGA\SOFTIC~1\WINICE.EXE这一行放时进Autoexec.bat(自动批处理文件),这样windows以后每次都运行Autoexec.bat这个文件,自动装载SOFTICE。另外,你可根据自身需要配制启动模式,具体参考第8步。

6、然后安装程序将复制文件到硬盘里,来到最后一个对话框(图七):

(图七)

最后一项是电子注册,注册成功后,以后可在线升级SOFTICE版本,这里选最后一项Regiter later.

7、至此安装完成,重新启动windows,微机先到DOS下,自动或手动运行相应批处理文件,运行其内的winice.exe文件,装载windows。

8、启动菜单配制:

通过配制启动菜单,启动时根据自己的需要选择是否装载SOFTICE。

AUTOEXEC.BAT配制样例

@ECHO OFF

goto %config%

:SICE
C:\PROGRA~1\NUMEGA\SOFTIC~1\WINICE.EXE
goto common

:NORM
goto common

:common

CONFIG.SYS配制样例:

[MENU]
MENUITEM NORM,Windows 9x
MENUITEM SICE,Windows 9x with SoftICE
MENUDEFAULT NORM,2


[NORM]

[SICE]

[common]

 

㈡、SOFTICE配制

1、Symbol Loader的使用


(图八)

你在开始SOFTICE的菜单里有一项ymbol Loader快捷方式,运行后,在其菜单EDIT→SOFTICE Initialization Settings选项,打开后如图(图八)。这里你就可配制SOFTICE了。

①General选项

在Initialization string里,你可填上需要SOFTICE一启动自动运行的命令。如:

WD 2; WC 14; FAULTS OFF; IXHERE OFF; IYHERE OFF; set font 2;lines 40;x;(各行以分号分开)

②Exports选项

在这里可添加相关的DLL文件,以便在SOFTICE下拦截这些DLL的函数。特别是破解VB程序时,定要将VB运行库装载进去。

③Keyboard Mappings选项

这里配制各功能热键。如:F5="^x;"用F5键代替命令X.

④Macro Definitions选项

宏定义,你可定制各种命令宏,以方便平时的操作。
如:s7878="S 30:0 L ffffffff '78787878' " 用命令s7878代替一串命令:S 30:0 L ffffffff '78787878'

⑤Remote Debugging

利用网络远程调试配制。

注:以上所有配制好后的参数,都保存在winice.dat文件里。

2、winice.dat配制

在Windows 9x下 SoftICE配制除了用上面的方法外,也可通过文件winice.dat来实现的。Soft-ICE 在启动的时候通过它装入一些 DLL/EXE 的信息。
你可在SOFTICE安装目录下发现winice.dat,可用任何文本编辑软件打开它(如记事本)。如我机子里的

;注意分号后是描述语言,不被执行。PENTIUM=ON;<=Pentium Op-CodesNMI=ONECHOKEYS=OFFNOLEDS=OFFNOPAGE=OFFSIWVIDRANGE=ONTHREADP=ONLOWERCASE=OFFWDMEXPORTS=OFFMONITOR=0
PHYSMB=128;<=这个值是你的物理内存大小
SYM=1024
HST=256;<=历史缓冲区为256K
TRA=8
MACROS=32;<=宏操作的最大个数,此处是32个
DRAWSIZE=2048;<= 我的显卡内存是2MB ,此处值是你显卡内存大小

INIT=" wd 2;wc 20;FAULTS OFF; IXHERE OFF; IYHERE OFF; set font 2;lines 40;code on;x;";<=初始化,此处默认的是800*600分分辨率
;如你是全屏请换上:lines 57

F1="h;"
F2="^wr;"
F3="^src;"
F4="^rs;"
F5="^x;"
F6="^ec;"
F7="^here;"
F8="^t;"
F9="^bpx;"
F10="^p;"
F11="^G @SS:ESP;"
F12="^p ret;"
SF3="^format;"
CF8="^XT;"
CF9="TRACE OFF;"
CF10="^XP;"
CF11="SHOW B;"
CF12="TRACE B;"
AF1="^wr;"
AF2="^wd;"
AF3="^S 0 L FFFFFFFF 8B,CA,F3,A6,74,01,9F,92,8D,5E,08;";<=VB3特征字符串
AF4="^s 0 l ffffffff 56,57,8B,7C,24,10,8B,74,24,0C,8B,4C,24,14,33,C0,F3,66,A7;" ;<=VB4特征字符串
AF5="^s 0 l ffffffff FF,75,E0,E8,85,EF,FF,FF,DC,1D,28,10,40,00,DF,E0,9E,75,03;" ;<=VB5特征字符串
                           
AF8="^XT R;"
AF11="^dd dataaddr->0;"
AF12="^dd dataaddr->4;"
CF1="altscr off; lines 60; wc 32; wd 8;"
CF2="^wr;^wd;^wc;"

;<=以下是宏操作命令:
MACRO s7878="S 30:0 L ffffffff '78787878' "
MACRO sname="S 0 L FFFFFFFF 'toye' "
MACRO swide="s 0 l FFFFFFFF '7','8,'7','8,'7','8,'7','8,'7','8,'7','8,'7','8','7','8' "
MACRO reg="bpx regqueryvalueexa if *(esp->8)>='Soft' do "d(esp->14)" "
MACRO bpxpe="bpx loadlibrarya do "dd esp->4" "
MACRO bpxgeta="bpx GetDlgItemTextA; bpx getwindowtexta; bpx getdlgitemint; bpx getdlgitemtext;"


; ***** Examples of sym files that can be included if you have the SDK *****
; Change the path to the appropriate drive and directory
;LOAD=c:\windows\system\user.exe
;LOAD=c:\windows\system\gdi.exe
;LOAD=c:\windows\system\krnl386.exe
;LOAD=c:\windows\system\mmsystem.dll
;LOAD=c:\windows\system\win386.exe

; Exports - change the path to the appropriate drive and directory

EXP=c:\windows\system\advapi32.dll ;<=这四行前不要加分号,否则不被装载,SOFTICE可能什么也拦不到 :
EXP=c:\windows\system\kernel32.dll
EXP=c:\windows\system\user32.dll
exp=c:\windows\system\gdi32.dll
exp=c:\windows\system\comctl32.dll ;


; 如你要破解VB程序,下面的VB运行库将要装载,SOFTICE默认值是没有这几行,你需手动加上。

;EXP=c:\windows\system\msvbvm60.dll;<= Visual Basic 6 具体参考第十五课VB破解
EXP=c:\windows\system\msvbvm50.dll ;<= Visual Basic 5 注意在这五个DLL中最好不要同时装载2个以上
; EXP=c:\windows\system\vb40032.dll;<= Visual Basic 4(32bit)
; EXP=c:\windows\system\vb40016.dll;<=Visual Basic 4(16-bit)较少见
; EXP=c:\windows\system\vbrun300.dll;<=Visual Basic 3


;EXP=c:\windows\system\vga.drv;
;EXP=c:\windows\system\vga.3gr
;EXP=c:\windows\system\sound.drv
;EXP=c:\windows\system\mouse.drv
;EXP=c:\windows\system\netware.drv
;EXP=c:\windows\system\system.drv
;EXP=c:\windows\system\keyboard.drv
;EXP=c:\windows\system\toolhelp.dll
;EXP=c:\windows\system\shell.dll
;EXP=c:\windows\system\commdlg.dll
;EXP=c:\windows\system\olesvr.dll
;EXP=c:\windows\system\olecli.dll
;EXP=c:\windows\system\mmsystem.dll
;EXP=c:\windows\system\winoldap.mod
;EXP=c:\windows\progman.exe
;EXP=c:\windows\drwatson.exe
; ***** Examples of export symbols that can be included for Windows 95 *****
; Change the path to the appropriate drive and directory
EXP=c:\windows\system\kernel32.dll
EXP=c:\windows\system\user32.dll
EXP=c:\windows\system\gdi32.dll
EXP=c:\windows\system\comdlg32.dll
EXP=c:\windows\system\shell32.dll
EXP=c:\windows\system\advapi32.dll
EXP=c:\windows\system\shell232.dll
EXP=c:\windows\system\comctl32.dll
;EXP=c:\windows\system\crtdll.dll
;EXP=c:\windows\system\version.dll
EXP=c:\windows\system\netlib32.dll
;EXP=c:\windows\system\msshrui.dll
EXP=c:\windows\system\msnet32.dll
EXP=c:\windows\system\mspwl32.dll
;EXP=c:\windows\system\mpr.dll

启动windows装载SOFTICE后,咦!怎么没反应,没调试画面!哈哈,别着急,按CTRL+D看看,再按一下回到windows下,或按F5也能回来。此时调试窗口象windows开的一窗口,如是象全屏DOS一样窗口,那就是安装显卡时,参数没选好,此时按上文修正即可。下面的命令是调整SOFTICE窗口状态:

  set font n(n=1,2,3)设置字体;本人建议set font 2(在800*600条件下)
  set origin x,y(x,y)锁定窗口;
  lines n n=(25-128)设置显示行数;本人建议lines 40
  Ctrl+Alt+光标键 移动窗口;
  Ctrl+Alt+home 重设窗口位置原点(0,0);
  Ctrl+L 刷新。

如你以默认winice.dat启动SOFTICE,有可能需用WD打开数据窗口;用SET FONT 2 设置字体等重复工作。你可在winice.dat文件内设置自动执行命令操作,方法是在INIT这一行,各命令用分号分开,如:

INIT=" WD 2; WC 14; FAULTS OFF; IXHERE OFF; IYHERE OFF; set font 2;lines 40;x;"这样配制后界面类似TRW2000。(这些是在800*600条件下的情况,如你不是此分辩率可调整set font n;lines n)

二、SOFTICE for Windows Millennium

 由于Windows Millennium没有了DOS平台,因此不能用常用的方法来安装SOFTICE,在此平台上可以运行SOFTICE for WIN9x版本和TRW2000版本。要实现SOFTICE在Windows Millennium平台的安装,需要工具Winice Loader,安装过程如下:

1 正常安装Windows Millennium,如在C:\WIN98ME;
2 正常安装Softice 405 Build 334;
3 复制WINICE.EXE、WINICE.DAT、SIWVID.386 三个文件到 C:\WIN98ME下;
4 从Winice Loader内解压 LOADER.EXE,复制这个文件到C:\WINME98\SYSTEM\VMM32\ 下.
5 重新启动系统。

三、SOFTICE for NT/2K安装与配制

1、SOFTICE for NT/2k的安装与for 9x版本差不多,所不同的是在第五步:装载SOFTICE方式选择,如图(图九):

(图九)

你可根据需要选择不同的装载方式,注:如你选择了Manual方式,要装载SOFTICE,需要来SOFTICE的菜单里运行选项:START SOFTICE快捷方式来装载SOFTICE。

2、在NT下,配制SOFTICE是用SOFTICE Loader(从你的开始菜单选),选择Edit/SoftICE,一般的选项是初始化,这里你可参考手册了解不同的开关选项的详细描述。如:

CODE ON; FAULTS OFF; I3HERE OFF; WD 3; WF; X;

其它两个重要的选项是Symbols & Exports。如果你拥有自己系统的SDK(软件开发工具包),你可用SOFTICE装载并调试它。那些没有SDK应该用exports选项从%WINNT%/System32 目录下增加下面的DLL文件。

advapi32.dll, comctl32.dll, comdlg32.dll, gdi32.dll, kernel32.dll, msvbvm(50/60).dll (如果需要), msvcrt.dll (如果需要), ole32.dll, oleaut32.dll, shell32.dll, user32.dll, version.dll.

 

四、TRW2000的安装与配制

㈠、TRW2000安装

 

TRW安装简单多了,没SOFTICE那样复杂,但目前TRW2000不支持windows NT。它发布版本是一个ZIP压缩包,才200多K。只要将其解压缩到一个目录下,然后运TRW2000.EXE即可(图十) , 无须安装或者重启计算机。

(图十)

激活方式同SOFTICE不一样:

1. Ctrl + M 特权级0级的热键,能够立即中断Win9x。 相当于 Soft-ICE 的热键 Ctrl+D.

2. Ctrl + N 特权级3级的热键。 在绝大多数时候,我们并不需要在0级上中断。 Ctrl + N可以中断Windows的特权级3级的前台线程。 这应该是我们最常用的。

其它指令同SOFTICE兼容,也就说你在上一节学得东西完全可用在TRW2000上。

但是TRW2000有许多更新的思想,具体看后面几课介绍及范例。

另外,TRW2000可支持plug-ins,也可装载dll文件,在1.15版本以上,在安装目录下有一DLL目录,如你特别需要的dll复制到此目录,即可装载,如破解VB时,就需要将VB dll复制此目录,具体参考后面的VB破解。

其它的请读其Readme.

㈡、TRW2000的配制

TRW2000的配制是通过其安装目录下的

TRW2000.ini 来实现的,你可按自己的需要配制它(一般按默认即可)。

; TRW2000 Initialize file

; Please modify it as your habit .

;rem PLUGS=C:\PLUGS\HELLO.SYS
;No, you don't put this line. Now we have changed plug-ins load-method.
;Please copy your SYS to <TRW2000 Directory>\SYS, TRW2000 will load it
;automatic.

; Now, we don't support keyword LINES=, please use command LINES instead.
INIT="lines 35;wr 3;wd 4;wc 16"

F1=^HELP ; Command length CAN'T be longer than 15 characters !
; This command length is 5 charcaters .
F3=^SRC
F4=^RS
F5=^X
F6=^EC
F7=^HERE
F8=^T
F9=^BPX
F10=^P
F12=^PRET

;HOTKEY=320D ;Ctrl+M
;R3HOTKEY=310E ;Ctrl+N

GRAPHICS=ON ;Use graphics mode driver

VESA=OFF

VGA=ON

INTELLIMOUSE=ON ;If your mouse is a intellmouse, set this to ON

WINMOUSE=ON ;If you found your mouse is not work properly, try it to ON. But we do NOT recommend this, because it maybe decrease stabilization.

;HST=256 ;History buffer size, default = 256k

SYMBUFFER=1024

CAPITAL=ON

WONDER=ON

TESTMODE=OFF

第二节 SoftICE与TRW2000操作入门

  由于TRW2000命令和操作完全兼容SoftICE,因此如不特殊说明,在本文对SoftICE的叙说都适合TRW2000。
  SoftICE的所有操作都发生在一个可以随时可激活的调试窗口中,在这个窗口中可以监视Windows应用程序和系统的运行。
一、 调试窗口简介
  我们假设你的SoftICE己经正常运行,此时在Windows里按"Ctrl+D"键就可以呼出SoftICE的调试窗口,当需要返回到Windows系统时,再按"Ctrl+D"键,也可使用X命令或按F5键。激活的调试窗口如图2.14所示,分为寄存器窗口、数据窗口、代码窗口、浮点窗口和命令窗口等部分。
如是在TRW2000环境下,激活是按"CTRL+N",和SoftICE不同的是TRW2000中没有浮点窗口,不过有一个堆栈窗口。

(图一)SoftICE或TRW2000调试截图

1、寄存器窗口
  在这里可以观察到各种寄存器的当前值,如数据寄存器EAX、EBX、ECX、EDX和控制寄存器(EIP和PSW)等,有一点要注意了,由于我们是在Windows平台下,所以看到的都是80386寄存器集,其与16位寄存器差别在前多了一字符"E",意为16位寄存器扩展。
2、数据窗口
  在数据窗口显示指定内存处中的数据,以十六进制和ASCII同时显示,这可以说是我们的眼睛,因此有必要了解一下各部分的含义。

(图二)

①号位置的0030:这是段选择器。
  在Windows的保护模式下CS、DS、ES、SS、FS和GS不叫段寄存器,叫段选择器。在保护模式中,内存分为了好多的段,在TRW200下用GDT就可以看到段的编号、类型、开始物理地址、大小、属性。让我们看看编号0030是什么东西:

(图三)

  这个段是32位数据类型,长度为4G ,我们还可以看到很多的段,它们有可能会指向同一个物理地址,但它们的类型,属性可能不同。如一些段指向的地址是不可读写的,但另外一个段指向的同一物理地址是可读写的!如果我们通过不可写的那段的编号放到段选择器,然后进行读写操作,肯定死掉了。 但换了另外一个段对同一个地方读写那就没问题!保护模式的内存管理挺有趣的,感兴趣的不妨看看这方面的书,当然作为初学者只需稍微了解就可。
②号位置00000000:此处表示内存的虚拟地址。
③号位置的值是当前内存的数据,以十六进制表示。
④号位置的值是"③"处值的另一种表示方法:ASCII码。
3、代码窗口
  此处显示的是当前程序的代码,因为不管是什么程序,最终在CPU执行时都是以机器语言方式,而汇编语言和机器语言是一一对应的,因此SoftICE为了方便我们理解,把所监视的代码以汇编代码形式显示在我们面前。例如:

(图四)

①段选择器;
②虚拟地址;
③机器码:这就是CPU执行的机器代码,此处是以十六进制表示。你可用Code on/off打开或关闭这项的显示。
④汇编指令:和机器码对应的程序代码。
4、堆栈窗口
  这个是TRW2000特有的,通过它很方便监视堆栈的状况。
5、命令窗口
  这是各种命令执行的地方,在屏幕底部的动作状态行显示执行命令的各种提示,以及可提供指令语法帮助。
6、程序领空
  所谓领空,实际上是指:在某一时刻,CPU 的 CS:IP(EIP) 所指向的某一段代码的所有者所在的区域。此例中SoftICE所停下来时光标所指的那一句代码是属于KERNEL32.DLL的,因此就叫KERNEL32.DLL领空,在图2.14中,可看到的领空名是KERNEL32!.text,那我怎么知道它就是KERNEL32.DLL文件呢?这个主要是经验,KERNEL32.DLL是Windows系统文件,在SoftICE里显示领空名时不显示扩展名,只是显示前一部份。

二、SoftICE常用命令简介

由于SoftICE命令操作较多,在此就把几个常用的命令介绍一下,其它详细说明请参考附录的"SoftICE手册"。
1、 G命令
语法:G [=start-address] [break-address]
作用:执行程序,后面如果加地址,则执行到该地址为止。
注意: TRW2000 中G命令与SoftICE稍有不同,SoftICE中G命令必须是在当前段中,这时IP(EIP)为指定值才中断;而TRW2000则不管段址如何,只要IP(EIP)是指定的值便停下,TRW2000这个特性大大方便我们的操作。
2、P命令
语法: P [ret]
作用:单步执行程序。
只执行P时,相当于按下F10键。在汇编模式中,当遇到 CALL、INT、LOOP、REP指令时,P将不跟踪进去,直到这些指令执行完毕,控制才返回SoftICE,换句话说,P命令是"跨"过这些指令的。
P RET 命令相当于快捷键 F12。SoftICE将一直单步执行直到它找到一条返回语句(RET、RETF),也就是说让SoftICE一直执行代码,直到出现 RET (XXXX) 命令,再跳出来拦截,这时,当前 IP(EIP) 会是停在 RET (XXXX) 后的某一条语句上,通常是在某一个CALL XXXXXXXX 后面。由于我们通常用SoftICE在某些底层的Windows函数上设置断点,所以 F12 是很管用的。因为程序的作者用的是高级语言,Windows又是提倡"透明",不希望程序员知道底层的操作,而只提供给他们高层的接口,而相当多的高级函数调用某个一定的底层函数,所以当你在底层函数上下断点,再用F12,就可以知道他用的是什么函数了。
3、T命令
语法:T [=start-address] [count]
start-address:执行起始地址;
count:指定SoftICE将单步跟踪多少次才停止。
作用:单步跟踪。
T命令相当于功能键F8,如没指定起始地址,将从CS:IP(EIP)指向的指令开始执行,此时当遇到 CALL、LOOP等指令时,T将跟踪进去。
注意: F8和F10功能键的主要差别就在这,遇到 CALL、LOOP等指令时,F10是路过,而F8是跟进去。
4、BPX命令
语法:BPX [address] [IF expression] [DO "command1;command2;..."]
address :断点所在的线性地址;
IF expression:条件表达式,只有条件为"真"时,SoftICE才在断点处弹出;
Do command:当SoftICE弹出时,自动执行的一些命令。
作用:在可执行语句上设置(或清除)断点。
BPX 用来在指令处下断点,程序一旦执行到此,SoftICE就会弹出。当光标在代码窗口中时,直接打入BPX就会在光标所在语句处设断点,再打BPX 就取消。BPX的快捷键是 F9,当光标在代码窗口中时,按F9就是设定(取消)。
BPX 也可用函数名来作地址参数:格式为"BPX 函数名"。
这个函数名可以是任意一个API函数、虚拟机指令、DLL文件的引出函数等等,功能强劲。例:
:bpx messageboxa(不用区分大小写)//只要程序调用了此函数,SoftICE将中断;
:bpx GetWindowTexta if EAX==8 // 当调用GetWindowTexta函数时EAX=8,SoftICE将中断;
:BPX GetWindowTexta do "d EAX"// 当 GetWindowTexta被中断,自动显示EAX的值。
注意: TRW2000与SoftICE条件格式有点不同,如在SoftICE下的是:bpx loadlibrarya do "dd esp->4",而相同的用法在TRW2000中是:bpx loadlibrarya do "dd *(esp+4)" 。另外SoftICE中用鼠标双击指令行可设断,而TRW2000中不行,只能按F9.
5、BPM命令
语法:BPM[size] address [条件表达式] DO[执行的命令]
size:内存单元大小,B为字节(默认);W 为字;D 为双字;
verb:所进行的操作,R为读;W为写;RW为读写(默认);X 为执行。
作用:设置内存访问断点。
注意: BPM用了DR3-DR0寄存器,所以最多只能设四个断点。
6、BMSG命令
语法:BMSG window-handle [条件表达式] DO[执行的命令]
window-handle:消息发向的窗口句柄,即消息名
作用:在Windows的消息上下断点。
Windows本身是由消息驱动的, 所以跟踪一个消息会得到相当底层的答案。如:
我们执行记事本程序(Notepad),然后Ctrl+D激活SoftICE输入:
   :bmsg wm_char
   :g
然后回到Notepad中,随便按一个键,SoftICE就激活了;原因在于我们在按键消息上设置了断点(退出SoftICE别忘下命令"BC *"清除刚才下的断点)。
7、BL命令
语法:BL
作用:显示当前所设的断点
注意: SoftICE会把所有断点按从0开始的编号列出,而TRW2000是从1开始编号列出。
8、BC命令
语法:BC list | *
list:可以清除指定编号的断点,多个时中间用空格或逗号隔开。
* :清除所有的断点。
作用:清除一个或多个断点
9、BD命令
语法: BD list | *
list:可以是单个,也可以是一系列断点,中间用空格或逗号隔开。
* :禁止所有的断点
作用:使一个或多个断点失效。
10、BE命令
语法:BE list | *
作用:使一个或多个断点恢复有效。
用来恢复前次用 BD 命令使之失效的断点。 (每当新定义断点或编辑断点时,系统自动将其置为有效)
11、BPE命令
语法:BPE index_number(断点索引号)
作用:编辑一个已存在的断点。
12、R命令
语法:R 寄存器名
作用:显示或更改寄存器的内容。
其可更改所有的寄存器的值。此命令较常用的一个功能是更改状态寄存器(PSW )的值,格式:R FL 标志位。比如当前 Z标志位(零位)为置位状态,执行"r fl z"之后会被清除;如果C标志位为清除状态,那么"r fl c"将使之置位。
注意: 利用此命令很方便在一些跳转指令上改变方向。
13、A命令
语法:A [地址]
作用:进入小汇编状态,可直接写入汇编代码。
如不加地址值,直接在当前CS:IP(EIP)处汇编。用SoftICE内置的汇编器在内存中写入汇编代码。汇编器支持标准的80x86指令集,包括386、486、Pentium、Pentium-Pro、MMX协处理器,新版的SoftICE还支持AMD的3D Now!、PII、PIII的特有指令集。
14、D命令
语法:D[size] [address [l length]]
size:B 字节;W 字;D 双字; S 短实型;L 长实型;T 10b长实型
作用:显示某内存区域的内容。
15、S命令
语法:S [-cu][address L length data-list]
address:搜索的起始地址
length :搜索的长度(字节长)
data-lis:可以是一系列字节,也可以是字符串,字符串可以用单引号,也
可以用双引号括住.
-c :使查找区分大小写
-u :查找Unicode 编码的字符串.
作用:在内存中搜寻特定数据,如果找到数据,那将在数据窗口中显示出来,如果在找到后,你还要继续查找,使用不带参数的S命令。由于S命令忽略不在内存中的页面,因此你可以使用32位平面地址数据段描述符30h在整个4GB(0~FFFFFFFFh )空间查找。如:
s 30:0 l FFFFFFFF "78787878" //在此令在内存中查找字串"78787878"位置。
注意: TRW2000中S命令的字串应是单引号(而SoftICE皆可)。如:s 30:0 l FFFFFFFF '78787878'.
16、E命令
语法:E[size] [address [data-list]]
作用: 修改内存单元
17、U命令
语法:U [address [l length]] | [symbol-name]
address :段:偏移量或选择符:偏移量
symbol-name:将从指定的函数开始反汇编
length :反汇编的长度(字节)
作用: 反汇编指令
你可以利用此命令抓取汇编代码,运行LOADER32后,将历史缓冲区(history buffer)调大些(默认为256,不能放足够多的缓冲数据)。然后切换到SoftICE调试画面下,来到你要抓取的地方,反汇编这些代码,如:U CS:EIP L 1000 ,立即按Ctrl+D返回到Windows环境,再次来到symbol loader程序,选择"File/Save SoftICE History As…"。
注意: 在TRW2000下可以直接反汇编代码输出到一个文件:
u 401000,402000 >路径/myfile。
18、FAULTS命令
语法:FAULTS [on | off]
作用:打开或关闭错误跟踪功能
由于SoftICE做为一个DEBUGGER,FAULTS 默认为ON,所以一旦CPU有非法指令,SoftICE就会不停地弹出。
19、?命令
语法:? 表达式
作用:计算一个表达式的值
一个非常高级的计算器,另外由于可以显示ASCII,所以可以很方便地在各种数制之间察看。
20、.命令
语法: .
作用:在代码窗口中定位当前指令
当你在代码窗口中上下浏览时,有可能走得很远,那么这时一个"."命令会让你在下一瞬间回到SoftICE当前所在的CS:EIP处。
21、EXP命令
语法: EXP [函数名]
作用: 显示DLL中的出口函数
函数名可以指定出其前几个字符, 可以用?来做替代不定字符,这样你就可查找相关函数及其是哪个DLL文件了。这对于你在Win2K系统上非常实用,Win2K系统的KERNEL32.DLL中许多函数形式和Windows 9x可能不同,用此命令你就可找到正确的函数名了。
22、PMODULE命令(TRW2000特有命令)
作用:'pret'(相当于按<F12>) 直至CS:EIP位于模块中,但比F12更实用,其可以快速回到你的当前程序领空,不用按多次F12了
23、SUSPEND命令(TRW2000特有命令)
作用: 暂停当前的线程,并退出 TRW2000,按热键返回,此命令相当方便。
24、ver blue命令(TRW2000特有命令)
如你的TRW2000背景颜色很暗,可通过此命令来调整背景。

第三节 常用Win32 API函数简介


  现在很多讲Windows程序设计的书都是讲基于MFC库和OWL库的Windows设计,对Windows实现的细节都鲜有讨论,而调试程序都是和系统底层打交道,所以有必要掌握一些Win32 API函数的知识,这样我们可快捷地找出程序调用错在哪?是哪个参数出了问题。
  Windows程序模块包括KERNEL、USER和GDI,其中KERNEL完成内存管理、程序的装人与执行和任务调度等功能,它需要调用原MS―DOS中的文件管理、磁盘输入输出和程序执行等功能;USER是一个程序库,它用来对声音、时钟、鼠标器及键盘输入等操作进行管理;GDI是一功能十分丰富的子程序库,它提供了图形与文字输出、图象操作和窗口管理等各种与显示和打印有关的功能。上述KERNEL、USER和GDI模块中的库函数可被应用程序调用,也可被其他程序模块调用。把包含库函数的模块称为输出者(export)。你应明白为什么跟踪软件时经常在KERNEL32!.text和USER32.text等系统领空转的问题吧。
  这里列出几个经常碰到的Win 32 API函数,它们都是存在Windows系统核心文件KERNEL32.DLL中和视窗管理文件USER32.DLL中。
Windows函数是区分字符集的:A表示ANSI,W表示Wide,即Unicode (Wide character-set),前者就是通常使用的单字节方式,但这种方式处理象中文这样的双字节字符不方便,容易出现半个汉字的情况。而后者是双字节方式,方便处理双字节字符。Windows的所有与字符有关的函数都提供两种方式的版本。尽管你编程时使用GetWindowText,但实际上编译程序会根据设置自动调用GetWindowTextA或GetWindowTextW。函数的最后一个字母告诉我们函数是使用单字节还是双字节字符串。
1、 Hmemcpy函数
void hmemcpy(hpvDest, hpvSource, cbCopy)
void _huge* hpvDest; // 目的数据地址
const void _huge* hpvSource; // 源数据地址
long cbCopy; // 数据大小 (Bytes)
这个函数在KERNEL32.DLL中,它很常用,俗称万能断点,但一般的编程书籍上很少提到,原因它是底层的东西,没有特殊需要,一般不直接调用。但的确它是很有用的!有意思的是它执行的操作很简单,只是将内存中的一块数据拷贝到另一个地方。
注意:此函数只在Windows 9x系统上有效,在Win NT/2K系统上相关的函数是memcpy,但在Win NT/2K上不同于Windows 9x上,很少再调用memcpy来处理数据了,用此函数设断基本上什么也拦不住。
2、 GetWindowText函数
此函数在USER32.DLL用户模块中,它的作用是复制指定窗口中的字符到缓冲区。函数原型:
int GetWindowText(
HWND hWnd//欲获取文字的那个窗口的句柄
LPTSTR lpString //预定义的一个缓冲区,至少有cch+1个字符大小;随同窗口文字载入
int nMaxCount//lpString缓冲区的长度
);
16位:GetWindowText
32位:GetWindowTextA,GetWindowTextW
3、 GetDlgItemText
此函数在USER32.DLL用户模块中,它的作用是返回对话框中某一个窗口的标题或文字。函数原型:
UINT GetDlgItemText(
HWND hDlg, // 对话框句柄
int nIDDlgItem, //控制标识符
LPTSTR lpString, / 预定义的一个字符缓冲区
int nMaxCount// 字符缓冲区的长度
);
16位:GetDlgItemText
32位:GetDlgItemTextA,GetDlgItemTextW
4、 MessageBox函数
此函数是在USER32.DLL用户模块中,它的作用创建、显示和操作信息框。函数原型:
int MessageBox(
HWND hWnd, //窗口句柄
LPCTSTR lpText, // 信息框中文字的地址
LPCTSTR lpCaption, // 信息框标题地址
UINT uType // 信息框类型
);
16位:MessageBox
32位:MessageBoxA,MessageBoxW

第四节 拆解教程

======================================================================== ED!SON's Windows 95 拆解教程 V1.00 (中文翻译: JIM TYAN) ========================================================================
附:ED!SON教程的示范程序下载

目录 ======== 1. Windows 拆解简介 2. SoftICE for windows 2.00 快速入门 3. 如何找注册码 3.1 Task Lock 3.00 - 一个简单的、仅有注册号保护的拆解例子 3.2 Command Line 95 - 容易的“用户名/注册号"注册方式的拆解 4. 为Command Line 95制作注册器 5. 当程序调用一个函数时,PUSH和CALL这些指令是如何工作的 6. 关于VB程序

附录 ======== A. 如何让SOFTICE载入符号 B. 函数的语法 C. 到哪里获取软件 D. 如何与我联系

1. WINDOWS拆解简介 =================================== 拆解一个WINDOWS程序要比拆解一个在DOS下运行的程序要容易得多。因为在WINDOWS 中,只要WINDOWS的函数被使用了,想对任何真正要寻找蛛丝马迹的人隐藏什么东西 是比较困难的。

你需要的第一个(常常也是唯一的一个)工具就是SoftICE/Win 2.oo, 它是NuMega 出品的一个非常强大的调试工具。有些人发现它很难用,但我会教你如何使用它进行 有效的调试,也希望你们能够明白我将要告诉你们的:-)。 你应该看看在附录A 中有 关SoftICE/Win 2.oo的一些资料。我在安装SoftICE中从来没有碰到任何问题, 如果 你碰到了,我只好让你查它的参考手册了。

你所需要的所有软件的URL列在附录C中

- ED!SON, edison@ccnux.utm.my

2. SOFTICE/WIN 2.OO 快速入门 ========================================= 首先你应该对SOFTICE的屏幕有个大概的了解

|--------------------| | 寄存器窗 | 用 'R' 编辑 |--------------------| | 数据窗 | 用 'D' 列出某个地址的数据, 用 'E' 编辑 |--------------------| | 代码窗 | 用 'U' 反汇编, 'A' 加入汇编代码 |--------------------| | 命令窗 | 在这里输入命令和读出结果 |--------------------|

其它重要的功能键(在缺省的键定义下) 'H'/F1 - 在线帮助 F5/Ctr+D - 运行 F8 - 单步执行,切入子程序和中断 F10 - 单步执行,跳过子程序和中断 F11 - 跳出子程序,回到CALL的下一条指令

3. 如何寻找注册码 ============================= 最容易的练习莫过于找个共享软件来试试把它注册。

3.1 Task Lock 3.00 - 一个简单的、仅有注册号保护的拆解例子 ================================================================= 这是一个简单的保护,只有一个而且不会变化的注册码。

3.1.1 检查程序 =========================== 它是16 bit程序,还是32 bit的? 在哪里输入注册信息? 在它的帮助里有没有 发现关于注册的一些线索?在你继续往下读之前,去把它们找一找!

....你现在应该在找吧!.....你是在找吗?.....你找到了吗?....... 好,你现在知道了,它是一个32位的WINDOWS 95应用程序,你可以在一个选择了 “Register|Register..."菜单就会弹出来的对话框中,输入一个注册码来注册 程序。通过阅读它的帮助,你也知道可以有两种注册方式:Individual和Site License。所以这里对合法的注册码就可能有两次核对。

3.1.2 捕捉注册代码 =========================== 注册码通常在普通的WINDOWS文字框中输入。为了检查输入的注册码, 程序必须 采用下面这些函数中的一个来把文字框中的内容读出来。

16-bit 32-bit ------ ------ GetWindowText GetWindowTextA, GetWindowTextW GetDlgItemText GetDlgItemTextA, GetDlgItemTextW

32-BIT函数的最后一个字母告诉我们函数是使用单字节还是双字节字符串。双字 节的注册码是很少见的。

也许你已经体会到我的意思了...“如果我能在GetWindowText时中断...", 你 的确能这样做!但是你首先必须确认这些符号已经由SOFTICE载入了(详见附录A)

在SoftICE中设定一个“陷阱"(实际上我们叫断点),你得先按Ctrl+D进入调 试状态,然后用命令BPX,后面跟著是函数的名字或者内存地址。因为Task Lock 是32位程序,所以我们在GetWindowTextA处设一个断点。 如果这个不行, 我们 可以再试其它的。

象这样在SoftICE中输入:

:bpx getwindowtexta

如果你得到“No LDT"这样的错误信息,就要注意不要运行其它程序。我已经注 意到Norton Commander/Dos 会干扰这个功能。 你可以列出所有断点来检查一下 是否设好断点: :bl

你会看到这样的信息:

00) BPX USER32!GetWindowTextA C=01

你可以再按一次Ctrl+D,从SoftICE中退出,。

好了,不管怎么样,你已经设定好了断点以捕捉任何对GetWinowTextA的调用。 现在我们来在该输入注册码的地方输入一些数字,然后按下OK....你只得到了 一个信息框告诉你输入的注册码是无效的。看来不是GetWindowTextA....我们 来试试GetDlgItemTextA。首先删除旧的断点: :bc 0 (0 表示在断点列表中的第0个断点)

然后设定新的断点: :bpx getdlgitemtexta

再来试一次.....

3.1.3 在调试器中 ===================== 哇!行了!你已经在SoftICE中了,就在函数GetDlgItemTextA开始的地方。按 F11键,回到调用函数的地方。现在你到了SGLSET.EXE的内部,如果你还没把握 的话,看看代码窗和数据窗中间的一行,你应该看到这样的东西:

----------SGLSET!.text+1B13----------

你可以这样禁止一个断点:

:bd 0

以后想再开启它的话,可以这样:

:be 0

代码窗的第一行是:

CALL [USER32!GetDlgItemTextA]

按几次Ctrl+Up 直到你看到下面这几行。如果对汇编一点也不懂的话,看我加的 注解吧:

RET ; 函数结束 PUSH EBP ; 函数开始 MOV EBP, ESP SUB ESP, 0000009C PUSH ESI > LEA EAX, [EBP-34] ; EAX = EBP-34 PUSH EDI MOVE ESI, ECX PUSH 32 ; 输入字符串的最大长度 > PUSH EAX ; 输入字符串的缓冲地址 PUSH 000003F4 ; 控制标识 PUSH DWORD PTR [ESI+1C] ; 对话框的句柄 CALL [USER32!GetDlgItemTextA] ; 取得输入

PUSH指令保存那些数值以供后面使用。我已经在重要的地方加上了一个 '>'字符 作上记号. 看这几行我们就知道字符缓冲区的地址保存在EAX中,而EAX等于 EBP-34。

所以我们来看看EBP-34那里有什么:

:d ebp-3

你应该能在数据窗中看到你输入的东西。下面我们得来找开始核对输入注册码的 地方。按F10一步一步地单步运行直到你发现与EBP-34有点关系的地方.... 你不 用单步运行多久,就会看到这些代码:

> LEA EAX, [EBP+FFFFFF64] ; EAX = EBP-9C LEA ECX, [EBP-34] ; ECX = EBP-34 PUSH EAX ; 保存 EAX PUSH ECX ; 保存 ECX > CALL 00403DD0 ; Call 一子程序 ADD ESP, 08 ; 删除保存的信息 TEST EAX, EAX ; 检查返回值 JNZ 00402BC0 ; 如果不是零的话跳转

对我来说,马上就可以看出这象是一个字符比较程序。它们工作起来就是这样: * 输入两个字符串 如果相同就返回零 否则返回非零

那为什么程序要用一个字符串来和你输入的相比较呢?看它是不是合法的!(可 能你已经想到了)。那么是什么东西躲在 [EBP+FFFFFF64] ? SoftICE处理负数 还不是很好,所以得算算:

100000000 - FFFFFF64 = 9C

在 SoftICE 用这样的命令:

:? 0-FFFFFF64

100000000 对SoftICE来说太大了,但它还是给出了相同的结果。

现在是...来看看什么东西躲在EBP-9C那里的时候了...这样输入命令:

:d ebp-9c

数据窗口会显示出一大排数字 ─ 注册码!但是记住我前面说过的...两种注册 方式对应两个注册码....所以你把这些注册码抄下来以后,继续用F10单步运行 ....我们会遇到这些代码:

> LEA EAX, [EBP-68] ; EAX = EBP-68 LEA ECX, [EBP-34] ; ECX = EBP-34 PUSH EAX ; 保存 EAX PUSH ECX ; 保存 ECX > CALL 00403DD0 ; 再次调用子程序 ADD ESP, 08 ; 删除保存的信息 TEST EAX, EAX ; 检查返回结果 JNZ 00402BFF ; 如果非零跳转

你在EBP-68处找到了什么?不错吧...另一个注册码。

:d ebp-68

我们的练习结束了,希望一切顺利。

3.2 Command Line 95 -容易的用户名/注册码方式的注册、注册器 ================================================================= 这是一个非常好的例子,注册码的计算也很简单。

3.1.1 检查程序 =========================== 检查程序以后你知道它是32位的应用程序,要求输入名字和注册码。 让我们开始!

3.1.2 捕捉代码 =========================== 我们象拆解TaskLock那样 ─ 设置断点。我们可以在两个可能性最大的两个函数 都设上断点:GetWindowTextA 和 GetDlgItemTextA. 按下Ctrl+D 进入SoftICE, 然后:

:bpx getwindowtexta :bpx getdlgitemtexta

接下来进入注册对话框,输入一个名字和一些数字(多数情况下是一个整数), 我是这么写的,然后按OK....

Name: ED!SON '96 Code: 12345

程序在 GetDlgItemTextA 处停住了,就象TaskLock一样。我们按F11回到调用它 的地方。用 Ctrl+Up卷动窗口直到看到这些:

MOV ESI, [ESP+0C] PUSH 1E ; 最大长度 PUSH 0040A680 ; 缓冲地址 PUSH 000003ED ; 控制柄 PUSH ESI ; 对话柄 CALL [User32!GetDlgItemTextA]

数字40A680引起了我们的注意,看看那里有什么: :d 40a680

如果没有我们输入的名字,数据窗口里有些什么呢?好了,我们来研究下面的一 段代码:

PUSH 00 PUSH 00 PUSH 000003F6 ; 控制柄 MOV EDI, 0040A680 ; 保存缓冲区地址 PUSH ESI ; 对话柄 CALL [User32!GetDlgItemInt]

GetDlgItemInt 和 GetDlgItemText差不多,但它从文字框中返回一个整数。 它出在EAX中返回来的,所以单步运行通过这些代码,再来看看寄存器窗.... 对我而言是:

EAX=00003039

十六进制数3039是多少? 输入: :? 3039

我们得到:

00003039 0000012345 "09" ^ 16进制 ^ 十进制 ^ ASCII

正如你看到(和已经猜到)的那样,它是你输入的注册码。OK,下面怎么办?让 我们来看下面的代码:

MOV [0040A548], EAX ; 返回注册码 MOV EDX, EAX ; 同时保存在DX中

3.1.3 计算注册码 ========================== 这样注册码就算出来了

MOV ECX, FFFFFFFF ; 这几行计算字符长度 SUB EAX, EAX ; . REPNZ SCASB ; . NOT ECX ; . DEC ECX ; ECX <-- 长度 MOVSX EAX, BYTE PTR [0040A680] ; 读入40A680处的一字节 IMUL ECX, EAX ; ECX = ECX * EAX SHL ECX, 0A ; 左移 0A 次 ADD ECX, 0002F8CC ; 结果加上2F8CC MOV [0040A664], ECX

验证合法性....

CMP ECX, EDX ; 比较 JZ 00402DA6 ; 如果相同就....

当你运行到比较这一步时,就可以得到你真正的注册码:

:? ecx

对我而言它是: 000DC0CC 0000901324

也就是说我的正确的注册码是901324.

按F5或者Ctrl+D让它运行,然后用正确的注册码(十进制)再来一次。这一次 成功了!

4. 为COMMAND LINE 95制作注册器 ========================================= 我们把上面计算注册码的代码翻译成C语言程序。 最明了的计算公式就是:

code=((uppercase_first_char * length_of_string) << 0x0A) + 0x2f8cc;

注(1): 别忘了一件事 就是把所有字符转成大写 (2): "<< 0x0A" 实际上就是 "乘以 2^10"

完整的程序就是:

#include <string.h> #include <stdio.h>

int main() { unsigned long code; unsigned char buffer[0x1e];

printf("CommandLine95 Keymaker by ED!SON '96\n"); printf("Enter name: "); gets(buffer);

strupr(buffer); code = ( ((unsigned long)buffer[0] * (unsigned long)strlen(buffer)) << 0x0A) + 0x2f8cc;

printf("Your code is: %lu", code);

return 0; }

爽吧?

4. 当程序调用一个函数时,PUSH和CALL这些指令是如何工作的 ============================================================================ 我们重新来看看TaskLock中的这段代码:

PUSH 32 ; 字符串最大长度 PUSH EAX ; 字符缓冲区地址 PUSH 000003F4 ; 控制标识 PUSH DWORD PTR [ESI+1C] ; 对话框柄 CALL [USER32!GetDlgItemTextA] ; 获得字符串

如果认为是C语言编译出来的话,这个CALL应该是这样:

GetDlgItemTextA(hwndDlg, 0x3F4, buffer, 0x32); ^ [ESI+1C] ^ EAX

PUSH把数据保存在叫做堆栈的地方。每个PUSH把新的数据放在堆栈的顶部,被调 用的子程序就挨个地检查躺在堆栈中的数据,按照定义来使用它们。

附录

A. 让SoftICE载入符号 ============================== 你可以用exp getwindowtext命令来检查SoftICE是否已经为GetWindowText装入 了符号,象这样: :exp getwindowtext

如果你没有得到所有GetWindowText函数的列表,你就得编辑\SIW95\WINICE.DAT, 在"Examples of export symbols that can be included for chicago"这段文字 以后的那些 'exp='的行首去掉';',为了节省内存,选择最重要的几个就可以了:

kernel32.dll user32.dll gdi32.dll

编辑完后,重新起动计算机使其生效。

B. 函数语法 ============================ 如果你看看下面的函数声明,对我们上面讲到的函数调用就容易明白了:

int GetWindowText(int windowhandle, char *buffer, int maxlen); int GetDlgItemText(int dialoghandle, int controlid, char *buffer, int maxlen); int GetDlgItemInt(int dialoghandle, int controlid, int *flag, int type);

这些函数的详细描述,可参考Windows/Win32编程手册

C. 如何与我联系 ================ On IRC (EFNet): In #Ucf96, #Cracking By e-mail: edison@ccnux.utm.my OR an461165@anon.penet.fi On my homepage: http://www.geocities.com/SoHo/2680/cracking.html

======================================================================

译后记: 花了一个下午的时间(上班时间啊!),译完这篇拆解教程。不知大家看不看 得懂?ED!SON的文章是很浅显易懂的,我担心会让我毛手毛脚地闹出歧义来, 如果真有什么错误的话,帐应该算在我头上(请大家来信指出)。ED!SON的这 篇文章对初学者来说非常值得一读,我就是看完这篇文章以后,马上连续CRACK 了几个程序(就这么快、这么简单!)下次我就把CRACK WINZIP6.2的过程讲讲 吧(WINZIP6.2的注册器已经泛滥成灾了,就当练习练习吧)。欢迎来信交流, 你CRACK了什么程序,别忘了告诉我你用的方法;如果觉得我翻译得还算看得下 去话,就给些鼓励吧。

CFIDO ID : Jim Tyan EMAIL : jimtyan@tasteful.com

田学军 8878888 CALL 29549 jimtyan@tasteful.co


 

 

 

 

文章录入:onegreen    责任编辑:onegreen 
  • 上一篇文章:

  • 下一篇文章:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口


    相 关 信 息
    最 新 文 章
    热点推荐
    最 新 热 门
    最 新 推 荐
    相 关 文 章
    脱壳基础知识入门(2006年版)(9)
    脱壳基础知识入门(2006年版)(8)
    脱壳基础知识入门(2006年版)(7)
    脱壳基础知识入门(2006年版)(6)
    脱壳基础知识入门(2006年版)(5)
    脱壳基础知识入门(2006年版)(4)
    脱壳基础知识入门(2006年版)(3)
    脱壳基础知识入门(2006年版)(2)
    脱壳基础知识入门(2006年版)(1)
    看雪解密:第9章 注册机和补丁制作