滥用未公开特性伪造PE节区头部
引言
在调试其他项目时,我偶然发现PE文件的特殊行为:当NT头中的SectionAlignment值小于页面大小(4096)时,镜像的内存映射方式会出现显著差异。加载器不会按常规方式解析节区表构造内存镜像,而是将整个文件(包括头部)以RWX权限映射到内存中 - 完全忽略单独的节区头部。
这种特性使得我们可以创建不含任何节区但仍能执行自身代码的PE可执行文件。由于默认具有写权限,这些代码甚至可以实现自我修改。
Windows内核机制
在MiCreateImageFileMap函数中可见PE头解析逻辑:当SectionAlignment小于0x1000时,系统会在映射镜像前设置未公开标志位(0x200000):
|
|
当该标志置位时,MiBuildImageControlArea将整个文件视为单个节区:
|
|
技术验证
示例1:无节区可执行PE
通过手工构造的PE头部演示该技术(关键字段):
|
|
附加的位置无关代码通过动态加载user32.dll调用MessageBoxA,该payload同时兼容32/64位环境:
|
|
示例2:带伪造节区的可执行PE
更有趣的是可以创建虚假的只读节区。虽然节区标记为只读,但实际内存仍具有RWX权限:
|
|
技术细节
- 有效载荷可以嵌入NT头部内部(SizeOfHeaders值可设为0)
- 从Vista到Win10所有版本均受影响
- 现代反汇编工具已能识别此类文件
- 可能最初设计用于超小镜像(整镜像小于内存页)
特别说明:该技术通过比较栈指针变化检测运行架构,虽非最优但足够用于概念验证。实际攻击中可采用更精细的检测方法。