Windbg 如何从DLL的堆标记中获益?

Windbg 如何从DLL的堆标记中获益?,windbg,gflags,Windbg,Gflags,我如何使用GFlags设置并从中受益 我知道如何激活进程的设置,但在的输出中没有找到有用的信息!WinDbg中的heap-t。我希望有这样的输出: 0:000> !heap -t Index Address Allocated by 1: 005c0000 MyDll.dll 2: 006b0000 AnotherDll.dll 因此,我可以识别哪个堆是由哪个DLL创建的,然后识别内存泄漏的来源 这是对术语“通过DLL进行堆标记”的误解,还是我需要更多的

我如何使用GFlags设置并从中受益

我知道如何激活进程的设置,但在
的输出中没有找到有用的信息!WinDbg中的heap-t
。我希望有这样的输出:

0:000> !heap -t
Index   Address   Allocated by 
1:      005c0000  MyDll.dll
2:      006b0000  AnotherDll.dll
因此,我可以识别哪个堆是由哪个DLL创建的,然后识别内存泄漏的来源

这是对术语“通过DLL进行堆标记”的误解,还是我需要更多的命令来获得所需的结果

到目前为止,我的研究:

  • 我在谷歌上搜索了关于这个主题的教程,但找不到详细的描述
  • 我读了WinDbg的
    .hh!堆
    ,但这里没有详细解释。标签仅在
    中使用!堆-b

    • 又是一个很晚的回答

      要从堆标记
      中获益,您需要首先在代码中创建一个标记。
      据我所知(即截至xp-sp3),没有用于创建标签的
      文档化API

      (从那时起,我就没有处理过heap,所以我不知道os>vista中的最新API对heap manager进行了重写,所以我在下面发布的许多
      ^^^^^
      功能可能已经被更正或改进,或者bug已经被删除)

      在xp-sp3中,您可以使用未记录的
      RtlCreateTagHeap
      进程堆
      私有堆

      创建tha标记后,需要设置全局标志8000 | 800

      htg - Enable heap tagging
      htd - Enable heap tagging by DLL
      
      从理论上讲,所有Alloc和Free都必须被标记

      但是
      在xp-sp3中,使用这些基本步骤,实际上只有大于512 kB的分配才会被标记

      它要么是一个bug,要么是一个将标记限制为分配并释放大于512 kB的功能
      HeapAlloc通过ZwAllocateVirtualMemory
      在32位进程中分配大于512 kB的情况下
      请参阅msdn中的HeapCreate/HeapAlloc文档

      作为
      调试辅助工具
      ,您可以
      上快速修补ntdll.dll
      ,为
      所有分配和释放启用标记

      下面是一个示例代码,演示了标记以及如何在windbg中查看所有标记

      使用
      cl/Zi/analyze/W4/link/RELEASE编译

      使用windbg执行应用程序并观看带有
      的标记!heap*-t
      命令

      #include <windows.h>
      #include <stdio.h>
      
      //heaptags are kinda broken or they are intentionally 
      //given only to allocations > 512 kb // allocation > 512 kb
      //go through VirtualAlloc Route for Heap created with maxsize 
      //set to 0 uncomment ALLOCSIZE 0xfdfd2 and recompile to watch 
      // tagging increase by 100% with ALLOCSIZE  0xfdfd1 only 50 allocs 
      // and frees that are > 512 kB will be tagged these magic numbers 
      // are related to comment in HeapCreate Documentation that state 
      // slightly less than 512 kB will be allocated for 32 bit process 
      // tagging can be dramatically increased by patching ntdll when 
      // stopped on system breakpoint patch 7c94b8a4 (xpsp3 ntdll.dll) 
      // use the below command in windbg for finding the offset of pattern
      // command must be in single line no line breaks
      // .foreach /pS 4 /ps 4 ( place  { !grep -i -e call -c 
      // "# call*RtlpUpdateTagEntry 7c900000 l?20000" } ) { ub place }
      // the instruction we are searching to patch is 
      //7c94b8a1 81e3ff0fffff    and     ebx,0FFFF0FFFh 
      // patch 0f to 00 at system breakpoint with eb 7c94b8a1+3 00 
      
      #define BUFFERSIZE 100
      #define ALLOCSIZE  0xfdfd1
      //#define ALLOCSIZE  0xfdfd2
      
      typedef int ( __stdcall *g_RtlCreateTagHeap) ( 
          HANDLE hHeap ,
          void * unknown, 
          wchar_t * BaseString, 
          wchar_t * TagString 
          );
      
      void HeapTagwithHeapAllocPrivate()
      {
          PCHAR pch[BUFFERSIZE] = {};
          HANDLE hHeap    = 0;
          ULONG tag1      = 0;
          ULONG tag2      = 0;
          ULONG tag3      = 0;
          ULONG tag4      = 0;
          ULONG tag5      = 0;
          g_RtlCreateTagHeap RtlCreateTagHeap = 0;
          HMODULE hMod = LoadLibrary("ntdll.dll");
          if(hMod)
          {
              RtlCreateTagHeap = (g_RtlCreateTagHeap) 
                  GetProcAddress( hMod,"RtlCreateTagHeap");
          }
          if (hHeap == 0)
          {
              hHeap = HeapCreate(0,0,0);
              if (RtlCreateTagHeap != NULL)
              {
                  tag1 = RtlCreateTagHeap (hHeap,0,L"HeapTag!",L"MyTag1");
                  tag2 = RtlCreateTagHeap (hHeap,0,L"HeapTag!",L"MyTag2"); 
                  tag3 = RtlCreateTagHeap (hHeap,0,L"HeapTag!",L"MyTag3");
                  tag4 = RtlCreateTagHeap (hHeap,0,L"HeapTag!",L"MyTag4");
              }
          }
          HANDLE DefHeap = GetProcessHeap();
          if ( (RtlCreateTagHeap != NULL)  && (DefHeap != NULL ))
          {
              tag5 = RtlCreateTagHeap (DefHeap,0,L"HeapTag!",L"MyTag5");
              for ( int i = 0; i < BUFFERSIZE ; i++ )
              {
                  pch[i]= (PCHAR) HeapAlloc( DefHeap,HEAP_ZERO_MEMORY| tag5, 1 );
                  HeapFree(DefHeap,NULL,pch[i]);
              }
      
          }
          if(hHeap)
          {
              for ( int i = 0; i < BUFFERSIZE ; i++ )
              {
                  pch[i]= (PCHAR) HeapAlloc( hHeap,HEAP_ZERO_MEMORY| tag1, 1 );
                  //lets leak all allocs patch ntdll to see the tagging details
                  //HeapFree(hHeap,NULL,pch[i]);
              }
              for ( int i = 0; i < BUFFERSIZE ; i++ )
              {
                  pch[i]= (PCHAR) HeapAlloc( hHeap,HEAP_ZERO_MEMORY| tag2, 100 );
                  // lets leak 40% allocs patch ntdll to see the tagging details
                  if(i >= 40)
                      HeapFree(hHeap,NULL,pch[i]);
              }
              // slightly less than 512 kb no tagging
              for ( int i = 0; i < BUFFERSIZE / 2 ; i++ ) 
              {
                  pch[i]= (PCHAR) HeapAlloc( 
                      hHeap,HEAP_ZERO_MEMORY| tag3, ALLOCSIZE / 2 );
              }
              // > 512 kb  default tagging 
              for ( int i = BUFFERSIZE / 2; i < BUFFERSIZE ; i++ ) 
              {
                  pch[i]= (PCHAR) HeapAlloc( 
                      hHeap,HEAP_ZERO_MEMORY | tag4 ,ALLOCSIZE );
              }
              for (int i =0 ; i < BUFFERSIZE ; i++)
              {
                  HeapFree(hHeap,NULL,pch[i]);
              }
          }
      }
      void _cdecl main()
      {
          HeapTagwithHeapAllocPrivate();
      }
      
      在系统断点上修补ntdll应使所有标记可见

      eb=写入字节 在退出时修补并运行exe检查带有标记的堆 cdb-c“eb 7c94b8a1+300;g;!heap*-t;q”newheaptag.exe|grep Tag

      heaptag:\>cdb -c "eb 7c94b8a1+3 00;g;!heap * -t;q" newheaptag.exe | grep Tag
       Tag  Name                   Allocs    Frees   Diff  Allocated
      0012: HeapTag!MyTag5            100      100      0        0  <-our tag in process heap
       Tag  Name                   Allocs    Frees   Diff  Allocated
       Tag  Name                   Allocs    Frees   Diff  Allocated
      0001: HeapTag!MyTag1            100        0    100     3200  <--- leak all
      0002: HeapTag!MyTag2            100       60     40     5120  <--- leak 40 %
      0003: HeapTag!MyTag3             50       50      0        0  <--- clean < 512 kB
      0004: HeapTag!MyTag4             50       50      0        0  <----clean > 512 kB
      
      heaptag:\>cdb-c“eb 7c94b8a1+3 00;g;!heap*-t;q”newheaptag.exe|grep标记
      标记名Allocs释放差异分配
      
      0012:希普塔!MyTag5 100 100 0 0对于较难的问题,可以等待更长的时间:-)我会继续尝试(Windows 7)。这个概念本身听起来没什么用处,因为有人需要提前考虑标记堆。通常我只在遇到问题的情况下才考虑堆标记。这个概念非常有用,您可以养成编写健壮代码的习惯:)在内核中,默认情况下,您必须这样做。。。。。ExAllocatePool已被弃用建议您使用ExAllocatePoolWithTag,因此您提前标记帮助程序使用的帮助程序在内核中为零。它在用户模式下进行了优化。如果您在任何os>xp上尝试,直到win 8.1(截至日期)后发回结果,则尚未进行优化
      heaptag:\>cdb -c "eb 7c94b8a1+3 00;g;!heap * -t;q" newheaptag.exe | grep Tag
       Tag  Name                   Allocs    Frees   Diff  Allocated
      0012: HeapTag!MyTag5            100      100      0        0  <-our tag in process heap
       Tag  Name                   Allocs    Frees   Diff  Allocated
       Tag  Name                   Allocs    Frees   Diff  Allocated
      0001: HeapTag!MyTag1            100        0    100     3200  <--- leak all
      0002: HeapTag!MyTag2            100       60     40     5120  <--- leak 40 %
      0003: HeapTag!MyTag3             50       50      0        0  <--- clean < 512 kB
      0004: HeapTag!MyTag4             50       50      0        0  <----clean > 512 kB