PE 文件格式详解
PE 文件结构全貌介绍
PE 文件结构全貌
PE 文件结构大致分为四大部分,每部分又可以细分。从数据管理角度来看,PE 文件大致分为两个部分,一是 DOS 头、PE 头和节表属于构成可执行文件的数据管理结构和数据组织结构部分,二是节表数据才是可执行文件真正的数据部分,包含着程序执行时真正的代码、数据、资源等内容。
DOS 头 | MZ 头部 |
DOS 存根 | |
PE 头 | PE 标识符(PE\0\0) |
文件头 | |
可选头 | |
节表 | 节表一 |
节表二 | |
... ... | |
节表N | |
节表数据 | 节表数据一(可能是代码或者数据) |
节表数据二(可能是代码或者数据) | |
... ... | |
节表数据N(可能是代码或者数据) |
PE 结构各部分简介
一、DOS 头
DOS 头分为“MZ 头部”和“DOS 存根”。MZ 头部才是真正的DOS头部,由于开始处的两个字节为“MZ”,因此 DOS 头也可以叫做 MZ 头。该头部用于程序在 DOS 系统下加载,他的结构被定义为 IMAGE_DOS_HEADER。
DOS 存根是一段简单的 DOS 程序,主要用于输出类似“This program cannot be run in DOS mode.”的提示字符串。
DOS 头主要是为了可执行程序可以兼容 DOS 系统。DOS 存根程序可以通过连接参数进行修改,使可执行文件同时在 Windows 和 DOS 系统同时运行。
二、PE 头
PE 头部保存着 Windows 系统加载可执行文件的重要信息。PE 头部又 IMAGE_NT_HEADERS 定义。IMAGE_NT_HEADERS 是由 IMAGE_NT_SIGNATRUE(宏定义)、IMAGE_FILE_HEADER 和 IMAGE_OPTIONAL_HEADER 多个结构体组成。
PE 头部在 PE 文件中的位置是不固定的,由 DOS 头部的某个字段给出。
三、节表
程序的组织按照各属性的不同而保存在不同的节中,在 PE 头部之后就是一个结构体数组构成的节表。节表中描述了各个节在整个文件中的位置与加载入内存后的位置,同时定义了节的属性(只读、可读写、可执行等)。描述节表的结构体是 IMAGE_SECTION_HEADER,如果 PE 文件中有 N 个节,那么节表就是由 N 个 IMAGE_SECTION_HEADER 组成的数组。
四、节数据
可执行文件中的真正程序代码部分就保存在 PE 结构的节中,当然,数据、资源等内容也保存在节中。节表只是描述了节数据的起始地址、大小及属性等信息。
详解 PE 文件结构
PSDK(Platform Software Development Kits,平台软件开发包)的头文件 Winnt.h 中包含了 PE 文件结构的定义格式。PE 头文件分为 32 位和 64 位版本。64 位的 PE 结构是对 32 位 PE 结构进行了扩展。
DOS 头部详解 --- IMAGE_DOS_HEADER
PE 文件的最开始的位置就是一个 DOS 程序。DOS 程序包含了一个 DOS 头部和一个 DOS 程序体( DOS 存根或 DOS 残留)。DOS 头是用来装载 DOS 存根用的。
IMAGE_DOS_HEADER 定义如下:
#define IMAGE_DOS_SIGNATURE 0x5A4D
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
WORD e_magic; // Magic number 幻数(魔法数字)
WORD e_cblp; // Bytes on last page of file 最后一页的字节数
WORD e_cp; // Pages in file 文件页数
WORD e_crlc; // Relocations 重定位
WORD e_cparhdr; // Size of header in paragraphs 段落标题的大小
WORD e_minalloc; // Minimum extra paragraphs needed 所需的最少额外段落
WORD e_maxalloc; // Maximum extra paragraphs needed 所需的最大额外段落
WORD e_ss; // Initial (relative) SS value 初始(相对) SS 值
WORD e_sp; // Initial SP value 初始 SP 值
WORD e_csum; // Checksum 校验和
WORD e_ip; // Initial IP value 初始 IP 值
WORD e_cs; // Initial (relative) CS value 初始(相对) CS 值
WORD e_lfarlc; // File address of relocation table 重定位表的文件地址
WORD e_ovno; // Overlay number 覆盖数
WORD e_res[4]; // Reserved words 保留字
WORD e_oemid; // OEM identifier (for e_oeminfo) OEM 标识符(用于 e_oeminfo)
WORD e_oeminfo; // OEM information; e_oemid specific OEM 信息;e_oemid 特定
WORD e_res2[10]; // Reserved words 保留字
LONG e_lfanew; // File address of new exe header PE 文件解析时用它找到 PE 头的位置
} IMAGE_DOS_HEADER,*PIMAGE_DOS_HEADER; // 结构体大小 64 字节
IMAGE_DOS_HEADER(汇编)
IMAGE_DOS_SIGNATURE equ 5A4Dh
IMAGE_DOS_HEADER STRUCT
e_magic WORD ?
e_cblp WORD ?
e_cp WORD ?
e_crlc WORD ?
e_cparhdr WORD ?
e_minalloc WORD ?
e_maxalloc WORD ?
e_ss WORD ?
e_sp WORD ?
e_csum WORD ?
e_ip WORD ?
e_cs WORD ?
e_lfarlc WORD ?
e_ovno WORD ?
e_res WORD 4 dup(?)
e_oemid WORD ?
e_oeminfo WORD ?
e_res2 WORD 10 dup(?)
e_lfanew DWORD ?
IMAGE_DOS_HEADER ENDS
该结构体中只需要记住 e_magic 和 e_lfanew 两个字段,e_magic 是 DOS 可执行文件的标识符,e_lfanew 保存着 PE 头的起始位置。
PE 头部详解 --- IMAGE_NT_HEADERS
PE 头部是真正用来装载 Windows 程序的头部,PE 头的定义为 IMAGE_NT_HEADERS,该结构体包含 PE 标识符、文件头 IMAGE_FILE_HEADER 和可选头 IMAGE_OPTIONAL_HEADER 三部分。IMAGE_NT_HEADERS 是一个宏定义,定义如下:
#ifdef _WIN64
typedef IMAGE_NT_HEADERS64 IMAGE_NT_HEADERS;
typedef PIMAGE_NT_HEADERS64 PIMAGE_NT_HEADERS;
#else
typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS;
typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS;
#endif
该头分为 32 位和 64 位,其定义依赖于是否定义了 _WIN64 宏。IMAGE_NT_HEADERS32 的定义如下:
#define IMAGE_NT_SIGNATURE 0x00004550 // PE00
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
IMAGE_NT_HEADERS(汇编)
IMAGE_NT_SIGNATURE equ 00004550h
IMAGE_NT_HEADERS STRUCT
Signature DWORD ?
FileHeader IMAGE_FILE_HEADER <>
OptionalHeader IMAGE_OPTIONAL_HEADER32 <>
IMAGE_NT_HEADERS ENDS
该结构体的 Signature 就是 PE 标识符,标识该文件是否是 PE 文件。该部分占 4 个字节。该值非常重要,在判断一个文件是否是 PE 文件时,首先要判断文件的起始位置是否为“MZ”,在通过 DOS 头部的相应偏移找到 PE 头部,判断 PE 头部是否为 PE\x00\x00。
文件头部详解 --- IMAGE_FILE_HEADER
IMAGE_FILE_HEADER 结构体紧跟在 PE 标识符后面,大小为 20 个字节。IMAGE_FILE_HEADER 定义如下:
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;
IMAGE_FILE_HEADER(汇编)
IMAGE_FILE_HEADER STRUCT
Machine WORD ?
NumberOfSections WORD ?
TimeDateStamp DWORD ?
PointerToSymbolTable DWORD ?
NumberOfSymbols DWORD ?
SizeOfOptionalHeader WORD ?
Characteristics WORD ?
IMAGE_FILE_HEADER ENDS
该结构体的各个字段:
Machine( WORD ):该字段表示可执行文件的目标 CPU 类型。
Machine 的取值
#define IMAGE_FILE_MACHINE_UNKNOWN 0
#define IMAGE_FILE_MACHINE_TARGET_HOST 0x0001 // Useful for indicating we want to interact with the host and not a WoW guest.
#define IMAGE_FILE_MACHINE_I386 0x014c // Intel 386.
#define IMAGE_FILE_MACHINE_R3000 0x0162 // MIPS little-endian, 0x160 big-endian
#define IMAGE_FILE_MACHINE_R4000 0x0166 // MIPS little-endian
#define IMAGE_FILE_MACHINE_R10000 0x0168 // MIPS little-endian
#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 // MIPS little-endian WCE v2
#define IMAGE_FILE_MACHINE_ALPHA 0x0184 // Alpha_AXP
#define IMAGE_FILE_MACHINE_SH3 0x01a2 // SH3 little-endian
#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3
#define IMAGE_FILE_MACHINE_SH3E 0x01a4 // SH3E little-endian
#define IMAGE_FILE_MACHINE_SH4 0x01a6 // SH4 little-endian
#define IMAGE_FILE_MACHINE_SH5 0x01a8 // SH5
#define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM Little-Endian
#define IMAGE_FILE_MACHINE_THUMB 0x01c2 // ARM Thumb/Thumb-2 Little-Endian
#define IMAGE_FILE_MACHINE_ARMNT 0x01c4 // ARM Thumb-2 Little-Endian
#define IMAGE_FILE_MACHINE_AM33 0x01d3
#define IMAGE_FILE_MACHINE_POWERPC 0x01F0 // IBM PowerPC Little-Endian
#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1
#define IMAGE_FILE_MACHINE_IA64 0x0200 // Intel 64
#define IMAGE_FILE_MACHINE_MIPS16 0x0266 // MIPS
#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 // ALPHA64
#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 // MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 // MIPS
#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64
#define IMAGE_FILE_MACHINE_TRICORE 0x0520 // Infineon
#define IMAGE_FILE_MACHINE_CEF 0x0CEF
#define IMAGE_FILE_MACHINE_EBC 0x0EBC // EFI Byte Code
#define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8)
#define IMAGE_FILE_MACHINE_M32R 0x9041 // M32R little-endian
#define IMAGE_FILE_MACHINE_ARM64 0xAA64 // ARM64 Little-Endian
#define IMAGE_FILE_MACHINE_CEE 0xC0EE
NumberOfSections( WORD ):该字段表示 PE 文件的节表数量。
TimeDataStamp( DWORD ):该字段表示文件是何时被创建的。这个值是自 1970 年 1 月 1 日以来用格林尼威治时间计算的秒数。
PointerToSymbolTable( DWORD ):该字段表示符号表的偏移量(以字节为单位)或零(如果不存在 COFF 符号表)。
NumberOfSymbols( DWORD ):该字段表示符号表中的符号数。
SizeOfOptionalHeader( WORD ):该字段指定 IMAGE_OPTIONAL_HEADER 结构体的大小。PE 文件需要定位节表的位置的时候,计算 IMAGE_OPTIONAL_HEADER 的大小时,应该从 IMAGE_FILE_HEADER 结构体中的 SizeOfOptionalHeader 字段指定的值来获取,而不是 sizeo(IMAGE_OPTIONAL_HEADER)。
Characteristics( WORD ):该字段指定文件的类型。
Characteristics 的取值
#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file. 从文件中去除了重定位信息。
#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved external references). 文件是可执行的(即没有未解析的外部引用)。
#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line nunbers stripped from file. COFF行号已从文件中删除。
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // Local symbols stripped from file. COFF 符号表条目已从文件中删除。
#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 // Aggressively trim working set 此值已过时。
#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 // App can handle >2gb addresses 应用程序可以处理大于 2 GB 的地址。
#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 // Bytes of machine word are reversed. 此标志已过时。
#define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine. 计算机支持 32 位字。
#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 // Debugging info stripped from file in .DBG file 调试信息已删除并单独存储在另一个文件中。
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 // If Image is on removable media, copy and run from the swap file. 如果映像位于可移动媒体上,请将其复制到交换文件并从交换文件运行它。
#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 // If Image is on Net, copy and run from the swap file. 如果映像在网络上,请将其复制到交换文件并从中运行它。
#define IMAGE_FILE_SYSTEM 0x1000 // System File. 系统文件。
#define IMAGE_FILE_DLL 0x2000 // File is a DLL. DLL文件.
#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 // File should only be run on a UP machine 该文件应仅在单处理器计算机上运行。
#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 // Bytes of machine word are reversed. 此标志已过时。
可选头详解 --- IMAGE_OPTIONAL_HEADER
IMAGE_OPTIONAL_HEADER 虽然叫可选头,但并不表示是可有可无的,是必须存在的头部,该头部的数据目录部分是可选的。可选头是对文件头的一个补充。文件头主要描述文件的相关信息,而可选头主要用来管理 PE 文件被操作系统装载时所需要的信息,该头同样有32 位和 64 位。IMAGE_OPTIONAL_HEADER 是一个宏,定义如下:
#ifdef _WIN64
typedef IMAGE_OPTIONAL_HEADER64 IMAGE_OPTIONAL_HEADER;
typedef PIMAGE_OPTIONAL_HEADER64 PIMAGE_OPTIONAL_HEADER;
#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR64_MAGIC
#else
typedef IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER;
typedef PIMAGE_OPTIONAL_HEADER32 PIMAGE_OPTIONAL_HEADER;
#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR32_MAGIC
#endif
32 位和 64 位的选择是根据是否定义 _WIN64 宏而决定的。在定义中能看到其他几个常量,分别定义如下:
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
IMAGE_OPTIONAL_HEADER32 结构体定义如下:
//
// Optional header format.
//
typedef struct _IMAGE_OPTIONAL_HEADER {
//
// Standard fields.
//
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;
//
// NT additional fields.
//
DWORD ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
IMAGE_OPTIONAL_HEADER32(汇编)
IMAGE_OPTIONAL_HEADER32 STRUCT
Magic WORD ?
MajorLinkerVersion BYTE ?
MinorLinkerVersion BYTE ?
SizeOfCode DWORD ?
SizeOfInitializedData DWORD ?
SizeOfUninitializedData DWORD ?
AddressOfEntryPoint DWORD ?
BaseOfCode DWORD ?
BaseOfData DWORD ?
ImageBase DWORD ?
SectionAlignment DWORD ?
FileAlignment DWORD ?
MajorOperatingSystemVersion WORD ?
MinorOperatingSystemVersion WORD ?
MajorImageVersion WORD ?
MinorImageVersion WORD ?
MajorSubsystemVersion WORD ?
MinorSubsystemVersion WORD ?
Win32VersionValue DWORD ?
SizeOfImage DWORD ?
SizeOfHeaders DWORD ?
CheckSum DWORD ?
Subsystem WORD ?
DllCharacteristics WORD ?
SizeOfStackReserve DWORD ?
SizeOfStackCommit DWORD ?
SizeOfHeapReserve DWORD ?
SizeOfHeapCommit DWORD ?
LoaderFlags DWORD ?
NumberOfRvaAndSizes DWORD ?
DataDirectory IMAGE_DATA_DIRECTORY IMAGE_NUMBEROF_DIRECTORY_ENTRIES dup(<>)
IMAGE_OPTIONAL_HEADER32 ENDS
该结构体的各个字段:
Machine:文件的标识。
Machine 的取值
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b // 32 位可执行文件
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b // 64 位可执行文件
#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 // ROM 文件
MajorLinkerVersion:链接器的主要版本号
MinorLinkerVersion:链接器的次要版本号
SizeOfCode:代码部分的大小(以字节为单位)或所有此类部分的总和(如果有多个代码) 部分。
SizeOfInitializedData:初始化的数据部分的大小(以字节为单位)或所有此类部分的总和(如果有多个) 初始化的数据部分。
SizeOfUninitializedData:未初始化的数据部分的大小(以字节为单位)或所有此类部分的总和(如果有多个) 未初始化的数据部分。
AddressOfEntryPoint:程序执行的入口地址。该地址是一个相对虚拟地址,简称 EP(EntryPoint),这个值指向了程序第一条要执行的代码。程序如果被加壳后会修改该字段的值,成为壳的入口地址,这样壳就有机会先执行。在脱壳过程中找到了加壳前的入口地址,就说明找到了原始入口点,原始入口点称为 OEP。该字段的地址指向不是 main 函数的地址,也不是 WinMain 函数的地址,而是运行库的启动代码地址。对于 DLL 来说这个值的意义不大,因为 DLL 甚至可以没有 DllMain 函数,没有 DllMain 只是无法捕获装载和卸载 DLL 时的四条消息。如果在 DLL 装载或卸载时没有需要进行处理的事件,可以将 DllMain 函数省略。
BaseOfCode:代码节的起始相对虚拟地址。
BaseOfData:数据节的起始相对虚拟地址
ImageBase:文件被载入内存后第一个字节的首选地址。对于 EXE 文件来说,通常情况下该地址就是装载地址,默认值是 0x00400000;对于 DLL 文件来说,可能就不是装入内存后的地址,默认值是 0x10000000。
SectionAlignment:节表数据被装入内存后的对齐值,也就是节表数据被映射到内存中需要对齐的单位。在 Win32 下,通常情况下,该值为 0x1000 字节,也就是 4KB 大小。
FileAlignment:节表数据在文件中的对齐值,通常情况下,该值为 0x1000 字节或 0x200 字节。在文件对齐为 0x1000 字节时,由于与内存对齐值相同,可以加快操作系统对可执行文件装载入内存的速度。而文件对齐值为 0x200 字节时,可以占用相对较少的磁盘空间。0x200 字节是 512 字节,通常磁盘的一个扇区即为 512 字节。
MajorOperatingSystemVersion:所需操作系统的主版本号
MinorOperatingSystemVersion:所需操作系统的次要版本号。
MajorImageVersion:可执行文件的主版本号。
MinorImageVersion:可执行文件的次要版本号。
MajorSubsystemVersion:子系统的主要版本号。
MinorSubsystemVersion:子系统的次要版本号。
Win32VersionValue:此成员是保留的,必须为 0。
SizeOfImage:可执行文件装入内存后的总大小。该大小按内存对齐方式对齐。
SizeOfHeaders:整个 PE 头部的大小。这个 PE 头部指 DOS 头、PE 头、节表的总合大小。该大小按文件对齐方式对齐。
CheckSum:校验和。对于 EXE 文件通常为 0;对于 SYS 文件(驱动文件、内核文件),则必须有一个校验和。
Subsystem:可执行文件的子系统类型。
SubSystem 的取值
#define IMAGE_SUBSYSTEM_UNKNOWN 0 // 未知子系统。
#define IMAGE_SUBSYSTEM_NATIVE 1 // 无需子系统(设备驱动程序和本机系统进程)。
#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // 窗口图形用户界面 (GUI) 子系统。
#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Windows 控制台 (CUI) 子系统。
#define IMAGE_SUBSYSTEM_OS2_CUI 5 // OS/2 CUI 子系统。
#define IMAGE_SUBSYSTEM_POSIX_CUI 7 // POSIX CUI 子系统。
#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8
#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 // Windows CE系统。
#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 // 可扩展固件接口 (EFI) 应用程序。
#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 // 具有启动服务的 EFI 驱动程序。
#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 // 具有运行时服务的 EFI 驱动程序。
#define IMAGE_SUBSYSTEM_EFI_ROM 13
#define IMAGE_SUBSYSTEM_XBOX 14 // Xbox 系统。
#define IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION 16 // 启动应用程序。
#define IMAGE_SUBSYSTEM_XBOX_CODE_CATALOG 17
DllCharacteristics:指定 DLL 文件的属性。
DllCharacteristics 取值
// IMAGE_LIBRARY_PROCESS_INIT 0x0001 // Reserved.
// IMAGE_LIBRARY_PROCESS_TERM 0x0002 // Reserved.
// IMAGE_LIBRARY_THREAD_INIT 0x0004 // Reserved.
// IMAGE_LIBRARY_THREAD_TERM 0x0008 // Reserved.
#define IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA 0x0020 // 具有 64 位地址空间的 ASLR。
#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040 // DLL可以在加载时重定位。
#define IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY 0x0080 // 强制进行代码完整性校验
#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100 // Image is NX compatible
#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200 // Image understands isolation and doesn't want it
#define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400 // Image does not use SEH. No SE handler may reside in this image
#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 // Do not bind this image.
#define IMAGE_DLLCHARACTERISTICS_APPCONTAINER 0x1000 // Image should execute in an AppContainer
#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 // Driver uses WDM model
#define IMAGE_DLLCHARACTERISTICS_GUARD_CF 0x4000 // Image supports Control Flow Guard.
#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000
SizeOfStackReserve:为线程保留的栈大小,以字节为单位。
SizeOfStackCommit: 为线程已提交的栈大小,以字节为单位。
SizeOfHeapReserve:为线程保留的堆大小。
SizeOfHeapCommit:为线程提交的堆大小。
LoaderFlags:保留字段,必须为 0。
NumberOfRvaAndSizes:数据目录项的个数。#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]:数据目录表,由 NumberOfRvaAndSizes 个 IMAGE_DATA_DIRECTORY 结构体组成的数组。该数组包含输入表、输出表、资源、重定位等数据目录项的 RVA(相对虚拟地址)和大小。IMAGE_DATA_DIRECTORY 结构体定义如下:
//
// Directory format.
//
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress; // 实际上数据目录的 RVA
DWORD Size; // 数据目录项的大小
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
IMAGE_DATA_DIRECTORY(汇编)
IMAGE_DATA_DIRECTORY STRUCT
VirtualAddress DWORD ?
isize DWORD ?
IMAGE_DATA_DIRECTORY ENDS
数据目录中的成员在数组中的索引
// Directory Entries
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // 导出表
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // 导入表
#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // 资源
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory
#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // 重定位
#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory
// IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage)
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP
#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers
#define IMAGE_DIRECTORY_ENTRY_IAT 12 // 导入地址表
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor
节表详解 --- IMAGE_SECTION_HEADER
节表的位置在 IMAGE_OPTIONAL_HEADER 结构体后面,节表中的每个 IMAGE_SECTION_HEADER 中都存放着可执行文件被映射到内存中所在位置的信息,节的个数由 IMAGE_FILE_HEADER 中的 NumberOfSections 给出。IMAGE_SECTION_HEADER 的大小为 40 字节,IMAGE_SECTION_HEADER 定义如下:
//
// Section header format.
//
#define IMAGE_SIZEOF_SHORT_NAME 8
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
union {
DWORD PhysicalAddress;
DWORD VirtualSize;
} Misc;
DWORD VirtualAddress;
DWORD SizeOfRawData;
DWORD PointerToRawData;
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
#define IMAGE_SIZEOF_SECTION_HEADER 40
IMAGE_SECTION_HEADER(汇编)
IMAGE_SECTION_HEADER STRUCT
Name1 db IMAGE_SIZEOF_SHORT_NAME dup(?)
union Misc
PhysicalAddress dd ?
VirtualSize dd ?
ends
VirtualAddress dd ?
SizeOfRawData dd ?
PointerToRawData dd ?
PointerToRelocations dd ?
PointerToLinenumbers dd ?
NumberOfRelocations dw ?
NumberOfLinenumbers dw ?
Characteristics dd ?
IMAGE_SECTION_HEADER ENDS
该结构体的各个字段:
Name[IMAGE_SIZEOF_SHORT_NAME]:一个 8 字节、NULL 填充的 UTF-8 字符串。多余字节会被自动截断。
Misc.PhysicalAddress:文件地址。
Misc.VirtualSize:加载到内存中的节的总大小(以字节为单位)。如果此值大于 SizeOfRawData 成员,则该节将用零填充。此字段仅对可执行映像有效,对于目标文件应设置为 0。
VirtualAddress:节区数据装入内存后的相对虚拟地址,这个地址是按内存对齐的,该地址加上 IMAGE_OPTIONAL_HEADER 结构体中的 ImageBase 才是内存中的虚拟地址。
SizeOfRawData:节区数据在磁盘上的大小,该值是按照文件对齐进行对齐后的值,但是也有例外。
PointerToRawData:节区在磁盘文件上的偏移地址。
PointerToRelocations:A file pointer to the beginning of the relocation entries for the section. If there are no relocations, this value is zero.
PointerToLinenumbers:A file pointer to the beginning of the line-number entries for the section. If there are no COFF line numbers, this value is zero.
NumberOfRelocations:The number of relocation entries for the section. This value is zero for executable images.
NumberOfLinenumbers:The number of line-number entries for the section.
Characteristics:节区的属性。
Characteristics 取值
//
// Section characteristics.
//
// IMAGE_SCN_TYPE_REG 0x00000000 // Reserved.
// IMAGE_SCN_TYPE_DSECT 0x00000001 // Reserved.
// IMAGE_SCN_TYPE_NOLOAD 0x00000002 // Reserved.
// IMAGE_SCN_TYPE_GROUP 0x00000004 // Reserved.
#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 // Reserved.
// IMAGE_SCN_TYPE_COPY 0x00000010 // Reserved.
#define IMAGE_SCN_CNT_CODE 0x00000020 // 部分包含代码。
#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 // 部分包含初始化的数据。
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 // 部分包含未初始化的数据。
#define IMAGE_SCN_LNK_OTHER 0x00000100 // Reserved.
#define IMAGE_SCN_LNK_INFO 0x00000200 // Section contains comments or some other type of information.
// IMAGE_SCN_TYPE_OVER 0x00000400 // Reserved.
#define IMAGE_SCN_LNK_REMOVE 0x00000800 // Section contents will not become part of image.
#define IMAGE_SCN_LNK_COMDAT 0x00001000 // Section contents comdat.
// 0x00002000 // Reserved.
// IMAGE_SCN_MEM_PROTECTED - Obsolete 0x00004000
#define IMAGE_SCN_NO_DEFER_SPEC_EXC 0x00004000 // Reset speculative exceptions handling bits in the TLB entries for this section.
#define IMAGE_SCN_GPREL 0x00008000 // Section content can be accessed relative to GP
#define IMAGE_SCN_MEM_FARDATA 0x00008000
// IMAGE_SCN_MEM_SYSHEAP - Obsolete 0x00010000
#define IMAGE_SCN_MEM_PURGEABLE 0x00020000
#define IMAGE_SCN_MEM_16BIT 0x00020000
#define IMAGE_SCN_MEM_LOCKED 0x00040000
#define IMAGE_SCN_MEM_PRELOAD 0x00080000
#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 //
#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 //
#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 //
#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 //
#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 // Default alignment if no others are specified.
#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 //
#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 //
#define IMAGE_SCN_ALIGN_128BYTES 0x00800000 //
#define IMAGE_SCN_ALIGN_256BYTES 0x00900000 //
#define IMAGE_SCN_ALIGN_512BYTES 0x00A00000 //
#define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000 //
#define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000 //
#define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000 //
#define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000 //
// Unused 0x00F00000
#define IMAGE_SCN_ALIGN_MASK 0x00F00000
#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 // 部分包含扩展的重定位。
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 // 节可以被丢弃。
#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 // 节不可缓存。
#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 // 节是不可分页的。
#define IMAGE_SCN_MEM_SHARED 0x10000000 // 节是可共享的。
#define IMAGE_SCN_MEM_EXECUTE 0x20000000 // 节是可执行的。
#define IMAGE_SCN_MEM_READ 0x40000000 // 节是可读的。
#define IMAGE_SCN_MEM_WRITE 0x80000000 // 节是可写的。