其他分享
首页 > 其他分享> > PE文件格式总结

PE文件格式总结

作者:互联网

PE文件格式总结


时间:202106

基本介绍

PE文件主要由 文件头区段(Section) 构成(如图所示),文件头记录相关信息,而区段则存放相关数据。相连代表数据在文件中存储紧接上一部分。

文件头部分包括:
(1) DOS Header
(2) DOS Stub
(3) NT Headers
(4) Section Headers
运行时PE文件由PE加载器加载到内存,文件头部分将会被加载到 内存基址(Image Base) 。但程序运行时一般会加载多个模块,如果都固定 Image Base 可能会导致内存使用冲突,所以PE文件会设置一个首选 Image Base,但实际的 Image Base 由 PE 加载器决定。因此,PE 文件中一般不使用绝对的内存地址,而采用相对于 Image Base 偏移的地址,称为 相对内存地址(Relative Virtual Address, RVA) ,其 绝对内存地址(Virtual Address, VA) 在加载后计算得到,关系如下:
VA = ImageBase + RVA

区段头(Section Header) 中包括了该区段的重要信息,主要包括:区段数据的文件位置和大小、加载到内存时的 RVA 和占用内存大小、区段属性。PE加载器通过读取区段头的信息,将文件中的区段数据加载到对应的内存地址中。文件中的位置由相对文件第一个字节的偏移描述,称为 文件偏移地址(File Offset Address, FOA)

1.DOS Header 和 DOS stub

DESC (Description) : 为兼容 ms-dos 系统而存在,DOS stub 为 DOS 根存程序。
FOA : 0x00000000

e_magic
DESC : 标识符, 必须为 ”MZ”, 0x5A4D。
e_lfanew
DESC : 新文件头 NT headers 的 FOA 。

2.NT headers

DESC : PE 文件头。
FOA : IMAGE_DOS_HEADER.elfanew

Signature
DESC : 标识符, 必须为 ”PE”,0x00004550。

2.1File header

FOA : IMAGE_DOS_HEADER.elfanew + 0x04

Machine
DESC : 标识符,映像文件适用的机器类型。

描述
0x014Cx86 处理器
0x0200Intel Itanium 处理器
0x8664x64 处理器

TimeDateStamp
DESC : 文件的创建时间,等于 1970/01/01 00:00:00 起经过的秒数。
SizeOfOptionalHeader
DESC : Optional Header 的大小,值可以为 224 字节和 240 字节,分别表示 32 位和 64 位。该值可以作为 32 位/ 64 位的判断依据。
Characteristics
DESC : 文件属性。

描述
0x0001重新定位信息已从文件中删除,文件必须在其首选基址处加载,如果基地址不可用,加载器会报错
0x0002文件可执行
0x0004COFF line number 已经从文件中删除
0x0008COFF 符号表条目已经从文件中删除
0x0010弃用
0x0020应用程序可以处理大于 2GB 的地址
0x0080保留
0x0100计算机支持 32 位体系架构
0x0200调试信息被移除并保存在另一个文件中
0x0400如果此镜像文件在可移动介质上,将其复制到交换文件中并从中运行
0x0800如果此镜像文件在网络介质上,将其复制到交换文件中并从中运行
0x1000此镜像文件是系统文件
0x2000此镜像文件是动态链接库 (DLL)
0x4000此文件只能运行于单处理器机器上
0x8000保留

值未列出表明官方文档缺失,之后的表格也是如此

2.2 Optional header

FOA : IMAGE_DOS_HEADER.elfanew + 0x18

Magic
DESC : 标识符。

描述
0x10B文件为 32 位程序的可执行映像
0x20B文件为 64 位程序的可执行映像
0x107文件为 ROM 映像。

SizeOfCode SizeOfInitializedData SizeOfUninitializedData
DESC : 代码段、已初始化和未初始化的数据段的字节大小,如果存在多个段则为所有段大小之和。

每个 Section 在文件中的数据都为已初始化的数据,可以直接加载到内存中。
未初始化数据应该是用于减小文件的大小,具体是:如果文件中 Section 某位置一直到该 Section 结束时的数据初始值均为 0x00,就可以将该部分删去,而 Section 加载到内存时的实际大小设置不变,加载时仅加载 Section 在文件中有的部分,剩下的内存则由PE加载器填充 0x00,即由PE加载器完成初始化工作。

AddressOfEntryPoint
DESC : 程序入口点相对于 ImageBase 的偏移地址,即入口点的 RVA。
ImageBase
DESC : 映像被加载到内存时第一个字节的首选基址, 值为 64KB 的倍数。Dll 默认为 0x10000000; 应用程序除了在 Windows CE 上为默认为 0x00010000,其他默认为 0x00400000。

当加载到内存后, PE装载器会将其修改为实际加载的基址。

SectionAlignment
DESC : 区段加载到内存时的对齐字节值,即加载到 SectionAlignment 倍数的内存地址处。该值必须不小于 FileAlignment,默认值为系统的页大小。因此内存中相邻 Section 间一般存在间隙。
FileAlignment
DESC : 区段数据在映像文件中的对齐字节值。该值为 512 到 64K 之间 2 的幂(含边界值),默认值为 512 字节。因此每个区段末一般会有填充 0x00 的部分,且未被使用。
SizeOfImage
DESC : 映像加载到内存后占用的总大小,值必须为 SectionAlignment 的倍数。
SizeOfHeaders
DESC : 文件头的大小,为以下几个值的和,且最终向上舍入到 FileAlignment 的倍数。

a) IMAGE_DOS_HEADER.e_lfanew
b) 4字节的标识符
c) IMAGE_FILE_HEADER 的大小
d) 可选头的大小
e) 所有区段头的大小

CheckSum
DESC : 校验和,在以下文件加载时验证:所有驱动程序、任何引导时加载的 DLL 和任何加载到关键系统进程中的 DLL。
Subsystem
DESC : 运行该映像所需要的子系统类型。

描述
0未知子系统
1无子系统要求(设备驱动程序和本地系统进程)
2Windows 图形用户界面 (GUI) 子系统
3Windows 字符模式用户界面 (CUI) 子系统
5OS/2 CUI 子系统
7POSIX CUI 子系统
9Windows CE 子系统
10可扩展固件接口 (EFI) 应用程序
11带引导服务的 EFI 驱动
12带运行时服务的 EFI 驱动
13EFI ROM 映像
14Xbox 子系统

DllCharacteristics
DESC : Dll 属性。

描述
32 位64 位
0x0001保留
0x0002保留
0x0004保留
0x0008保留
0x0020具有64位地址空间的ASLR无文档信息
0x0040DLL 可以在加载时重新定位
0x0080强制进行代码完整性校验
0x0100映像与数据执行保护 (DEP) 兼容
0x0200映像可以隔离,但不应该隔离
0x0400映像不使用结构化异常处理 (SHE),无法在映像中调用任何处理程序
0x0800不绑定映像
0x1000映像应该在 AppContainer 中执行保留
0x2000WDM 驱动
0x4000映像支持控制流保护保留
0x8000映像支持终端服务器

SizeOfStackReserve SizeOfStackCommit
DESC : 栈保留大小和栈提交大小。栈在加载时仅使用 SizeOfStackCommit 大小的内存, 剩余的在达到栈保留大小前每次仅使用一页。
SizeOfHeapReserve SizeOfHeapCommit
DESC : 堆保留大小和堆提交大小。堆在加载时仅使用 SizeOfHeapCommit 大小的内存, 剩余的在达到堆保留大小前每次仅使用一页。
DataDirectory
DESC : 目录表,为 IMAGE_DATA_DIRECTORY 结构体数组,共 16 个元素,描述相应表项的位置和大小信息。

IMAGE_DATA_DIRECTORY.VirtualAddress 为表项内容的 RVA。

表项如下:

索引值描述
0导出表
1导入表
2资源目录
3异常目录
4安全目录
5基本重定位表
6调试信息目录
7特殊结构数据表
8全局指针寄存器相对虚拟地址
9线程局部储存 (TLS) 表
10加载配置表
11绑定导入表
12导入地址表
13延迟导入描述
14CLR 头
15保留

3.Section headers

DESC : 区段表,由 IMAGE_SECTION_HEADER 结构体数组构成,每个元素描述一个区段的信息,以 NULL 元素结束。
FOA : IMAGE_DOS_HEADER.elfanew + NT headers大小 (紧跟 NT headers)

Name
DESC : 区段名, 一个 8 字节、0x00 填充的 UTF-8 字符串。

如果字符串长度正好为 8 个字符,则不存在 ’\0’ 终止符。如果名称较长, 此成员值为 正斜杠 (/) + ASCII 表示的十进制数, 该十进制数为名称在字符串表中的偏移量。可执行映像不使用字符串表,也不支持长度超过 8 个字符的区段名。

Misc.VirtualSize
DESC : 加载到内存时整个区段的实际大小, 如果值大于 SizeOfRawData , 说明有未初始化的数据,这部分将由 PE 加载器完成初始化。

仅可执行映像有效,对于 obj 文件该值为 0。

VirtualAddress
DESC : 区段的 RVA。

对于 obj 文件该值为重定位前的地址。

SizeOfRawData
DESC : 区段在磁盘上已初始化数据的大小。值必须为 IMAGE_OPTIONAL_HEADER.FileAlignment 的倍数。如果该值小于 Misc.VirtualSize,区段剩余部分由 PE 加载器填充零,完成初始化。如果区段仅包含未初始化数据, 该值为 0。
PointerToRawData
DESC : 区段数据的 FOA, 值必须为 IMAGE_OPTIONAL_HEADER.FileAlignment 的倍数。如果区段仅包含未初始化数据, 该值为 0。
PointerToRelocations PointerToLinenumbers
DESC : 区段的重定位项和行号项的文件指针。如果没有, 该值为 0。
NumberOfRelocations NumberOfLinenumbers
DESC: 重定位项数和行号项数。

可执行映像的重定位项数为 0。

Characteristics
DESC : 区段的属性。

描述
0x00000000保留
0x00000001保留
0x00000002保留
0x00000004保留
0x00000008弃用
0x00000010保留
0x00000020区段包含可执行代码
0x00000040区段包含已初始化数据
0x00000080区段包含未初始化数据
0x00000100保留
0x00000200区段包含注释或其他信息, 仅对 obj 文件有效
0x00000400保留
0x00000800区段不会成为映像一部分, 仅对 obj 文件有效
0x00001000区段包含 COMDAT 数据, 仅对 obj 文件有效
0x00002000保留
0x00004000重置 TLB 表的风险异常处理位
0x00008000区段包含通过全局指针引用的数据
0x00010000保留
0x00020000保留
0x00040000保留
0x00080000保留
0x00100000按1字节对齐数据, 仅对 obj 文件有效
0x00200000按2字节对齐数据, 仅对 obj 文件有效
0x00300000按4字节对齐数据, 仅对 obj 文件有效
0x00400000按8字节对齐数据, 仅对 obj 文件有效
0x00500000按16字节对齐数据, 仅对 obj 文件有效
0x00600000按32字节对齐数据, 仅对 obj 文件有效
0x00700000按64字节对齐数据, 仅对 obj 文件有效
0x00800000按128字节对齐数据, 仅对 obj 文件有效
0x00900000按256字节对齐数据, 仅对 obj 文件有效
0x00A00000按512字节对齐数据, 仅对 obj 文件有效
0x00B00000按1024字节对齐数据, 仅对 obj 文件有效
0x00C00000按2048字节对齐数据, 仅对 obj 文件有效
0x00D00000按4096字节对齐数据, 仅对 obj 文件有效
0x00E00000按8192字节对齐数据, 仅对 obj 文件有效
0x01000000区段包含扩展重定位
0x02000000可以根据需要丢弃该区段
0x04000000区段不能被缓存
0x08000000区段不能分页
0x10000000区段在内存中可共享
0x20000000区段可执行
0x40000000区段可读
0x80000000区段可写

4.Sections

DESC: 每个区段在文件中的数据(已初始化数据),大小为相应区段表项的 IMAGE_SECTION_HEADER. SizeOfRawData 值。
FOA : 区段表各项的 PointerToRawData 成员值。

区段在文件中的数据为已初始化数据,因为对齐要求必须为 IMAGE_OPTIONAL_HEADER. FileAlignment 的倍数,所以文件中区段末尾一般存在编译时填充的 0x00 字节,而 Section Header 中 Misc.VirtualSize 值通常没有包括这部分填充的初始化数据。但 Misc.VirtualSize 值还包括了未初始化数据大小,所以他们的值在不同情况下有不同大小关系。
IMAGE_SECTION_HEADER.SizeOfRawData = 已初始化数据(含填充数据)大小
IMAGE_SECTION_HEADER.Misc.VirtualSize = 已初始化数据(一般不含填充数据)大小 + 未初始化数据大小

其他

通过 RVA 确定其 FOA 的方法:

a) 分析 Section Headers 确定各区段数据的 RVA 范围和 FOA 范围。
b) 比较已知 RVA 和各区段 RVA 范围,确定已知 RVA 属于哪个区段。
c) 计算已知 RVA 相对于该区段起始 RVA 的偏移值 Offset。
d) 已知 RVA 对应的 FOA 为该区段起始 FOA 加上一步得到的 Offset。

标签:总结,文件,字节,映像,文件格式,PE,区段,加载,DESC
来源: https://blog.csdn.net/m0_48995611/article/details/117793473