第
3
章
软件调试基础
学习要求:理解PE文件格式,了解软件加壳与脱壳的思想;理解虚拟内存
的概念;掌握PE导入表和IAT的概念;学会使用OllyDbg和IDAPro等工具, 
了解PE文件代码注入实验的原理。
能掌握其基本用法; 

课时:2课时。

分布:[二进制文件][调试分析工具—演示示例]。

..3.1 
二进制文件

3.1 
PE文件格式
1.
源代码通过编译和连接后形成可执行文件。可执行文件之所以可以被操
作系统加载且运行,是因为它们遵循相同的规范。

PE(PortableExecutable)是Win32平台下可执行文件遵守的数据格式。
常见的可执行文件(如*.xd都是典型的PE文件。

ee文件和*.
l 
文件) 

一个可执行文件不光包含了二进制的机器码,还会自带许多其他信息,如
字符串、菜单、图标、位图、字体等。PE文件格式规定了所有的这些信息在可执
行文件中如何组织。在程序被执行时,操作系统会按照PE文件格式的约定去
相应的地方准确地定位各种类型的资源,并分别装入内存的不同区域。如果没
有这种通用的文件格式约定,可执行文件装入内存将会变成一件非常困难的
事情。

PE文件格式把可执行文件分成若干数据节(Section),不同的资源被存放
在不同的节中。一个典型的PE文件中包含的节如下。
对象
(
。
1).et:由编译器产生,存放着二进制的机器码,也是反汇编和调试的

tx

(2).data:初始化的数据块,如宏定义、全局变量、静态变量等。

(3).a:可执行文件所使用的动态链接库等外来函数与文件的信息,即

idat
输入表。
(4).sc:存放程序的资源,如图标、菜单等。

rr
除此以外,还可能出现的节包括.eo.dt.l.dt


rlc、eaa、ts、raa等。


46软件安全:漏洞利用及渗透测试
题外话:如果是正常编译出的标准PE 文件,其节信息往往是大致相同的。但这些
节的名字只是为了方便人的记忆与使用,使用MicrosoftVisualC++中的编译指示符
#pragmadata_seg() 可以把代码中的任意部分编译到PE 的任意节中,节名也可以自
己定义,如果可执行文件经过了加壳处理,PE 的节信息就会变得非常“古怪”。在
Crack和反病毒分析中需要经常处理这类古怪的PE 文件。
3.1.2软件加壳
加壳的全称应该是可执行程序资源压缩,是保护文件的常用手段。加壳过的程序可
以直接运行,但是不能查看源代码。要经过脱壳才可以查看源代码。
1.基本原理
加壳其实是利用特殊的算法,对EXE、DLL文件里的代码、资源等进行压缩、加密。
类似WinZip的效果,只不过这个压缩之后的文件,可以独立运行,解压过程完全隐蔽,都
在内存中完成。它们附加在原始程序上通过Windows加载器载入内存后,先于原始程序
执行,得到控制权,执行过程中对原始程序进行解密、还原,还原完成后再把控制权交还给
原始程序,执行原来的代码部分。加上外壳后,原始程序代码在磁盘文件中一般是以加密
后的形式存在的,只在执行时在内存中还原,这样就可以比较有效地防止破解者对程序文
件的非法修改,同时也可以防止程序被静态反编译。

加壳工具在文件头里加了一段指令,告诉CPU 
怎么才能解压自己。现在的CPU 运
行速度都很快,所以这个解压过程看不出差别。软件一下子就打开了,只有机器配置非常
差,才会感觉到不加壳和加壳后的软件运行速度的差别。当加壳时,其实就是给可执行的
文件加上个外衣。用户执行的只是这个外壳程序。当执行这个程序的时候这个外壳就会
把原来的程序在内存中解开,解开以后就交给真正的程序。所以,这些工作只是在内存中
运行,具体怎样在内存中运行并不可知。通常说的对外壳加密,都是指很多网上免费或者
非免费的软件,被一些专门的加壳程序加壳,基本上是对程序的压缩或者不压缩。因为有
的时候程序会过大,需要压缩。但是大部分的程序是因为防止反跟踪,防止程序被人跟踪
调试,防止算法程序不想被别人静态分析。加密代码和数据,保护程序数据的完整性。不
被修改或者窥视程序的内幕。

加壳虽然增加了CPU 负担,但是减少了硬盘读写时间,实际应用时加壳以后程序的
运行速度更快(当然有的加壳以后会变慢,那是选择的加壳工具问题)。如果程序员给
EXE 程序加壳,那么这个加壳的EXE 程序就不容易被修改,如果想修改就必须先脱壳。

2. 
加壳分类
加壳工具通常分为压缩壳和加密壳两类。

(1)压缩壳的特点是减小软件体积大小,加密保护不是重点。
(2)加密壳种类比较多,不同的壳侧重点不同。一些壳单纯保护程序;另一些壳提供
额外的功能。例如,提供注册机制、使用次数、时间限制等。

第3章软件调试基础473.1.3虚拟内存
为了防止用户程序访问并篡改操作系统的关键部分,Windows使用了两种处理器存
取模式:用户模式和内核模式。用户程序运行在用户模式,而操作系统代码(如系统服务
和设备驱动程序)则运行在内核模式。在内核模式下程序可以访问所有的内存和硬件,并
使用所有的处理器指令。操作系统程序比用户程序有更高的权限,使得系统设计者可以
确保用户程序不会破坏系统的稳定性。
Windows的内存可以被分为两个层面:物理内存和虚拟内存。其中,物理内存非常
复杂,需要进入Windows内核级别才能看到。通常,在用户模式下,用调试器看到的内存
地址都是虚拟内存。用户编制和调试程序时使用的地址称为虚拟地址(VirtualAddress) 
或逻辑地址(LogicalAddress),其对应的存储空间称为虚拟内存或逻辑地址空间;而计算
机物理内存的访问地址则称为实地址或物理地址,其对应的存储空间称为物理存储空间
或主存空间。程序进行虚拟地址到物理地址转换的过程称为程序的再定位。
在Windows系统中,在运行PE文件时,操作系统会自动加载该文件到内存,并为其
映射出4GB的虚拟存储空间,然后继续运行,这就形成了进程空间。用户的PE文件被
操作系统加载进内存后,PE对应的进程支配了自己独立的4GB虚拟空间。在这个空间
中定位的地址称为虚拟内存地址。
目前,系统运行在x64架构的硬件上,可访问的内存也突破了以前4GB的限制,但是
独立的进程拥有独立的虚拟地址空间的内存管理机制还在沿用。Windows装载器在装
载的时候仅仅建立好虚拟地址和PE文件之间的映射关系,只有真正执行到某个内存页
中的指令或访问某页中的数据时,该页才会从磁盘被提交到物理内存。但因为装载可执
行文件时,有些数据在装入前会被预先处理(如需要重定位的代码),装入以后,数据之间
的相对位置也可能发生改变。因此,一个节的偏移和大小在装入内存前后可能是完全不
同的。

注意:操作系统原理中也有虚拟内存的概念,那是指当实际的物理内存不够时,有时
操作系统会把部分硬盘空间当作内存使用,从而使程序得到装载运行的现象。请不要将
用硬盘充当内存的虚拟内存与本书介绍的虚拟内存相混淆。此外,本书中所述的内存均
指Windows用户态内存映射机制下的虚拟内存。

3.4 
PE文件与虚拟内存的映射
1.
在调试漏洞时,可能经常需要做以下两种操作。

(1)静态反汇编工具看到的PE文件中某条指令的位置是相对于磁盘文件而言的,即
文件偏移,我们可能还需要知道这条指令在内存中所处的位置,即虚拟内存地址。
(2)反之,在调试时看到的某条指令的地址是虚拟内存地址,我们也经常需要回到
PE文件中找到这条指令对应的机器码。
为此,需要弄清楚PE文件地址和虚拟内存地址之间的映射关系,首先看下面4个重
要的概念。

.文件偏移地址(FileOfset) 

48软件安全:漏洞利用及渗透测试
数据在PE文件中的地址称为文件偏移地址,是文件在磁盘上存放时相对文件开头
的偏移。
.装载基址(ImageBase)
PE文件装入内存时的基址。在默认情况下,EXE文件在内存中的基址是
0x00400000,DLL文件是0x10000000。这些位置可以通过修改编译选项更改。
.虚拟内存地址(VirtualAddress,VA)
PE文件中的指令被装入内存后的地址。
.相对虚拟地址(RelativeVirtualAddress,RVA) 
相对虚拟地址是虚拟内存地址相对于装载基址的偏移量。
虚拟内存地址、装载基址、相对虚拟内存地址三者之间有如下关系: 
VA=ImageBase+RVA 
如图3-1所示,在默认情况下,一般PE文件的0字节将映射到虚拟内存的
0x00400000位置,这个地址就是装载基址。
图3-
1 
PE文件与内存的映射关系

文件偏移是相对于文件开始处0字节的偏移,相对虚拟地址则是相对于装载基址
0x00400000处的偏移。由于操作系统在进行装载时基本上保持PE中的各种数据结构, 
所以文件偏移地址和相对虚拟地址基本一致。

之所以说基本一致是因为还有一些细微的差异。这些差异是由于文件数据的存放单

位与内存数据存放单位不同而造成的。

(1)PE文件中的数据按照磁盘数据标准存放,以0x200字节为基本单位进行组织。
当一个数据节不足0x200字节时,不足的地方将被0x00填充:当一个数据节超过0x200 
字节时,下一个0x200块将分配给这个节使用。因此,PE数据节的大小永远是0x200的


第3章软件调试基础49
整数倍。
(2)当代码装入内存后,将按照内存数据标准存放,并以0x1000 字节为基本单位进
行组织。类似地,不足将被补全,若超出将分配下一个0x1000 块为其所用。因此,内存中
的节总是0x1000 的整数倍。
1.使用LordPE可以查看节信息
LordPE 是一款功能强大的PE 文件分析、修改、脱壳软件。LordPE 是查看PE 格式
文件信息的首选工具,并且可以修改相关信息,其界面如图3-2所示。
图3-2LordPE界面
单击PEEditor按钮,选择需要查看的PE 文件,如图3-3所示。


图3-
3 
LordPE 
查看PE 
文件界面

单击Sections按钮,可以查看节信息,如图3-4所示。


图3-
4 
LordPE 
查看节信息界面


50软件安全:漏洞利用及渗透测试
在图3-4中,VOffset是RVA,ROffset是文件偏移地址。也就是说,在系统进程
中,代码(.text节)将被加载到0x400000+0x11000=0x411000的虚拟地址中(装载基
址+RVA )。而在文件中,可以使用二进制文件打开,看到对应的代码在0x1000位
置处。
通过文件位置计算器,如图3-5所示,也可以看出上述装载基址、RVA、VA和文件偏
移地址的关系。
图3-5LordPE文件位置计算器界面
2.使用LordPE查看导入表信息
使用LordPE可以查看相关节信息,打开另一个文件,查看区段表信息如图3-6 
所示。
图3-
6 
LordPE查看区段表信息界面

导入表在文件里的偏移地址ROfset为0x24000,RVA是0x25000 。

如图3-7所示,打开目录表可以看到输入表的RVA确实是0x25000 。单击L按钮可
以查看具体输入表里的内容,如图3-8所示。可以看到API的字符串名字(在按钮H打
开PE文件相关内容后,向后翻阅,可以看到PE文件中的相关API字符串的内容)。

同时,在目录表里,也可以看到IAT(e,导入地址表)的RVA是
0x2513C,如图3-7所示。
ImportAddresTabl

认识IAT。每个API函数在对应的进程空间中都有其相应的入口地址。众所周知, 
操作系统动态库版本的更新,其包含的API函数入口地址通常也会改变。由于入口地址
的不确定性,程序在不同的计算机上很有可能会出错,为了解决程序的兼容问题,操作系
统就必须提供一些措施来确保程序可以在其他版本的Windows操作系统,以及DLL版
本下也能正常运行。这时IAT就应运而生了。

单击IAT右侧的H按钮,就可以打开IAT信息在PE文件中的内容,如图3-9所示。


第3章软件调试基础51
图3-7LordPE查看目录表界面
图3-
8 
LordPE 
查看输入表内容界面


图3-
9 
查看IAT 
信息在PE 
文件中的内容


52软件安全:漏洞利用及渗透测试
注意:有很多工具可以更加直观地查看PE文件格式,如PEview(见图3-10)等,可以
自行下载查阅PE文件,加深对PE文件格式的认识和理解。
图3-10PEview查看PE文件格式
..3.2 
调试分析工具

在软件调试分析过程中,出现了很多分析工具,被广泛用在逆向分析、调试等领域,包
括OlyDbg、IDAPro、WinDbg、SoftiCE等。本书主要介绍前两个工具,并基于这两个工
具演示相关的漏洞案例。

3.1 
OlyDb
2.
g 
OlyDbg是一种具有可视化界面的32位汇编-分析调试器,适合动态调试。

1.安装
OlyDbg版的发布版本是个Zip压缩包,解压就可以使用了,如图3-11所示。

反汇编窗口:显示被调试程序的反汇编代码。

寄存器窗口:显示当前所选线程的CPU寄存器内容。

信息窗口:显示反汇编窗口中选中的第一个命令的参数及一些跳转目的地址、字符
串等。数
据窗口:显示内存或文件的内容。
堆栈窗口:显示当前线程的堆栈。
如果要调整上述各窗口的大小,只需按住左键拖动边框,等调整好了,重新启动

OlyDbg即可。


第3章软件调试基础53
图3-11OllyDbg界面功能区域说明
2.基本调试方法
OllyDbg有两种方式来载入程序进行调试:一种是选择菜单“文件” →“打开”命令
(快捷键是F3)打开可执行文件进行调试;另一种是选择菜单“文件”→“附加”命令附加到
一个已运行的进程上进行调试,要附加的程序必须已运行。通常采用第一种。
例如,选择一个Firs.xe来调试,通过选择菜单“文件”→“打开”命令载入这个程序,

teOlyDbg中显示的内容如图3-12所示。


图3-12 
OlyDbg载入程序


54软件安全:漏洞利用及渗透测试
入口点是程序载入后暂停的位置,也可以通过LordPE查看入口点的偏移地址。断
点可以通过快捷键F2来增加或者删除,断点的作用是只要程序运行到这里就会暂停。
调试中经常要用到的快捷键如下。
(1)F2:设置断点,只要在光标定位的位置(图3-12中灰色条)按F2键即可,再按一
次F2键则会删除断点。
(2)F8:单步步过。每按一次F8键执行反汇编窗口中的一条指令,遇到CALL等子
程序不进入其代码。
(3)F7:单步步入。功能同单步步过类似,区别是遇到CALL等子程序时会进入其
中,进入后首先会停留在子程序的第一条指令上。
(4)F4:运行到选定位置。作用就是直接运行到光标所在位置处暂停。
(5)F9:运行。按F9键如果没有设置相应断点,被调试的程序将直接开始运行。
(6)Ctrl+F9:执行到返回。此命令在执行到一个ret(返回)指令时暂停,常用于从
系统返回到调试的程序中。
(7)Alt+F9:执行到用户代码。可用于从系统快速返回到调试的程序中。
3.跟踪
使用调试功能时通常会碰到在断点处无法定位入口的情况,即无法确定前序执行指
令,通过跟踪(Trace)功能可以记录调试过程中执行的指令,用于分析前序执行指令。
Trace记录可选择是否记录寄存器的值,如图3-13所示。
图3-13 
OlyDbg的Trace功能

3.2 
IDAPo
2.r
IDAPro简称IDA(InteractiveDisasembler),是一个世界顶级的交互式反汇编工
具。其有两种可用版本:标准版(Standard)支持20多种处理器,高级版(Advanced)支持
50多种处理器。IDA是逆向分析的主流工具。

打开IDA,主界面如图3-14所示。

IDA使用File菜单中的Open命令,可以打开一个计划逆向分析的可执行文件,打开
的过程是需要耗费一些时间的。IDA会对可执行文件进行分析。一旦成功打开,会提示
你是否进入Proximityview。通常都会单击Yes按钮,按默认选项进入。如图3-14的树
状结构的示意图。


第3章软件调试基础55
图3-14IDAPro主界面
1.主要的数据窗口
在默认配置下,3个立即可见的窗口分别为IDAViw窗口、ams窗口和

IDA 打开后,eNe
消息输出窗口。在IDA 中,ESC 键是一个非常有用的热键,在反汇编窗口中,ESC 键的作用
与Web浏览器中的“后退”按钮类似,但是在其他打开的窗口中,ESC 键用于关闭窗口。

1)反汇编窗口

反汇编窗口也称IDAView窗口,是操作和分析二进制文件的主要工具。以前的反
汇编窗口有两种显示格式:图形视图(Graphview)和文本视图(Textview)。在默认情况
下,会以图形视图显示,在新的版本(IDA6)里,启动时会提示是否进入Proximityview, 
该视图将显示函数及其调用关系。

在图3-14 的Proximityview视图中,选择一个块,如_main函数块,在其上右击,可
以看到Textview和Graphview等选项。通过右键可以实现不同视图的切换。

图形视图:将一个函数分解为许多基本块,类似程序流程图,显示该函数由一个块到
另一个块的控制流程。

图3-15 为_main函数的图形视图。

在屏幕上可以发现,s

IDA 使用不同的彩色箭头区分函数块之间各种类型的流:Ye
边的箭头默认为绿色,No 边的箭头默认为红色。蓝色箭头表示指向下一个即将执行

的块。
IDA 一次显示一个函数, 可以使用“

在图形视图下,使用滑轮鼠标的用户, Ctrl键+ 
鼠标滑轮”来调整图形大小。键盘缩放控制需要使用“Ctrl+ 加号键”来放大,或者“Ctrl+ 
减号键”来缩小。如果图形太大太乱,不能通过一个视图就完整阅读,则需要结合左侧的
图形概况视图(Graphoverview)来定位需要阅读的区域。


56软件安全:漏洞利用及渗透测试
扫码见彩图
图3-15IDAPro中_main函数的图形视图
文本视图:文本视图则呈现一个程序的完整反汇编代码清单(在图形视图下一次只
能显示一个函数), 用户只有通过这个窗口才能查看一个二进制文件的数据部分。
如图3-16 所示的文本视图。
图3-16 
IDAPro切换到文本视图

在图3-16 显示的文本视图中,窗口的反汇编代码分行显示,虚拟地址则默认显示。
通常虚拟地址以[区域名称]:[ 虚拟地址]这种格式显示,如.t:0040110C0 。

tex

显示窗口的左边部分称为箭头窗口,用于描述函数中的非线性流程。实线箭头表示
非条件跳转,虚线箭头则表示条件跳转。如果一个跳转将控制权交给程序中的某个地址, 
这时会使用粗线,出现这类逆向流程,通常表示程序中存在循环。

通过选择Views→Opensubviews命令可以打开更多窗口。

2)Names窗口

简要列举了一个二进制文件的所有全局名称。名称是指对一个程序虚拟地址的符号


第3章软件调试基础57
描述。在最初加载文件的过程中,IDA会根据符号表和签名分析派生出名称列表。用户
可以通过Names窗口迅速导航到程序列表中的已知位置。双击Names窗口中的名称, 
立即跳转到显示该名称的反汇编窗口。
Names窗口显示的名称采用了颜色和字母编码,其编码方案总结如下。
(1)F:常规函数。
(2)L:库函数。
(3)导入的名称,通常为共享库导入的函数名。
(4)D:数据。已命名数据的位置通常表示全局变量。
(5)字符串数据。
如图3-17所示的Names窗口。
图3-17 
IDAPro切换到Names窗口

3)Strings窗口
Strings窗口功能在IDA5及以前的版本是默认打开的窗口。新版本已经不再默认
打开,但是可以通过选择Views→Opensubviews→Strings命令打开。

Strings窗口中显示的是从二进制文件中提取出的字符串,以及每个字符串所在的地
址。与双击Names窗口中的名称得到的结果类似,双击Strings窗口中的任何字符串,反
汇编窗口将跳转到该字符串所在的地址。将Strings窗口与交叉引用结合,可以迅速定
义感兴趣的字符串,并追踪到程序中任何引用该字符串的位置。

4)Functions窗口

Functions窗口显示所有的函数。单击函数名,可以快速导航到反汇编窗口中的该函
数区域。
Functions窗口中的条目如图3-18所示。
这一行信息指出:用户可以在二进制文件中虚拟地址为00401040的.t部分找到

_main函数,该函数长度为0x50字节。
tex

5)Functioncals窗口

Functioncals(函数调用)窗口将显示所有函数的调用关系,如图3-19所示。


58软件安全:漏洞利用及渗透测试
图3-18IDAPro的Functions窗口
图3-19 
IDAPro的Functioncals窗口

2.反编译功能
新版本的IDA增加了反编译功能,加强了分析能力。
在IDAView窗口下制定汇编代码, IDA会将当前所在位置的汇编代

按F5快捷键,
码编译成C/C++形式的代码,并在Pseudocode窗口中显示,如图3-20所示。


图3-20 
IDAPro的反编译窗口


第3章软件调试基础59 

3.脚本和插件功能
IDA新版本支持脚本和插件功能,在IDA安装目录下plugins文件夹里可以存放开
发的插件。已经加载的插件可以通过选择Edit→Plugins命令查看。

IDA也支持自己开发的脚本,对于一些经验性操作,可以通过脚本来编程实现。主
要支持两类语言的脚本:Python和IDC 。其中,
中,将演示一个基于IDA脚本的漏洞挖掘示例。
IDC是IDA自己的脚本语言。在第6章

..3.3 
演示示例

3.1 
PE文件代码注入
3.
本节将演示利用PE文件输入表API实现代码注入:让目标程序运行之前,先运行
注入的代码,注入的代码将运行PE文件输入表里包含的API 。

【实验3-1】对WindowsXP下扫雷程序,使用OlyDbg进行代码注入。

目标PE文件为WindowsXP下的扫雷程序,使用的工具包括OlyDbg和LordPE 。
在Windows下找到附件里的扫雷程序右击,在弹出的快捷菜单中选择“属性”命令可以看
到具体文件的位置,即C:\WINDOWS\system32\winmine.exe。为了方便使用,可以将
其复制到桌面上。

首先,用OlyDbg打开桌面上的扫雷程序,如图3-21所示。


图3-21 
OlyDbg打开扫雷程序

可以看到,程序会停下来,自动停下来的这一行代码位置就是程序入口点。可以通过
LordPE文件来查看,得知程序入口点的RVA是0x00003E21,同时也可以看到装载基址
是0x01000000(扫雷程序是C+
+ 
语言编写);也可以通过右侧寄存器EIP的值


60 软件安全:漏洞利用及渗透测试
0x01003E21观察到注释信息里,提示是ModuleEntryPoint。
在反汇编区域往下翻页,可以看到相关的导入表动态链接库及其相关函数的信息,如
图3-22所示。
图3-22 导入表动态链接库及其相关函数的信息
再往下翻页,可以找到大量的空白代码区域,因为这段区域也是在代码区,因此,如果
往这里植入代码,直接修改PE文件相关跳转地址,就可以执行相关的植入代码。例如, 
本实验就演示让扫雷程序运行之前,先运行注入的代码,注入的代码将调用PE文件输入
表里包含的MessageBox函数,弹出对话框,显示相关信息。
MSDN 对MessageBox函数的解释如下: 
int MessageBox( 
HWND hWnd, //handle to owner window 
LPCTSTR lpText, //text in message box 
LPCTSTR lpCaption, //message box title 
UINT uType //message box style 
); 
. hWnd:消息框所属窗口的句柄,如果为NULL,消息框则不属于任何窗口。
.lpText:字符串指针,所指字符串会在消息框中显示。
.lpCaption:字符串指针,所指字符串将成为消息框的标题。
. uType:消息框的风格(单个按钮、多个按钮等),NULL代表默认风格。
注意:熟悉MFC的程序员一定知道,其实系统中并不存在真正的MessageBox函
数,对MessageBox这类API的调用最终都将由系统按照参数中的字符串的类型选择A 
类函数(ASCII)或者W 类函数(UNICODE)调用。因此,在汇编语言中调用的函数应该
是MessageBoxA。
1.编辑及注入代码
首先,演示如何直接在PE文件里注入代码,计划注入的代码的功能:弹出对话框,显
示“YouareInjected!”。要达到这个目的,首先要构造相关的字符串,然后构造函数调用
的相关汇编代码。
在代码空白区域右击,在弹出的快捷菜单中选择“编辑”→“二进制编辑”命令(不同的

第3章软件调试基础61OllyDbg版本可能稍有差异,有的右击后,直接在快捷菜单里可以看到ASCII、汇编等功
能),如图3-23所示。
图3-23选择“二进制编辑”命令
如图3-24所示,在弹出的“编辑地址处的数据”界面里,输入ASCII为PEInject,将
取消勾选“保持代码空间大小”复选框,单击“确定”按钮后,状态如图3-25所示。
图3-24 
“编辑地址处的数据”界面


图3-25 
编辑后的代码状态

按Ctrl+A快捷键(分析),将根据具体内容,显示为ASCI
。依这个方式,再加入另
一条语句“YouareInjected!”,如图3-26所示。


图3-26 
再加入另一条语句“YouareInjected!” 


62 软件安全:漏洞利用及渗透测试
注意:上面的每条语句后面都留了一行00。因为,字符串后面是需要结束符0x00的。
接下来,构造函数调用的代码: 
push 0(默认风格) 
push 0x01004AA7(标题字符串地址) 
push 0x01004A9C(内容字符串地址) 
push 0(窗口归属) 
call MessageBoxA 
注意:直接双击要修改的当前行,就进入修改当前汇编代码的状态,如图3-27所示。
图3-27 双击进入修改当前汇编代码状态
注意:取消勾选“保持代码空间大小”复选框,直接写汇编代码即可。
我们输入的汇编指令callMessageBoxA 之所以后面能成功运行,也是因为PE文件
的输入表里已经有这个函数的入口地址了。以上代码完成输入后,结果如图3-28所示。
图3-28 修改后的代码状态
2.挂接代码及完成跳转
首先继续输入一条指令jmp0x01003E21。该条指令的意思是运行完注入的弹出对
话框后,会跳转到原来的PE文件的入口点继续运行。
结果如图3-29所示。
需要注意的是,上述修改是在原始文件副本里修改的,如果要保存修改,需要做到以
下两点:①在代码空白区域右击,在弹出的快捷菜单中选择“编辑”→“复制所有修改到可
执行文件”命令,会弹出一个对话框,包含所有修改后的代码;②在这个对话框空白处继
续右击,在弹出的快捷菜单中选择“编辑”→“保存文件”命令,弹出保存文件的界面,在这
里选择保存类型为“可执行文件”或DLL,输入新的文件名,如winmine1.exe,单击“保存”

第3章软件调试基础63
图3-29程序跳入原来的PE文件入口点
按钮。到
此,文件修改完毕,但是如果直接运行这个扫雷程序,并没有发生任何变化。
因为,我们只是编辑了一段代码,只有这些代码被运行了才算真正被注入。
利用LordPE文件,更改一下程序入口点,为程序的起始位置,即编辑的代码段的第
一个push0的位置,地址为0x01004ABA,因为只需要更改RVA,就修改为0x00004ABA 
即可,如图3-30所示。
图3-30 
修改程序入口点

单击“保存”按钮,运行程序,先弹出如图3-31所示对话框,单击“确定”按钮后,才会
出现扫雷程序。


图3-31 
运行程序显示被注
入
思考:如果运行程序前注入的不是弹出对话框代码呢? 会给我们带来哪些危害
?


3.2 
软件破解示例
3.
本节将对一个简单的密码验证程序,演示如何使用OlyDbg进行破解。


64 软件安全:漏洞利用及渗透测试 
【实验3-2】 对示例3-1源代码生成的Debug模式的可执行文件,使用OllyDbg进
行破解。
【示例3-1】 
#include<iostream> 
using namespace std; 
#define password "12345678" 
bool verifyPwd(char * pwd) 
{ 
int flag; 
flag=strcmp(password, pwd); 
return flag==0; 
}v
oid main() 
{ 
bool bFlag; 
char pwd[1024]; 
printf("please input your password:\n"); 
while (1) 
{ 
scanf("%s",pwd); 
bFlag=verifyPwd(pwd); 
if (bFlag) 
{ 
printf("passed\n"); 
break; 
}else{ 
printf("wrong password, please input again:\n"); 
} 
} 
}
破解对象是该程序生成的Debug模式的exe程序。
注意:Debug模式和Release模式生成的可执行文件是不同的,采用了不同的编译和
连接过程。Release模式生成的可执行文件不包含调试信息,代码更加精简、干练。
对得到的exe程序(假定不知道上面的源代码)有多种方式实现破解。例如,一种方
式是使用OllyDbg,通过运行程序,观察关键信息,通过对关键信息定位得到关键分支语
句,通过对该分支语句进行修改,达到破解的目的;另一种方式可以通过IDAPro观察代
码结构,确定函数入口地址,对函数体返回值进行更改。
运行程序,输入一个密码,发现运行结果如图3-32所示。
在OllyDbg中,为了尽快定位到分支语句处,在反汇编窗口右击,在弹出的快捷菜单
中选择“查找”→“所有引用的字符串”命令,如图3-33所示。