第5章
PE病毒 
5.1 实验概述 
本章实验旨在让读者了解PE病毒的基本原理,熟悉PE病毒中的部分关键技术以及
PE病毒的典型清除方法。实验过程分为以下四个阶段。
1. 熟悉masm32 
先编写HelloWorld程序,总体步骤如下。
(1)下载masm32v11。
(2)熟悉masm32的基本环境。
(3)写一个最简单的HelloWorld程序(如调用MessageBoxA 弹出一个对话框),并编
译成功。
(4)对得到的可执行文件进行反汇编,比较其反汇编代码与汇编代码异同。
(5)查看并理解masm32\bin下各个批处理程序,了解他们的大致功能,以及与qeditor 
程序Project菜单的具体对应关系(Edit-Setting-EditMenus)。
(6)探索其他菜单功能,并列出你认为对本课程后续学习有用的功能。
2. 熟悉病毒重定位的基本思路和方法
在HelloWorld.exe中添加一段代码,具体要求如下。
(1)该段代码弹出一个对话框(标题:武大网安病毒重定位,内容:姓名+学号)。
(2)该段代码同时包括代码和字符串数据。
(3)该段代码可以插入.text节的任意指令之间,而不修改该段代码中的任何字节,对
其可移动性进行验证(移动产生的空闲区域可用nop代替)。
3. kernel32 基地址定位及API 函数地址搜索
搜索kernel32.dll的导出API函数地址。
(1)用OllyDbg打开HelloWorld.exe,获取kernel32.dll模块基地址,定位到kernel32. 
dll模块。
(2)从内存中的kernel32.dll模块获取函数LoadLibraryA 和GetProcessAddress的函
数地址,并实际检验获得的地址是否正确。

第5章 PE病毒 
4. 分析病毒感染过程
分析并清除病毒,总体步骤如下。
(1)编译本书中的感染示例程序bookexample-old.rar,使用该感染示例程序对
HelloWorld.exe进行感染。分析该病毒在感染文件时具体做了哪些操作,该病毒如何返回
HOST。利用HelloWorld继续感染其他目标程序,定位目标程序运行时存在的问题并予以
解决。
(2)编译本书中的感染示例程序bookexample-new.rar,使用该感染示例程序对计算器
程序(calc.exe)进行感染。
(3)病毒感染示例程序在64位系统中无法正常感染,请定位其原因,并以最小范围的
源码修改方案解决该问题。
(4)清除病毒:在被感染的程序中定位HOST程序原程序入口地址,并手工恢复被感
染的计算器程序(calc.exe)。 
5.2 实验预备知识与基础 
5.2.1 反汇编和反编译
(1)汇编:将汇编源代码转变为目标程序(当然还不是最终的可执行的,因为还没有链
接程序)。
(2)编译:将高级语言编写的源程序通过编译器转变为目标程序。
(3)反汇编:将可执行的文件中的二进制经过分析转变为汇编程序。
(4)反编译:将可执行的程序经过分析转变为高级语言的源代码格式,由于编译器优
化原因,一般难以进行完全一致的转换。
5.2.2 反汇编的原理
反汇编的核心工作就是要能够解析(parse)机器码,根据CPU 的指令集规范理解它的
含义,并且将其展现为对应的汇编文本形式。然而反汇编器中同样重要的一个组成部分,是
对其所支持的平台的可执行文件格式的解析。
例如Windows上的PE、PE+,*-nix上的ELF,macOS上的Mach-O 格式等。这些可
执行文件的封装中包含可执行文件的结构元数据、导出/导入表、字符串常量池、调试符号信
息等诸多辅助信息,以及很重要的,该文件的首选的加载地址以及代码的入口地址等。
通过这些封装在可执行文件里的辅助信息,反汇编器才可以正确识别文件中哪些部分
是机器码,并对其进行反汇编操作。对用户友好的反汇编器还会进一步结合辅助信息来在
反汇编结果中给出更丰富的内容,例如一个地址如果指向字符串常量则在注释中显示字符
串内容,如果一个函数调用的参数列表已知,则根据调用约定(callingconvention)分析调用
点前传递参数的代码。
5.2.3 病毒重定位的原理
病毒重定位主要是利用call指令的push+jmp机制,push到堆栈中的是call指令结束
105

软件安全实践
之后的地址,jump跳转的机制是从call指令结束之后的地址算起,偏移大小为E8之后紧跟
的数值。利用push机制将数据压入堆栈,jump跳转到下一条需要执行指令的地址。对于
MessageBoxA 和ExitProcess函数的调用,利用call间接调用的方式即FF15,跳转到IAT 
表中指向的函数入口点。
5.2.4 获取kernel32 基地址的方法
(1)CreateProcess函数在完成装载应用程序后,会先将一个返回地址压入堆栈顶端, 
而这个返回地址恰好在kernel32.dll中,利用这个原理可以顺着这个返回地址按64KB大小
往地址搜索,那么一定可以找到kernel32模块的基地址。
(2)通过PEB枚举当前进程空间中用户模块列表也可以获取kernel32模块的基地址, 
fs:[0]指向TEB,fs:[30H]指向PEB,PEB偏移0ch是LDR 指针,以下可以分别通过加载
顺序、内存顺序、初始化顺序获取kernel32模块的基地址。此方法对于32位程序有效,在
64位系统下,PEB指向位置位gs:[60]。
(3)通过遍历SEH 链的方法,在SEH 链中查找成员prev的值为0xFFFFFFFFh的
EXCEPTION_REGISTER结构。该结构中的handler值是系统异常处理例程,总是位于
kernerl32.dll中。当前线程的TIB保存在fs段选择器指定的数据段的0偏移处,所以fs: 
[0] 的地方就是TIB 结构中的ExceptionList 字段。而ExceptionList 指向一个
EXCEPTION_ REGISTRATION 结构,SEH 异常处理回调函数的入口地址就由
EXCEPTION_REGISTRATION 结构指定。此方法在WindowsXP系统有效。
5.2.5 PE 病毒感染文件恢复
结合前面分析出的病毒的感染过程,要修复感染后的文件,至少要知道以下几个信息, 
同时也是需要修复的数据。
(1)感染前的文件大小。前面已经知道,病毒直接从文件末开始写入shellcode,要去掉
病毒写入的内容,就必须知道感染前原文件大小。
(2)感染前最后一个区段的RawSize。因为RawSize增加的大小等于文件增加的大
小,所以知道了感染前文件大小也就是RawSize的大小。
(3)感染前最后一个区段的VirtualSize。在获取正确的RawSize之后就可以根据对齐
来计算VirtualSize,也就是说第二个问题解决了,这个问题也就解决了。
(4)感染前的映像和。在获取最后一个区段正确的VirtualSize之后就可以计算映像
和,第三个问题解决了,这个问题也就解决了。
(5)感染前的入口点。前四个信息一环扣一环,所以总体来说,要获取的关键数据只有
两个,感染前的文件大小和感染之前的入口点。
5.2.6 修复过程总结
(1)通过在感染后的文件中搜索shellcode得到原始入口点,原文件大小。
(2)根据当前文件大小,得出增加部分的大小ExtraSize。
(3)根据ExtraSize修正最后一个区段的RawSize,当前值减去多的部分即可得正确
RawSize。
106

第5章 PE病毒 
(4)由正确的RawSize和内存对齐大小,计算正确的VirtualSize。
(5)根据PE头的大小和所有区段映像大小,计算总的SizeofImage。
(6)原始入口点减去映像基址即得AddressofEntryPoint。
(7)将文件大小减小ExtraSize,设置结束标记。 
5.3 熟悉masm32 
5.3.1 实验目的
掌握masm32 工具的基本使用方法和环境配置,学习编写、编译和调试简单的汇编语
言程序,理解masm32工具在汇编语言程序开发中的重要性,并通过本实验为后续更复杂
的汇编语言实验打下坚实的基础。
5.3.2 实验内容及实验环境
1. 实验内容 
(1)下载masm32v11。
(2)熟悉masm32的基本环境。
(3)写一个最简单的HelloWorld程序,并编译成功。
(4)对得到的可执行文件进行反汇编,比较其反汇编代码和最初的汇编代码有哪些
异同。
(5)查看并理解masm32\bin 下各个批处理程序,了解它们的大致功能,以及与
QEditor程序Project菜单的具体对应关系(Edit-Setting-EditMenus)。
(6)探索其他菜单功能,并列出你认为对本课程后续学习有用的功能。
2. 实验环境
(1)硬件:一台装有Windows操作系统的普通PC(使用虚拟机亦可)。
(2)软件:masm32。
5.3.3 实验步骤
1. 软件和环境准备 
进入官网下载地址:http://www.masm32.com,进入下载页面后,单击Australia1/2 
开始下载,压缩后得到安装文件,成功安装后,右击“计算机”→属性→高级系统设置→环境
变量,在用户变量新建并添加如下内容,配置环境变量。
然后将bin添加到Path中,编辑系统变量Path,如图5-1~图5-3所示。
2. masm 的使用
首先打开HelloWorld.asm,如图5-4所示。
大致对程序功能进行分析,如图5-5所示,程序调用了user32、kernel32。
在数据段存储了弹窗中的数据,如图5-6所示。
107

软件安全实践
图5-1 新建系统变量lib 图5-2 新建系统变量include 


图5-3 编辑系统变量Pah 图5-4 打开HeloWola

trd.sm 

图5-5 分析库文件图5-6 分析数据段
图5-7显示了程序的代码段,它会调用一个mesageBoxA弹窗,然后退出。


图5-7 分析代码段
启动汇编,如图5-8所示。也可在命令行中输入“ml/c/oloWola。

cf 
Herd.sm” 
单击链接,如图5-9所示。也可在命令行输入lik/sbysem:nosHerdoj。

nustWidwloWol.b

108 


第5章 PE病毒 
图5-8 启动汇编
现在就可以运行程序了,结果如图5-10所示。
图5-9 单击链接 图5-10 程序运行结果
3. 反汇编
使用masm32Editor打开HelloWorld.exe,在Tools工具栏下打开如图5-11所示的反
汇编exe文件。
图5-11 打开反汇编exe文件
109

软件安全实践
仔细观察,可以发现相关内容是PE文件格式的内容。
然后在后面是反汇编的代码,如图5-12所示。
图5-12 反汇编代码
通过图5-13的对比可以发现很明显的区别。
图5-13 对比
反汇编代码的逻辑大致是将数据压栈,首先执行calljmp_messageBoxA,然后开始执
行弹窗操作,最后再跳转到jmp_ExitProcess。 
5.4 病毒重定位 
5.4.1 实验目的
深入理解病毒重定位的基本思路和方法,掌握病毒在内存中的重定位技术,为后续深入
研究和防范恶意软件奠定坚实的基础。
5.4.2 实验内容及实验环境
1. 实验内容 
在HelloWorld.exe中添加一段代码,具体要求如下。
(1)该段代码弹出一个对话框(标题:武大网安病毒重定位,内容:姓名+学号)。
(2)该段代码同时包括代码和字符串数据。
(3)该段代码可以插入.text节的任意指令之间,而不修改该段代码中的任何字节,对
其可移动性进行验证(移动产生的空闲区域可用nop代替)。
110

第5章 PE病毒 
2. 实验环境
(1)硬件:一台装有Windows操作系统的普通PC(使用虚拟机亦可)。
(2)软件:OllyDebug。
5.4.3 实验步骤
1. 观察call 指令 
call=push+jmp。
如果call调用一个内存地址,那么编译器编译的是相对偏移。
call指令调用的地址=call指令所处偏移+5+相对偏移。
首先用OD打开HelloWorld.exe文件,在地址40100E开始使用nop填充字段,结果如
图5-14所示。
图5-14 填充nop 
2. 在地址100E 处添加汇编指令call MessageBoxA 
该步骤如图5-15所示。
图5-15 添加汇编指令
3. 选择1020 地址插入代码
首先添加push0,之后push的第二个参数是“武大网安病毒重定位”,再加上最后一字
节为0,一共19字节,也就是13H。需要使用call指令的特性,如图5-16所示。
注意最后添加0,这样一来call指令向后跳转13H,如图5-17所示。
111

软件安全实践
图5-16 添加push0 


图5-17 添加cal 

接下来在下一条插入上述数据(在ASCI 
处输入“武大网安病毒重定位”),如图5-18 
所示。


图5-18 添加ASCI 
文字数据

运行结果如图5-19所示。


图5-19 运行结果

然后输入第三个参数,“名字+学号”一共16字节,10H 。此时插入这个数据后,数据偏
移到了40104F,所以先添加一个cal 
指令到这个地址,如图5-20所示。


图5-20 添加cal 
指令

接着编辑代码输入数据“名字+学号”,如图5-21所示。

然后添加push0,再调用MesageBoxA,如图5-22所示。

注意:由于为了能使得弹窗在不同的位置都能被调用,所以这里需要使用IAT来进行

MesageBox的寻址。通过查看PE文件结构,可知IAT的地址为00402008H 。

112 


第5章 PE病毒 
图5-21 编辑数据
图5-22 调用MessageBoxA 
最后退出进程,如图5-23所示。
图5-23 退出进程
这里也需要找到IAT的地址然后调用退出函数,如图5-24所示。
图5-24 调用退出函数
4. 将修改复制到可执行文件
存储之后,对代码进行移动。
首先进行数据跟随,结果如图5-25所示。
图5-25 数据跟随结果
113