Windbg 如何从DLL的堆标记中获益?
我如何使用GFlags设置并从中受益 我知道如何激活进程的设置,但在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进行堆标记”的误解,还是我需要更多的
的输出中没有找到有用的信息!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