Rizin
unix-like reverse engineering framework and cli tools
windows_heap.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2019 GustavoLCR <gugulcr@gmail.com>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_windows.h>
5 #include <rz_core.h>
6 #include <TlHelp32.h>
7 #include <windows_heap.h>
8 #include "..\..\debug\p\native\maps\windows_maps.h"
9 #include "..\..\bin\pdb\pdb_downloader.h"
10 #include "..\..\bin\pdb\pdb.h"
11 
12 /*
13  * Viewer discretion advised: Spaghetti code ahead
14  * Some Code references:
15  * https://securityxploded.com/enumheaps.php
16  * https://bitbucket.org/evolution536/crysearch-memory-scanner/
17  * https://processhacker.sourceforge.io
18  * http://www.tssc.de/winint
19  * https://www.nirsoft.net/kernel_struct/vista/
20  * https://github.com/yoichi/HeapStat/blob/master/heapstat.cpp
21  * https://doxygen.reactos.org/
22  *
23  * References:
24  * Windows NT(2000) Native API Reference (Book)
25  * Papers:
26  * http://illmatics.com/Understanding_the_LFH.pdf
27  * http://illmatics.com/Windows%208%20Heap%20Internals.pdf
28  * https://www.blackhat.com/docs/us-16/materials/us-16-Yason-Windows-10-Segment-Heap-Internals-wp.pdf
29  *
30  * This code has 2 different approaches to getting the heap info:
31  * 1) Calling InitHeapInfo with both PDI_HEAPS and PDI_HEAP_BLOCKS.
32  * This will fill a buffer with HeapBlockBasicInfo like structures which
33  * is then walked through by calling GetFirstHeapBlock and subsequently GetNextHeapBlock
34  * (see 1st link). This approach is the more generic one as it uses Windows functions.
35  * Unfortunately it fails to offer more detailed information about each block (although it is possible to get this info later) and
36  * also fails misteriously once the count of allocated blocks reach a certain threshold (1mil or so) or if segment heap is active for the
37  * program (in this case everything locks in the next call for the function)
38  * 2) In case 1 fails, Calling GetHeapBlocks, which will manually read and parse (poorly :[ ) each block.
39  * First it calls InitHeapInfo with only the PDI_HEAPS flag, with the only objective of getting a list of heap header addresses. It will then
40  * do the job that InitHeapInfo would do if it was called with PDI_HEAP_BLOCKS as well, filling a buffer with HeapBlockBasicInfo structures that
41  * can also be walked with GetFirstHeapBlock and GetNextHeapBlock (and HeapBlockExtraInfo when needed).
42  *
43  * TODO:
44  * Var to select algorithm?
45  * x86 vs x64 vs WOW64
46  * Graphs
47  * Print structures
48  * Make sure GetHeapBlocks actually works
49  * Maybe instead of using hardcoded structs we can get the offsets from ntdll.pdb
50  */
51 
52 #define PDI_MODULES 0x01
53 #define PDI_HEAPS 0x04
54 #define PDI_HEAP_TAGS 0x08
55 #define PDI_HEAP_BLOCKS 0x10
56 #define PDI_HEAP_ENTRIES_EX 0x200
57 
58 static size_t RtlpHpHeapGlobalsOffset = 0;
59 static size_t RtlpLFHKeyOffset = 0;
60 
61 #define CHECK_INFO(heapInfo) \
62  if (!heapInfo) { \
63  eprintf("It wasn't possible to get the heap information\n"); \
64  return; \
65  } \
66  if (!heapInfo->count) { \
67  rz_cons_print("No heaps for this process\n"); \
68  return; \
69  }
70 
71 #define CHECK_INFO_RETURN_NULL(heapInfo) \
72  if (!heapInfo) { \
73  eprintf("It wasn't possible to get the heap information\n"); \
74  return NULL; \
75  } \
76  if (!heapInfo->count) { \
77  rz_cons_print("No heaps for this process\n"); \
78  return NULL; \
79  }
80 
81 #define UPDATE_FLAGS(hb, flags) \
82  if (((flags)&0xf1) || ((flags)&0x0200)) { \
83  hb->dwFlags = LF32_FIXED; \
84  } else if ((flags)&0x20) { \
85  hb->dwFlags = LF32_MOVEABLE; \
86  } else if ((flags)&0x0100) { \
87  hb->dwFlags = LF32_FREE; \
88  } \
89  hb->dwFlags |= ((flags) >> SHIFT) << SHIFT;
90 
91 static bool __is_windows_ten(void) {
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 }
104 
105 static char *get_type(WPARAM flags) {
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 }
136 
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 }
156 
157 static bool is_segment_heap(HANDLE h_proc, PVOID heapBase) {
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 }
166 
167 // These functions are basically Heap32First and Heap32Next but faster
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 }
207 
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 }
256 
259  HeapBlock hb;
260  if (GetFirstHeapBlock(heap, &hb)) {
261  do {
262  RZ_FREE(hb.extraInfo);
263  } while (GetNextHeapBlock(heap, &hb));
264  }
265 }
266 
267 static inline bool has_heap_globals(void) {
269 }
270 
271 static bool GetHeapGlobalsOffset(RzDebug *dbg, HANDLE h_proc) {
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 }
392 
393 static bool GetLFHKey(RzDebug *dbg, HANDLE h_proc, bool segment, WPARAM *lfhKey) {
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 }
415 
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 }
429 
430 static bool DecodeLFHEntry(RzDebug *dbg, PHEAP heap, PHEAP_ENTRY entry, PHEAP_USERDATA_HEADER userBlocks, WPARAM key, WPARAM addr) {
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 }
441 
442 typedef struct _th_query_params {
447  bool fin;
448  bool hanged;
450 
451 static DWORD WINAPI __th_QueryDebugBuffer(void *param) {
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 }
461 
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 }
488 
489 /*
490  * This function may fail with PDI_HEAP_BLOCKS if:
491  * There's too many allocations
492  * The Segment Heap is activated (will block next time called)
493  * Notes:
494  * Some LFH allocations seem misaligned
495  */
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 }
578 
579 #define GROW_BLOCKS() \
580  if (allocated <= count * sizeof(HeapBlockBasicInfo)) { \
581  SIZE_T old_alloc = allocated; \
582  allocated *= 2; \
583  PVOID tmp = blocks; \
584  blocks = realloc(blocks, allocated); \
585  if (!blocks) { \
586  blocks = tmp; \
587  goto err; \
588  } \
589  memset((BYTE *)blocks + old_alloc, 0, old_alloc); \
590  }
591 
592 #define GROW_PBLOCKS() \
593  if (*allocated <= *count * sizeof(HeapBlockBasicInfo)) { \
594  SIZE_T old_alloc = *allocated; \
595  *allocated *= 2; \
596  PVOID tmp = *blocks; \
597  tmp = realloc(*blocks, *allocated); \
598  if (!tmp) { \
599  return false; \
600  } \
601  *blocks = tmp; \
602  memset((BYTE *)(*blocks) + old_alloc, 0, old_alloc); \
603  }
604 
605 static bool __lfh_segment_loop(HANDLE h_proc, PHeapBlockBasicInfo *blocks, SIZE_T *allocated, WPARAM lfhKey, WPARAM *count, WPARAM first, WPARAM next) {
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 }
640 
641 static bool GetSegmentHeapBlocks(RzDebug *dbg, HANDLE h_proc, PVOID heapBase, PHeapBlockBasicInfo *blocks, WPARAM *count, SIZE_T *allocated) {
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 }
779 
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 }
1008 
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 }
1111 
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 }
1225 
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 }
1236 
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 }
1287 
1288 static void w32_list_heaps_blocks(RzCore *core, RzOutputMode mode, bool flag) {
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 }
1369 
1370 RZ_IPI void rz_heap_debug_block_win(RzCore *core, const char *addr, RzOutputMode mode, bool flag) {
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 }
1411 
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 }
1469 
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 }
#define mask()
#define RZ_IPI
Definition: analysis_wasm.c:11
lzma_index ** i
Definition: index.h:629
static bool err
Definition: armass.c:435
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
RzBinInfo * info(RzBinFile *bf)
Definition: bin_ne.c:86
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 void rz_cons_println(const char *str)
Definition: cons.c:233
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
#define NULL
Definition: cris-opc.c:27
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
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
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
RzDebug * dbg
Definition: desil.c:30
size_t map(int syms, int left, int len)
Definition: enough.c:237
RZ_API RzFlagItem * rz_flag_set(RzFlag *f, const char *name, ut64 off, ut32 size)
Definition: flag.c:521
#define major(dev)
Definition: fsmagic.c:56
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
RZ_API const KEY_TYPE bool * found
Definition: ht_inc.h:130
RZ_API bool rz_cons_yesno(int def, const char *fmt,...)
Definition: input.c:666
voidpf uLong offset
Definition: ioapi.h:144
const char int mode
Definition: ioapi.h:137
#define offsetof(type, member)
uint8_t ut8
Definition: lh5801.h:11
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_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
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
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
void * realloc(void *ptr, size_t size)
Definition: malloc.c:144
void * malloc(size_t size)
Definition: malloc.c:123
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
unsigned char BYTE
Definition: lz4.c:286
#define header(is_bt, len_min, ret_op)
int type
Definition: mipsasm.c:17
#define FALSE
Definition: mybfd.h:102
modules
Definition: regress.py:20
-lz4-versions
int off
Definition: pal.c:13
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.
#define ph(a_type)
Definition: ph.h:27
#define eprintf(x, y...)
Definition: rlcc.c:7
static RzSocket * s
Definition: rtr.c:28
#define rz_return_if_fail(expr)
Definition: rz_assert.h:100
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
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
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
RZ_API ut64 rz_num_math(RzNum *num, const char *str)
Definition: unum.c:456
RZ_API PJ * pj_new(void)
Definition: pj.c:25
RZ_API PJ * pj_k(PJ *j, const char *k)
Definition: pj.c:104
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 void pj_free(PJ *j)
Definition: pj.c:34
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_a(PJ *j)
Definition: pj.c:81
RZ_API PJ * pj_kN(PJ *j, const char *k, st64 n)
Definition: pj.c:128
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
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API void rz_sys_info_free(RSysInfo *si)
Definition: sys.c:1251
RZ_API RSysInfo * rz_sys_info(void)
Definition: sys.c:1175
@ RZ_SYS_BITS_32
Definition: rz_sys.h:20
@ RZ_SYS_BITS_64
Definition: rz_sys.h:21
RZ_API void rz_table_add_column(RzTable *t, RzTableColumnType *type, const char *name, int maxWidth)
Definition: table.c:134
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_API RzTable * rz_table_new(void)
Definition: table.c:103
RZ_API RzTableColumnType * rz_table_type(const char *name)
Definition: table.c:24
#define rz_sys_perror(x)
Definition: rz_types.h:336
#define RZ_PERM_R
Definition: rz_types.h:93
#define RZ_NEW0(x)
Definition: rz_types.h:284
RzOutputMode
Enum to describe the way data are printed.
Definition: rz_types.h:38
@ RZ_OUTPUT_MODE_JSON
Definition: rz_types.h:40
@ RZ_OUTPUT_MODE_STANDARD
Definition: rz_types.h:39
#define RZ_FREE(x)
Definition: rz_types.h:369
#define PFMT64x
Definition: rz_types.h:393
static struct sockaddr static addrlen static backlog const void static flags void struct sockaddr from
Definition: sfsocketcall.h:123
static struct sockaddr static addrlen static backlog const void static flags void flags
Definition: sfsocketcall.h:123
#define h(i)
Definition: sha256.c:48
const char * symbol_server
const char * symbol_store_path
PVOID HeapInformation
Definition: windows_heap.h:961
ULONG InfoClassMask
Definition: windows_heap.h:955
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
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_LFH_SUBSEGMENT_ENCODED_OFFSETS BlockOffsets
Definition: windows_heap.h:537
PLFH_BLOCK_ZONE CrtZone
Definition: windows_heap.h:864
HEAP_PAGE_RANGE_DESCRIPTOR DescArray[256]
Definition: windows_heap.h:430
LIST_ENTRY ListEntry
Definition: windows_heap.h:425
LIST_ENTRY SegmentListEntry
Definition: windows_heap.h:638
PHEAP_ENTRY LastValidEntry
Definition: windows_heap.h:646
PHEAP_ENTRY FirstEntry
Definition: windows_heap.h:645
PHEAP_SUBSEGMENT SubSegment
Definition: windows_heap.h:801
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_VS_CHUNK_HEADER_SIZE Sizes
Definition: windows_heap.h:379
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
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
PHeapBlockExtraInfo extraInfo
Definition: windows_heap.h:943
DEBUG_HEAP_INFORMATION heaps[]
Definition: windows_heap.h:991
LIST_ENTRY SubSegmentZones
Definition: windows_heap.h:904
PRTL_BALANCED_NODE Left
Definition: windows_heap.h:48
PRTL_BALANCED_NODE Right
Definition: windows_heap.h:49
WPARAM * Buffer
Definition: windows_heap.h:795
WPARAM SizeOfBitMap
Definition: windows_heap.h:794
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
PDEBUG_BUFFER db
Definition: windows_heap.c:445
Definition: zipcmp.c:77
Definition: heap-inl.h:40
Definition: z80asm.h:102
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
RzDebug * dbg
Definition: rz_core.h:329
RzIO * io
Definition: rz_core.h:313
RzNum * num
Definition: rz_core.h:316
RzFlag * flags
Definition: rz_core.h:330
RzConfig * config
Definition: rz_core.h:300
RzCoreBind corebind
Definition: rz_debug.h:314
int bits
Definition: rz_debug.h:243
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
ut32 length
Definition: rz_list.h:22
Definition: dis.h:43
uint64_t blocks
Definition: list.c:104
#define fail(test)
Definition: tests.h:29
LONG NTSTATUS
Definition: win.h:198
if(dbg->bits==RZ_SYS_BITS_64)
Definition: windows-arm64.h:4
DWORD * HANDLE
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
ULONG
PVOID
DWORD
PULONG
static size_t RtlpHpHeapGlobalsOffset
Definition: windows_heap.c:58
static char * get_type(WPARAM flags)
Definition: windows_heap.c:105
static bool GetNextHeapBlock(PDEBUG_HEAP_INFORMATION heapInfo, PHeapBlock hb)
Definition: windows_heap.c:208
RZ_IPI void rz_heap_list_w32(RzCore *core, RzOutputMode mode)
#define CHECK_INFO(heapInfo)
Definition: windows_heap.c:61
static bool has_heap_globals(void)
Definition: windows_heap.c:267
#define PDI_HEAPS
Definition: windows_heap.c:53
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
static bool is_segment_heap(HANDLE h_proc, PVOID heapBase)
Definition: windows_heap.c:157
static DWORD WINAPI __th_QueryDebugBuffer(void *param)
Definition: windows_heap.c:451
static bool DecodeHeapEntry(RzDebug *dbg, PHEAP heap, PHEAP_ENTRY entry)
Definition: windows_heap.c:416
#define GROW_PBLOCKS()
Definition: windows_heap.c:592
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)
static RzList * GetListOfHeaps(RzDebug *dbg, HANDLE ph)
Definition: windows_heap.c:462
static RzTable * __new_heapblock_tbl(void)
RZ_IPI RzList * rz_heap_list(RzCore *core)
static bool GetFirstHeapBlock(PDEBUG_HEAP_INFORMATION heapInfo, PHeapBlock hb)
Definition: windows_heap.c:168
static bool GetHeapGlobalsOffset(RzDebug *dbg, HANDLE h_proc)
Definition: windows_heap.c:271
struct _th_query_params th_query_params
static bool __is_windows_ten(void)
Definition: windows_heap.c:91
static PDEBUG_BUFFER GetHeapBlocks(DWORD pid, RzDebug *dbg)
Definition: windows_heap.c:780
static bool GetLFHKey(RzDebug *dbg, HANDLE h_proc, bool segment, WPARAM *lfhKey)
Definition: windows_heap.c:393
#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
static bool DecodeLFHEntry(RzDebug *dbg, PHEAP heap, PHEAP_ENTRY entry, PHEAP_USERDATA_HEADER userBlocks, WPARAM key, WPARAM addr)
Definition: windows_heap.c:430
static size_t RtlpLFHKeyOffset
Definition: windows_heap.c:59
static PHeapBlock GetSingleBlock(RzDebug *dbg, ut64 offset)
#define PDI_HEAP_BLOCKS
Definition: windows_heap.c:55
RZ_IPI RzList * rz_heap_blocks_list(RzCore *core)
#define UPDATE_FLAGS(hb, flags)
Definition: windows_heap.c:81
static PDEBUG_BUFFER InitHeapInfo(RzDebug *dbg, DWORD mask)
Definition: windows_heap.c:496
static PHeapBlock GetSingleSegmentBlock(RzDebug *dbg, HANDLE h_proc, PSEGMENT_HEAP heapBase, WPARAM offset)
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
#define VS_BLOCK
Definition: windows_heap.h:35
struct _HEAP_ENTRY * PHEAP_ENTRY
struct _DEBUG_BUFFER * PDEBUG_BUFFER
struct _HeapBlockExtraInfo * PHeapBlockExtraInfo
struct _HEAP_SEG_CONTEXT HEAP_SEG_CONTEXT
struct _RTL_BALANCED_NODE RTL_BALANCED_NODE
struct _HEAP_VIRTUAL_ALLOC_ENTRY HEAP_VIRTUAL_ALLOC_ENTRY
@ PAGE_RANGE_FLAGS_LFH_SUBSEGMENT
Definition: windows_heap.h:390
@ PAGE_RANGE_FLAGS_ALLOCATED
Definition: windows_heap.h:392
@ PAGE_RANGE_FLAGS_FIRST
Definition: windows_heap.h:393
struct _HeapBlockBasicInfo * PHeapBlockBasicInfo
#define LARGE_BLOCK
Definition: windows_heap.h:32
#define SEGMENT_HEAP_BLOCK
Definition: windows_heap.h:34
struct _HEAP_VS_CHUNK_HEADER HEAP_VS_CHUNK_HEADER
#define LFH_BLOCK
Definition: windows_heap.h:31
struct _RTL_BALANCED_NODE * PRTL_BALANCED_NODE
Definition: windows_heap.h:43
#define BACKEND_BLOCK
Definition: windows_heap.h:36
struct _HeapBlockBasicInfo HeapBlockBasicInfo
struct _HEAP * PHEAP
Definition: windows_heap.h:41
struct _HEAP_SUBSEGMENT HEAP_SUBSEGMENT
#define EXTRA_FLAG
Definition: windows_heap.h:28
struct _HEAP_ENTRY HEAP_ENTRY
struct _HEAP_VS_SUBSEGMENT HEAP_VS_SUBSEGMENT
struct _HEAP_PAGE_SEGMENT HEAP_PAGE_SEGMENT
#define NT_BLOCK
Definition: windows_heap.h:33
struct _HEAP_PAGE_RANGE_DESCRIPTOR HEAP_PAGE_RANGE_DESCRIPTOR
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
static int addr
Definition: z80asm.c:58