0x00
首先使用 gflags 设置heap堆栈追踪参数:
Gflags.exe /i +ust
设置完成后后,我们可以在
“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options<Image Name>” GlobalFlag 中看到刚才设置的参数。
设置完不需要重启机器,直接启动需要跟踪的exe。
对于需要跟踪的exe可以使用windbg live调试或者dump调试。
0x01
使用 !heap –s 获取堆分配的情况,找到可疑的堆。
使用 !heap –stat –h ,获取特定堆各种size分配的block数量。注意,这里的heap handle就是 !heap –s 获取的第一列参数,实际上就是 _HEAP 的地址
这里我们随便找一个堆分析。
接下来,我们假设大小为 10ada0出现泄漏(一般是整体占比比较大的size在泄漏)。我们对这个size进行分析:
注意,这个命令会查找系统中所有堆的分配情况,所以列出的条目可能不只有你需要查看的堆。具体这个条目在不在需要分配的堆上,可以查看 _HEAP @ 字段。
接下来,我们检查当前条目的分配堆栈,这里需要用到 UserPtr字段:
到这里,这个堆分配的堆栈就已经找到了。
0x02
回到刚才 !heap –s之后,我们看到下图:
其中 Heap列对应的地址即 ntdll!_HEAP的地址
其中有两个字段:
+0x04c EncodeFlagMask : 0x100000
+0x050 Encoding : _HEAP_ENTRY
其中 EncodeFlagMask 表示是否对 _HEAP_ENTRY的数据进行异或处理。
我们看看 +0x50(Encoding字段)的数据:
在_HEAP结构中我们可以看到第一个有效的 _HEAP_ENTRY 地址为:11480498
通过 !heap –x 命令获取这个entry的信息:
但是我们 dt _HEAP_ENTRY 之后会发现长度数据是错乱的:
这里实际就是 Encoding的用处了,上面对 Encoding的打印,我们看到前四个字节为:
0x 57bf3d15,后四个字节为 0000a0e7。
我们对 11480489同样做dd操作:
头四个字节为 0x51be3d12,后四个字节为 4200a074。
分别作异或处理:
其中的低两位是size字段,32位上粒度为8,64位上粒度为16。
因此第一个size = 7 * 8 = 56 = 0x38 也就是我们上图打印的size
第二个size = 0x93 * 8 = 0x498,就是上图的PreSize.
0x03
!heap –a 可以查看heap的所有block信息
!heap –x 可以查看某个block的信息
0x04
完成调试后,使用 Gflags.exe /i -ust 删除调试选项。