Rizin
unix-like reverse engineering framework and cli tools
windows_heap.c File Reference
#include <rz_windows.h>
#include <rz_core.h>
#include <TlHelp32.h>
#include <windows_heap.h>
#include "..\..\debug\p\native\maps\windows_maps.h"
#include "..\..\bin\pdb\pdb_downloader.h"
#include "..\..\bin\pdb\pdb.h"

Go to the source code of this file.

Classes

struct  _th_query_params
 

Macros

#define PDI_MODULES   0x01
 
#define PDI_HEAPS   0x04
 
#define PDI_HEAP_TAGS   0x08
 
#define PDI_HEAP_BLOCKS   0x10
 
#define PDI_HEAP_ENTRIES_EX   0x200
 
#define CHECK_INFO(heapInfo)
 
#define CHECK_INFO_RETURN_NULL(heapInfo)
 
#define UPDATE_FLAGS(hb, flags)
 
#define GROW_BLOCKS()
 
#define GROW_PBLOCKS()
 

Typedefs

typedef struct _th_query_params th_query_params
 

Functions

static bool __is_windows_ten (void)
 
static char * get_type (WPARAM flags)
 
static bool initialize_windows_ntdll_query_api_functions (void)
 
static bool is_segment_heap (HANDLE h_proc, PVOID heapBase)
 
static bool GetFirstHeapBlock (PDEBUG_HEAP_INFORMATION heapInfo, PHeapBlock hb)
 
static bool GetNextHeapBlock (PDEBUG_HEAP_INFORMATION heapInfo, PHeapBlock hb)
 
static void free_extra_info (PDEBUG_HEAP_INFORMATION heap)
 
static bool has_heap_globals (void)
 
static bool GetHeapGlobalsOffset (RzDebug *dbg, HANDLE h_proc)
 
static bool GetLFHKey (RzDebug *dbg, HANDLE h_proc, bool segment, WPARAM *lfhKey)
 
static bool DecodeHeapEntry (RzDebug *dbg, PHEAP heap, PHEAP_ENTRY entry)
 
static bool DecodeLFHEntry (RzDebug *dbg, PHEAP heap, PHEAP_ENTRY entry, PHEAP_USERDATA_HEADER userBlocks, WPARAM key, WPARAM addr)
 
static DWORD WINAPI __th_QueryDebugBuffer (void *param)
 
static RzListGetListOfHeaps (RzDebug *dbg, HANDLE ph)
 
static PDEBUG_BUFFER InitHeapInfo (RzDebug *dbg, DWORD mask)
 
static bool __lfh_segment_loop (HANDLE h_proc, PHeapBlockBasicInfo *blocks, SIZE_T *allocated, WPARAM lfhKey, WPARAM *count, WPARAM first, WPARAM next)
 
static bool GetSegmentHeapBlocks (RzDebug *dbg, HANDLE h_proc, PVOID heapBase, PHeapBlockBasicInfo *blocks, WPARAM *count, SIZE_T *allocated)
 
static PDEBUG_BUFFER GetHeapBlocks (DWORD pid, RzDebug *dbg)
 
static PHeapBlock GetSingleSegmentBlock (RzDebug *dbg, HANDLE h_proc, PSEGMENT_HEAP heapBase, WPARAM offset)
 
static PHeapBlock GetSingleBlock (RzDebug *dbg, ut64 offset)
 
static RzTable__new_heapblock_tbl (void)
 
RZ_IPI void rz_heap_list_w32 (RzCore *core, RzOutputMode mode)
 
static void w32_list_heaps_blocks (RzCore *core, RzOutputMode mode, bool flag)
 
RZ_IPI void rz_heap_debug_block_win (RzCore *core, const char *addr, RzOutputMode mode, bool flag)
 
RZ_IPI RzListrz_heap_blocks_list (RzCore *core)
 
RZ_IPI RzListrz_heap_list (RzCore *core)
 

Variables

static size_t RtlpHpHeapGlobalsOffset = 0
 
static size_t RtlpLFHKeyOffset = 0
 

Macro Definition Documentation

◆ CHECK_INFO

#define CHECK_INFO (   heapInfo)
Value:
if (!heapInfo) { \
eprintf("It wasn't possible to get the heap information\n"); \
return; \
} \
if (!heapInfo->count) { \
rz_cons_print("No heaps for this process\n"); \
return; \
}

Definition at line 61 of file windows_heap.c.

◆ CHECK_INFO_RETURN_NULL

#define CHECK_INFO_RETURN_NULL (   heapInfo)
Value:
if (!heapInfo) { \
eprintf("It wasn't possible to get the heap information\n"); \
return NULL; \
} \
if (!heapInfo->count) { \
rz_cons_print("No heaps for this process\n"); \
return NULL; \
}
#define NULL
Definition: cris-opc.c:27

Definition at line 71 of file windows_heap.c.

◆ GROW_BLOCKS

#define GROW_BLOCKS ( )
Value:
if (allocated <= count * sizeof(HeapBlockBasicInfo)) { \
SIZE_T old_alloc = allocated; \
allocated *= 2; \
PVOID tmp = blocks; \
blocks = realloc(blocks, allocated); \
if (!blocks) { \
blocks = tmp; \
goto err; \
} \
memset((BYTE *)blocks + old_alloc, 0, old_alloc); \
}
static bool err
Definition: armass.c:435
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void count
Definition: sflib.h:98
void * realloc(void *ptr, size_t size)
Definition: malloc.c:144
unsigned char BYTE
Definition: lz4.c:286
uint64_t blocks
Definition: list.c:104

Definition at line 579 of file windows_heap.c.

◆ GROW_PBLOCKS

#define GROW_PBLOCKS ( )
Value:
if (*allocated <= *count * sizeof(HeapBlockBasicInfo)) { \
SIZE_T old_alloc = *allocated; \
*allocated *= 2; \
PVOID tmp = *blocks; \
tmp = realloc(*blocks, *allocated); \
if (!tmp) { \
return false; \
} \
*blocks = tmp; \
memset((BYTE *)(*blocks) + old_alloc, 0, old_alloc); \
}

Definition at line 592 of file windows_heap.c.

◆ PDI_HEAP_BLOCKS

#define PDI_HEAP_BLOCKS   0x10

Definition at line 55 of file windows_heap.c.

◆ PDI_HEAP_ENTRIES_EX

#define PDI_HEAP_ENTRIES_EX   0x200

Definition at line 56 of file windows_heap.c.

◆ PDI_HEAP_TAGS

#define PDI_HEAP_TAGS   0x08

Definition at line 54 of file windows_heap.c.

◆ PDI_HEAPS

#define PDI_HEAPS   0x04

Definition at line 53 of file windows_heap.c.

◆ PDI_MODULES

#define PDI_MODULES   0x01

Definition at line 52 of file windows_heap.c.

◆ UPDATE_FLAGS

#define UPDATE_FLAGS (   hb,
  flags 
)
Value:
if (((flags)&0xf1) || ((flags)&0x0200)) { \
hb->dwFlags = LF32_FIXED; \
} else if ((flags)&0x20) { \
hb->dwFlags = LF32_MOVEABLE; \
} else if ((flags)&0x0100) { \
hb->dwFlags = LF32_FREE; \
} \
hb->dwFlags |= ((flags) >> SHIFT) << SHIFT;
#define SHIFT(state_value)
Definition: parser.h:175
static struct sockaddr static addrlen static backlog const void static flags void flags
Definition: sfsocketcall.h:123

Definition at line 81 of file windows_heap.c.

Typedef Documentation

◆ th_query_params

Function Documentation

◆ __is_windows_ten()

static bool __is_windows_ten ( void  )
static

Definition at line 91 of file windows_heap.c.

91  {
92  int major = 0;
94  if (info && info->version) {
95  char *dot = strchr(info->version, '.');
96  if (dot) {
97  *dot = '\0';
98  major = atoi(info->version);
99  }
100  }
102  return major == 10;
103 }
RzBinInfo * info(RzBinFile *bf)
Definition: bin_ne.c:86
#define major(dev)
Definition: fsmagic.c:56
RZ_API void rz_sys_info_free(RSysInfo *si)
Definition: sys.c:1251
RZ_API RSysInfo * rz_sys_info(void)
Definition: sys.c:1175

References info(), major, rz_sys_info(), and rz_sys_info_free().

Referenced by InitHeapInfo(), rz_heap_blocks_list(), rz_heap_list(), rz_heap_list_w32(), and w32_list_heaps_blocks().

◆ __lfh_segment_loop()

static bool __lfh_segment_loop ( HANDLE  h_proc,
PHeapBlockBasicInfo blocks,
SIZE_T *  allocated,
WPARAM  lfhKey,
WPARAM *  count,
WPARAM  first,
WPARAM  next 
)
static

Definition at line 605 of file windows_heap.c.

605  {
606  while ((first != next) && next) {
607  HEAP_LFH_SUBSEGMENT subsegment;
608  ReadProcessMemory(h_proc, (void *)next, &subsegment, sizeof(HEAP_LFH_SUBSEGMENT), NULL);
609  subsegment.BlockOffsets.EncodedData ^= (DWORD)lfhKey ^ ((DWORD)next >> 0xC);
610  WPARAM mask = 1, offset = 0;
611  int l;
612  for (l = 0; l < subsegment.BlockCount; l++) {
613  if (!mask) {
614  mask = 1;
615  offset++;
616  ReadProcessMemory(h_proc, (WPARAM *)(next + offsetof(HEAP_LFH_SUBSEGMENT, BlockBitmap)) + offset,
617  &subsegment.BlockBitmap, sizeof(WPARAM), NULL);
618  }
619  if (subsegment.BlockBitmap[0] & mask) {
620  GROW_PBLOCKS();
621  WPARAM off = (WPARAM)subsegment.BlockOffsets.FirstBlockOffset + l * (WPARAM)subsegment.BlockOffsets.BlockSize;
622  (*blocks)[*count].address = next + off;
623  (*blocks)[*count].size = subsegment.BlockOffsets.BlockSize;
624  (*blocks)[*count].flags = 1 | SEGMENT_HEAP_BLOCK | LFH_BLOCK;
626  if (!extra) {
627  return false;
628  }
629  extra->segment = next;
630  extra->granularity = sizeof(HEAP_ENTRY);
631  (*blocks)[*count].extra = EXTRA_FLAG | (WPARAM)extra;
632  *count += 1;
633  }
634  mask <<= 2;
635  }
636  next = (WPARAM)subsegment.ListEntry.Flink;
637  }
638  return true;
639 }
#define mask()
voidpf uLong offset
Definition: ioapi.h:144
#define offsetof(type, member)
int off
Definition: pal.c:13
#define RZ_NEW0(x)
Definition: rz_types.h:284
HEAP_LFH_SUBSEGMENT_ENCODED_OFFSETS BlockOffsets
Definition: windows_heap.h:537
DWORD
#define GROW_PBLOCKS()
Definition: windows_heap.c:592
#define SEGMENT_HEAP_BLOCK
Definition: windows_heap.h:34
#define LFH_BLOCK
Definition: windows_heap.h:31
#define EXTRA_FLAG
Definition: windows_heap.h:28
struct _HEAP_ENTRY HEAP_ENTRY

References _HEAP_LFH_SUBSEGMENT::BlockBitmap, _HEAP_LFH_SUBSEGMENT::BlockCount, _HEAP_LFH_SUBSEGMENT::BlockOffsets, _HEAP_LFH_SUBSEGMENT_ENCODED_OFFSETS::BlockSize, count, DWORD, _HEAP_LFH_SUBSEGMENT_ENCODED_OFFSETS::EncodedData, EXTRA_FLAG, _HEAP_LFH_SUBSEGMENT_ENCODED_OFFSETS::FirstBlockOffset, _HeapBlockExtraInfo::granularity, GROW_PBLOCKS, LFH_BLOCK, _HEAP_LFH_SUBSEGMENT::ListEntry, mask, NULL, off, offsetof, RZ_NEW0, _HeapBlockExtraInfo::segment, and SEGMENT_HEAP_BLOCK.

Referenced by GetSegmentHeapBlocks().

◆ __new_heapblock_tbl()

static RzTable* __new_heapblock_tbl ( void  )
static

Definition at line 1226 of file windows_heap.c.

1226  {
1227  RzTable *tbl = rz_table_new();
1228  rz_table_add_column(tbl, rz_table_type("number"), "HeaderAddress", -1);
1229  rz_table_add_column(tbl, rz_table_type("number"), "UserAddress", -1);
1230  rz_table_add_column(tbl, rz_table_type("number"), "Size", -1);
1231  rz_table_add_column(tbl, rz_table_type("number"), "Granularity", -1);
1232  rz_table_add_column(tbl, rz_table_type("number"), "Unused", -1);
1233  rz_table_add_column(tbl, rz_table_type("String"), "Type", -1);
1234  return tbl;
1235 }
RZ_API void rz_table_add_column(RzTable *t, RzTableColumnType *type, const char *name, int maxWidth)
Definition: table.c:134
RZ_API RzTable * rz_table_new(void)
Definition: table.c:103
RZ_API RzTableColumnType * rz_table_type(const char *name)
Definition: table.c:24

References rz_table_add_column(), rz_table_new(), and rz_table_type().

Referenced by rz_heap_debug_block_win(), and w32_list_heaps_blocks().

◆ __th_QueryDebugBuffer()

static DWORD WINAPI __th_QueryDebugBuffer ( void *  param)
static

Definition at line 451 of file windows_heap.c.

451  {
452  th_query_params *params = (th_query_params *)param;
453  params->ret = RtlQueryProcessDebugInformation(params->dbg->pid, params->mask, params->db);
454  params->fin = true;
455  if (params->hanged) {
456  RtlDestroyQueryDebugBuffer(params->db);
457  free(params);
458  }
459  return 0;
460 }
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
PDEBUG_BUFFER db
Definition: windows_heap.c:445

References _th_query_params::db, _th_query_params::dbg, _th_query_params::fin, free(), _th_query_params::hanged, _th_query_params::mask, rz_debug_t::pid, and _th_query_params::ret.

Referenced by InitHeapInfo().

◆ DecodeHeapEntry()

static bool DecodeHeapEntry ( RzDebug dbg,
PHEAP  heap,
PHEAP_ENTRY  entry 
)
static

Definition at line 416 of file windows_heap.c.

416  {
417  rz_return_val_if_fail(heap && entry, false);
418  if (dbg->bits == RZ_SYS_BITS_64) {
419  entry = (PHEAP_ENTRY)((ut8 *)entry + dbg->bits);
420  }
421  if (heap->EncodeFlagMask && (*(UINT32 *)entry & heap->EncodeFlagMask)) {
422  if (dbg->bits == RZ_SYS_BITS_64) {
423  heap = (PHEAP)((ut8 *)heap + dbg->bits);
424  }
425  *(WPARAM *)entry ^= *(WPARAM *)&heap->Encoding;
426  }
427  return !(((BYTE *)entry)[0] ^ ((BYTE *)entry)[1] ^ ((BYTE *)entry)[2] ^ ((BYTE *)entry)[3]);
428 }
RzDebug * dbg
Definition: desil.c:30
uint8_t ut8
Definition: lh5801.h:11
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
@ RZ_SYS_BITS_64
Definition: rz_sys.h:21
Definition: zipcmp.c:77
Definition: heap-inl.h:40
int bits
Definition: rz_debug.h:243
struct _HEAP_ENTRY * PHEAP_ENTRY
struct _HEAP * PHEAP
Definition: windows_heap.h:41

References rz_debug_t::bits, dbg, rz_return_val_if_fail, and RZ_SYS_BITS_64.

Referenced by GetHeapBlocks(), and GetSingleBlock().

◆ DecodeLFHEntry()

static bool DecodeLFHEntry ( RzDebug dbg,
PHEAP  heap,
PHEAP_ENTRY  entry,
PHEAP_USERDATA_HEADER  userBlocks,
WPARAM  key,
WPARAM  addr 
)
static

Definition at line 430 of file windows_heap.c.

430  {
431  rz_return_val_if_fail(heap && entry, false);
432  if (dbg->bits == RZ_SYS_BITS_64) {
433  entry = (PHEAP_ENTRY)((ut8 *)entry + dbg->bits);
434  }
435 
436  if (heap->EncodeFlagMask) {
437  *(DWORD *)entry ^= PtrToInt(heap->BaseAddress) ^ (DWORD)(((DWORD)addr - PtrToInt(userBlocks)) << 0xC) ^ (DWORD)key ^ (addr >> 4);
438  }
439  return !(((BYTE *)entry)[0] ^ ((BYTE *)entry)[1] ^ ((BYTE *)entry)[2] ^ ((BYTE *)entry)[3]);
440 }
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len key
Definition: sflib.h:118
static int addr
Definition: z80asm.c:58

References addr, rz_debug_t::bits, dbg, DWORD, key, rz_return_val_if_fail, and RZ_SYS_BITS_64.

Referenced by GetHeapBlocks(), and GetSingleBlock().

◆ free_extra_info()

static void free_extra_info ( PDEBUG_HEAP_INFORMATION  heap)
static

Definition at line 257 of file windows_heap.c.

257  {
259  HeapBlock hb;
260  if (GetFirstHeapBlock(heap, &hb)) {
261  do {
262  RZ_FREE(hb.extraInfo);
263  } while (GetNextHeapBlock(heap, &hb));
264  }
265 }
#define rz_return_if_fail(expr)
Definition: rz_assert.h:100
#define RZ_FREE(x)
Definition: rz_types.h:369
PHeapBlockExtraInfo extraInfo
Definition: windows_heap.h:943
static bool GetNextHeapBlock(PDEBUG_HEAP_INFORMATION heapInfo, PHeapBlock hb)
Definition: windows_heap.c:208
static bool GetFirstHeapBlock(PDEBUG_HEAP_INFORMATION heapInfo, PHeapBlock hb)
Definition: windows_heap.c:168

References _HeapBlock::extraInfo, GetFirstHeapBlock(), GetNextHeapBlock(), RZ_FREE, and rz_return_if_fail.

Referenced by GetHeapBlocks(), rz_heap_blocks_list(), rz_heap_list(), rz_heap_list_w32(), and w32_list_heaps_blocks().

◆ get_type()

static char* get_type ( WPARAM  flags)
static

Definition at line 105 of file windows_heap.c.

105  {
106  char *state = "";
107  switch (flags & 0xFFFF) {
108  case LF32_FIXED:
109  state = "(FIXED)";
110  break;
111  case LF32_FREE:
112  state = "(FREE)";
113  break;
114  case LF32_MOVEABLE:
115  state = "(MOVEABLE)";
116  break;
117  }
118  char *heaptype = "";
119  if (flags & SEGMENT_HEAP_BLOCK) {
120  heaptype = "Segment";
121  } else if (flags & NT_BLOCK) {
122  heaptype = "NT";
123  }
124  char *type = "";
125  if (flags & LFH_BLOCK) {
126  type = "/LFH";
127  } else if (flags & LARGE_BLOCK) {
128  type = "/LARGE";
129  } else if (flags & BACKEND_BLOCK) {
130  type = "/BACKEND";
131  } else if (flags & VS_BLOCK) {
132  type = "/VS";
133  }
134  return rz_str_newf("%s %s%s", state, heaptype, type);
135 }
int type
Definition: mipsasm.c:17
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
Definition: dis.h:43
#define VS_BLOCK
Definition: windows_heap.h:35
#define LARGE_BLOCK
Definition: windows_heap.h:32
#define BACKEND_BLOCK
Definition: windows_heap.h:36
#define NT_BLOCK
Definition: windows_heap.h:33

References BACKEND_BLOCK, flags, LARGE_BLOCK, LFH_BLOCK, NT_BLOCK, rz_str_newf(), SEGMENT_HEAP_BLOCK, type, and VS_BLOCK.

Referenced by rz_heap_blocks_list(), rz_heap_debug_block_win(), and w32_list_heaps_blocks().

◆ GetFirstHeapBlock()

static bool GetFirstHeapBlock ( PDEBUG_HEAP_INFORMATION  heapInfo,
PHeapBlock  hb 
)
static

Definition at line 168 of file windows_heap.c.

168  {
169  rz_return_val_if_fail(heapInfo && hb, false);
170  PHeapBlockBasicInfo block;
171 
172  hb->index = 0;
173  hb->dwAddress = 0;
174  hb->dwFlags = 0;
175  hb->extraInfo = NULL;
176 
177  block = (PHeapBlockBasicInfo)heapInfo->Blocks;
178  if (!block) {
179  return false;
180  }
181 
182  SIZE_T index = hb->index;
183  do {
184  if (index > heapInfo->BlockCount) {
185  return false;
186  }
187  hb->dwAddress = block[index].address;
188  hb->dwSize = block->size;
189  if (block[index].extra & EXTRA_FLAG) {
190  PHeapBlockExtraInfo extra = (PHeapBlockExtraInfo)(block[index].extra & ~EXTRA_FLAG);
191  hb->dwSize -= extra->unusedBytes;
192  hb->extraInfo = extra;
193  hb->dwAddress = (WPARAM)hb->dwAddress + extra->granularity;
194  } else {
195  hb->dwAddress = (WPARAM)hb->dwAddress + heapInfo->Granularity;
196  hb->extraInfo = NULL;
197  }
198  index++;
199  } while (block[index].flags & 2);
200 
201  WPARAM flags = block[hb->index].flags;
202  UPDATE_FLAGS(hb, flags);
203 
204  hb->index = index;
205  return true;
206 }
ULONG_PTR dwAddress
Definition: windows_heap.h:939
SIZE_T index
Definition: windows_heap.h:942
DWORD dwFlags
Definition: windows_heap.h:941
SIZE_T dwSize
Definition: windows_heap.h:940
if(dbg->bits==RZ_SYS_BITS_64)
Definition: windows-arm64.h:4
#define UPDATE_FLAGS(hb, flags)
Definition: windows_heap.c:81
struct _HeapBlockExtraInfo * PHeapBlockExtraInfo
struct _HeapBlockBasicInfo * PHeapBlockBasicInfo

References _HeapBlockBasicInfo::address, _DEBUG_HEAP_INFORMATION::BlockCount, _DEBUG_HEAP_INFORMATION::Blocks, _HeapBlock::dwAddress, _HeapBlock::dwFlags, _HeapBlock::dwSize, EXTRA_FLAG, _HeapBlock::extraInfo, flags, _HeapBlockBasicInfo::flags, _HeapBlockExtraInfo::granularity, _DEBUG_HEAP_INFORMATION::Granularity, if(), _HeapBlock::index, NULL, rz_return_val_if_fail, _HeapBlockBasicInfo::size, _HeapBlockExtraInfo::unusedBytes, and UPDATE_FLAGS.

Referenced by free_extra_info(), rz_heap_blocks_list(), and w32_list_heaps_blocks().

◆ GetHeapBlocks()

static PDEBUG_BUFFER GetHeapBlocks ( DWORD  pid,
RzDebug dbg 
)
static

Definition at line 780 of file windows_heap.c.

780  {
781  // TODO:
782  // - Break this behemoth
783  // - x86 vs x64 vs WOW64 (use dbg->bits or new structs or just a big union with both versions)
784 #if defined(_M_X64)
785  if (dbg->bits == RZ_SYS_BITS_32) {
786  return NULL; // Nope nope nope
787  }
788 #endif
789  WPARAM bytesRead;
790  HANDLE h_proc = NULL;
792  if (!db || !db->HeapInformation) {
793  RZ_LOG_ERROR("InitHeapInfo Failed\n");
794  goto err;
795  }
796  h_proc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
797  if (!h_proc) {
798  RZ_LOG_ERROR("OpenProcess failed\n");
799  goto err;
800  }
801 
802  WPARAM lfhKey;
803  if (!GetLFHKey(dbg, h_proc, false, &lfhKey)) {
804  RtlDestroyQueryDebugBuffer(db);
805  CloseHandle(h_proc);
806  eprintf("GetHeapBlocks: Failed to get LFH key.\n");
807  return NULL;
808  }
809 
810  PHeapInformation heapInfo = db->HeapInformation;
811  int i;
812  for (i = 0; i < heapInfo->count; i++) {
813  WPARAM from = 0;
814  ut64 count = 0;
815  PDEBUG_HEAP_INFORMATION heap = &heapInfo->heaps[i];
816  HEAP_ENTRY heapEntry;
817  HEAP heapHeader;
818  const SIZE_T sz_entry = sizeof(HEAP_ENTRY);
819  ReadProcessMemory(h_proc, heap->Base, &heapHeader, sizeof(HEAP), &bytesRead);
820 
821  SIZE_T allocated = 128 * sizeof(HeapBlockBasicInfo);
822  PHeapBlockBasicInfo blocks = calloc(allocated, 1);
823  if (!blocks) {
824  RZ_LOG_ERROR("Memory Allocation failed\n");
825  goto err;
826  }
827 
828  // SEGMENT_HEAP
829  if (heapHeader.SegmentSignature == 0xddeeddee) {
830  bool ret = GetSegmentHeapBlocks(dbg, h_proc, heap->Base, &blocks, &count, &allocated);
831  heap->Blocks = blocks;
832  heap->BlockCount = count;
833  if (!ret) {
834  goto err;
835  }
836  continue;
837  }
838 
839  // VirtualAlloc'd blocks
840  PLIST_ENTRY fentry = (PVOID)((WPARAM)heapHeader.BaseAddress + offsetof(HEAP, VirtualAllocdBlocks));
841  PLIST_ENTRY entry = heapHeader.VirtualAllocdBlocks.Flink;
842  while (entry && (entry != fentry)) {
844  ReadProcessMemory(h_proc, entry, &vAlloc, sizeof(HEAP_VIRTUAL_ALLOC_ENTRY), &bytesRead);
845  DecodeHeapEntry(dbg, &heapHeader, &vAlloc.BusyBlock);
846  GROW_BLOCKS();
847  blocks[count].address = (WPARAM)entry;
848  blocks[count].flags = 1 | ((vAlloc.BusyBlock.Flags | NT_BLOCK | LARGE_BLOCK) & ~2ULL);
849  blocks[count].size = vAlloc.ReserveSize;
851  if (!extra) {
852  goto err;
853  }
854  extra->granularity = sizeof(HEAP_VIRTUAL_ALLOC_ENTRY);
855  extra->unusedBytes = vAlloc.ReserveSize - vAlloc.CommitSize;
856  blocks[count].extra = EXTRA_FLAG | (WPARAM)extra;
857  count++;
858  entry = vAlloc.Entry.Flink;
859  }
860 
861  // LFH Activated
862  if (heapHeader.FrontEndHeap && heapHeader.FrontEndHeapType == 0x2) {
863  LFH_HEAP lfhHeader;
864  if (!ReadProcessMemory(h_proc, heapHeader.FrontEndHeap, &lfhHeader, sizeof(LFH_HEAP), &bytesRead)) {
865  rz_sys_perror("ReadProcessMemory");
866  goto err;
867  }
868 
869  PLIST_ENTRY curEntry, firstEntry = (PVOID)((WPARAM)heapHeader.FrontEndHeap + offsetof(LFH_HEAP, SubSegmentZones));
870  curEntry = lfhHeader.SubSegmentZones.Flink;
871 
872  // Loops through all _HEAP_SUBSEGMENTs
873  do { // (curEntry != firstEntry)
875  HEAP_LOCAL_DATA localData;
876  HEAP_SUBSEGMENT subsegment;
877  HEAP_USERDATA_HEADER userdata;
878  LFH_BLOCK_ZONE blockZone;
879 
880  WPARAM curSubsegment = (WPARAM)(curEntry + 2);
881  int next = 0;
882  do { // (next < blockZone.NextIndex)
883  if (!ReadProcessMemory(h_proc, (PVOID)curSubsegment, &subsegment, sizeof(HEAP_SUBSEGMENT), &bytesRead) || !subsegment.BlockSize || !ReadProcessMemory(h_proc, subsegment.LocalInfo, &info, sizeof(HEAP_LOCAL_SEGMENT_INFO), &bytesRead) || !ReadProcessMemory(h_proc, info.LocalData, &localData, sizeof(HEAP_LOCAL_DATA), &bytesRead) || !ReadProcessMemory(h_proc, localData.CrtZone, &blockZone, sizeof(LFH_BLOCK_ZONE), &bytesRead)) {
884  break;
885  }
886 
887  if (!subsegment.UserBlocks || !subsegment.BlockSize) {
888  goto next_subsegment;
889  }
890 
891  size_t sz = subsegment.BlockSize * sizeof(HEAP_ENTRY);
892  ReadProcessMemory(h_proc, subsegment.UserBlocks, &userdata, sizeof(HEAP_USERDATA_HEADER), &bytesRead);
893  userdata.EncodedOffsets.StrideAndOffset ^= PtrToInt(subsegment.UserBlocks) ^ PtrToInt(heapHeader.FrontEndHeap) ^ (WPARAM)lfhKey;
894  size_t bitmapsz = (userdata.BusyBitmap.SizeOfBitMap + 8 - userdata.BusyBitmap.SizeOfBitMap % 8) / 8;
895  WPARAM *bitmap = calloc(bitmapsz > sizeof(WPARAM) ? bitmapsz : sizeof(WPARAM), 1);
896  if (!bitmap) {
897  goto err;
898  }
899  ReadProcessMemory(h_proc, userdata.BusyBitmap.Buffer, bitmap, bitmapsz, &bytesRead);
900  WPARAM mask = 1;
901  // Walk through the busy bitmap
902  int j;
903  size_t offset;
904  for (j = 0, offset = 0; j < userdata.BusyBitmap.SizeOfBitMap; j++) {
905  if (!mask) {
906  mask = 1;
907  offset++;
908  }
909  // Only if block is busy
910  if (*(bitmap + offset) & mask) {
911  GROW_BLOCKS();
912  WPARAM off = userdata.EncodedOffsets.FirstAllocationOffset + sz * j;
913  from = (WPARAM)subsegment.UserBlocks + off;
914  ReadProcessMemory(h_proc, (PVOID)from, &heapEntry, sz_entry, &bytesRead);
915  DecodeLFHEntry(dbg, &heapHeader, &heapEntry, subsegment.UserBlocks, lfhKey, from);
916  blocks[count].address = from;
917  blocks[count].flags = 1 | NT_BLOCK | LFH_BLOCK;
918  blocks[count].size = sz;
920  if (!extra) {
921  goto err;
922  }
923  extra->granularity = sizeof(HEAP_ENTRY);
924  extra->segment = curSubsegment;
925  blocks[count].extra = EXTRA_FLAG | (WPARAM)extra;
926  count++;
927  }
928  mask <<= 1;
929  }
930  free(bitmap);
931  next_subsegment:
932  curSubsegment += sizeof(HEAP_SUBSEGMENT);
933  next++;
934  } while (next < blockZone.NextIndex || subsegment.BlockSize);
935 
936  LIST_ENTRY entry;
937  ReadProcessMemory(h_proc, curEntry, &entry, sizeof(entry), &bytesRead);
938  curEntry = entry.Flink;
939  } while (curEntry != firstEntry);
940  }
941 
942  HEAP_SEGMENT oldSegment, segment;
943  WPARAM firstSegment = (WPARAM)heapHeader.SegmentList.Flink;
944  ReadProcessMemory(h_proc, (PVOID)(firstSegment - offsetof(HEAP_SEGMENT, SegmentListEntry)), &segment, sizeof(HEAP_SEGMENT), &bytesRead);
945  // NT Blocks (Loops through all _HEAP_SEGMENTs)
946  do {
947  from = (WPARAM)segment.FirstEntry;
948  if (!from) {
949  goto next;
950  }
951  do {
952  if (!ReadProcessMemory(h_proc, (PVOID)from, &heapEntry, sz_entry, &bytesRead)) {
953  break;
954  }
955  DecodeHeapEntry(dbg, &heapHeader, &heapEntry);
956  if (!heapEntry.Size) {
957  // Last Heap block
958  count--;
959  break;
960  }
961 
962  SIZE_T real_sz = heapEntry.Size * sz_entry;
963 
964  GROW_BLOCKS();
966  if (!extra) {
967  goto err;
968  }
969  extra->granularity = sizeof(HEAP_ENTRY);
970  extra->segment = (WPARAM)segment.BaseAddress;
971  blocks[count].extra = EXTRA_FLAG | (WPARAM)extra;
972  blocks[count].address = from;
973  blocks[count].flags = heapEntry.Flags | NT_BLOCK | BACKEND_BLOCK;
974  blocks[count].size = real_sz;
975  from += real_sz;
976  count++;
977  } while (from <= (WPARAM)segment.LastValidEntry);
978  next:
979  oldSegment = segment;
980  from = (WPARAM)segment.SegmentListEntry.Flink - offsetof(HEAP_SEGMENT, SegmentListEntry);
981  ReadProcessMemory(h_proc, (PVOID)from, &segment, sizeof(HEAP_SEGMENT), &bytesRead);
982  } while ((WPARAM)oldSegment.SegmentListEntry.Flink != firstSegment);
983  heap->Blocks = blocks;
984  heap->BlockCount = count;
985 
986  if (!heap->Committed && !heap->Allocated) {
987  heap->Committed = heapHeader.Counters.TotalMemoryCommitted;
988  heap->Allocated = heapHeader.Counters.LastPolledSize;
989  }
990  }
991  CloseHandle(h_proc);
992  return db;
993 err:
994  if (h_proc) {
995  CloseHandle(h_proc);
996  }
997  if (db) {
998  int i;
999  for (i = 0; i < heapInfo->count; i++) {
1000  PDEBUG_HEAP_INFORMATION heap = &heapInfo->heaps[i];
1002  RZ_FREE(heap->Blocks);
1003  }
1004  RtlDestroyQueryDebugBuffer(db);
1005  }
1006  return NULL;
1007 }
lzma_index ** i
Definition: index.h:629
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
static static fork const void static count static fd const char const char static newpath char char char static envp time_t static t const char static mode static whence const char static dir time_t static t unsigned static seconds const char struct utimbuf static buf static inc pid
Definition: sflib.h:64
#define FALSE
Definition: mybfd.h:102
#define eprintf(x, y...)
Definition: rlcc.c:7
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
@ RZ_SYS_BITS_32
Definition: rz_sys.h:20
#define rz_sys_perror(x)
Definition: rz_types.h:336
static struct sockaddr static addrlen static backlog const void static flags void struct sockaddr from
Definition: sfsocketcall.h:123
PVOID HeapInformation
Definition: windows_heap.h:961
WPARAM TotalMemoryCommitted
Definition: windows_heap.h:69
WPARAM LastPolledSize
Definition: windows_heap.h:90
Definition: windows_heap.h:168
UINT8 Flags
Definition: windows_heap.h:193
PLFH_BLOCK_ZONE CrtZone
Definition: windows_heap.h:864
LIST_ENTRY SegmentListEntry
Definition: windows_heap.h:638
PHEAP_ENTRY LastValidEntry
Definition: windows_heap.h:646
PHEAP_ENTRY FirstEntry
Definition: windows_heap.h:645
RTL_BITMAP_EX BusyBitmap
Definition: windows_heap.h:814
HEAP_USERDATA_OFFSETS EncodedOffsets
Definition: windows_heap.h:813
Definition: windows_heap.h:766
LIST_ENTRY Entry
Definition: windows_heap.h:767
HEAP_ENTRY BusyBlock
Definition: windows_heap.h:771
WPARAM ReserveSize
Definition: windows_heap.h:770
WPARAM CommitSize
Definition: windows_heap.h:769
HEAP_COUNTERS Counters
Definition: windows_heap.h:741
ULONG32 SegmentSignature
Definition: windows_heap.h:662
LIST_ENTRY VirtualAllocdBlocks
Definition: windows_heap.h:709
PVOID BaseAddress
Definition: windows_heap.h:666
LIST_ENTRY SegmentList
Definition: windows_heap.h:710
UINT8 FrontEndHeapType
Definition: windows_heap.h:724
PVOID FrontEndHeap
Definition: windows_heap.h:722
DEBUG_HEAP_INFORMATION heaps[]
Definition: windows_heap.h:991
LIST_ENTRY SubSegmentZones
Definition: windows_heap.h:904
WPARAM * Buffer
Definition: windows_heap.h:795
WPARAM SizeOfBitMap
Definition: windows_heap.h:794
DWORD * HANDLE
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
PVOID
#define PDI_HEAPS
Definition: windows_heap.c:53
static bool DecodeHeapEntry(RzDebug *dbg, PHEAP heap, PHEAP_ENTRY entry)
Definition: windows_heap.c:416
static bool GetLFHKey(RzDebug *dbg, HANDLE h_proc, bool segment, WPARAM *lfhKey)
Definition: windows_heap.c:393
static bool DecodeLFHEntry(RzDebug *dbg, PHEAP heap, PHEAP_ENTRY entry, PHEAP_USERDATA_HEADER userBlocks, WPARAM key, WPARAM addr)
Definition: windows_heap.c:430
static PDEBUG_BUFFER InitHeapInfo(RzDebug *dbg, DWORD mask)
Definition: windows_heap.c:496
static void free_extra_info(PDEBUG_HEAP_INFORMATION heap)
Definition: windows_heap.c:257
#define GROW_BLOCKS()
Definition: windows_heap.c:579
static bool GetSegmentHeapBlocks(RzDebug *dbg, HANDLE h_proc, PVOID heapBase, PHeapBlockBasicInfo *blocks, WPARAM *count, SIZE_T *allocated)
Definition: windows_heap.c:641
struct _HEAP_VIRTUAL_ALLOC_ENTRY HEAP_VIRTUAL_ALLOC_ENTRY
struct _HeapBlockBasicInfo HeapBlockBasicInfo
struct _HEAP_SUBSEGMENT HEAP_SUBSEGMENT

References BACKEND_BLOCK, _HEAP_SEGMENT::BaseAddress, _HEAP::BaseAddress, rz_debug_t::bits, blocks, _HEAP_SUBSEGMENT::BlockSize, _RTL_BITMAP_EX::Buffer, _HEAP_USERDATA_HEADER::BusyBitmap, _HEAP_VIRTUAL_ALLOC_ENTRY::BusyBlock, calloc(), _HEAP_VIRTUAL_ALLOC_ENTRY::CommitSize, count, _HeapInformation::count, _HEAP::Counters, _HEAP_LOCAL_DATA::CrtZone, dbg, DecodeHeapEntry(), DecodeLFHEntry(), _HEAP_USERDATA_HEADER::EncodedOffsets, _HEAP_VIRTUAL_ALLOC_ENTRY::Entry, eprintf, err, EXTRA_FLAG, FALSE, _HEAP_USERDATA_OFFSETS::FirstAllocationOffset, _HEAP_SEGMENT::FirstEntry, _HEAP_ENTRY::Flags, free(), free_extra_info(), from, _HEAP::FrontEndHeap, _HEAP::FrontEndHeapType, GetLFHKey(), GetSegmentHeapBlocks(), _HeapBlockExtraInfo::granularity, GROW_BLOCKS, HANDLE, _DEBUG_BUFFER::HeapInformation, _HeapInformation::heaps, i, if(), info(), InitHeapInfo(), LARGE_BLOCK, _HEAP_COUNTERS::LastPolledSize, _HEAP_SEGMENT::LastValidEntry, LFH_BLOCK, mask, _LFH_BLOCK_ZONE::NextIndex, NT_BLOCK, NULL, off, offsetof, PDI_HEAPS, pid, PVOID, _HEAP_VIRTUAL_ALLOC_ENTRY::ReserveSize, RZ_FREE, RZ_LOG_ERROR, RZ_NEW0, RZ_SYS_BITS_32, rz_sys_perror, _HeapBlockExtraInfo::segment, _HEAP::SegmentList, _HEAP_SEGMENT::SegmentListEntry, _HEAP::SegmentSignature, _RTL_BITMAP_EX::SizeOfBitMap, _HEAP_USERDATA_OFFSETS::StrideAndOffset, _LFH_HEAP::SubSegmentZones, _HEAP_COUNTERS::TotalMemoryCommitted, _HeapBlockExtraInfo::unusedBytes, ut64(), and _HEAP::VirtualAllocdBlocks.

Referenced by rz_heap_blocks_list(), rz_heap_list(), rz_heap_list_w32(), and w32_list_heaps_blocks().

◆ GetHeapGlobalsOffset()

static bool GetHeapGlobalsOffset ( RzDebug dbg,
HANDLE  h_proc 
)
static

Definition at line 271 of file windows_heap.c.

271  {
272  if (has_heap_globals()) {
273  return true;
274  }
275  RzCore *core = dbg->corebind.core;
277  RzListIter *it;
278  RzDebugMap *map;
279  bool found = false;
280  rz_list_foreach (modules, it, map) {
281  if (!strcmp(map->name, "ntdll.dll")) {
282  found = true;
283  break;
284  }
285  }
286  if (!found) {
287  eprintf("ntdll.dll not loaded.\n");
289  return false;
290  }
291 
292  ut64 baseaddr = map->addr;
293 
294  // Open ntdll.dll file
295  int fd;
296  if ((fd = rz_io_fd_open(core->io, map->file, RZ_PERM_R, 0)) == -1) {
298  return false;
299  }
300 
302 
303  // Load ntdll.dll in RzBin to get its GUID
304  RzBinOptions opt = { 0 };
305  opt.fd = fd;
306  opt.sz = rz_io_fd_size(core->io, fd);
307  opt.obj_opts.baseaddr = baseaddr;
308  RzBinFile *obf = rz_bin_cur(core->bin);
309  RzBinFile *bf = rz_bin_open_io(core->bin, &opt);
310  if (!bf) {
311  rz_io_fd_close(core->io, fd);
312  return false;
313  }
314  RzBinInfo *info = rz_bin_get_info(core->bin);
315  if (!info) {
316  goto fail;
317  }
318  char *pdb_path = rz_str_newf("%s\\ntdll.pdb\\%s\\ntdll.pdb",
319  rz_config_get(core->config, "pdb.symstore"), info->guid);
320  if (!pdb_path) {
321  goto fail;
322  }
323  if (!rz_file_exists(pdb_path)) {
324  // Download ntdll.pdb
325  SPDBOptions opts;
326  opts.extract = rz_config_get_i(core->config, "pdb.extract");
327  opts.symbol_store_path = rz_config_get(core->config, "pdb.symstore");
328  opts.symbol_server = rz_config_get(core->config, "pdb.server");
329  if (rz_bin_pdb_download(core->bin, NULL, false, &opts)) {
330  eprintf("Failed to download ntdll.pdb file\n");
331  free(pdb_path);
332  goto fail;
333  }
334  }
335 
336  // Get ntdll.dll PDB info and parse json output
337  RzPdb *pdb = rz_bin_pdb_parse_from_file(pdb_path);
338  if (!pdb) {
339  free(pdb_path);
340  goto fail;
341  }
342 
343  free(pdb_path);
344  ut64 baddr = rz_config_get_i(core->config, "bin.baddr");
345  if (core->bin->cur && core->bin->cur->o && core->bin->cur->o->opts.baseaddr) {
346  baddr = core->bin->cur->o->opts.baseaddr;
347  } else {
348  eprintf("Warning: Cannot find base address, flags will probably be misplaced\n");
349  }
350  PJ *pj = pj_new();
351  if (!pj) {
352  rz_bin_pdb_free(pdb);
353  goto fail;
354  }
356  if (!j) {
357  rz_bin_pdb_free(pdb);
358  pj_free(pj);
359  goto fail;
360  }
361  pj_free(pj);
362  rz_bin_pdb_free(pdb);
363  RzJson *json = rz_json_parse(j);
364  if (!json) {
365  RZ_LOG_ERROR("rz_core_pdb_info returned invalid JSON");
366  free(j);
367  goto fail;
368  }
369  free(j);
370 
371  // Go through gvars array and search for the heap globals symbols
372  const RzJson *gvars = rz_json_get(json, "gvars");
373  gvars = gvars->children.first;
374  do {
375  const RzJson *gdata_name = rz_json_get(gvars, "gdata_name");
376  if (!strcmp(gdata_name->str_value, "RtlpHpHeapGlobals")) {
377  const RzJson *address = rz_json_get(gvars, "address");
378  RtlpHpHeapGlobalsOffset = address->num.u_value;
379  } else if (!strcmp(gdata_name->str_value, "RtlpLFHKey")) {
380  const RzJson *address = rz_json_get(gvars, "address");
381  RtlpLFHKeyOffset = address->num.u_value;
382  }
383  } while ((gvars = gvars->next) && !has_heap_globals());
384 
385  free(json);
386 fail:
387  rz_bin_file_delete(core->bin, bf);
388  rz_bin_file_set_cur_binfile(core->bin, obf);
389  rz_io_fd_close(core->io, fd);
390  return has_heap_globals();
391 }
RZ_API bool rz_bin_file_set_cur_binfile(RzBin *bin, RzBinFile *bf)
Definition: bfile.c:288
RZ_API bool rz_bin_file_delete(RzBin *bin, RzBinFile *bf)
Definition: bfile.c:213
RZ_DEPRECATE RZ_API RZ_BORROW RzBinInfo * rz_bin_get_info(RzBin *bin)
Definition: bin.c:585
RZ_API RzBinFile * rz_bin_open_io(RzBin *bin, RzBinOptions *opt)
Definition: bin.c:283
RZ_API RzBinFile * rz_bin_cur(RzBin *bin)
Definition: bin.c:895
static ut64 baddr(RzBinFile *bf)
Definition: bin_any.c:58
RZ_API ut64 rz_config_get_i(RzConfig *cfg, RZ_NONNULL const char *name)
Definition: config.c:119
RZ_API RZ_BORROW const char * rz_config_get(RzConfig *cfg, RZ_NONNULL const char *name)
Definition: config.c:75
RZ_API char * rz_core_bin_pdb_gvars_as_string(RZ_NONNULL const RzPdb *pdb, const ut64 img_base, PJ *pj, const RzOutputMode mode)
Return the PDB global vars string.
Definition: cpdb.c:128
size_t map(int syms, int left, int len)
Definition: enough.c:237
RZ_API const KEY_TYPE bool * found
Definition: ht_inc.h:130
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
modules
Definition: regress.py:20
RZ_API RZ_OWN RzPdb * rz_bin_pdb_parse_from_file(RZ_NONNULL const char *filename)
Parse PDB file given the path.
Definition: pdb.c:292
RZ_API void rz_bin_pdb_free(RzPdb *pdb)
Free PDB instance.
Definition: pdb.c:366
RZ_API int rz_bin_pdb_download(RZ_NONNULL RzBin *bin, RZ_NULLABLE PJ *pj, int isradjson, RZ_NONNULL SPDBOptions *options)
Download PDB file for currently opened RzBin file.
RZ_API bool rz_file_exists(const char *str)
Definition: file.c:192
RZ_API ut64 rz_io_fd_size(RzIO *io, int fd)
Definition: io_fd.c:42
RZ_API int rz_io_fd_open(RzIO *io, const char *uri, int flags, int mode)
Definition: io_fd.c:6
RZ_API bool rz_io_fd_close(RzIO *io, int fd)
Definition: io_fd.c:11
RZ_API const RzJson * rz_json_get(const RzJson *json, const char *key)
Definition: json_parser.c:405
RZ_API RzJson * rz_json_parse(char *text)
Definition: json_parser.c:382
RZ_API PJ * pj_new(void)
Definition: pj.c:25
RZ_API void pj_free(PJ *j)
Definition: pj.c:34
#define RZ_PERM_R
Definition: rz_types.h:93
@ RZ_OUTPUT_MODE_JSON
Definition: rz_types.h:40
const char * symbol_server
const char * symbol_store_path
Definition: rz_pj.h:12
ut64 baseaddr
where the linker maps the binary in memory
Definition: rz_bin.h:248
XX curplugin == o->plugin.
Definition: rz_bin.h:298
RzBinObject * o
Definition: rz_bin.h:305
char * guid
Definition: rz_bin.h:222
RzBinObjectLoadOptions opts
Definition: rz_bin.h:260
RZ_DEPRECATE RzBinFile * cur
never use this in new code! Get a file from the binfiles list or track it yourself.
Definition: rz_bin.h:330
void * core
Definition: rz_bind.h:31
RzBin * bin
Definition: rz_core.h:298
RzIO * io
Definition: rz_core.h:313
RzConfig * config
Definition: rz_core.h:300
RzCoreBind corebind
Definition: rz_debug.h:314
struct rz_json_t::@304::@307 children
const char * str_value
Definition: rz_json.h:42
struct rz_json_t * next
Definition: rz_json.h:56
struct rz_json_t::@304::@306 num
#define fail(test)
Definition: tests.h:29
static size_t RtlpHpHeapGlobalsOffset
Definition: windows_heap.c:58
static bool has_heap_globals(void)
Definition: windows_heap.c:267
static size_t RtlpLFHKeyOffset
Definition: windows_heap.c:59
RZ_API RzList * rz_w32_dbg_modules(RzDebug *dbg)
Definition: windows_maps.c:76
static const z80_opcode fd[]
Definition: z80_tab.h:997
static int baseaddr
Definition: z80asm.c:79

References baddr(), baseaddr, rz_bin_file_load_options_t::baseaddr, rz_core_t::bin, rz_json_t::children, rz_core_t::config, rz_core_bind_t::core, rz_debug_t::corebind, rz_bin_t::cur, dbg, eprintf, SPDBOptions::extract, fail, fd, found, free(), rz_bin_info_t::guid, has_heap_globals(), info(), rz_core_t::io, map(), regress::modules, rz_json_t::next, NULL, rz_json_t::num, rz_bin_file_t::o, rz_bin_object_t::opts, pj_free(), pj_new(), RtlpHpHeapGlobalsOffset, RtlpLFHKeyOffset, rz_bin_cur(), rz_bin_file_delete(), rz_bin_file_set_cur_binfile(), rz_bin_get_info(), rz_bin_open_io(), rz_bin_pdb_download(), rz_bin_pdb_free(), rz_bin_pdb_parse_from_file(), rz_config_get(), rz_config_get_i(), rz_core_bin_pdb_gvars_as_string(), rz_file_exists(), rz_io_fd_close(), rz_io_fd_open(), rz_io_fd_size(), rz_json_get(), rz_json_parse(), rz_list_free(), RZ_LOG_ERROR, RZ_OUTPUT_MODE_JSON, RZ_PERM_R, rz_str_newf(), rz_w32_dbg_modules(), rz_json_t::str_value, SPDBOptions::symbol_server, SPDBOptions::symbol_store_path, and ut64().

Referenced by GetLFHKey().

◆ GetLFHKey()

static bool GetLFHKey ( RzDebug dbg,
HANDLE  h_proc,
bool  segment,
WPARAM *  lfhKey 
)
static

Definition at line 393 of file windows_heap.c.

393  {
395  WPARAM lfhKeyLocation;
396 
397  if (!GetHeapGlobalsOffset(dbg, h_proc)) {
398  *lfhKey = 0;
399  return false;
400  }
401 
402  if (segment) {
403  lfhKeyLocation = RtlpHpHeapGlobalsOffset + sizeof(WPARAM);
404  } else {
405  lfhKeyLocation = RtlpLFHKeyOffset; // ntdll!RtlpLFHKey
406  }
407  if (!ReadProcessMemory(h_proc, (PVOID)lfhKeyLocation, lfhKey, sizeof(WPARAM), NULL)) {
408  rz_sys_perror("ReadProcessMemory");
409  eprintf("LFH key not found.\n");
410  *lfhKey = 0;
411  return false;
412  }
413  return true;
414 }
static bool GetHeapGlobalsOffset(RzDebug *dbg, HANDLE h_proc)
Definition: windows_heap.c:271

References dbg, eprintf, GetHeapGlobalsOffset(), NULL, PVOID, RtlpHpHeapGlobalsOffset, RtlpLFHKeyOffset, rz_return_val_if_fail, and rz_sys_perror.

Referenced by GetHeapBlocks(), GetSingleBlock(), and GetSingleSegmentBlock().

◆ GetListOfHeaps()

static RzList* GetListOfHeaps ( RzDebug dbg,
HANDLE  ph 
)
static

Definition at line 462 of file windows_heap.c.

462  {
463  PROCESS_BASIC_INFORMATION pib;
464  if (w32_NtQueryInformationProcess(ph, ProcessBasicInformation, &pib, sizeof(pib), NULL)) {
465  rz_sys_perror("NtQueryInformationProcess");
466  return NULL;
467  }
468  PEB peb;
469  ReadProcessMemory(ph, pib.PebBaseAddress, &peb, sizeof(PEB), NULL);
470  RzList *heaps = rz_list_new();
471  PVOID heapAddress;
472  PVOID *processHeaps;
473  ULONG numberOfHeaps;
474  if (dbg->bits == RZ_SYS_BITS_64) {
475  processHeaps = *((PVOID *)(((ut8 *)&peb) + 0xF0));
476  numberOfHeaps = *((ULONG *)(((ut8 *)&peb) + 0xE8));
477  } else {
478  processHeaps = *((PVOID *)(((ut8 *)&peb) + 0x90));
479  numberOfHeaps = *((ULONG *)(((ut8 *)&peb) + 0x88));
480  }
481  do {
482  ReadProcessMemory(ph, processHeaps, &heapAddress, sizeof(PVOID), NULL);
483  rz_list_push(heaps, heapAddress);
484  processHeaps += 1;
485  } while (--numberOfHeaps);
486  return heaps;
487 }
RZ_API RZ_OWN RzList * rz_list_new(void)
Returns a new initialized RzList pointer (free method is not initialized)
Definition: list.c:235
RZ_API RZ_BORROW RzListIter * rz_list_push(RZ_NONNULL RzList *list, void *item)
Alias for rz_list_append.
Definition: list.c:60
#define ph(a_type)
Definition: ph.h:27
ULONG

References rz_debug_t::bits, dbg, NULL, ph, PVOID, rz_list_new(), rz_list_push(), RZ_SYS_BITS_64, rz_sys_perror, and ULONG.

Referenced by InitHeapInfo().

◆ GetNextHeapBlock()

static bool GetNextHeapBlock ( PDEBUG_HEAP_INFORMATION  heapInfo,
PHeapBlock  hb 
)
static

Definition at line 208 of file windows_heap.c.

208  {
209  rz_return_val_if_fail(heapInfo && hb, false);
210  PHeapBlockBasicInfo block;
211 
212  block = (PHeapBlockBasicInfo)heapInfo->Blocks;
213  SIZE_T index = hb->index;
214 
215  if (index > heapInfo->BlockCount) {
216  return false;
217  }
218 
219  if (block[index].flags & 2) {
220  do {
221  if (index > heapInfo->BlockCount) {
222  return false;
223  }
224 
225  // new address = curBlockAddress + Granularity;
226  hb->dwAddress = block[index].address + heapInfo->Granularity;
227 
228  index++;
229  hb->dwSize = block->size;
230  } while (block[index].flags & 2);
231  hb->index = index;
232  } else {
233  hb->dwSize = block[index].size;
234  if (block[index].extra & EXTRA_FLAG) {
235  PHeapBlockExtraInfo extra = (PHeapBlockExtraInfo)(block[index].extra & ~EXTRA_FLAG);
236  hb->extraInfo = extra;
237  hb->dwSize -= extra->unusedBytes;
238  hb->dwAddress = block[index].address + extra->granularity;
239  } else {
240  hb->extraInfo = NULL;
241  hb->dwAddress = (WPARAM)hb->dwAddress + hb->dwSize;
242  }
243  hb->index++;
244  }
245 
246  WPARAM flags;
247  if (block[index].extra & EXTRA_FLAG) {
248  flags = block[index].flags;
249  } else {
250  flags = (USHORT)block[index].flags;
251  }
252  UPDATE_FLAGS(hb, flags);
253 
254  return true;
255 }

References _HeapBlockBasicInfo::address, _DEBUG_HEAP_INFORMATION::BlockCount, _DEBUG_HEAP_INFORMATION::Blocks, _HeapBlock::dwAddress, _HeapBlock::dwSize, EXTRA_FLAG, _HeapBlock::extraInfo, flags, _HeapBlockBasicInfo::flags, _HeapBlockExtraInfo::granularity, _DEBUG_HEAP_INFORMATION::Granularity, if(), _HeapBlock::index, NULL, rz_return_val_if_fail, _HeapBlockBasicInfo::size, _HeapBlockExtraInfo::unusedBytes, and UPDATE_FLAGS.

Referenced by free_extra_info(), rz_heap_blocks_list(), and w32_list_heaps_blocks().

◆ GetSegmentHeapBlocks()

static bool GetSegmentHeapBlocks ( RzDebug dbg,
HANDLE  h_proc,
PVOID  heapBase,
PHeapBlockBasicInfo blocks,
WPARAM *  count,
SIZE_T *  allocated 
)
static

Definition at line 641 of file windows_heap.c.

641  {
642  rz_return_val_if_fail(h_proc && blocks && count && allocated, false);
643  WPARAM bytesRead;
644  SEGMENT_HEAP segheapHeader;
645  ReadProcessMemory(h_proc, heapBase, &segheapHeader, sizeof(SEGMENT_HEAP), &bytesRead);
646 
647  if (segheapHeader.Signature != 0xddeeddee) {
648  return false;
649  }
650  WPARAM lfhKey;
651  WPARAM lfhKeyLocation = RtlpHpHeapGlobalsOffset + sizeof(WPARAM);
652  if (!ReadProcessMemory(h_proc, (PVOID)lfhKeyLocation, &lfhKey, sizeof(WPARAM), &bytesRead)) {
653  rz_sys_perror("ReadProcessMemory");
654  eprintf("LFH key not found.\n");
655  return false;
656  }
657 
658  // LFH
659  size_t numBuckets = _countof(segheapHeader.LfhContext.Buckets);
660  int j;
661  for (j = 0; j < numBuckets; j++) {
662  if ((WPARAM)segheapHeader.LfhContext.Buckets[j] & 1) {
663  continue;
664  }
665  HEAP_LFH_BUCKET bucket;
666  ReadProcessMemory(h_proc, segheapHeader.LfhContext.Buckets[j], &bucket, sizeof(HEAP_LFH_BUCKET), &bytesRead);
667  HEAP_LFH_AFFINITY_SLOT affinitySlot, *paffinitySlot;
668  ReadProcessMemory(h_proc, bucket.AffinitySlots, &paffinitySlot, sizeof(PHEAP_LFH_AFFINITY_SLOT), &bytesRead);
669  bucket.AffinitySlots++;
670  ReadProcessMemory(h_proc, paffinitySlot, &affinitySlot, sizeof(HEAP_LFH_AFFINITY_SLOT), &bytesRead);
671  WPARAM first = (WPARAM)paffinitySlot + offsetof(HEAP_LFH_SUBSEGMENT_OWNER, AvailableSubsegmentList);
672  WPARAM next = (WPARAM)affinitySlot.State.AvailableSubsegmentList.Flink;
673  if (!__lfh_segment_loop(h_proc, blocks, allocated, lfhKey, count, first, next)) {
674  return false;
675  }
676  first = (WPARAM)paffinitySlot + offsetof(HEAP_LFH_SUBSEGMENT_OWNER, FullSubsegmentList);
677  next = (WPARAM)affinitySlot.State.FullSubsegmentList.Flink;
678  if (!__lfh_segment_loop(h_proc, blocks, allocated, lfhKey, count, first, next)) {
679  return false;
680  }
681  }
682 
683  // Large Blocks
684  if (segheapHeader.LargeAllocMetadata.Root) {
686  RzStack *s = rz_stack_new(segheapHeader.LargeReservedPages);
687  PRTL_BALANCED_NODE curr = segheapHeader.LargeAllocMetadata.Root;
688  do { // while (!rz_stack_is_empty(s));
689  GROW_PBLOCKS();
690  while (curr) {
691  rz_stack_push(s, curr);
692  ReadProcessMemory(h_proc, curr, node, sizeof(RTL_BALANCED_NODE), &bytesRead);
693  curr = node->Left;
694  };
697  ReadProcessMemory(h_proc, curr, &entry, sizeof(HEAP_LARGE_ALLOC_DATA), &bytesRead);
698  (*blocks)[*count].address = entry.VirtualAddess - entry.UnusedBytes; // This is a union
699  (*blocks)[*count].flags = 1 | SEGMENT_HEAP_BLOCK | LARGE_BLOCK;
700  (*blocks)[*count].size = ((entry.AllocatedPages >> 12) << 12);
702  if (!extra) {
703  return false;
704  }
705  extra->unusedBytes = entry.UnusedBytes;
706  ReadProcessMemory(h_proc, (void *)(*blocks)[*count].address, &extra->granularity, sizeof(USHORT), &bytesRead);
707  (*blocks)[*count].extra = EXTRA_FLAG | (WPARAM)extra;
708  curr = entry.TreeNode.Right;
709  *count += 1;
710  } while (curr || !rz_stack_is_empty(s));
711  rz_stack_free(s);
712  free(node);
713  }
714 
715  WPARAM RtlpHpHeapGlobal;
716  ReadProcessMemory(h_proc, (PVOID)RtlpHpHeapGlobalsOffset, &RtlpHpHeapGlobal, sizeof(WPARAM), &bytesRead);
717  // Backend Blocks (And VS)
718  int i;
719  for (i = 0; i < 2; i++) {
720  HEAP_SEG_CONTEXT ctx = segheapHeader.SegContexts[i];
721  WPARAM ctxFirstEntry = (WPARAM)heapBase + offsetof(SEGMENT_HEAP, SegContexts) + sizeof(HEAP_SEG_CONTEXT) * i + offsetof(HEAP_SEG_CONTEXT, SegmentListHead);
722  HEAP_PAGE_SEGMENT pageSegment;
723  WPARAM currPageSegment = (WPARAM)ctx.SegmentListHead.Flink;
724  do {
725  if (!ReadProcessMemory(h_proc, (PVOID)currPageSegment, &pageSegment, sizeof(HEAP_PAGE_SEGMENT), &bytesRead)) {
726  break;
727  }
728  for (WPARAM j = 2; j < 256; j++) {
729  if ((pageSegment.DescArray[j].RangeFlags &
732  GROW_PBLOCKS();
733  (*blocks)[*count].address = currPageSegment + j * 0x1000;
734  (*blocks)[*count].size = (WPARAM)pageSegment.DescArray[j].UnitSize * 0x1000;
735  (*blocks)[*count].flags = SEGMENT_HEAP_BLOCK | BACKEND_BLOCK | 1;
737  if (!extra) {
738  return false;
739  }
740  extra->segment = currPageSegment;
741  extra->unusedBytes = pageSegment.DescArray[j].UnusedBytes;
742  (*blocks)[*count].extra = EXTRA_FLAG | (WPARAM)extra;
743  *count += 1;
744  }
745  // Hack (i don't know if all blocks like this are VS or not)
746  if (pageSegment.DescArray[j].RangeFlags & 0xF && pageSegment.DescArray[j].UnusedBytes == 0x1000) {
747  HEAP_VS_SUBSEGMENT vsSubsegment;
748  WPARAM start, from = currPageSegment + j * 0x1000;
749  ReadProcessMemory(h_proc, (PVOID)from, &vsSubsegment, sizeof(HEAP_VS_SUBSEGMENT), &bytesRead);
750  // Walk through subsegment
751  start = from += sizeof(HEAP_VS_SUBSEGMENT);
752  while (from < (WPARAM)start + vsSubsegment.Size * sizeof(HEAP_VS_CHUNK_HEADER)) {
753  HEAP_VS_CHUNK_HEADER vsChunk;
754  ReadProcessMemory(h_proc, (PVOID)from, &vsChunk, sizeof(HEAP_VS_CHUNK_HEADER), &bytesRead);
755  vsChunk.Sizes.HeaderBits ^= from ^ RtlpHpHeapGlobal;
756  WPARAM sz = vsChunk.Sizes.UnsafeSize * sizeof(HEAP_VS_CHUNK_HEADER);
757  if (vsChunk.Sizes.Allocated) {
758  GROW_PBLOCKS();
759  (*blocks)[*count].address = from;
760  (*blocks)[*count].size = sz;
761  (*blocks)[*count].flags = VS_BLOCK | SEGMENT_HEAP_BLOCK | 1;
763  if (!extra) {
764  return false;
765  }
766  extra->granularity = sizeof(HEAP_VS_CHUNK_HEADER) * 2;
767  (*blocks)[*count].extra = EXTRA_FLAG | (WPARAM)extra;
768  *count += 1;
769  }
770  from += sz;
771  }
772  }
773  }
774  currPageSegment = (WPARAM)pageSegment.ListEntry.Flink;
775  } while (currPageSegment && currPageSegment != ctxFirstEntry);
776  }
777  return true;
778 }
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len static semflg const void static shmflg const struct timespec struct timespec static rem const char static group const void start
Definition: sflib.h:133
void * malloc(size_t size)
Definition: malloc.c:123
static RzSocket * s
Definition: rtr.c:28
RZ_API bool rz_stack_is_empty(RzStack *s)
Definition: stack.c:68
RZ_API void * rz_stack_pop(RzStack *s)
Definition: stack.c:59
RZ_API bool rz_stack_push(RzStack *s, void *el)
Definition: stack.c:42
RZ_API RzStack * rz_stack_new(ut32 n)
Definition: stack.c:6
RZ_API void rz_stack_free(RzStack *s)
Definition: stack.c:29
HEAP_LFH_SUBSEGMENT_OWNER State
Definition: windows_heap.h:477
PHEAP_LFH_AFFINITY_SLOT * AffinitySlots
Definition: windows_heap.h:490
PHEAP_LFH_BUCKET Buckets[129]
Definition: windows_heap.h:504
LIST_ENTRY AvailableSubsegmentList
Definition: windows_heap.h:464
HEAP_VS_CHUNK_HEADER_SIZE Sizes
Definition: windows_heap.h:379
PRTL_BALANCED_NODE Left
Definition: windows_heap.h:48
PRTL_BALANCED_NODE Root
Definition: windows_heap.h:60
WPARAM LargeReservedPages
Definition: windows_heap.h:618
HEAP_SEG_CONTEXT SegContexts[2]
Definition: windows_heap.h:629
HEAP_LFH_CONTEXT LfhContext
Definition: windows_heap.h:631
RTL_RB_TREE LargeAllocMetadata
Definition: windows_heap.h:617
static bool __lfh_segment_loop(HANDLE h_proc, PHeapBlockBasicInfo *blocks, SIZE_T *allocated, WPARAM lfhKey, WPARAM *count, WPARAM first, WPARAM next)
Definition: windows_heap.c:605
struct _HEAP_SEG_CONTEXT HEAP_SEG_CONTEXT
@ PAGE_RANGE_FLAGS_ALLOCATED
Definition: windows_heap.h:392
@ PAGE_RANGE_FLAGS_FIRST
Definition: windows_heap.h:393
struct _HEAP_VS_CHUNK_HEADER HEAP_VS_CHUNK_HEADER
struct _RTL_BALANCED_NODE * PRTL_BALANCED_NODE
Definition: windows_heap.h:43
struct _HEAP_VS_SUBSEGMENT HEAP_VS_SUBSEGMENT
struct _HEAP_PAGE_SEGMENT HEAP_PAGE_SEGMENT

References __lfh_segment_loop(), _HEAP_LFH_BUCKET::AffinitySlots, _HEAP_VS_CHUNK_HEADER_SIZE::Allocated, _HEAP_LFH_SUBSEGMENT_OWNER::AvailableSubsegmentList, BACKEND_BLOCK, blocks, _HEAP_LFH_CONTEXT::Buckets, count, _HEAP_PAGE_SEGMENT::DescArray, eprintf, EXTRA_FLAG, free(), from, _HEAP_LFH_SUBSEGMENT_OWNER::FullSubsegmentList, _HeapBlockExtraInfo::granularity, GROW_PBLOCKS, _HEAP_VS_CHUNK_HEADER_SIZE::HeaderBits, i, if(), LARGE_BLOCK, _SEGMENT_HEAP::LargeAllocMetadata, _SEGMENT_HEAP::LargeReservedPages, _RTL_BALANCED_NODE::Left, _SEGMENT_HEAP::LfhContext, _HEAP_PAGE_SEGMENT::ListEntry, malloc(), offsetof, PAGE_RANGE_FLAGS_ALLOCATED, PAGE_RANGE_FLAGS_FIRST, PVOID, _HEAP_PAGE_RANGE_DESCRIPTOR::RangeFlags, _RTL_RB_TREE::Root, RtlpHpHeapGlobalsOffset, RZ_NEW0, rz_return_val_if_fail, rz_stack_free(), rz_stack_is_empty(), rz_stack_new(), rz_stack_pop(), rz_stack_push(), rz_sys_perror, s, _SEGMENT_HEAP::SegContexts, _HeapBlockExtraInfo::segment, SEGMENT_HEAP_BLOCK, _SEGMENT_HEAP::Signature, _HEAP_VS_SUBSEGMENT::Size, _HEAP_VS_CHUNK_HEADER::Sizes, start, _HEAP_LFH_AFFINITY_SLOT::State, _HEAP_PAGE_RANGE_DESCRIPTOR::UnitSize, _HEAP_VS_CHUNK_HEADER_SIZE::UnsafeSize, _HEAP_PAGE_RANGE_DESCRIPTOR::UnusedBytes, _HeapBlockExtraInfo::unusedBytes, and VS_BLOCK.

Referenced by GetHeapBlocks().

◆ GetSingleBlock()

static PHeapBlock GetSingleBlock ( RzDebug dbg,
ut64  offset 
)
static

Definition at line 1112 of file windows_heap.c.

1112  {
1114  PDEBUG_BUFFER db = NULL;
1115  PHeapBlockExtraInfo extra = NULL;
1116 
1117  if (!hb) {
1118  RZ_LOG_ERROR("GetSingleBlock: Allocation failed.\n");
1119  return NULL;
1120  }
1121  HANDLE h_proc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dbg->pid);
1122  if (!h_proc) {
1123  rz_sys_perror("GetSingleBlock/OpenProcess");
1124  goto err;
1125  }
1126  db = InitHeapInfo(dbg, PDI_HEAPS);
1127  if (!db) {
1128  goto err;
1129  }
1130  extra = RZ_NEW0(HeapBlockExtraInfo);
1131  if (!extra) {
1132  RZ_LOG_ERROR("GetSingleBlock: Allocation failed.\n");
1133  goto err;
1134  }
1135  WPARAM NtLFHKey;
1136  GetLFHKey(dbg, h_proc, false, &NtLFHKey);
1137  PHeapInformation heapInfo = db->HeapInformation;
1138  int i;
1139  for (i = 0; i < heapInfo->count; i++) {
1140  DEBUG_HEAP_INFORMATION heap = heapInfo->heaps[i];
1141  if (is_segment_heap(h_proc, heap.Base)) {
1142  free(hb);
1143  RZ_FREE(extra);
1144  hb = GetSingleSegmentBlock(dbg, h_proc, heap.Base, offset);
1145  if (!hb) {
1146  goto err;
1147  }
1148  break;
1149  } else {
1150  HEAP h;
1151  HEAP_ENTRY entry;
1152  WPARAM entryOffset = offset - heap.Granularity;
1153  if (!ReadProcessMemory(h_proc, heap.Base, &h, sizeof(HEAP), NULL) ||
1154  !ReadProcessMemory(h_proc, (PVOID)entryOffset, &entry, sizeof(HEAP_ENTRY), NULL)) {
1155  goto err;
1156  }
1157  extra->granularity = heap.Granularity;
1158  hb->extraInfo = extra;
1159  HEAP_ENTRY tmpEntry = entry;
1160  if (DecodeHeapEntry(dbg, &h, &tmpEntry)) {
1161  entry = tmpEntry;
1162  hb->dwAddress = offset;
1163  UPDATE_FLAGS(hb, (DWORD)entry.Flags | NT_BLOCK);
1164  if (entry.UnusedBytes == 0x4) {
1165  HEAP_VIRTUAL_ALLOC_ENTRY largeEntry;
1166  if (ReadProcessMemory(h_proc, (PVOID)(offset - sizeof(HEAP_VIRTUAL_ALLOC_ENTRY)), &largeEntry, sizeof(HEAP_VIRTUAL_ALLOC_ENTRY), NULL)) {
1167  hb->dwSize = largeEntry.CommitSize;
1168  hb->dwFlags |= LARGE_BLOCK;
1169  extra->unusedBytes = largeEntry.ReserveSize - largeEntry.CommitSize;
1170  extra->granularity = sizeof(HEAP_VIRTUAL_ALLOC_ENTRY);
1171  }
1172  } else {
1173  hb->dwSize = (WPARAM)entry.Size * heap.Granularity;
1174  hb->dwFlags |= BACKEND_BLOCK;
1175  }
1176  break;
1177  }
1178  // LFH
1179  if (entry.UnusedBytes & 0x80) {
1180  tmpEntry = entry;
1181  WPARAM userBlocksOffset;
1182  if (dbg->bits == RZ_SYS_BITS_64) {
1183  *(((WPARAM *)&tmpEntry) + 1) ^= PtrToInt(h.BaseAddress) ^ (entryOffset >> 0x4) ^ (DWORD)NtLFHKey;
1184  userBlocksOffset = entryOffset - (USHORT)((*(((WPARAM *)&tmpEntry) + 1)) >> 0xC);
1185  } else {
1186  *((WPARAM *)&tmpEntry) ^= PtrToInt(h.BaseAddress) ^ ((DWORD)(entryOffset) >> 0x4) ^ (DWORD)NtLFHKey;
1187  userBlocksOffset = entryOffset - (USHORT)(*((WPARAM *)&tmpEntry) >> 0xC);
1188  }
1189  // Confirm it is LFH
1190  if (DecodeLFHEntry(dbg, &h, &entry, (PVOID)userBlocksOffset, NtLFHKey, entryOffset)) {
1191  HEAP_USERDATA_HEADER UserBlocks;
1192  HEAP_SUBSEGMENT subsegment;
1193  if (!ReadProcessMemory(h_proc, (PVOID)userBlocksOffset, &UserBlocks, sizeof(HEAP_USERDATA_HEADER), NULL)) {
1194  rz_sys_perror("GetSingleBlock/ReadProcessMemory");
1195  continue;
1196  }
1197  if (!ReadProcessMemory(h_proc, (PVOID)UserBlocks.SubSegment, &subsegment, sizeof(HEAP_SUBSEGMENT), NULL)) {
1198  continue;
1199  }
1200  hb->dwAddress = offset;
1201  hb->dwSize = (WPARAM)subsegment.BlockSize * heap.Granularity;
1202  hb->dwFlags = 1 | LFH_BLOCK | NT_BLOCK;
1203  break;
1204  }
1205  }
1206  }
1207  }
1208  if (!hb->dwSize) {
1209  goto err;
1210  }
1211  RtlDestroyQueryDebugBuffer(db);
1212  CloseHandle(h_proc);
1213  return hb;
1214 err:
1215  if (h_proc) {
1216  CloseHandle(h_proc);
1217  }
1218  if (db) {
1219  RtlDestroyQueryDebugBuffer(db);
1220  }
1221  free(hb);
1222  free(extra);
1223  return NULL;
1224 }
#define h(i)
Definition: sha256.c:48
PHEAP_SUBSEGMENT SubSegment
Definition: windows_heap.h:801
static bool is_segment_heap(HANDLE h_proc, PVOID heapBase)
Definition: windows_heap.c:157
static PHeapBlock GetSingleSegmentBlock(RzDebug *dbg, HANDLE h_proc, PSEGMENT_HEAP heapBase, WPARAM offset)

References BACKEND_BLOCK, rz_debug_t::bits, _HEAP_SUBSEGMENT::BlockSize, _HEAP_VIRTUAL_ALLOC_ENTRY::CommitSize, _HeapInformation::count, dbg, DecodeHeapEntry(), DecodeLFHEntry(), _HeapBlock::dwAddress, _HeapBlock::dwFlags, DWORD, _HeapBlock::dwSize, err, _HeapBlock::extraInfo, FALSE, free(), GetLFHKey(), GetSingleSegmentBlock(), _HeapBlockExtraInfo::granularity, h, HANDLE, _DEBUG_BUFFER::HeapInformation, _HeapInformation::heaps, i, InitHeapInfo(), is_segment_heap(), LARGE_BLOCK, LFH_BLOCK, NT_BLOCK, NULL, PDI_HEAPS, rz_debug_t::pid, PVOID, _HEAP_VIRTUAL_ALLOC_ENTRY::ReserveSize, RZ_FREE, RZ_LOG_ERROR, RZ_NEW0, RZ_SYS_BITS_64, rz_sys_perror, _HEAP_USERDATA_HEADER::SubSegment, _HeapBlockExtraInfo::unusedBytes, and UPDATE_FLAGS.

Referenced by rz_heap_debug_block_win().

◆ GetSingleSegmentBlock()

static PHeapBlock GetSingleSegmentBlock ( RzDebug dbg,
HANDLE  h_proc,
PSEGMENT_HEAP  heapBase,
WPARAM  offset 
)
static

Definition at line 1009 of file windows_heap.c.

1009  {
1010  // TODO:
1011  // - Backend (Is this needed?)
1013  if (!hb) {
1014  RZ_LOG_ERROR("GetSingleSegmentBlock: Allocation failed.\n");
1015  return NULL;
1016  }
1018  if (!extra) {
1019  RZ_LOG_ERROR("GetSingleSegmentBlock: Allocation failed.\n");
1020  goto err;
1021  }
1022  hb->extraInfo = extra;
1023  extra->heap = (WPARAM)heapBase;
1024  WPARAM granularity = (WPARAM)dbg->bits * 2;
1025  WPARAM headerOff = offset - granularity;
1027  ReadProcessMemory(h_proc, heapBase, &heap, sizeof(SEGMENT_HEAP), NULL);
1028  WPARAM RtlpHpHeapGlobal;
1029  ReadProcessMemory(h_proc, (PVOID)RtlpHpHeapGlobalsOffset, &RtlpHpHeapGlobal, sizeof(WPARAM), NULL);
1030 
1031  WPARAM pgSegOff = headerOff & heap.SegContexts[0].SegmentMask;
1032  WPARAM segSignature;
1033  ReadProcessMemory(h_proc, (PVOID)(pgSegOff + sizeof(LIST_ENTRY)), &segSignature, sizeof(WPARAM), NULL); // HEAP_PAGE_SEGMENT.Signature
1034  WPARAM test = RtlpHpHeapGlobal ^ pgSegOff ^ segSignature ^ ((WPARAM)heapBase + offsetof(SEGMENT_HEAP, SegContexts));
1035  if (test == 0xa2e64eada2e64ead) { // Hardcoded in ntdll
1036  HEAP_PAGE_SEGMENT segment;
1037  ReadProcessMemory(h_proc, (PVOID)pgSegOff, &segment, sizeof(HEAP_PAGE_SEGMENT), NULL);
1038  WPARAM pgRangeDescOff = ((headerOff - pgSegOff) >> heap.SegContexts[0].UnitShift) << 5;
1039  WPARAM pageIndex = pgRangeDescOff / sizeof(HEAP_PAGE_RANGE_DESCRIPTOR);
1040  if (!(segment.DescArray[pageIndex].RangeFlags & PAGE_RANGE_FLAGS_FIRST)) {
1041  pageIndex -= segment.DescArray[pageIndex].UnitOffset;
1042  }
1043  // VS
1044  WPARAM subsegmentOffset = pgSegOff + pageIndex * 0x1000;
1045  if (segment.DescArray[pageIndex].RangeFlags & 0xF && segment.DescArray[pageIndex].UnusedBytes == 0x1000) {
1046  HEAP_VS_SUBSEGMENT subsegment;
1047  ReadProcessMemory(h_proc, (PVOID)subsegmentOffset, &subsegment, sizeof(HEAP_VS_SUBSEGMENT), NULL);
1048  if ((subsegment.Size ^ 0x2BED) == subsegment.Signature) {
1050  ReadProcessMemory(h_proc, (PVOID)(headerOff - sizeof(HEAP_VS_CHUNK_HEADER)), &header, sizeof(HEAP_VS_CHUNK_HEADER), NULL);
1051  header.Sizes.HeaderBits ^= RtlpHpHeapGlobal ^ headerOff;
1052  hb->dwAddress = offset;
1053  hb->dwSize = header.Sizes.UnsafeSize * sizeof(HEAP_VS_CHUNK_HEADER);
1054  hb->dwFlags = 1 | SEGMENT_HEAP_BLOCK | VS_BLOCK;
1055  extra->granularity = granularity + sizeof(HEAP_VS_CHUNK_HEADER);
1056  extra->segment = subsegmentOffset;
1057  return hb;
1058  }
1059  }
1060  // LFH
1061  if (segment.DescArray[pageIndex].RangeFlags & PAGE_RANGE_FLAGS_LFH_SUBSEGMENT) {
1062  HEAP_LFH_SUBSEGMENT subsegment;
1063  ReadProcessMemory(h_proc, (PVOID)subsegmentOffset, &subsegment, sizeof(HEAP_LFH_SUBSEGMENT), NULL);
1064  WPARAM lfhKey;
1065  GetLFHKey(dbg, h_proc, true, &lfhKey);
1066  subsegment.BlockOffsets.EncodedData ^= (DWORD)lfhKey ^ ((DWORD)subsegmentOffset >> 0xC);
1067  hb->dwAddress = offset;
1068  hb->dwSize = subsegment.BlockOffsets.BlockSize;
1069  hb->dwFlags = 1 | SEGMENT_HEAP_BLOCK | LFH_BLOCK;
1070  extra->granularity = granularity;
1071  extra->segment = subsegmentOffset;
1072  return hb;
1073  }
1074  }
1075 
1076  // Try Large Blocks
1077  if ((offset & 0xFFFF) < 0x100) {
1078  if (!heap.LargeAllocMetadata.Root) {
1079  goto err;
1080  }
1081  RTL_BALANCED_NODE node;
1082  WPARAM curr = (WPARAM)heap.LargeAllocMetadata.Root;
1083  ReadProcessMemory(h_proc, (PVOID)curr, &node, sizeof(RTL_BALANCED_NODE), NULL);
1084 
1085  while (curr) {
1087  ReadProcessMemory(h_proc, (PVOID)curr, &entry, sizeof(HEAP_LARGE_ALLOC_DATA), NULL);
1088  WPARAM VirtualAddess = entry.VirtualAddess - entry.UnusedBytes;
1089  if ((offset & ~0xFFFFULL) > VirtualAddess) {
1090  curr = (WPARAM)node.Right;
1091  } else if ((offset & ~0xFFFFULL) < VirtualAddess) {
1092  curr = (WPARAM)node.Left;
1093  } else {
1094  hb->dwAddress = VirtualAddess;
1095  hb->dwSize = ((entry.AllocatedPages >> 12) << 12) - entry.UnusedBytes;
1097  extra->unusedBytes = entry.UnusedBytes;
1098  ReadProcessMemory(h_proc, (PVOID)hb->dwAddress, &extra->granularity, sizeof(USHORT), NULL);
1099  return hb;
1100  }
1101  if (curr) {
1102  ReadProcessMemory(h_proc, (PVOID)curr, &node, sizeof(RTL_BALANCED_NODE), NULL);
1103  }
1104  }
1105  }
1106 err:
1107  free(hb);
1108  free(extra);
1109  return NULL;
1110 }
#define header(is_bt, len_min, ret_op)
-lz4-versions
HEAP_PAGE_RANGE_DESCRIPTOR DescArray[256]
Definition: windows_heap.h:430
struct _RTL_BALANCED_NODE RTL_BALANCED_NODE
@ PAGE_RANGE_FLAGS_LFH_SUBSEGMENT
Definition: windows_heap.h:390
struct _HEAP_PAGE_RANGE_DESCRIPTOR HEAP_PAGE_RANGE_DESCRIPTOR

References rz_debug_t::bits, _HEAP_LFH_SUBSEGMENT::BlockOffsets, _HEAP_LFH_SUBSEGMENT_ENCODED_OFFSETS::BlockSize, dbg, _HEAP_PAGE_SEGMENT::DescArray, _HeapBlock::dwAddress, _HeapBlock::dwFlags, DWORD, _HeapBlock::dwSize, _HEAP_LFH_SUBSEGMENT_ENCODED_OFFSETS::EncodedData, err, _HeapBlock::extraInfo, free(), GetLFHKey(), _HeapBlockExtraInfo::granularity, header, _HeapBlockExtraInfo::heap, LARGE_BLOCK, _RTL_BALANCED_NODE::Left, LFH_BLOCK, NULL, offsetof, PAGE_RANGE_FLAGS_FIRST, PAGE_RANGE_FLAGS_LFH_SUBSEGMENT, PVOID, _HEAP_PAGE_RANGE_DESCRIPTOR::RangeFlags, _RTL_BALANCED_NODE::Right, RtlpHpHeapGlobalsOffset, RZ_LOG_ERROR, RZ_NEW0, _HeapBlockExtraInfo::segment, SEGMENT_HEAP_BLOCK, _HEAP_VS_SUBSEGMENT::Signature, _HEAP_VS_SUBSEGMENT::Size, _HEAP_PAGE_RANGE_DESCRIPTOR::UnitOffset, _HEAP_PAGE_RANGE_DESCRIPTOR::UnusedBytes, _HeapBlockExtraInfo::unusedBytes, and VS_BLOCK.

Referenced by GetSingleBlock().

◆ has_heap_globals()

static bool has_heap_globals ( void  )
inlinestatic

Definition at line 267 of file windows_heap.c.

267  {
269 }

References RtlpHpHeapGlobalsOffset, and RtlpLFHKeyOffset.

Referenced by GetHeapGlobalsOffset().

◆ InitHeapInfo()

static PDEBUG_BUFFER InitHeapInfo ( RzDebug dbg,
DWORD  mask 
)
static

Definition at line 496 of file windows_heap.c.

496  {
497  // Check:
498  // RtlpQueryProcessDebugInformationFromWow64
499  // RtlpQueryProcessDebugInformationRemote
500  PDEBUG_BUFFER db = RtlCreateQueryDebugBuffer(0, FALSE);
501  if (!db) {
502  return NULL;
503  }
505  if (!params) {
506  RtlDestroyQueryDebugBuffer(db);
507  return NULL;
508  }
509  *params = (th_query_params){ dbg, mask, db, 0, false, false };
510  HANDLE th = CreateThread(NULL, 0, &__th_QueryDebugBuffer, params, 0, NULL);
511  if (th) {
512  WaitForSingleObject(th, 5000);
513  } else {
514  RtlDestroyQueryDebugBuffer(db);
515  return NULL;
516  }
517  if (!params->fin) {
518  // why after it fails the first time it blocks on the second? That's annoying
519  // It stops blocking if i pause rizin in the debugger. is it a race?
520  // why it fails with 1000000 allocs? also with processes with segment heap enabled?
521  params->hanged = true;
522  eprintf("RtlQueryProcessDebugInformation hanged\n");
523  db = NULL;
524  } else if (params->ret) {
525  RtlDestroyQueryDebugBuffer(db);
526  db = NULL;
527  rz_sys_perror("RtlQueryProcessDebugInformation");
528  }
529  CloseHandle(th);
530  if (db) {
531  return db;
532  }
533 
534  // TODO: Not do this
535  if (mask == PDI_HEAPS && __is_windows_ten()) {
536  db = RtlCreateQueryDebugBuffer(0, FALSE);
537  if (!db) {
538  return NULL;
539  }
541  if (!heapInfo) {
542  RtlDestroyQueryDebugBuffer(db);
543  return NULL;
544  }
545  HANDLE h_proc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dbg->pid);
546  if (!h_proc) {
547  RZ_LOG_ERROR("OpenProcess failed\n");
548  free(heapInfo);
549  RtlDestroyQueryDebugBuffer(db);
550  return NULL;
551  }
552  RzList *heaps = GetListOfHeaps(dbg, h_proc);
553  CloseHandle(h_proc);
554  heapInfo->count = heaps->length;
555  void *tmp = realloc(heapInfo, sizeof(DEBUG_HEAP_INFORMATION) * heapInfo->count + sizeof(heapInfo));
556  if (!tmp) {
557  free(heapInfo);
558  RtlDestroyQueryDebugBuffer(db);
559  return NULL;
560  }
561  heapInfo = tmp;
562  int i = 0;
563  RzListIter *it;
564  void *heapBase;
565  rz_list_foreach (heaps, it, heapBase) {
566  heapInfo->heaps[i].Base = heapBase;
567  heapInfo->heaps[i].Granularity = sizeof(HEAP_ENTRY);
568  heapInfo->heaps[i].Allocated = 0;
569  heapInfo->heaps[i].Committed = 0;
570  i++;
571  }
572  db->HeapInformation = heapInfo;
573  rz_list_free(heaps);
574  return db;
575  }
576  return NULL;
577 }
ut32 length
Definition: rz_list.h:22
static DWORD WINAPI __th_QueryDebugBuffer(void *param)
Definition: windows_heap.c:451
static RzList * GetListOfHeaps(RzDebug *dbg, HANDLE ph)
Definition: windows_heap.c:462
struct _th_query_params th_query_params
static bool __is_windows_ten(void)
Definition: windows_heap.c:91

References __is_windows_ten(), __th_QueryDebugBuffer(), _DEBUG_HEAP_INFORMATION::Allocated, _DEBUG_HEAP_INFORMATION::Base, _DEBUG_HEAP_INFORMATION::Committed, _HeapInformation::count, dbg, eprintf, FALSE, _th_query_params::fin, free(), GetListOfHeaps(), _DEBUG_HEAP_INFORMATION::Granularity, HANDLE, _th_query_params::hanged, _DEBUG_BUFFER::HeapInformation, _HeapInformation::heaps, i, rz_list_t::length, mask, NULL, PDI_HEAPS, rz_debug_t::pid, realloc(), _th_query_params::ret, rz_list_free(), RZ_LOG_ERROR, RZ_NEW0, rz_sys_perror, and autogen_x86imm::tmp.

Referenced by GetHeapBlocks(), GetSingleBlock(), rz_heap_blocks_list(), rz_heap_list(), rz_heap_list_w32(), and w32_list_heaps_blocks().

◆ initialize_windows_ntdll_query_api_functions()

static bool initialize_windows_ntdll_query_api_functions ( void  )
static

Definition at line 137 of file windows_heap.c.

137  {
138  HANDLE ntdll = LoadLibrary(TEXT("ntdll.dll"));
139  if (!ntdll) {
140  return false;
141  }
142  if (!RtlCreateQueryDebugBuffer) {
143  RtlCreateQueryDebugBuffer = (PDEBUG_BUFFER(NTAPI *)(DWORD, BOOLEAN))GetProcAddress(ntdll, "RtlCreateQueryDebugBuffer");
144  }
145  if (!RtlQueryProcessDebugInformation) {
146  RtlQueryProcessDebugInformation = (NTSTATUS(NTAPI *)(DWORD, DWORD, PDEBUG_BUFFER))GetProcAddress(ntdll, "RtlQueryProcessDebugInformation");
147  }
148  if (!RtlDestroyQueryDebugBuffer) {
149  RtlDestroyQueryDebugBuffer = (NTSTATUS(NTAPI *)(PDEBUG_BUFFER))GetProcAddress(ntdll, "RtlDestroyQueryDebugBuffer");
150  }
151  if (!w32_NtQueryInformationProcess) {
152  w32_NtQueryInformationProcess = (NTSTATUS(NTAPI *)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG))GetProcAddress(ntdll, "NtQueryInformationProcess");
153  }
154  return true;
155 }
LONG NTSTATUS
Definition: win.h:198
PULONG
struct _DEBUG_BUFFER * PDEBUG_BUFFER

References DWORD, HANDLE, PULONG, PVOID, and ULONG.

Referenced by rz_heap_blocks_list(), rz_heap_debug_block_win(), rz_heap_list(), and rz_heap_list_w32().

◆ is_segment_heap()

static bool is_segment_heap ( HANDLE  h_proc,
PVOID  heapBase 
)
static

Definition at line 157 of file windows_heap.c.

157  {
158  HEAP heap;
159  if (ReadProcessMemory(h_proc, heapBase, &heap, sizeof(HEAP), NULL)) {
160  if (heap.SegmentSignature == 0xddeeddee) {
161  return true;
162  }
163  }
164  return false;
165 }

References NULL.

Referenced by GetSingleBlock().

◆ rz_heap_blocks_list()

RZ_IPI RzList* rz_heap_blocks_list ( RzCore core)

Definition at line 1412 of file windows_heap.c.

1412  {
1414  DWORD pid = core->dbg->pid;
1415  PDEBUG_BUFFER db;
1416  RzList *blocks_list = rz_list_newf(free);
1417  if (__is_windows_ten()) {
1418  db = GetHeapBlocks(pid, core->dbg);
1419  } else {
1420  db = InitHeapInfo(core->dbg, PDI_HEAPS | PDI_HEAP_BLOCKS);
1421  }
1422  if (!db) {
1423  eprintf("Couldn't get heap info.\n");
1424  return blocks_list;
1425  }
1426 
1427  PHeapInformation heapInfo = db->HeapInformation;
1428  CHECK_INFO_RETURN_NULL(heapInfo);
1429  HeapBlock *block = malloc(sizeof(HeapBlock));
1430  for (int i = 0; i < heapInfo->count; i++) {
1431  bool go = true;
1432  char *type;
1433  if (GetFirstHeapBlock(&heapInfo->heaps[i], block) & go) {
1434  do {
1435  type = get_type(block->dwFlags);
1436  if (!type) {
1437  type = "";
1438  }
1439  ut64 granularity = block->extraInfo ? block->extraInfo->granularity : heapInfo->heaps[i].Granularity;
1440  ut64 address = (ut64)block->dwAddress - granularity;
1441  ut64 unusedBytes = block->extraInfo ? block->extraInfo->unusedBytes : 0;
1442 
1443  // add blocks to list
1445  if (!heap_block) {
1446  rz_list_free(blocks_list);
1447  RtlDestroyQueryDebugBuffer(db);
1448  return NULL;
1449  }
1450  heap_block->headerAddress = address;
1451  heap_block->userAddress = (ut64)block->dwAddress;
1452  heap_block->size = block->dwSize;
1453  strcpy(heap_block->type, type);
1454  heap_block->unusedBytes = unusedBytes;
1455  heap_block->granularity = granularity;
1456 
1457  rz_list_append(blocks_list, heap_block);
1458  } while (GetNextHeapBlock(&heapInfo->heaps[i], block));
1459  }
1460  if (!(db->InfoClassMask & PDI_HEAP_BLOCKS)) {
1461  // RtlDestroyQueryDebugBuffer wont free this for some reason
1462  free_extra_info(&heapInfo->heaps[i]);
1463  RZ_FREE(heapInfo->heaps[i].Blocks);
1464  }
1465  }
1466  RtlDestroyQueryDebugBuffer(db);
1467  return blocks_list;
1468 }
RZ_API RZ_OWN RzList * rz_list_newf(RzListFree f)
Returns a new initialized RzList pointer and sets the free method.
Definition: list.c:248
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
ULONG InfoClassMask
Definition: windows_heap.h:955
RzDebug * dbg
Definition: rz_core.h:329
static char * get_type(WPARAM flags)
Definition: windows_heap.c:105
static PDEBUG_BUFFER GetHeapBlocks(DWORD pid, RzDebug *dbg)
Definition: windows_heap.c:780
#define CHECK_INFO_RETURN_NULL(heapInfo)
Definition: windows_heap.c:71
static bool initialize_windows_ntdll_query_api_functions(void)
Definition: windows_heap.c:137
#define PDI_HEAP_BLOCKS
Definition: windows_heap.c:55

References __is_windows_ten(), _DEBUG_HEAP_INFORMATION::Blocks, CHECK_INFO_RETURN_NULL, _HeapInformation::count, rz_core_t::dbg, _HeapBlock::dwAddress, _HeapBlock::dwFlags, DWORD, _HeapBlock::dwSize, eprintf, _HeapBlock::extraInfo, free(), free_extra_info(), get_type(), GetFirstHeapBlock(), GetHeapBlocks(), GetNextHeapBlock(), _HeapBlockExtraInfo::granularity, _DEBUG_HEAP_INFORMATION::Granularity, _DEBUG_BUFFER::HeapInformation, _HeapInformation::heaps, i, _DEBUG_BUFFER::InfoClassMask, InitHeapInfo(), initialize_windows_ntdll_query_api_functions(), malloc(), NULL, PDI_HEAP_BLOCKS, PDI_HEAPS, rz_debug_t::pid, pid, RZ_FREE, rz_list_append(), rz_list_free(), rz_list_newf(), RZ_NEW0, type, _HeapBlockExtraInfo::unusedBytes, and ut64().

◆ rz_heap_debug_block_win()

RZ_IPI void rz_heap_debug_block_win ( RzCore core,
const char *  addr,
RzOutputMode  mode,
bool  flag 
)

Definition at line 1370 of file windows_heap.c.

1370  {
1372  ut64 off = 0;
1373  if (!addr) {
1374  w32_list_heaps_blocks(core, mode, flag);
1375  return;
1376  }
1377 
1378  off = rz_num_math(core->num, addr);
1379  PHeapBlock hb = GetSingleBlock(core->dbg, off);
1380  if (!hb) {
1381  return;
1382  }
1383  ut64 granularity = hb->extraInfo->granularity;
1384  char *type = get_type(hb->dwFlags);
1385  if (!type) {
1386  type = "";
1387  }
1388  PJ *pj = pj_new();
1389  RzTable *tbl = __new_heapblock_tbl();
1390  ut64 headerAddr = off - granularity;
1391  if (mode == RZ_OUTPUT_MODE_STANDARD) {
1392  rz_table_add_rowf(tbl, "xxnnns", headerAddr, off, (ut64)hb->dwSize, granularity, (ut64)hb->extraInfo->unusedBytes, type);
1394  } else if (mode == RZ_OUTPUT_MODE_JSON) {
1395  pj_o(pj);
1396  pj_kN(pj, "header_address", headerAddr);
1397  pj_kN(pj, "user_address", off);
1398  pj_ks(pj, "type", type);
1399  pj_kN(pj, "size", hb->dwSize);
1400  if (hb->extraInfo->unusedBytes) {
1401  pj_kN(pj, "unused", hb->extraInfo->unusedBytes);
1402  }
1403  pj_end(pj);
1405  }
1406  free(hb->extraInfo);
1407  free(hb);
1408  rz_table_free(tbl);
1409  pj_free(pj);
1410 }
RZ_API void rz_cons_println(const char *str)
Definition: cons.c:233
const char int mode
Definition: ioapi.h:137
RZ_API ut64 rz_num_math(RzNum *num, const char *str)
Definition: unum.c:456
RZ_API PJ * pj_end(PJ *j)
Definition: pj.c:87
RZ_API const char * pj_string(PJ *pj)
Definition: pj.c:57
RZ_API PJ * pj_o(PJ *j)
Definition: pj.c:75
RZ_API PJ * pj_ks(PJ *j, const char *k, const char *v)
Definition: pj.c:170
RZ_API PJ * pj_kN(PJ *j, const char *k, st64 n)
Definition: pj.c:128
RZ_API void rz_table_add_rowf(RzTable *t, const char *fmt,...)
Definition: table.c:316
RZ_API void rz_table_free(RzTable *t)
Definition: table.c:114
RZ_API char * rz_table_tostring(RzTable *t)
Definition: table.c:510
@ RZ_OUTPUT_MODE_STANDARD
Definition: rz_types.h:39
RzNum * num
Definition: rz_core.h:316
static void w32_list_heaps_blocks(RzCore *core, RzOutputMode mode, bool flag)
static RzTable * __new_heapblock_tbl(void)
static PHeapBlock GetSingleBlock(RzDebug *dbg, ut64 offset)

References __new_heapblock_tbl(), addr, rz_core_t::dbg, _HeapBlock::dwFlags, _HeapBlock::dwSize, _HeapBlock::extraInfo, free(), get_type(), GetSingleBlock(), _HeapBlockExtraInfo::granularity, initialize_windows_ntdll_query_api_functions(), rz_core_t::num, off, pj_end(), pj_free(), pj_kN(), pj_ks(), pj_new(), pj_o(), pj_string(), rz_cons_println(), rz_num_math(), RZ_OUTPUT_MODE_JSON, RZ_OUTPUT_MODE_STANDARD, rz_table_add_rowf(), rz_table_free(), rz_table_tostring(), type, _HeapBlockExtraInfo::unusedBytes, ut64(), and w32_list_heaps_blocks().

◆ rz_heap_list()

RZ_IPI RzList* rz_heap_list ( RzCore core)

Definition at line 1470 of file windows_heap.c.

1470  {
1472  ULONG pid = core->dbg->pid;
1474  if (!db) {
1475  if (__is_windows_ten()) {
1476  db = GetHeapBlocks(pid, core->dbg);
1477  }
1478  if (!db) {
1479  eprintf("Couldn't get heap info.\n");
1480  return NULL;
1481  }
1482  }
1483 
1484  RzList *heaps_list = rz_list_newf(free);
1485  PHeapInformation heapInfo = db->HeapInformation;
1486  CHECK_INFO_RETURN_NULL(heapInfo);
1487  for (int i = 0; i < heapInfo->count; i++) {
1488  DEBUG_HEAP_INFORMATION heap = heapInfo->heaps[i];
1489  // add heaps to list
1491  if (!rzHeapInfo) {
1492  rz_list_free(heaps_list);
1493  RtlDestroyQueryDebugBuffer(db);
1494  return NULL;
1495  }
1496  rzHeapInfo->base = (ut64)heap.Base;
1497  rzHeapInfo->blockCount = (ut64)heap.BlockCount;
1498  rzHeapInfo->allocated = (ut64)heap.Allocated;
1499  rzHeapInfo->committed = (ut64)heap.Committed;
1500 
1501  rz_list_append(heaps_list, rzHeapInfo);
1502 
1503  if (!(db->InfoClassMask & PDI_HEAP_BLOCKS)) {
1505  RZ_FREE(heap.Blocks);
1506  }
1507  }
1508 
1509  RtlDestroyQueryDebugBuffer(db);
1510  return heaps_list;
1511 }

References __is_windows_ten(), rz_heap_info::allocated, rz_heap_info::base, rz_heap_info::blockCount, CHECK_INFO_RETURN_NULL, rz_heap_info::committed, _HeapInformation::count, rz_core_t::dbg, eprintf, free(), free_extra_info(), GetHeapBlocks(), _DEBUG_BUFFER::HeapInformation, _HeapInformation::heaps, i, _DEBUG_BUFFER::InfoClassMask, InitHeapInfo(), initialize_windows_ntdll_query_api_functions(), NULL, PDI_HEAP_BLOCKS, PDI_HEAPS, rz_debug_t::pid, pid, RZ_FREE, rz_list_append(), rz_list_free(), rz_list_newf(), RZ_NEW0, ULONG, and ut64().

◆ rz_heap_list_w32()

RZ_IPI void rz_heap_list_w32 ( RzCore core,
RzOutputMode  mode 
)

Definition at line 1237 of file windows_heap.c.

1237  {
1239  ULONG pid = core->dbg->pid;
1241  if (!db) {
1242  if (__is_windows_ten()) {
1243  db = GetHeapBlocks(pid, core->dbg);
1244  }
1245  if (!db) {
1246  eprintf("Couldn't get heap info.\n");
1247  return;
1248  }
1249  }
1250  PHeapInformation heapInfo = db->HeapInformation;
1251  CHECK_INFO(heapInfo);
1252  int i;
1253  RzTable *tbl = rz_table_new();
1254  rz_table_add_column(tbl, rz_table_type("number"), "Address", -1);
1255  rz_table_add_column(tbl, rz_table_type("number"), "Blocks", -1);
1256  rz_table_add_column(tbl, rz_table_type("number"), "Allocated", -1);
1257  rz_table_add_column(tbl, rz_table_type("number"), "Commited", -1);
1258  PJ *pj = pj_new();
1259  pj_a(pj);
1260  for (i = 0; i < heapInfo->count; i++) {
1261  DEBUG_HEAP_INFORMATION heap = heapInfo->heaps[i];
1262  if (mode == RZ_OUTPUT_MODE_JSON) {
1263  pj_o(pj);
1264  pj_kN(pj, "address", (ut64)heap.Base);
1265  pj_kN(pj, "count", (ut64)heap.BlockCount);
1266  pj_kN(pj, "allocated", (ut64)heap.Allocated);
1267  pj_kN(pj, "committed", (ut64)heap.Committed);
1268  pj_end(pj);
1269  } else {
1270  rz_table_add_rowf(tbl, "xnnn", (ut64)heap.Base, (ut64)heap.BlockCount, (ut64)heap.Allocated, (ut64)heap.Committed);
1271  }
1272  if (!(db->InfoClassMask & PDI_HEAP_BLOCKS)) {
1274  RZ_FREE(heap.Blocks);
1275  }
1276  }
1277  if (mode == RZ_OUTPUT_MODE_JSON) {
1278  pj_end(pj);
1280  } else {
1282  }
1283  rz_table_free(tbl);
1284  pj_free(pj);
1285  RtlDestroyQueryDebugBuffer(db);
1286 }
RZ_API PJ * pj_a(PJ *j)
Definition: pj.c:81
#define CHECK_INFO(heapInfo)
Definition: windows_heap.c:61

References __is_windows_ten(), CHECK_INFO, _HeapInformation::count, rz_core_t::dbg, eprintf, free_extra_info(), GetHeapBlocks(), _DEBUG_BUFFER::HeapInformation, _HeapInformation::heaps, i, _DEBUG_BUFFER::InfoClassMask, InitHeapInfo(), initialize_windows_ntdll_query_api_functions(), PDI_HEAP_BLOCKS, PDI_HEAPS, rz_debug_t::pid, pid, pj_a(), pj_end(), pj_free(), pj_kN(), pj_new(), pj_o(), pj_string(), rz_cons_println(), RZ_FREE, RZ_OUTPUT_MODE_JSON, rz_table_add_column(), rz_table_add_rowf(), rz_table_free(), rz_table_new(), rz_table_tostring(), rz_table_type(), ULONG, and ut64().

◆ w32_list_heaps_blocks()

static void w32_list_heaps_blocks ( RzCore core,
RzOutputMode  mode,
bool  flag 
)
static

Definition at line 1288 of file windows_heap.c.

1288  {
1289  DWORD pid = core->dbg->pid;
1290  PDEBUG_BUFFER db;
1291  if (__is_windows_ten()) {
1292  db = GetHeapBlocks(pid, core->dbg);
1293  } else {
1294  db = InitHeapInfo(core->dbg, PDI_HEAPS | PDI_HEAP_BLOCKS);
1295  }
1296  if (!db) {
1297  eprintf("Couldn't get heap info.\n");
1298  return;
1299  }
1300  PHeapInformation heapInfo = db->HeapInformation;
1301  CHECK_INFO(heapInfo);
1302  HeapBlock *block = malloc(sizeof(HeapBlock));
1303  int i;
1304  RzTable *tbl = __new_heapblock_tbl();
1305  PJ *pj = pj_new();
1306  pj_a(pj);
1307  for (i = 0; i < heapInfo->count; i++) {
1308  bool go = true;
1309  if (flag) {
1310  if (heapInfo->heaps[i].BlockCount > 50000) {
1311  go = rz_cons_yesno('n', "Are you sure you want to add %lu flags? (y/N)", heapInfo->heaps[i].BlockCount);
1312  }
1313  } else if (mode == RZ_OUTPUT_MODE_JSON) {
1314  pj_o(pj);
1315  pj_kN(pj, "heap", (WPARAM)heapInfo->heaps[i].Base);
1316  pj_k(pj, "blocks");
1317  pj_a(pj);
1318  }
1319 
1320  char *type;
1321  if (GetFirstHeapBlock(&heapInfo->heaps[i], block) & go) {
1322  do {
1323  type = get_type(block->dwFlags);
1324  if (!type) {
1325  type = "";
1326  }
1327  ut64 granularity = block->extraInfo ? block->extraInfo->granularity : heapInfo->heaps[i].Granularity;
1328  ut64 address = (ut64)block->dwAddress - granularity;
1329  ut64 unusedBytes = block->extraInfo ? block->extraInfo->unusedBytes : 0;
1330  if (flag) {
1331  char *name = rz_str_newf("alloc.%" PFMT64x "", address);
1332  if (!rz_flag_set(core->flags, name, address, block->dwSize)) {
1333  eprintf("Flag couldn't be set for block at 0x%" PFMT64x, address);
1334  }
1335  free(name);
1336  } else if (mode == RZ_OUTPUT_MODE_JSON) {
1337  pj_o(pj);
1338  pj_kN(pj, "header_address", address);
1339  pj_kN(pj, "user_address", (ut64)block->dwAddress);
1340  pj_kN(pj, "unused", unusedBytes);
1341  pj_kN(pj, "size", block->dwSize);
1342  pj_ks(pj, "type", type);
1343  pj_end(pj);
1344  } else {
1345  rz_table_add_rowf(tbl, "xxnnns", address, (ut64)block->dwAddress, block->dwSize, granularity, unusedBytes, type);
1346  }
1347  } while (GetNextHeapBlock(&heapInfo->heaps[i], block));
1348  }
1349  if (mode == RZ_OUTPUT_MODE_JSON) {
1350  pj_end(pj);
1351  pj_end(pj);
1352  }
1353  if (!(db->InfoClassMask & PDI_HEAP_BLOCKS)) {
1354  // RtlDestroyQueryDebugBuffer wont free this for some reason
1355  free_extra_info(&heapInfo->heaps[i]);
1356  RZ_FREE(heapInfo->heaps[i].Blocks);
1357  }
1358  }
1359  if (mode == RZ_OUTPUT_MODE_JSON) {
1360  pj_end(pj);
1362  } else if (!flag) {
1364  }
1365  rz_table_free(tbl);
1366  pj_free(pj);
1367  RtlDestroyQueryDebugBuffer(db);
1368 }
RZ_API RzFlagItem * rz_flag_set(RzFlag *f, const char *name, ut64 off, ut32 size)
Definition: flag.c:521
RZ_API bool rz_cons_yesno(int def, const char *fmt,...)
Definition: input.c:666
RZ_API PJ * pj_k(PJ *j, const char *k)
Definition: pj.c:104
#define PFMT64x
Definition: rz_types.h:393
Definition: z80asm.h:102
RzFlag * flags
Definition: rz_core.h:330

References __is_windows_ten(), __new_heapblock_tbl(), _DEBUG_HEAP_INFORMATION::Base, _DEBUG_HEAP_INFORMATION::BlockCount, _DEBUG_HEAP_INFORMATION::Blocks, CHECK_INFO, _HeapInformation::count, rz_core_t::dbg, _HeapBlock::dwAddress, _HeapBlock::dwFlags, DWORD, _HeapBlock::dwSize, eprintf, _HeapBlock::extraInfo, rz_core_t::flags, free(), free_extra_info(), get_type(), GetFirstHeapBlock(), GetHeapBlocks(), GetNextHeapBlock(), _HeapBlockExtraInfo::granularity, _DEBUG_HEAP_INFORMATION::Granularity, _DEBUG_BUFFER::HeapInformation, _HeapInformation::heaps, i, if(), _DEBUG_BUFFER::InfoClassMask, InitHeapInfo(), malloc(), PDI_HEAP_BLOCKS, PDI_HEAPS, PFMT64x, rz_debug_t::pid, pid, pj_a(), pj_end(), pj_free(), pj_k(), pj_kN(), pj_ks(), pj_new(), pj_o(), pj_string(), rz_cons_println(), rz_cons_yesno(), rz_flag_set(), RZ_FREE, RZ_OUTPUT_MODE_JSON, rz_str_newf(), rz_table_add_rowf(), rz_table_free(), rz_table_tostring(), type, _HeapBlockExtraInfo::unusedBytes, and ut64().

Referenced by rz_heap_debug_block_win().

Variable Documentation

◆ RtlpHpHeapGlobalsOffset

size_t RtlpHpHeapGlobalsOffset = 0
static

◆ RtlpLFHKeyOffset

size_t RtlpLFHKeyOffset = 0
static

Definition at line 59 of file windows_heap.c.

Referenced by GetHeapGlobalsOffset(), GetLFHKey(), and has_heap_globals().