Как извлечь выгоду из кучи тегов DLL?


Как я могу использовать и извлекать выгоду из настройки GFlags включить тегирование кучи DLL ?

Я знаю, как активировать настройку для процесса, но я не нашел полезной информации в выводе !heap -t в WinDbg. Я ожидал получить такой результат:

0:000> !heap -t
Index   Address   Allocated by 
1:      005c0000  MyDll.dll
2:      006b0000  AnotherDll.dll

Таким образом, я могу определить, какая куча была создана какой DLL, а затем, например, определить источник утечки памяти.

Является ли это неправильным толкованием термина "пометка кучи DLL" или мне нужно еще что-то команды, чтобы получить желаемый результат?

Мои исследования до сих пор:

  • я погуглил учебник по этой теме, но не смог найти подробного описания
  • я читал Windbg'S .hh !heap, но там это тоже не объясняется подробно. Тег используется только в !heap -b
1 5

1 ответ:

Опять очень поздний ответ

Чтобы извлечь выгоду из HeapTagging you need to create a tag сначала в вашем коде.
насколько я знаю (то есть до xp-sp3) были no Documented APIS to Create a tag

(С тех пор я не сталкивался с кучей, поэтому я не знаю о последних API в os > vista перезаписи были сделаны в менеджере кучи, поэтому, вероятно, многие из ^^^features^^^, которые я публикую ниже, возможно, были исправлены или улучшены или удалены ошибки)

В XP-SP3, но вы можете использовать недокументированные RtlCreateTagHeap, чтобы создать новый тег либо Process Heap или Private Heap

И после того, как вы создадите тег tha, вам нужно установить глобальный флаг 8000 / 800

htg - Enable heap tagging
htd - Enable heap tagging by DLL

И theoratically all allocs and frees must get tagged.

Но practically only allocations > 512 kB gets tagged в xp-sp3 с этими основными шагами

Это либо ошибка, либо функция, ограничивающая выделение тегов и освобождающая > 512 кб
HeapAlloc goes through ZwAllocateVirtualMemory в случае выделения > 512 кб в 32-битном процессе refer HeapCreate / HeapAlloc Documentation in msdn

И в качестве debuging aid вы можете patch ntdll.dll на the fly to enable tagging для all Allocations and frees.

Ниже приведен пример кода, который демонстрирует тегирование и как просмотреть все это в windbg

Компиляция с использованием cl /Zi /analyze /W4 <src> /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();
}

Скомпилированный exe-файл для запуска с windbg, как показано ниже

Исполнение и проверка по умолчанию
**будет видно только 50 тегов, все они > 512 кб выделения

Cdb-c "g;!куча * - t; q " newheaptag.тег exe / grep**

heaptag:\>cdb -c "g;!heap * -t;q" newheaptag.exe | grep Tag
 Tag  Name                   Allocs    Frees   Diff  Allocated
 Tag  Name                   Allocs    Frees   Diff  Allocated
 Tag  Name                   Allocs    Frees   Diff  Allocated
0004: HeapTag!MyTag4             50       50      0        0

Исправление ntdll в системе точка останова должна сделать все теги видимыми

Eb = записать байт исправьте и запустите exe на выходе inspect heaps with tags cdb-c " eb 7c94b8a1+3 00; g;!куча * - t; q " newheaptag.тег exe / grep

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