一、PE文件原理
PE即Portable Executable,是win32环境自身所带的可执行文件格式,其部分特性继承自Unix的COFF(Common Object File Format)文件格式。PE表示该文件格式是跨win32平台的,即使Windows运行在非Intel的CPU上,任何Win32平台的PE装载器也能识别和使用该文件格式的文件。
所有Win32执行体(除了VxD和16位的DLL)都使用PE文件格式,如EXE文件、DLL文件等,包括NT的内核模式驱动程序(Kernel Mode Driver)。
上图给出了PE文件结构的示意图。
PE文件至少包含两个段,即数据段和代码段。Windows NT 的应用程序有9个预定义的段,分别为 .text 、.bss 、.rdata 、.data 、.pdata 和.debug 段,这些段并不是都是必须的,当然,也可以根据需要定义更多的段(比如一些加壳程序)。
在应用程序中最常出现的段有以下6种:
.执行代码段,通常 .text (Microsoft)或 CODE(Borland)命名;
.数据段,通常以 .data 、.rdata 或 .bss(Microsoft)、DATA(Borland)命名;
.资源段,通常以 .rsrc命名;
.导出表,通常以 .edata命名;
.导入表,通常以 .idata命名;
.调试信息段,通常以 .debug命名;
PE文件的结构在磁盘和内存中是基本一样的,但在装入内存中时又不是完全复制。Windows装载器在装载的时候仅仅建立好虚拟地址和PE文件之间的映射关系,只有真正执行到某个内存页中的指令或访问某一页中的数据时,这个页才会被从磁盘提交到物理内存。但因为装载可执行文件时,有些数据在装入前会被预先处理(如需要重定位的代码),装入以后,数据之间的相对位置也可能发生改变。因此,一个节的偏移和大小在装入内存前后可能是完全不同的。
上图中,左边代表在磁盘中PE文件各个部分的对齐方式(对齐基准大小为0x200),右边是在内存中PE文件各个部分的对齐方式(对齐基准大小为0x1000),这个基准可以在PE文件的OPTION_HEADER中找到,如下图:
1. IMAGE_DOS_HEADER和Dos Stub
其实IMAGE_DOS_HEADER和Dos Stub没有什么重要的,只是IMAGE_DOS_HEADER中的第十九个成员指向IMAGE_NT_HEADERS的位置。
所有PE文件(包括DLL)均必须以一个简单的DOS MZ header开始,在偏移0处有可执行文件的“MZ”标志,确保该程序能够在DOS下运行。
2. PE头
PE header是相关结构IMAGE_NT_HEADER的简称,其中包含了许多PE装载器用到的域。
3. 节
PE真正的内容划分为块,称作节(section)。如上图中IMAGE_NT_HEADER下面就是节表和节。
感染PE格式文件的win32病毒,简称PE病毒。PE病毒同时也是所有病毒中数量极多、破坏性极大、技巧性最强的一类病毒。为了更好地发展反病毒技术,了解病毒的原理是极为必要的。一个PE病毒基本上需要具有重定位、截获API函数地址、搜索感染目标文件、内存文件映射、实施感染等几个功能,这也是病毒必须解决的几个基本问题。
PE病毒感染文件的基本步骤如下:
(1) 判断目标文件开始的两个字节是否为“MZ”。
(2) 判断PE文件标记“PE”。
(3) 判断感染标记,如果已被感染过则跳出继续执行HOST程序,否则继续。
(4) 获得Directory(数据目录)的个数,(每个数据目录信息占8个字节)。
(5) 得到节表起始位置。(Directory的偏移地址+数据目录占用的字节数=节表起始位置)。
(6) 遍历所有的节表,找到第一个具有可以容纳所有病毒代码空闲空间的节。
每个节的空闲空间的计算方法:
第i个节的空闲空间=第i+1个节的虚拟地址-第i个节的虚拟地址-第i个节的Misc.VirtualSize
(7) 开始写入目标代码:
计算目标代码的文件偏移位置,以后目标代码将从该位置写入PE文件。其计算方法为:目标节表的Misc.VirtualSize+目标节表的PointerToRawData
修改目标节的节属性为0xE00000E0,使得目标节变成可读、可写、可执行。
写入目标代码的数据段
写入目标代码的执行主体
修改AddressOfEntryPoint(即程序入口点指向病毒入口位置),同时保存旧的AddressOfEntryPoint,以便返回HOST继续执行。
更新SizeOfImage(内存中整个PE映像尺寸=原SizeOfImage+病毒节经过内存节对齐后的大小)。SizeOfCode 代码的大小,即是原SizeOfCode+病毒代码经内存对齐后的大小。
写入感染标记,在感染标记后面写入旧的AddressOfEntryPoint利于解毒。
二、代码注入
1.使用visualstudio系列编写一个EXE文件,或者使用本次实验提供的“扫雷”程序,用x64dbg调入可执行程序
2.找到程序入口点并记录下来01003e21
3.在同样的代码节寻找空白的内存区域
4.写入如下Win32函数的汇编代码
MessageBox 函数 显示一个模式对话框,其中包含系统图标、一组按钮和一条简短的应用程序特定消息,例如状态或错误信息。 消息框 返回一个整数值,该值指示用户单击的按钮。 int MessageBox( [in, optional] HWND hWnd, [in, optional] LPCTSTR lpText, [in, optional] LPCTSTR lpCaption, [in] UINT uType ); |
对应的汇编指令: push 0x31 #对话框类型 push 0x01004A90 #标题 push 0x01004AB0 #内容 push 0x0 #hWnd call messageboxA jmp 0x01003E21 #PE文件的原始入口点 |
5.应用补丁得到代码注入后的程序
点右键,“补丁”à “修补文件”,然后输入文件名: xxx-cracked.exe
6.使用PE工具修改程序入口点为: 0x01004B00
7.运行程序
三、总结
1.PE文件的开头标记是什么
PE00
2.PE程序的入口点在PE文件的何处,如何修改
入口点=基址+偏移量,使用xdgb输入汇编指令并用补丁进行修改。
3.代码注入的方法
- 寻找最大的代码空白,cave mine,将 shellcode 写入 cave 中。这种方式比较方便,缺点是只适合较小的 shellcode,windows 上的 shellcode 要比 linux 上的 shellcode 大许多,这种方式的泛用性不高。
- 新增 PE 节,这种方式修改 PE 文件的节头表和节,可以插入任意大小的 shellcode。