Skip to content

Instantly share code, notes, and snippets.

@akkuman
Forked from reinsteam/enum_heaps.c
Created September 16, 2021 15:14
Show Gist options
  • Select an option

  • Save akkuman/cc552d6575ce73dafd2cfa4d417d606b to your computer and use it in GitHub Desktop.

Select an option

Save akkuman/cc552d6575ce73dafd2cfa4d417d606b to your computer and use it in GitHub Desktop.

Revisions

  1. @reinsteam reinsteam created this gist Aug 28, 2015.
    228 changes: 228 additions & 0 deletions enum_heaps.c
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,228 @@
    #ifndef WIN32_LEAN_AND_MEAN
    # define WIN32_LEAN_AND_MEAN
    #endif

    #pragma warning (push)
    /* 4820: '<struct-name>' : 'n' bytes padding added after data member '<member-name>'*/
    # pragma warning (disable : 4820)

    # include <windows.h>
    # include <stdio.h>
    # include <stdlib.h>
    #pragma warning (pop)

    typedef unsigned int u32;

    /*--------------------------------------------------------------------------------------------------------------------*/
    #define DYNAMIC_IMPORTED_FUNC(rval, func, ...)\
    typedef rval (WINAPI *tpfn_##func)(__VA_ARGS__); \
    static tpfn_##func pfn_##func = 0;

    #define DYNAMIC_SYSTEM_LOAD(lib, func)\
    ( ( pfn_##func = (tpfn_##func)dynamic_system_func_load(lib, #func) ) != 0 )

    #define CALL(func, ...)\
    pfn_##func(__VA_ARGS__)

    /*--------------------------------------------------------------------------------------------------------------------*/
    #ifdef __cplusplus
    # define INLINE __forceinline
    #else
    # define INLINE __inline
    #endif

    /* To prevent MSVC warning 4820 when compiling for x64 */
    #ifdef _WIN64
    # define EXPLICIT_PADDING(n, size) BYTE padding_##n[size]
    #else
    # define EXPLICIT_PADDING(n, size)
    #endif

    /*--------------------------------------------------------------------------------------------------------------------*/
    static INLINE FARPROC dynamic_system_func_load(const char * module, const char * func)
    {
    void * handle = GetModuleHandleA(module);

    if (handle == 0)
    {
    handle = LoadLibraryA(module);
    }

    if (handle != 0)
    {
    return GetProcAddress(handle, func);
    }
    return 0;
    }

    /*----------------------------------------------------------------------------------------------------------------------
    /* Helper structures to query debug heap info
    /*--------------------------------------------------------------------------------------------------------------------*/
    typedef struct _RTL_HEAP_TAG
    {
    ULONG NumberOfAllocations;
    ULONG NumberOfFrees;
    SIZE_T BytesAllocated;
    USHORT TagIndex;
    USHORT CreatorBackTraceIndex;
    WCHAR TagName[24];
    EXPLICIT_PADDING(0, 4);

    } RTL_HEAP_TAG, *PRTL_HEAP_TAG;

    typedef struct _RTL_HEAP_ENTRY
    {
    SIZE_T Size;
    USHORT Flags;
    USHORT AllocatorBackTraceIndex;

    EXPLICIT_PADDING(0, 4);

    union
    {
    struct
    {
    SIZE_T Settable;
    ULONG Tag;
    EXPLICIT_PADDING(1, 4);

    } s1;
    struct
    {
    SIZE_T CommitedSize;
    PVOID FirstBlock;
    } s2;
    } u;
    } RTL_HEAP_ENTRY, *PRTL_HEAP_ENTRY;

    typedef struct _RTL_DEBUG_HEAP_INFORMATION
    {
    PVOID BaseAddress;
    ULONG Flags;
    USHORT EntryOverhead;
    USHORT CreatorBackTraceIndex;
    SIZE_T BytesAllocated;
    SIZE_T BytesCommited;
    ULONG NumberOfTags;
    ULONG NumberOfEntries;
    ULONG NumberOfPseudoTags;
    ULONG PseudoTagGranularity;
    ULONG Reserved[5];
    EXPLICIT_PADDING(0, 4);
    PRTL_HEAP_TAG Tags;
    PRTL_HEAP_ENTRY Entries;

    } RTL_DEBUG_HEAP_INFORMATION, *PRTL_DEBUG_HEAP_INFORMATION;

    typedef struct _RTL_PROCESS_HEAPS
    {
    ULONG NumberOfHeaps;
    EXPLICIT_PADDING(0, 4);
    RTL_DEBUG_HEAP_INFORMATION Heaps[1];

    } RTL_PROCESS_HEAPS, *PRTL_PROCESS_HEAPS;

    typedef struct _RTL_DEBUG_INFORMATION
    {
    HANDLE SectionHandleClient;
    PVOID ViewBaseClient;
    PVOID ViewBaseTarget;
    ULONG_PTR ViewBaseDelta;
    HANDLE EventPairClient;
    HANDLE EventPairTarget;
    HANDLE TargetProcessId;
    HANDLE TargetThreadHandle;
    ULONG Flags;
    EXPLICIT_PADDING(0, 4);
    SIZE_T OffsetFree;
    SIZE_T CommitSize;
    SIZE_T ViewSize;
    union
    {
    PVOID Modules;
    PVOID ModulesEx;
    };
    PVOID BackTraces;
    struct _RTL_PROCESS_HEAPS *Heaps;
    PVOID Locks;
    PVOID SpecificHeap;
    HANDLE TargetProcessHandle;
    PVOID VerifierOptions;
    PVOID ProcessHeap;
    HANDLE CriticalSectionHandle;
    HANDLE CriticalSectionOwnerThread;
    PVOID Reserved[4];
    } RTL_DEBUG_INFORMATION, *PRTL_DEBUG_INFORMATION;

    typedef struct _RTL_HEAP_USAGE_ENTRY
    {
    struct _RTL_HEAP_USAGE_ENTRY * Next;
    PVOID Address;
    SIZE_T Size;
    USHORT AllocatorBackTraceIndex;
    USHORT TagIndex;
    EXPLICIT_PADDING(0, 4);
    } RTL_HEAP_USAGE_ENTRY, *PRTL_HEAP_USAGE_ENTRY;

    typedef enum DebugInfoClassMask
    {
    PDI_MODULES = 0x01,
    PDI_BACKTRACE = 0x02,
    PDI_HEAPS = 0x04,
    PDI_HEAP_TAGS = 0x08,
    PDI_HEAP_BLOCKS = 0x10,
    PDI_LOCKS = 0x20

    } DebugInfoClassMask;

    DYNAMIC_IMPORTED_FUNC(PRTL_DEBUG_INFORMATION, RtlCreateQueryDebugBuffer, u32, u32);
    DYNAMIC_IMPORTED_FUNC(u32, RtlDestroyQueryDebugBuffer, PRTL_DEBUG_INFORMATION);
    DYNAMIC_IMPORTED_FUNC(u32, RtlQueryProcessDebugInformation, u32, u32, PRTL_DEBUG_INFORMATION);

    int main(int argc, char ** argv)
    {
    u32 proc_id = 0;

    if (argc > 1)
    {
    proc_id = atoi(argv[1]);
    }

    u32 result = 1;

    result = result && DYNAMIC_SYSTEM_LOAD("ntdll.dll", RtlCreateQueryDebugBuffer);
    result = result && DYNAMIC_SYSTEM_LOAD("ntdll.dll", RtlDestroyQueryDebugBuffer);
    result = result && DYNAMIC_SYSTEM_LOAD("ntdll.dll", RtlQueryProcessDebugInformation);

    printf("---- Heap stats for PID : %u ---- \n", proc_id);

    if (result)
    {
    PRTL_DEBUG_INFORMATION buffer = CALL(RtlCreateQueryDebugBuffer, 0, 0);

    if (buffer)
    {
    u32 i;

    CALL(RtlQueryProcessDebugInformation, proc_id, PDI_HEAPS, buffer);

    PRTL_PROCESS_HEAPS prtl_heaps = buffer->Heaps;

    if (prtl_heaps != 0)
    {
    printf("---------------------------------------------------------------------------\n");
    printf("Heap # | Address | Commited | Allocated | Flags | \n");
    printf("---------------------------------------------------------------------------\n");

    for (i = 0; i < prtl_heaps->NumberOfHeaps; ++i)
    {
    PRTL_DEBUG_HEAP_INFORMATION heap = prtl_heaps->Heaps + i;

    printf("%6u | 0x%p | %9u bytes | %9u bytes | %#06x |\n", i, heap->BaseAddress, (u32)heap->BytesCommited, (u32)heap->BytesAllocated, heap->Flags);
    }
    }
    CALL(RtlDestroyQueryDebugBuffer, buffer);
    }
    }
    return 0;
    }