一:背景 1. 讲故事 前段时间有位朋友在分析他的非托管泄漏时,发现NT堆的_HEAP_ENTRY的 Size 和!heap命令中的 Size 对不上,来咨询是怎么回事? 比如下面这段输出: 1 2 3 4 5 6 7 8 9 10 11 12
一:背景1. 讲故事前段时间有位朋友在分析他的非托管泄漏时,发现NT堆的_HEAP_ENTRY 的 Size 和 !heap 命令中的 Size 对不上,来咨询是怎么回事? 比如下面这段输出:
从输出中可以看到,用 !heap 命令的显示 0000000000550740 的 size=0x00110 ,而 dt 显示的 size=0xa6a7,那为什么这两个 size 不一样呢? 毫无疑问 !heap 命令中显示的 0x00110 是对的,而 0xa6a7 是错的,那为什么会错呢? 很显然 Windows 团队并不想让你能轻松的从 ntheap 上把当前的 entry 给挖出来,所以给了你各种假数据,言外之意就是 size 已经编码了。 原因给大家解释清楚了,那我能不能对抗一下,硬从NtHeap上将正确的size给推导出来呢? 办法肯定是有办法的,这篇我们就试着聊一聊。 二:如何正确推导1. 原理是什么?其实原理很简单,_HEAP_ENTRY 中的 Size 已经和 _HEAP 下的 Encoding 做了异或处理。
那如何验证这句话是否正确呢?接下来启动 WinDbg 来验证下,为了方便说明,先上一段测试代码。
既然代码中会用到 Encoding 字段来编解码size,那我是不是可以用 ba 在这个内存地址中下一个硬件条件,如果命中了,就可以通过汇编代码观察编解码逻辑,对吧? 有了思路就可以开干了。 2. 通过汇编观察编解码逻辑因为 malloc 默认是分配在进程堆上,所以用 !heap -s 找到进程堆句柄进而获取 Encoding 的内存地址。
可以看到 Encoding 中的 Size 偏移是 +0x008,所以我们硬件条件断点的偏移值是 0x88 ,命令为 ba r4 00000000004a0000+0x88 ,设置好之后就可以继续 go 啦。 从图中可以看到在 ntdll!RtlpAllocateHeap+0x55c 方法处成功命中,从汇编中可以看到。
最后就是做一个 xor 异或操作,也就是正确的 size 值。
可以看到最后的size=7d10, 这里为什么乘 0x10,过一会再说,接下来我们找一下 edi 所属的堆块。 3. 寻找 edi 所属的堆块要想找到所属堆块,可以用内存搜索的方式,再用 !heap -x 观察即可。
有了这些信息就可以纯手工推导了。
怎么样,最后的size 也是size=7d10, 这和刚才汇编代码中计算的是一致的,这里要乘 0x10 是因为 entry 的粒度按 16byte 计算的,可以用 !heap -h 00000000004a0000 ;观察下方的 Granularity 字段即可。
总结这就是解答异或的完整推导逻辑,总的来说思路很重要,这些知识也是我们调试 dump 的必备功底,了解的越深,解决的问题域会越大。 |
2022-05-13
2022-03-10
2021-07-02
2021-08-14
2021-05-17