PE结构(1)

DOS头

DOS头是为了兼容DOS系统遗留

MZ头

大小为64字节

偏移地址 (十六进制) 字段长度 (字节) 字段名称 描述
00H 2 e_magic 文件标识("MZ")。必须是 4DH 5AH(ASCII "MZ")。
02H 2 e_cblp 文件中最后512字节块的字节数。如果文件大小是512的倍数,则为0。如果不是,则表示最后一个块中包含的字节数。
04H 2 e_cp 文件中的512字节块数。文件的总大小可以通过 (e_cp - 1) * 512 + e_cblp 计算。
06H 2 e_crlc 重定位项的数目。重定位表用于调整程序中对内存地址的引用,以便程序可以在内存中的任何位置加载和运行。
08H 2 e_cparhdr 头部大小(以段为单位)。指定MZ头以及其后的重定位表所占用的段数(每个段16字节)。程序实际代码和数据从这个偏移量开始。
0AH 2 e_minalloc 所需的最小额外内存(以段为单位)。程序运行时除了其本身大小外,至少需要额外分配的内存量。
0CH 2 e_maxalloc 所需的最大额外内存(以段为单位)。程序运行时除了其本身大小外,最多可以额外分配的内存量。通常为 FFFFH,表示尽可能多。
0EH 2 e_ss 初始栈段(SS)寄存器的值。相对于加载模块的起始地址。
10H 2 e_sp 初始栈指针(SP)寄存器的值
12H 2 e_csum 文件校验和。用于验证文件的完整性,但在实际中很少被使用或校验。
14H 2 e_ip 初始指令指针(IP)寄存器的值
16H 2 e_cs 初始代码段(CS)寄存器的值。相对于加载模块的起始地址。
18H 2 e_lfarlc 重定位表在文件中的偏移地址。指明了重定位表在文件中的起始位置。
1AH 2 e_ovno 覆盖号(Overlay Number)。对于非覆盖程序,此字段通常为0。

e_magic

用于标注该文件

e_lfarlc

用于标注PE头偏移

DOS块

大小为16字节
如果不在DOS系统上执行可以修改此部分代码

PE头

PE签名

大小为4字节,标识文件为PE文件

标准PE头

大小为20字节

typedef struct _IMAGE_FILE_HEADER {
    WORD    Machine;              // 目标 CPU 架构
    WORD    NumberOfSections;     // 节(Section)的数量
    DWORD   TimeDateStamp;        // 文件创建/修改时间戳
    DWORD   PointerToSymbolTable; // COFF 符号表的文件偏移
    DWORD   NumberOfSymbols;      // COFF 符号表中的符号数量
    WORD    SizeOfOptionalHeader; // 可选头(Optional Header)的大小
    WORD    Characteristics;      // 文件特性标志
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

Characteristics 字段的标志位详解

值 (十六进制) 符号常量 描述
0x0001 IMAGE_FILE_RELOCS_STRIPPED 重定位信息已剥离。表示文件不包含基址重定位信息。如果文件不能加载到其首选基址,加载器会报错。链接器的默认行为通常是剥离基址重定位。
0x0002 IMAGE_FILE_EXECUTABLE_IMAGE 可执行映像。表示文件是有效的可执行映像(即 .exe.dll),而不是对象文件 (.obj)。如果此标志未设置,通常表示链接器错误。
0x0004 IMAGE_FILE_LINE_NUMS_STRIPPED 行号信息已剥离。表示 COFF 行号信息已从文件中移除。此标志已弃用,通常应为 0。
0x0008 IMAGE_FILE_LOCAL_SYMS_STRIPPED 本地符号信息已剥离。表示 COFF 符号表中的本地符号条目已从文件中移除。此标志已弃用,通常应为 0。
0x0010 IMAGE_FILE_AGGRESIVE_WS_TRIM 积极裁剪工作集。此值已废弃,且在 Windows 2000 及更高版本中必须为 0。
0x0020 IMAGE_FILE_LARGE_ADDRESS_AWARE 大地址感知。表示应用程序能够处理大于 2 GB 的地址(对于 32 位程序,这意味着它在启用 PAE 的系统上可以访问超过 2GB 的虚拟内存空间)。
0x0040 (未使用) 未使用。
0x0080 IMAGE_FILE_BYTES_REVERSED_LO 字节序反转(低位在前)。此标志已废弃,通常应为 0。
0x0100 IMAGE_FILE_32BIT_MACHINE 32 位机器。表示文件是为 32 位字长架构的计算机设计的。对于 x64 PE 文件,此标志通常不设置。
0x0200 IMAGE_FILE_DEBUG_STRIPPED 调试信息已剥离。表示调试信息已从映像文件中移除,可能已存储在单独的调试文件(如 .pdb)中。
0x0400 IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 从可移动媒体运行,复制到交换文件。如果映像在可移动媒体上,则将其完全加载并复制到交换文件中运行。
0x0800 IMAGE_FILE_NET_RUN_FROM_SWAP 从网络运行,复制到交换文件。如果映像在网络媒体上,则将其完全加载并复制到交换文件中运行。
0x1000 IMAGE_FILE_SYSTEM 系统文件。表示映像文件是一个系统文件(例如驱动程序),而不是用户应用程序。
0x2000 IMAGE_FILE_DLL DLL 文件。表示映像文件是一个动态链接库 (DLL)。这类文件在大多数情况下被视为可执行文件,但不能直接运行,通常由其他程序加载。
0x4000 IMAGE_FILE_UP_SYSTEM_ONLY 仅限于单处理器系统。表示文件应仅在单处理器计算机上运行。在实践中,它可能会导致程序在多核系统上运行时,其进程的 CPU 亲和性被设置为单个 CPU 核心,且该核心可能轮换。
0x8000 IMAGE_FILE_BYTES_REVERSED_HI 字节序反转(高位在前)。此标志已废弃,通常应为 0。

拓展PE头

大小不固定,具体大小由SizeOfOptionalHeader字段决定

标准头

字段名称 大小 (32位/64位) 描述
Magic 2 字节 魔法数字。指示可选头的类型和 PE 文件的位宽。加载器根据此值判断文件是 32 位还是 64 位。
- 0x10B (IMAGE_NT_OPTIONAL_HDR32_MAGIC): 32 位 PE (PE32) 文件
- 0x20B (IMAGE_NT_OPTIONAL_HDR64_MAGIC): 64 位 PE (PE32+) 文件
- 0x107 (IMAGE_ROM_OPTIONAL_HDR_MAGIC): ROM 映像
MajorLinkerVersion 1 字节 创建此 PE 文件的链接器的主版本号
MinorLinkerVersion 1 字节 创建此 PE 文件的链接器的次版本号
SizeOfCode 4 字节 所有可执行代码节的总大小(例如 .text 节)。此大小指的是文件中的原始字节数。
SizeOfInitializedData 4 字节 所有已初始化数据节的总大小(例如 .data 节)。此大小指的是文件中的原始字节数。
SizeOfUninitializedData 4 字节 所有未初始化数据节的总大小(例如 .bss 节)。此大小指的是在内存中所需的空间,在文件中通常不占用实际存储空间。
AddressOfEntryPoint 4 字节 程序执行的入口点 RVA (Relative Virtual Address,相对虚拟地址)。这是加载器将控制权交给程序的第一个指令的内存地址。对于 DLL,此字段可能是 0,表示没有一个标准的入口函数。
BaseOfCode 4 字节 代码节的基地址 RVA。这是所有代码节在内存中的起始相对地址。
BaseOfData 4 字节 (仅限 32 位) 数据节的基地址 RVA。这是所有数据节在内存中的起始相对地址。在 64 位 PE 文件(PE32+)中,此字段已移除,因为在 64 位寻址下,数据节通常不需要独立的基地址。

Windows特定字段

字段名称 大小 (32位/64位) 描述
ImageBase 4/8 字节 映像加载到内存中的首选基地址。这是加载器尝试将 PE 文件(EXE 或 DLL)加载到的虚拟内存地址。如果该地址已被占用,加载器会寻找其他可用地址,并使用基址重定位表 (IMAGE_DIRECTORY_ENTRY_BASERELOC) 来调整程序内部的绝对地址引用。这对于 DLL 文件尤其重要,因为它们可能被加载到任意地址。
- EXE 文件的默认值通常是 0x00400000
- DLL 文件的默认值通常是 0x10000000
SectionAlignment 4 字节 内存中节的对齐粒度。当 PE 文件的各个节(如 .text, .data)被加载到内存中时,它们的起始地址必须是这个值的倍数。通常,这个值与系统页大小相同(如 4KB 或 0x1000 字节),以优化内存管理器的性能。
FileAlignment 4 字节 文件中节的对齐粒度。这是节在磁盘上的原始数据在文件中的对齐方式。节的原始数据大小(SizeOfRawData)和文件偏移量(PointerToRawData)都必须是这个值的倍数。常见的 FileAlignment 值是 512 字节 (0x200) 或 4KB (0x1000)。
MajorOperatingSystemVersion 2 字节 程序运行所需的最低操作系统主版本号。例如,如果程序需要 Windows XP 或更高版本,此值可能是 5。
MinorOperatingSystemVersion 2 字节 程序运行所需的最低操作系统次版本号。例如,如果程序需要 Windows XP (5.1),则此值可能是 1。
MajorImageVersion 2 字节 PE 映像(文件本身)的主版本号。由链接器设置,通常反映程序的内部版本。
MinorImageVersion 2 字节 PE 映像的次版本号
MajorSubsystemVersion 2 字节 程序所需的子系统主版本号。例如,如果程序是为 Windows GUI 子系统编写的,则会有对应的版本号。
MinorSubsystemVersion 2 字节 程序所需的子系统次版本号
Win32VersionValue 4 字节 保留字段,目前通常为 0
SizeOfImage 4 字节 整个 PE 映像加载到内存中后所占用的总大小。这个值必须是 SectionAlignment 的倍数。它包括了所有的头、节以及所有节在内存中对齐后所需的填充空间。
SizeOfHeaders 4 字节 所有头部(DOS 头、PE 签名、COFF 文件头、可选头和节表)在文件中的总大小。这个值必须是 FileAlignment 的倍数。它也指示了文件中第一个实际的节(代码或数据)的原始数据开始的偏移量。
CheckSum 4 字节 映像文件的校验和。对于某些系统文件(如 DLL 和驱动程序),Windows 加载器在加载前会计算并验证此校验和,以确保文件在传输过程中未被损坏或篡改。对于 EXE 文件,校验和通常是可选的。
Subsystem 2 字节 运行程序所需的子系统类型。这个字段决定了 Windows 如何启动和管理该进程。
- IMAGE_SUBSYSTEM_WINDOWS_GUI (2): Windows 图形用户界面 (GUI) 应用程序。
- IMAGE_SUBSYSTEM_WINDOWS_CUI (3): Windows 字符用户界面 (CUI) 应用程序(控制台应用程序)。
- IMAGE_SUBSYSTEM_NATIVE (1): 不需任何子系统(例如内核模式驱动程序,直接与操作系统内核交互)。
- 还有其他用于 EFI、Posix、OS/2 等的子系统类型。
DllCharacteristics 2 字节 DLL/可执行文件的特性标志。这是一组位标志,指示映像支持的特定特性或行为。它们是加载器和操作系统在加载时要考虑的重要标志。
- IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE (0x0040): 动态基址重定位 (ASLR)。表示 DLL 或 EXE 可以在任意地址加载,支持地址空间布局随机化。强烈推荐设置此标志以提高安全性。
- IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY (0x0080): 强制代码完整性检查。要求在加载时对映像进行数字签名验证。
- IMAGE_DLLCHARACTERISTICS_NX_COMPAT (0x0100): 数据执行保护 (DEP) 兼容。表示映像与 DEP 兼容,其数据区不会被执行代码。几乎所有现代可执行文件都设置此标志。
- IMAGE_DLLCHARACTERISTICS_NO_SEH (0x0400): 不使用结构化异常处理 (SEH)。表示映像不使用传统的 SEH 机制(通常用于 Windows CE 或一些安全强化代码)。
- IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE (0x8000): 终端服务器感知。表示应用程序在多用户(如远程桌面服务)环境下能正常运行,不会出现资源冲突。
SizeOfStackReserve 4/8 字节 线程初始堆栈的保留大小。这是为堆栈预留的虚拟内存空间大小。
SizeOfStackCommit 4/8 字节 线程初始堆栈的提交大小。这是为堆栈实际分配的物理内存(RAM)大小。
SizeOfHeapReserve 4/8 字节 进程默认堆的保留大小。这是为进程的默认堆预留的虚拟内存空间大小。
SizeOfHeapCommit 4/8 字节 进程默认堆的提交大小。这是为进程的默认堆实际分配的物理内存大小。
LoaderFlags 4 字节 加载器标志。此字段现在已弃用,通常为 0。在过去用于一些特殊的加载器行为。
NumberOfRvaAndSizes 4 字节 数据目录数组中包含的条目数量。这个值通常是 IMAGE_NUMBEROF_DIRECTORY_ENTRIES (即 16)。它指明了 DataDirectory 数组的有效条目个数。

SizeOfImage

文件从磁盘映射到内存后的大小

SizeOfHeaders

文件从磁盘映射到内存后的文件头大小,包括DOS头,标准PE头,拓展PE头

数据目录

typedef struct _IMAGE_DATA_DIRECTORY {
    DWORD   VirtualAddress; // 相对虚拟地址 (RVA)
    DWORD   Size;           // 数据结构的大小
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

节表

typedef struct _IMAGE_SECTION_HEADER {
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME]; // 节的名称,8 字节
    union {
        DWORD   PhysicalAddress;
        DWORD   VirtualSize;             // 节在内存中的实际大小(字节)
    } Misc;
    DWORD   VirtualAddress;              // 节在内存中的相对虚拟地址 (RVA)
    DWORD   SizeOfRawData;               // 节在文件中原始数据的大小(字节)
    DWORD   PointerToRawData;            // 节在文件中的原始数据偏移量(字节)
    DWORD   PointerToRelocations;        // 重定位表的偏移量(对于目标文件)
    DWORD   PointerToLinenumbers;        // 行号信息的偏移量(对于目标文件)
    WORD    NumberOfRelocations;         // 重定位项的数量
    WORD    NumberOfLinenumbers;         // 行号信息的数量
    DWORD   Characteristics;             // 节的属性标志
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
posted @ 2025-07-16 10:49  iHtAlgorithm  阅读(13)  评论(0)    收藏  举报