Windows 10 x86/wow64用户态堆
引言
过去几周我收到多位亲友的紧急求助,称电脑出现异常且疑似被黑客入侵。调查发现他们的系统均被升级至Windows 10。尽管可讨论强制升级策略,但显然Win10市场份额正在增长,已成为值得深入研究的操作系统版本。
本文汇集了关于Windows 10中32位进程用户态堆管理器行为的笔记,重点记录与Windows 7的异同,并探讨如何操纵堆行为以提高可预测性。具体研究问题包括:
- 后端分配器的行为特征
- 激活LFH(低碎片堆)的条件
- Win7与Win10的LFH行为差异
- 创建特定堆布局(同尺寸/不同尺寸对象相邻)的方法
- 实现可靠精确堆喷洒的可能性
需要说明的是:本人逆向工程能力有限,以下内容仅为观察记录,未基于ntdll.dll的反汇编/反编译分析。由于测试样本有限,结论未必完全准确,希望这些笔记能激励更多人进行测试和逆向工程研究。
本文假设读者已熟悉Windows 7堆管理机制(前端/后端分配器),并能理解WinDBG的!heap命令输出。所有测试均使用默认进程堆,结论应适用于所有Windows堆及依赖Windows堆管理的应用程序。
术语说明:
- 块(chunk):连续内存区域
- 块单位(block):8字节内存单位(注意:WinDBG用"block"指代chunk)
- 虚拟分配块(virtualallocdblock):通过RtlAllocateHeap分配且大于VirtualMemoryThreshold的块(不存储在段内,而是作为独立内存块管理)
- 段(segment):堆管理单元,用于分配和管理块
- 子段(SubSegment):LFH管理单元
测试环境
- Windows 10 Enterprise x64(VirtualBox虚拟机,2CPU+1.8GB内存)
- Visual Studio Express 2015桌面版
- WinDBG for Windows 10(确保使用最新版本以正确解析堆结构)
- 符号服务器配置:_NT_SYMBOL_PATH=srvc:\symbolshttp://msdl.microsoft.com/download/symbols
测试用例源码:https://github.com/corelan/win10_heap
堆结构分析
与早期版本相同,Windows 10堆位于ASLR影响的随机地址,以头部结构起始。关键字段包括:
- 偏移0x4c(EncodeFlagMask)和0x50(Encoding):块头部编码信息(与Win7相同)
- 偏移0x5c(VirtualMemoryThreshold):值0xfe00(0x7F000字节),仍可通过分配大于此值的块触发VirtualAllocdBlocks
- 偏移0xd6(FrontEndHeapType):前端分配器类型(0x2表示LFH)
- 偏移0xd0(FrontEndHeap):指向LFH头部结构
图形化表示堆由以下组件构成:
- 后端分配器
- LFH前端分配器
后端分配器(BEA)行为测试
BEA_Alloc1测试
分配两个0x300字节块验证分配来源和相邻性。结果显示块从段尾空闲块分割获得,彼此相邻。释放后合并回空闲列表,新请求时会再次分割。
BEA_Alloc2测试
分配10个0x300字节块(避免触发LFH)后释放最后一个,随后分配两个0x100字节块。发现分配优先使用精确匹配的空闲块(0x100字节),其次使用更大块(0x198字节)进行分割,段尾合并后的大块未被使用。
BEA_Alloc3测试
通过精心布局实现0x58字节块的精确回收:先用0x100字节块包围目标块,确保释放后不被合并,然后通过相同大小分配重新占用该内存空间。
BEA_Alloc4测试
尝试用0x80字节分配覆盖0x58字节块的前4个双字(仅控制0x80字节块的后4个双字)。通过合并相邻空闲块创造合适条件,虽因计算偏差未完全成功,但验证了概念可行性。
前端分配器(LFH)行为测试
LFH激活条件
- 基础测试:18次连续分配后激活LFH(第18次分配开始标记为LFH)
- 干扰测试:在分配序列中插入不同桶大小的分配/释放操作,不影响18次激活阈值
- 同桶释放测试:释放同桶大小的块不影响激活计数
LFH分配特性
- LIFO行为消失:释放后重新分配的顺序不再遵循后进先出
- 最大尺寸限制:仍保持0x4000字节上限
- 地址随机化:同一子段内的块不再连续排列
LFH内存回收
通过释放整个子段的所有块(包括目标漏洞块),可使该内存区域被重新用于不同桶大小的分配,实现跨桶尺寸的内存重用。
大块分配与堆喷洒
VirtualAllocdBlocks分配
分配大于VirtualMemoryThreshold(0x7F000字节)的块仍会触发VirtualAllocdBlocks机制,但这些分配之间的间隙比Windows 7更大,降低了堆喷洒的精确性。
精确堆喷洒技术
通过以下方法实现可靠堆喷洒:
- 避免使用LFH和VirtualAllocdBlocks
- 使用对齐尺寸(如0x20000-8或0x40000-8字节)
- 在喷洒内容中每0x1000字节重复关键结构(垃圾数据+ROP链+shellcode)
- 通过预先分配/释放大块制造"噪声隔离区"
测试成功在0x0c0c0c0c地址精确放置标记数据,证实了Windows 10环境下精确堆喷洒的可行性。
结论
Windows 10堆管理在保持基础架构的同时引入了重要变化:
- LFH激活机制更稳定(18次分配阈值抗干扰)
- LFH内部行为随机化增强(取消LIFO,地址不连续)
- 后端分配器行为基本保持不变
- 精确堆喷洒仍可通过精心设计的分配策略实现
这些发现对漏洞利用开发具有重要意义,特别是在Use-After-Free和堆溢出场景中的内存布局操控。