在 PE(Portable Executable)格式中,IMAGE_OPTIONAL_HEADER 扮演着非常重要的角色,它提供了操作系统加载程序时所需的关键信息。
Magic 字段
1 2 3
| WORD Magic; IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
|
- 含义:
Magic
字段用于标识可执行文件是32位还是64位。
- 对于32位 PE 文件,其值为
0x10b
(IMAGE_NT_OPTIONAL_HDR32_MAGIC
)。
- 对于64位 PE 文件,其值为
0x20b
(IMAGE_NT_OPTIONAL_HDR64_MAGIC
)。
- 作用:
加载器通过检测该字段来判断如何解析后续的可选头结构,从而选择正确的数据结构和加载方式。
链接器版本
1 2 3
| BYTE MajorLinkerVersion; BYTE MinorLinkerVersion;
|
- 含义:
这两个字段分别表示链接器的主版本号和次版本号。它们通常反映了编译和链接过程中所使用的 Visual Studio 版本或其他编译工具的版本信息。
- 作用:
虽然对程序的加载影响不大,但这些版本信息有助于开发者和逆向工程人员了解程序的构建环境,可能在调试和兼容性分析时提供参考。
代码和数据大小字段
1 2 3
| DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData;
|
- SizeOfCode:
- 含义:表示所有代码段(.text节)的总大小。
- 作用:用于确定在内存中加载代码部分的空间大小。
- SizeOfInitializedData:
- 含义:表示所有已初始化数据段(如 .data 节)的总大小。
- 作用:加载器会根据该大小为已初始化的数据分配内存,并将文件中相应的数据复制到内存中。
- SizeOfUninitializedData:
- 含义:表示所有未初始化数据(通常是 BSS 段)的总大小。
- 作用:虽然文件中没有存储这部分数据,但加载器会为其分配内存,并通常将其初始化为零。
入口点和代码、数据基地址
1 2 3 4
| DWORD AddressOfEntryPoint; DWORD BaseOfCode; DWORD BaseOfData;
|
- AddressOfEntryPoint:
- 含义:指定程序入口点的相对虚拟地址(RVA),即程序开始执行时的入口位置。
- 作用:加载器在映射可执行文件到内存后,会跳转到这个地址开始执行程序。对于调试、逆向工程以及安全检测来说,该字段至关重要。
- BaseOfCode:
- 含义:表示代码段在内存中的起始地址(也是一个 RVA)。
- 作用:帮助加载器确定代码段的内存位置,从而正确加载和执行代码。
- BaseOfData:
- 含义:表示数据段在内存中的起始地址(RVA),主要适用于32位的 PE 文件(在64位版本中,该字段被省略)。
- 作用:为已初始化和未初始化数据分配内存时,加载器需要知道数据区的起始位置。
小结
- Magic 字段:通过
0x10b
或 0x20b
判断 PE 文件的位数,指导加载器使用相应的数据结构。
- 链接器版本:提供编译环境信息,辅助后续分析和调试。
- SizeOfCode、SizeOfInitializedData、SizeOfUninitializedData:描述了代码与数据在文件中的大小,为内存分配和文件映射提供依据。
- AddressOfEntryPoint:指明程序执行入口,是程序启动时最重要的地址信息之一。
- BaseOfCode 与 BaseOfData:分别标识代码和数据段在内存中的基地址,确保程序在加载时能够正确定位各个部分。