windows PE学习
PE介绍
PE(Portable Execute)文件是Windows下可移植可执行文件的总称,常见的有DLL,EXE,OCX,SYS等,事实上,一个文件是否是PE文件与其扩展名无关。本文要说的PE文件结构,就是指的Window可移植可执行文件结构。
PE文件结构
PE文件具有较强的移植性;
PE结构是一种数据组织方式;
PE结构主要应用于windows系统;
具有PE结构的文件称为PE文件;
EXE、DLL都是PE文件;
- 完整的PE文件主要有4个部分组成:DOS头,PE头,节表以及节数据。
- DOs头部主要用于对非PE格式文件的处理,DOS时代遗留的产物,是PE文件的一个遗传;
- PE头部部分用于宏观上记录文件的一些信息,,运行平台,大小,创建日期,属性等;
- 节表部分用于对各种类型的数据进行定义分段;
- 节数据不言而喻就是文件的数据部分,实际上我们编写程序的过程中就是对该部分的数据进行编写。而其他的部分则是由编译器依照我们编写的部分进行相应的填写而得到的。
整个结构如下
解析过程:DOS头->PE头->节段(包括导入表那些)->运行
DOS头解析
e_magic头部是固定的,用于表示这是个二进制可执行文件。
IMAGE_DOS_HEADER {
WORD e_magic; // +0000h - EXE标志,“MZ”
WORD e_cblp; // +0002h - 最后(部分)页中的字节数
WORD e_cp; // +0004h - 文件中的全部和部分页数
WORD e_crlc; // +0006h - 重定位表中的指针数
WORD e_cparhdr; // +0008h - 头部尺寸,以段落为单位
WORD e_minalloc; // +000ah - 所需的最小附加段
WORD e_maxalloc; // +000ch - 所需的最大附加段
WORD e_ss; // +000eh - 初始的SS值(相对偏移量)
WORD e_sp; // +0010h - 初始的SP值
WORD e_csum; // +0012h - 补码校验值
WORD e_ip; // +0014h - 初始的IP值
WORD e_cs; // +0016h - 初始的CS值
WORD e_lfarlc; // +0018h - 重定位表的字节偏移量
WORD e_ovno; // +001ah - 覆盖号
WORD e_res[4]; // +001ch - 保留字00
WORD e_oemid; // +0024h - OEM标识符
WORD e_oeminfo; // +0026h - OEM信息
WORD e_res2[10]; // +0028h - 保留字
LONG e_lfanew; // +003ch - PE头相对于文件的偏移地址
}
- 用黄色框框框住的是Dos头部,绿色框框框住的是Dos字节块;
- Dos字节块大小是不固定的。
Dos头:长度40h;
Dos块:长度不定,DOS插桩代码,是DOS下的16位程序代码,只是为了显示上面的提示数据。这段代码是编译器在程序编译过程中自动添加的。
Dos头里最重要的是e_lfanew字段,也就是Dos头最后四个字符,表示了PE头的偏移地址。
PE地址=Dos头部地址+偏移地址
Ps:这里的e_lfanew字段为:000000E8(在内存里要从右往左读,高位在右边,低位在左边)。
通过计算可以得到PE头部地址
PE头解析
typedef struct _IMAGE_FILE_HEADER {
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
- 50 45固定PE头标识;
- Machine为014C -> 处理器为x86;
- 段数目这里为5;
- 段表相对偏移E0;
- EXE/DLL。
可选头部:
- 0B 01 -> 32位程序;
- 00002000 -> 程序开始执行的入口地址;
- ImageBase(文件映射到内存的基地址) -> 00002000;
- SectionAlignment(内存中段对齐地址) -> 0000000A;
- FileAlignment(文件中段对齐地址) -> 0000000A;
- MajorSubsystemVersion(所需的windows系统版本) -> 0A00 -> 十进制 10 (为UWP);
- SizeOfImage(所需内存总大小) -> 01171A;
- SizeofHeaders(头部的总大小) -> 000200
- SubSystem(驱动/GUI/命令行) -> 2000
- NumberOfRvaAndSizes(数据目录个数) -> 00000010
数据目录项:
IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress; // +0000h - 数据的起始RVA
DWORD Size; // +0004h - 数据块的长度
}
ImportSva(导入表相对虚拟地址) -> 00004000
可选头中定义了如下重要信息:
* 所有含代码的节的总大小
* 所有含已初始化数据的节的总大小
* 所有含未初始化数据的节的大小
* 程序执行入口RVA
* 代码的节的起始RVA
* 数据的节的起始RVA
* 程序的建议装载地址
* 内存中的节的对齐粒度
* 文件中的节的对齐粒度
* 内存中整个PE映像尺寸
* 所有头+节表的大小
* 导出表
* 导入表
* 资源
* 重定位表
* 调试信息
* 版权信息
* 导入函数地址表
这么说导入表和导出表算在可选头,emmm…
常见的节数据:
.text:代码段,是在编译或汇编结束时产生的一种块,它的内容全部是指令代码。也有的编译器将该段命名为.code
.data:初始化的数据块,是初始化的数据块,包含那些编译时被初始化的变量、字符串
.idata:输入表,包含其他外来dll的函数和数据信息,也就是输入表,也有人称之为导入表。
.rsrc:资源数据块,包含模块的全部资源数据,如图标、菜单、位图等。
.reloc:重定位表,用于保存基址的重定位表。即当装在程序不能按照连接器所指定的地址装载文件时,需要对指令或已经初始化的变量进行调整,该块中也包含了调整过程中所需要的一些数据,如果装载能够正常装在则忽略此段中的数据。
.edata:导出表,是pe文件的输出表,以供其他模块使用,并不是每个pe文件都有此数据段,因为有的文件并不需要输出一些函数,该数据段常见于动态连接库文件中。
.radata:存放调试目录、说明字符串,该数据块并不常见主要是用于存放一些调试信息。
更方便的手动查找
利用010 Editor的模板
参考链接: https://bbs.pediy.com/thread-221766.htm
官方模板链接:http://www.sweetscape.com/010editor/repository/templates/
下载EXE.bt,使用010 Editor加载运行模板
点击Open Template,打开对应的模板,按F5运行
运行后会多处一个窗口,里面就是解析好的数据。(然后点开对应的结构,跟着表看就行)
定位对应的段是使用地址来定位的,查看对应的VirtualAddress地址通过计算即可得到对应的节段地址
这里查看重定位表示例:
对应VirtualAddress(虚拟地址):28648h、Size:900
使用LordPE进行计算,得到地址
010 Editor按Ctrl+G输入24248即可到达对应的地址
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。
文章标题:windows PE学习
本文作者:九世
发布时间:2020-07-05, 11:57:15
最后更新:2020-07-05, 12:43:32
原始链接:http://jiushill.github.io/posts/c925c057.html版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。