加载配置表在PE文件中的位置
加载配置表(Load Configuration Table)是存储在PE文件可选头(Optional Header)数据目录(Data Directory)数组中的一个关键结构。它位于该数组的第11个条目,索引值为10。
数据目录结构:
数据目录数组(共16个条目):
0. 导出表 (Export Table)
1. 导入表 (Import Table)
2. 资源表 (Resource Table)
3. 异常表 (Exception Table)
4. 证书表 (Certificate Table)
5. 基址重定位表 (Base Relocation Table)
6. 调试数据 (Debug Data)
7. 版权信息 (Architecture Specific Data)
8. 全局指针 (Global Pointer)
9. TLS表 (Thread Local Storage Table)
10. 加载配置表 (Load Configuration Table) // 索引为10
11. 绑定导入表 (Bound Import Table)
12. 导入地址表 (Import Address Table)
13. 延迟导入表 (Delay Import Descriptor)
14. CLR运行时头 (CLR Runtime Header)
15. 保留 (Reserved)
加载配置表的数据结构
加载配置表的核心是一个名为IMAGE_LOAD_CONFIG_DIRECTORY的结构体,它针对32位和64位架构有不同版本,以适应不同位宽的地址。
32位版本 (IMAGE_LOAD_CONFIG_DIRECTORY32)
typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32 {
DWORD Size; // 结构体大小
DWORD TimeDateStamp; // 时间戳
WORD MajorVersion; // 主版本号
WORD MinorVersion; // 次版本号
DWORD GlobalFlagsClear; // 全局标志清除
DWORD GlobalFlagsSet; // 全局标志设置
DWORD CriticalSectionDefaultTimeout; // 临界区默认超时
DWORD DeCommitFreeBlockThreshold; // 释放块阈值
DWORD DeCommitTotalFreeThreshold; // 总释放阈值
DWORD LockPrefixTable; // 锁前缀表地址
DWORD MaximumAllocationSize; // 最大分配大小
DWORD VirtualMemoryThreshold; // 虚拟内存阈值
DWORD ProcessHeapFlags; // 进程堆标志
DWORD ProcessAffinityMask; // 进程亲和性掩码
WORD CSDVersion; // CSD版本
WORD DependentLoadFlags; // 依赖加载标志
DWORD EditList; // 编辑列表地址
DWORD SecurityCookie; // 安全Cookie地址
DWORD SEHandlerTable; // SE异常处理表地址
DWORD SEHandlerCount; // SE异常处理程序数量
// Windows 10 1607及以后版本新增字段
DWORD GuardCFCheckFunctionPointer;
DWORD GuardCFDispatchFunctionPointer;
DWORD GuardCFFunctionTable;
DWORD GuardCFFunctionCount;
DWORD GuardFlags;
// Windows 10 1703及以后版本新增字段
IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity;
// Windows 10 1903及以后版本新增字段
DWORD GuardAddressTakenIatEntryTable;
DWORD GuardAddressTakenIatEntryCount;
DWORD GuardLongJumpTargetTable;
DWORD GuardLongJumpTargetCount;
// Windows 10 2004及以后版本新增字段
DWORD DynamicValueRelocTable;
DWORD CHPEMetadataPointer;
// Windows 10 20H1及以后版本新增字段
DWORD GuardRFFailureRoutine;
DWORD GuardRFFailureRoutineFunctionPointer;
DWORD DynamicValueRelocTableOffset;
DWORD DynamicValueRelocTableSection;
DWORD Reserved2;
// Windows 10 21H1及以后版本新增字段
DWORD GuardRFVerifyStackPointerFunctionPointer;
DWORD HotPatchTableOffset;
// Windows 11及以后版本新增字段
DWORD Reserved3;
DWORD EnclaveConfigurationPointer;
DWORD VolatileMetadataPointer;
} IMAGE_LOAD_CONFIG_DIRECTORY32;
64位版本 (IMAGE_LOAD_CONFIG_DIRECTORY64)
64位版本结构体与32位版本基本对应,主要区别在于地址相关的字段(如指针和阈值)使用了ULONGLONG类型以适应64位地址空间。
typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64 {
DWORD Size;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD GlobalFlagsClear;
DWORD GlobalFlagsSet;
DWORD CriticalSectionDefaultTimeout;
ULONGLONG DeCommitFreeBlockThreshold;
ULONGLONG DeCommitTotalFreeThreshold;
ULONGLONG LockPrefixTable;
ULONGLONG MaximumAllocationSize;
ULONGLONG VirtualMemoryThreshold;
ULONGLONG ProcessAffinityMask;
DWORD ProcessHeapFlags;
WORD CSDVersion;
WORD DependentLoadFlags;
ULONGLONG EditList;
ULONGLONG SecurityCookie;
ULONGLONG SEHandlerTable;
ULONGLONG SEHandlerCount;
// 后续字段与32位版本含义相同,类型为ULONGLONG
ULONGLONG GuardCFCheckFunctionPointer;
ULONGLONG GuardCFDispatchFunctionPointer;
ULONGLONG GuardCFFunctionTable;
ULONGLONG GuardCFFunctionCount;
DWORD GuardFlags;
IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity;
ULONGLONG GuardAddressTakenIatEntryTable;
ULONGLONG GuardAddressTakenIatEntryCount;
ULONGLONG GuardLongJumpTargetTable;
ULONGLONG GuardLongJumpTargetCount;
ULONGLONG DynamicValueRelocTable;
ULONGLONG CHPEMetadataPointer;
ULONGLONG GuardRFFailureRoutine;
ULONGLONG GuardRFFailureRoutineFunctionPointer;
DWORD DynamicValueRelocTableOffset;
DWORD DynamicValueRelocTableSection;
DWORD Reserved2;
ULONGLONG GuardRFVerifyStackPointerFunctionPointer;
DWORD HotPatchTableOffset;
DWORD Reserved3;
ULONGLONG EnclaveConfigurationPointer;
ULONGLONG VolatileMetadataPointer;
} IMAGE_LOAD_CONFIG_DIRECTORY64;
加载配置表各字段详解
了解PE文件结构是深入系统底层和网络/系统知识的基础。加载配置表中的字段可大致分为以下几类:
基础字段
Size: 结构体大小,用于标识版本和确定需要解析的字段范围。
TimeDateStamp: 时间戳,标识结构体的创建或修改时间。
MajorVersion/MinorVersion: 主次版本号,对应不同Windows版本的功能集。
GlobalFlagsClear/Set: 用于控制进程的全局标志位。
CriticalSectionDefaultTimeout: 临界区(Critical Section)操作的默认超时值。
内存管理字段
DeCommitFreeBlockThreshold: 内存释放的块大小阈值。
DeCommitTotalFreeThreshold: 内存释放的总大小阈值。
MaximumAllocationSize: 单次内存分配允许的最大尺寸。
VirtualMemoryThreshold: 虚拟内存管理的相关阈值。
ProcessHeapFlags: 进程堆的创建标志,影响堆的内存布局和行为。
安全防护字段
这是加载配置表在现代Windows中的核心价值所在,构成了重要的安全防护机制。
SecurityCookie: /GS编译选项生成的安全Cookie地址,用于防范栈缓冲区溢出。
SEHandlerTable/SEHandlerCount: 安全结构化异常处理(SafeSEH)表的信息,防止SEH记录被恶意覆盖。
GuardCF...系列字段: 控制流防护(Control Flow Guard, CFG)相关数据,用于抵御面向返回编程(ROP)等代码复用攻击。
GuardFlags: 控制流保护的各种功能开关。
CodeIntegrity: 包含代码完整性校验信息。
加载配置表的核心作用与安全特性
加载配置表在程序加载和运行时扮演着关键角色,其设计初衷和主要作用集中在以下几个方面:
1. 增强程序安全性
- 栈缓冲区溢出保护 (
/GS): 通过SecurityCookie(又称“栈Cookie”)在函数栈帧中插入随机值,并在函数返回前验证其完整性,有效检测和阻止经典的栈溢出攻击。
- 安全结构化异常处理 (
/SafeSEH): 通过SEHandlerTable维护一个合法的异常处理程序列表。当异常发生时,系统会验证异常处理函数指针是否位于该表中,从而阻止攻击者利用溢出漏洞篡改SEH链并执行恶意代码。
- 控制流防护 (
/Guard:CF): 这是现代Windows最强大的缓解措施之一。它通过GuardCFFunctionTable维护一个有效的间接调用目标地址集合。在每次进行间接调用(如通过函数指针或虚函数表)前,运行时会对目标地址进行检查,确保其是合法的函数入口点,极大增加了ROP/JOP攻击的难度。
2. 优化内存管理
加载配置表提供了多个字段供系统加载器(Loader)和堆管理器(Heap Manager)进行内存管理优化,例如调整内存提交与回收的策略、设置进程堆的初始属性等,以平衡性能与资源使用。
3. 支持系统兼容性与演进
通过Size和MajorVersion/MinorVersion字段,该结构体能够优雅地扩展。新版本的Windows可以定义包含新字段的新版本结构体,而旧系统在加载时仅会处理其已知的字段部分,确保了向后兼容性。
实际应用与查看方法
编译器选项启用
在Visual Studio等编译环境中,可以通过以下选项启用相关安全功能,编译器会自动生成并填充加载配置表中的对应字段:
/GS // 启用栈安全检查(生成SecurityCookie)
/SafeSEH // 启用安全结构化异常处理
/Guard:CF // 启用控制流防护
查看加载配置表内容
可以使用以下工具查看PE文件中的加载配置信息:
- dumpbin (Visual Studio 命令行工具): 使用
dumpbin /loadconfig <filename.exe> 命令。
- PE解析工具: 如CFF Explorer、PE-bear等图形化工具,可以直观地查看数据目录及加载配置结构的各个字段值。
一个典型的dumpbin /loadconfig输出示例如下:
Load Configuration Directory:
Size: 00000048
TimeDateStamp: 00000000
MajorVersion: 0000
MinorVersion: 0000
GlobalFlagsClear: 00000000
GlobalFlagsSet: 00000000
CriticalSectionDefaultTimeout: 00000000
DeCommitFreeBlockThreshold: 00000000
DeCommitTotalFreeThreshold: 00000000
LockPrefixTable: 00000000
MaximumAllocationSize: 00000000
VirtualMemoryThreshold: 00000000
ProcessHeapFlags: 00000000
ProcessAffinityMask: 00000000
CSDVersion: 0000
DependentLoadFlags: 0000
EditList: 00000000
SecurityCookie: 00401000
SEHandlerTable: 00000000
SEHandlerCount: 00000000
版本演进与总结
加载配置表随着Windows系统的安全需求而不断演进:
- 早期版本 (如 Windows XP): 主要包含基础字段和内存管理字段。
- Windows Vista/7: 引入了
SecurityCookie和SEHandlerTable等关键安全字段。
- Windows 8/8.1 及 Windows 10 初期: 加入了控制流防护(CFG)的基础字段。
- Windows 10 后续更新及 Windows 11: 持续扩展,增加了更精细的CFG策略(如
GuardAddressTakenIatEntryTable)、返回流防护(RFG)、代码完整性验证等高级安全字段。
总结
加载配置表是PE文件格式中至关重要的组成部分,它作为连接编译器、链接器和操作系统加载器的桥梁,承载了丰富的安全策略与运行时配置信息。其核心价值在于为现代Windows应用程序提供了纵深防御的安全基础,包括栈保护、异常处理保护和控制流完整性保护等关键缓解措施。对于软件开发者、安全研究员和逆向工程师而言,深入理解加载配置表是分析Windows程序行为、评估其安全态势和进行漏洞挖掘的必备知识。