​!htrace​​:扩展用于显示一个或多个句柄的堆栈回溯信息

!htrace [Handle [Max_Traces]] 
!htrace -enable [Max_Traces]
!htrace -snapshot
!htrace -diff
!htrace -disable
!htrace -?

​!htrace​​​,显示当前的所有句柄信息
使用!htrace 定位句柄内存泄露基本步骤:

  • ​!htrace -enable​​,启用handle trace,并且创建第一个快照作为初始状态,方便使用 -diff选项
  • ​!htrace -snapshot​​,创建快照,用作-diff选项
  • ​!htrace -diff​​,使用当前状态的信息,和最近一次的快照信息做对比
  • ​!htrace -disable​​,禁用handle trace

下面我们将使用一个简单的demo来分析一下

DWORD WINAPI _tfunc(LPVOID lparam){
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
while (true)
{
CreateEvent(NULL, true, false, NULL);
CreateThread(NULL, 0, _tfunc, NULL, 0, NULL);
Sleep(10000);
}
return 0; return 0;
}

第一步,运行程序,然后break之后启用handle trace

windbg !htrace 定位句柄泄露_内存泄露


并且使用​​!htrace​​​查看一下当前信息,并且创建一下​​!htrace -snapshot​

windbg !htrace 定位句柄泄露_句柄_02


运行一段时间之后,我们使用​​!htrace -diff​​查看一下handle的变化信息

windbg !htrace 定位句柄泄露_句柄_03


从这里可以看出,这次比上次快照多了​​0x02​​​个handle,分别是NtCreateEvent和ZwCreateThreadEx创建的句柄,然后调用这两个函数的位置分别在​​0x00007ff77ac61032: test!wmain+0x0000000000000022​​和

​0x00007ff77ac6104f: test!wmain+0x000000000000003f​​​,所以此时我们通过​​lsa​​定位源码信息:

windbg !htrace 定位句柄泄露_句柄泄露_04


此时可以一眼就看到因为我们创建了事件和句柄都没有关闭,到此位置句柄泄露定位完毕。

同时我们也可以使用​​!handle xx f​​ 查看一下handle的信息

​!handle​​,列举所有的句柄信息

windbg !htrace 定位句柄泄露_句柄_05


windbg !htrace 定位句柄泄露_句柄泄露_06


所以通过上述信息我们可以知道​​c4​​​是​​Event​​​类型,​​c0​​​是​​Thread​​的类型。