Refactor windows heap parser (#6014)

This commit is contained in:
bubblepipe 2026-04-10 14:46:11 +07:00 committed by GitHub
parent 58a39e6411
commit bb76233c2e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 903 additions and 148 deletions

View file

@ -2957,6 +2957,12 @@ RZ_API int rz_core_config_init(RzCore *core) {
SETDESC(n, "Select page size for jemalloc heap parsing (auto-detected if 'auto')"); SETDESC(n, "Select page size for jemalloc heap parsing (auto-detected if 'auto')");
SETOPTIONS(n, "auto", "4k", "16k", "64k", NULL); SETOPTIONS(n, "auto", "4k", "16k", "64k", NULL);
n = NODECB("dbg.windows.version", "auto", NULL);
SETDESC(n, "Set Windows 10 version for heap parsing (default '1511' if 'auto')");
SETOPTIONS(n, "auto",
"1511", "1607", "1703", "1709", "1803", "1809",
"1903", "1909", "2004", "20H2", "21H1", "21H2", "22H2", NULL);
SETBPREF("esil.prestep", "true", "Step before esil evaluation in `de` commands"); SETBPREF("esil.prestep", "true", "Step before esil evaluation in `de` commands");
SETPREF("esil.fillstack", "", "Initialize ESIL stack with (random, debrujn, sequence, zeros, ...)"); SETPREF("esil.fillstack", "", "Initialize ESIL stack with (random, debrujn, sequence, zeros, ...)");
SETICB("esil.verbose", 0, &cb_esilverbose, "Show ESIL verbose level (0, 1, 2)"); SETICB("esil.verbose", 0, &cb_esilverbose, "Show ESIL verbose level (0, 1, 2)");

View file

@ -1,36 +0,0 @@
// SPDX-FileCopyrightText: 2021 Pulak Malhotra <pulakmalhotra2000@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_core.h>
#include "core_private.h"
/* API calls of windows heap for Cutter */
#if __WINDOWS__
/**
* \brief Get a list of heap blocks (Windows heap)
* \param core RzCore Pointer
* \return RzList of RzWindowsHeapBlock structs
*/
RZ_API RZ_OWN RzList /*<RzWindowsHeapBlock *>*/ *rz_heap_windows_blocks_list(RzCore *core) {
return rz_heap_blocks_list(core);
}
/**
* \brief Get a list of heaps (Windows heap)
* \param core RzCore Pointer
* \return RzList of RzWindowsHeapInfo structs
*/
RZ_API RZ_OWN RzList /*<RzWindowsHeapInfo *>*/ *rz_heap_windows_heap_list(RzCore *core) {
return rz_heap_list(core);
}
#else
RZ_API RZ_OWN RzList /*<RzWindowsHeapBlock *>*/ *rz_heap_windows_blocks_list(RzCore *core) {
return NULL;
}
RZ_API RZ_OWN RzList /*<RzWindowsHeapInfo *>*/ *rz_heap_windows_heap_list(RzCore *core) {
return NULL;
}
#endif

View file

@ -1,43 +1,262 @@
// SPDX-FileCopyrightText: 2021 Pulak Malhotra <pulakmalhotra2000@gmail.com> // SPDX-FileCopyrightText: 2021 Pulak Malhotra <pulakmalhotra2000@gmail.com>
// SPDX-FileCopyrightText: 2026 bubblepipe <bubblepipe42@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only // SPDX-License-Identifier: LGPL-3.0-only
#include "analysis_private.h"
#include <rz_core.h> #include <rz_core.h>
#include "../core_private.h" #include <rz_windows_heap.h>
#define NOT_SUPPORTED_ERROR_MESSAGE \
RZ_LOG_ERROR("core: Windows heap parsing is not supported on this platform\n"); \
return RZ_CMD_STATUS_ERROR;
#if __WINDOWS__ #if __WINDOWS__
RZ_IPI RzCmdStatus rz_cmd_debug_process_heaps_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { bool is_windows_live_debug(RzCore *core) {
rz_heap_list_w32(core, mode); return core->dbg && core->dbg->cur && !rz_debug_is_dead(core->dbg);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_debug_process_heap_block_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
if (argc == 2) {
rz_heap_debug_block_win(core, argv[1], mode, false);
} else {
rz_heap_debug_block_win(core, NULL, mode, false);
}
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_debug_heap_block_flag_handler(RzCore *core, int argc, const char **argv) {
rz_heap_debug_block_win(core, NULL, RZ_OUTPUT_MODE_STANDARD, true);
return RZ_CMD_STATUS_OK;
}
#else
RZ_IPI RzCmdStatus rz_cmd_debug_heap_block_flag_handler(RzCore *core, int argc, const char **argv) {
NOT_SUPPORTED_ERROR_MESSAGE;
}
RZ_IPI RzCmdStatus rz_cmd_debug_process_heaps_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
NOT_SUPPORTED_ERROR_MESSAGE;
}
RZ_IPI RzCmdStatus rz_cmd_debug_process_heap_block_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
NOT_SUPPORTED_ERROR_MESSAGE;
} }
#endif #endif
void init_heap_config(RzCore *core, RzWindowsHeapConfig *config) {
ut8 ptr_size = 8;
int build = RZ_W10_BUILD_21H1;
ut8 bits = (ut8)rz_asm_get_bits(core->rasm);
if (!bits && core->analysis) {
bits = (ut8)core->analysis->bits;
}
if (bits) {
ptr_size = (bits == 32) ? 4 : 8;
}
const char *version_cfg = rz_config_get(core->config, "dbg.windows.version");
if (version_cfg && RZ_STR_NE(version_cfg, "auto")) {
if (RZ_STR_EQ(version_cfg, "21H1") || RZ_STR_EQ(version_cfg, "21H2") ||
RZ_STR_EQ(version_cfg, "22H2")) {
build = RZ_W10_BUILD_21H1;
} else if (RZ_STR_EQ(version_cfg, "1607") || RZ_STR_EQ(version_cfg, "1703") ||
RZ_STR_EQ(version_cfg, "1709") || RZ_STR_EQ(version_cfg, "1803") ||
RZ_STR_EQ(version_cfg, "1809") || RZ_STR_EQ(version_cfg, "1903") ||
RZ_STR_EQ(version_cfg, "1909") || RZ_STR_EQ(version_cfg, "2004") ||
RZ_STR_EQ(version_cfg, "20H2")) {
build = RZ_W10_BUILD_1607;
} else { // default case
build = RZ_W10_BUILD_1511;
}
}
rz_w32_heap_config_init(config, ptr_size, build);
}
ut64 get_heap_base(RzIO *io, const RzWindowsHeapConfig *config) {
ut8 buf[8];
if (!rz_io_read_at_mapped(io, config->segment.base_address, buf, config->ptr_size)) {
return 0;
}
if (config->ptr_size == 8) {
return rz_read_le64(buf);
}
return (ut64)rz_read_le32(buf);
}
RZ_IPI RzCmdStatus rz_cmd_debug_process_heaps_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
#if __WINDOWS__
if (is_windows_live_debug(core)) {
rz_heap_list_w32(core, state->mode);
return RZ_CMD_STATUS_OK;
}
#endif
RzWindowsHeapConfig config;
init_heap_config(core, &config);
ut64 heap_base = get_heap_base(core->io, &config);
RzWindowsHeapInfo *info = rz_w32_heap_info_parse(core->io, heap_base, &config);
if (!info) {
return RZ_CMD_STATUS_ERROR;
}
RzList *blocks = rz_w32_heap_blocks_list(core->io, info, &config);
ut64 block_count = blocks ? rz_list_length(blocks) : 0;
if (state->mode == RZ_OUTPUT_MODE_JSON) {
PJ *pj = state->d.pj;
pj_a(pj);
pj_o(pj);
pj_kN(pj, "address", info->base_address);
pj_kN(pj, "count", block_count);
pj_kN(pj, "flags", info->flags);
pj_kN(pj, "signature", info->heap_signature);
pj_end(pj);
pj_end(pj);
} else {
RzTable *tbl = state->d.t;
rz_table_add_column(tbl, RZ_TABLE_COLUMN_TYPE_NUMBER, "Address");
rz_table_add_column(tbl, RZ_TABLE_COLUMN_TYPE_NUMBER, "Blocks");
rz_table_add_column(tbl, RZ_TABLE_COLUMN_TYPE_NUMBER, "Pages");
rz_table_add_column(tbl, RZ_TABLE_COLUMN_TYPE_STRING, "FrontEnd");
const char *fe_type = "None";
if (info->front_end_heap_type == 2) {
fe_type = "LFH";
} else if (info->front_end_heap_type == 1) {
fe_type = "Lookaside";
}
rz_table_add_rowf(tbl, "xnns", info->base_address, block_count,
(ut64)info->number_of_pages, fe_type);
}
rz_list_free(blocks);
RZ_FREE(info);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_debug_process_heap_block_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
#if __WINDOWS__
if (is_windows_live_debug(core)) {
if (argc == 2) {
rz_heap_debug_block_win(core, argv[1], state->mode, false);
} else {
rz_heap_debug_block_win(core, NULL, state->mode, false);
}
return RZ_CMD_STATUS_OK;
}
#endif
RzWindowsHeapConfig config;
init_heap_config(core, &config);
ut64 heap_base = get_heap_base(core->io, &config);
RzWindowsHeapInfo *info = rz_w32_heap_info_parse(core->io, heap_base, &config);
if (!info) {
return RZ_CMD_STATUS_ERROR;
}
RzList *blocks = rz_w32_heap_blocks_list(core->io, info, &config);
if (!blocks) {
RZ_FREE(info);
return RZ_CMD_STATUS_ERROR;
}
// an address argument is given, find and display just that block
if (argc == 2) {
ut64 target = rz_num_math(core->num, argv[1]);
RzListIter *iter;
RzWindowsHeapEntry *block;
bool found = false;
rz_list_foreach (blocks, iter, block) {
if (block->user_address == target ||
block->header_address == target ||
(target >= block->header_address && target < block->header_address + block->size)) {
found = true;
const char *block_state = block->is_busy ? "BUSY" : "FREE";
if (state->mode == RZ_OUTPUT_MODE_JSON) {
PJ *pj = state->d.pj;
pj_o(pj);
pj_kN(pj, "header_address", block->header_address);
pj_kN(pj, "user_address", block->user_address);
pj_kN(pj, "size", block->size);
pj_kN(pj, "unused", block->unused_bytes);
pj_ks(pj, "type", block_state);
pj_end(pj);
} else {
RzTable *tbl = state->d.t;
rz_table_add_column(tbl, RZ_TABLE_COLUMN_TYPE_NUMBER, "HeaderAddress");
rz_table_add_column(tbl, RZ_TABLE_COLUMN_TYPE_NUMBER, "UserAddress");
rz_table_add_column(tbl, RZ_TABLE_COLUMN_TYPE_NUMBER, "Size");
rz_table_add_column(tbl, RZ_TABLE_COLUMN_TYPE_NUMBER, "Unused");
rz_table_add_column(tbl, RZ_TABLE_COLUMN_TYPE_STRING, "Type");
rz_table_add_rowf(tbl, "xxnns", block->header_address,
block->user_address, block->size,
(ut64)block->unused_bytes, block_state);
}
break;
}
}
if (!found) {
RZ_LOG_ERROR("core: Heap block not found at 0x%" PFMT64x "\n", target);
}
rz_list_free(blocks);
RZ_FREE(info);
return found ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
}
if (state->mode == RZ_OUTPUT_MODE_JSON) {
PJ *pj = state->d.pj;
pj_o(pj);
pj_kN(pj, "heap", info->base_address);
pj_k(pj, "blocks");
pj_a(pj);
RzListIter *iter;
RzWindowsHeapEntry *block;
rz_list_foreach (blocks, iter, block) {
const char *block_state = block->is_busy ? "BUSY" : "FREE";
pj_o(pj);
pj_kN(pj, "header_address", block->header_address);
pj_kN(pj, "user_address", block->user_address);
pj_kN(pj, "size", block->size);
pj_kN(pj, "unused", block->unused_bytes);
pj_ks(pj, "type", block_state);
pj_end(pj);
}
pj_end(pj);
pj_end(pj);
pj_end(pj);
} else {
RzTable *tbl = state->d.t;
rz_table_add_column(tbl, RZ_TABLE_COLUMN_TYPE_NUMBER, "HeaderAddress");
rz_table_add_column(tbl, RZ_TABLE_COLUMN_TYPE_NUMBER, "UserAddress");
rz_table_add_column(tbl, RZ_TABLE_COLUMN_TYPE_NUMBER, "Size");
rz_table_add_column(tbl, RZ_TABLE_COLUMN_TYPE_NUMBER, "Unused");
rz_table_add_column(tbl, RZ_TABLE_COLUMN_TYPE_STRING, "Type");
RzListIter *iter;
RzWindowsHeapEntry *block;
rz_list_foreach (blocks, iter, block) {
const char *block_state = block->is_busy ? "BUSY" : "FREE";
rz_table_add_rowf(tbl, "xxnns", block->header_address,
block->user_address, block->size,
(ut64)block->unused_bytes, block_state);
}
}
rz_list_free(blocks);
RZ_FREE(info);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_debug_heap_block_flag_handler(RzCore *core, int argc, const char **argv) {
#if __WINDOWS__
if (is_windows_live_debug(core)) {
rz_heap_debug_block_win(core, NULL, RZ_OUTPUT_MODE_STANDARD, true);
return RZ_CMD_STATUS_OK;
}
#endif
RzWindowsHeapConfig config;
init_heap_config(core, &config);
ut64 heap_base = get_heap_base(core->io, &config);
RzWindowsHeapInfo *info = rz_w32_heap_info_parse(core->io, heap_base, &config);
if (!info) {
return RZ_CMD_STATUS_ERROR;
}
RzList *blocks = rz_w32_heap_blocks_list(core->io, info, &config);
if (!blocks) {
RZ_FREE(info);
return RZ_CMD_STATUS_ERROR;
}
RzListIter *iter;
RzWindowsHeapEntry *block;
rz_list_foreach (blocks, iter, block) {
char *name = rz_str_newf("alloc.%" PFMT64x, block->header_address);
if (name) {
rz_flag_set(core->flags, name, block->header_address, block->size);
free(name);
}
}
rz_list_free(blocks);
RZ_FREE(info);
return RZ_CMD_STATUS_OK;
}

View file

@ -23596,10 +23596,12 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) {
RzCmdDesc *cmd_heap_tcache_print_cd = rz_cmd_desc_argv_new(core->rcmd, dmhg_cd, "dmhgt", rz_cmd_heap_tcache_print_handler, &cmd_heap_tcache_print_help); RzCmdDesc *cmd_heap_tcache_print_cd = rz_cmd_desc_argv_new(core->rcmd, dmhg_cd, "dmhgt", rz_cmd_heap_tcache_print_handler, &cmd_heap_tcache_print_help);
rz_warn_if_fail(cmd_heap_tcache_print_cd); rz_warn_if_fail(cmd_heap_tcache_print_cd);
RzCmdDesc *dmhw_cd = rz_cmd_desc_group_modes_new(core->rcmd, dmh_cd, "dmhw", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_debug_process_heaps_handler, &cmd_debug_process_heaps_help, &dmhw_help); RzCmdDesc *dmhw_cd = rz_cmd_desc_group_state_new(core->rcmd, dmh_cd, "dmhw", RZ_OUTPUT_MODE_TABLE | RZ_OUTPUT_MODE_JSON, rz_cmd_debug_process_heaps_handler, &cmd_debug_process_heaps_help, &dmhw_help);
rz_warn_if_fail(dmhw_cd); rz_warn_if_fail(dmhw_cd);
RzCmdDesc *cmd_debug_process_heap_block_cd = rz_cmd_desc_argv_modes_new(core->rcmd, dmhw_cd, "dmhwb", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_debug_process_heap_block_handler, &cmd_debug_process_heap_block_help); rz_cmd_desc_set_default_mode(dmhw_cd, RZ_OUTPUT_MODE_TABLE);
RzCmdDesc *cmd_debug_process_heap_block_cd = rz_cmd_desc_argv_state_new(core->rcmd, dmhw_cd, "dmhwb", RZ_OUTPUT_MODE_TABLE | RZ_OUTPUT_MODE_JSON, rz_cmd_debug_process_heap_block_handler, &cmd_debug_process_heap_block_help);
rz_warn_if_fail(cmd_debug_process_heap_block_cd); rz_warn_if_fail(cmd_debug_process_heap_block_cd);
rz_cmd_desc_set_default_mode(cmd_debug_process_heap_block_cd, RZ_OUTPUT_MODE_TABLE);
RzCmdDesc *cmd_debug_heap_block_flag_cd = rz_cmd_desc_argv_new(core->rcmd, dmhw_cd, "dmhwbf", rz_cmd_debug_heap_block_flag_handler, &cmd_debug_heap_block_flag_help); RzCmdDesc *cmd_debug_heap_block_flag_cd = rz_cmd_desc_argv_new(core->rcmd, dmhw_cd, "dmhwbf", rz_cmd_debug_heap_block_flag_handler, &cmd_debug_heap_block_flag_help);
rz_warn_if_fail(cmd_debug_heap_block_flag_cd); rz_warn_if_fail(cmd_debug_heap_block_flag_cd);

View file

@ -1350,9 +1350,9 @@ RZ_IPI RzCmdStatus rz_cmd_main_arena_print_handler(RzCore *core, int argc, const
// "dmhgt" // "dmhgt"
RZ_IPI RzCmdStatus rz_cmd_heap_tcache_print_handler(RzCore *core, int argc, const char **argv); RZ_IPI RzCmdStatus rz_cmd_heap_tcache_print_handler(RzCore *core, int argc, const char **argv);
// "dmhw" // "dmhw"
RZ_IPI RzCmdStatus rz_cmd_debug_process_heaps_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); RZ_IPI RzCmdStatus rz_cmd_debug_process_heaps_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state);
// "dmhwb" // "dmhwb"
RZ_IPI RzCmdStatus rz_cmd_debug_process_heap_block_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); RZ_IPI RzCmdStatus rz_cmd_debug_process_heap_block_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state);
// "dmhwbf" // "dmhwbf"
RZ_IPI RzCmdStatus rz_cmd_debug_heap_block_flag_handler(RzCore *core, int argc, const char **argv); RZ_IPI RzCmdStatus rz_cmd_debug_heap_block_flag_handler(RzCore *core, int argc, const char **argv);
// "dmhja" // "dmhja"

View file

@ -93,16 +93,20 @@ commands:
- name: dmhw - name: dmhw
summary: List process heaps summary: List process heaps
cname: cmd_debug_process_heaps cname: cmd_debug_process_heaps
type: RZ_CMD_DESC_TYPE_ARGV_STATE
modes: modes:
- RZ_OUTPUT_MODE_STANDARD - RZ_OUTPUT_MODE_TABLE
- RZ_OUTPUT_MODE_JSON - RZ_OUTPUT_MODE_JSON
default_mode: RZ_OUTPUT_MODE_TABLE
args: [] args: []
- name: dmhwb - name: dmhwb
summary: List allocated heap blocks summary: List allocated heap blocks
cname: cmd_debug_process_heap_block cname: cmd_debug_process_heap_block
type: RZ_CMD_DESC_TYPE_ARGV_STATE
modes: modes:
- RZ_OUTPUT_MODE_STANDARD - RZ_OUTPUT_MODE_TABLE
- RZ_OUTPUT_MODE_JSON - RZ_OUTPUT_MODE_JSON
default_mode: RZ_OUTPUT_MODE_TABLE
args: args:
- name: addr - name: addr
type: RZ_CMD_ARG_TYPE_RZNUM type: RZ_CMD_ARG_TYPE_RZNUM

View file

@ -245,14 +245,6 @@ RZ_IPI void rz_core_print_hexdiff(RZ_NONNULL RzCore *core, ut64 aa, RZ_NONNULL c
// cmd_help.c // cmd_help.c
RZ_IPI void rz_core_clippy_print(RzCore *core, const char *msg); RZ_IPI void rz_core_clippy_print(RzCore *core, const char *msg);
#if __WINDOWS__
/* windows_heap.c */
RZ_IPI RzList *rz_heap_blocks_list(RzCore *core);
RZ_IPI RzList *rz_heap_list(RzCore *core);
RZ_IPI void rz_heap_debug_block_win(RzCore *core, const char *addr, RzOutputMode mode, bool flag);
RZ_IPI void rz_heap_list_w32(RzCore *core, RzOutputMode mode);
#endif
RZ_IPI bool rz_core_cmd_lastcmd_repeat(RzCore *core, bool next); RZ_IPI bool rz_core_cmd_lastcmd_repeat(RzCore *core, bool next);
static inline RzCmdStatus bool2status(bool val) { static inline RzCmdStatus bool2status(bool val) {

121
librz/core/heap_windows.c Normal file
View file

@ -0,0 +1,121 @@
// SPDX-FileCopyrightText: 2026 bubblepipe <bubblepipe42@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_core.h>
#include <rz_windows_heap.h>
#include <rz_windows/windows_heap_parser.h>
RZ_OWN RzWindowsHeapInfo *rz_w32_heap_info_parse(RZ_NONNULL RzIO *io,
ut64 heap_base, RZ_NONNULL const RzWindowsHeapConfig *config) {
rz_return_val_if_fail(io && config, NULL);
RzWindowsHeapInfo *info = RZ_NEW0(RzWindowsHeapInfo);
if (!info) {
return NULL;
}
if (!rz_w32_read_heap_info(io, heap_base, info, config)) {
RZ_LOG_ERROR("Failed to read heap header at 0x%" PFMT64x "\n", heap_base);
free(info);
return NULL;
}
// Verify NT heap segment signature
if (info->segment_signature != RZ_NT_HEAP_SIGNATURE) {
if (info->segment_signature == RZ_SEGMENT_HEAP_SIGNATURE) {
RZ_LOG_ERROR("Segment Heap detected (0x%08x) - not supported version\n",
info->segment_signature);
} else {
RZ_LOG_ERROR("Invalid NT heap signgature: 0x%08x (expected 0x%08x)\n",
info->segment_signature, RZ_NT_HEAP_SIGNATURE);
}
free(info);
return NULL;
}
// Use the provided heap_base if the one in the dump doesn't make sense
if (info->base_address == 0) {
info->base_address = heap_base;
}
return info;
}
RZ_API RZ_OWN RzList /*<RzWindowsHeapEntry *>*/ *rz_heap_windows_blocks_list(RzCore *core) {
RzWindowsHeapConfig config;
init_heap_config(core, &config);
ut64 heap_base = get_heap_base(core->io, &config);
RzWindowsHeapInfo *info = rz_w32_heap_info_parse(core->io, heap_base, &config);
if (!info) {
return NULL;
}
return rz_w32_heap_blocks_list(core->io, info, &config);
}
RZ_OWN RzList /*<RzWindowsHeapEntry *>*/ *rz_w32_heap_blocks_list(RZ_NONNULL RzIO *io,
RZ_NONNULL const RzWindowsHeapInfo *heap_info, RZ_NONNULL const RzWindowsHeapConfig *config) {
rz_return_val_if_fail(io && heap_info && config, NULL);
RzList *list = rz_list_newf(free);
if (!list) {
return NULL;
}
ut64 base = heap_info->base_address;
ut64 first_entry_va = heap_info->first_entry;
ut64 last_valid_va = heap_info->last_valid_entry;
const ut32 granularity = config->entry_granularity;
// Convert first entry VA to file offset
ut64 off = first_entry_va - base;
ut64 io_size = rz_io_size(io);
/* Allocate a reusable entry buffer */
ut8 *entry_buf = RZ_NEWS0(ut8, config->entry.struct_size);
if (!entry_buf) {
rz_list_free(list);
return NULL;
}
while (off + granularity <= io_size) {
ut64 entry_va = base + off;
// Safety: don't walk past LastValidEntry
if (entry_va >= last_valid_va) {
break;
}
if (!rz_io_read_at_mapped(io, off, entry_buf, config->entry.struct_size)) {
RZ_LOG_ERROR("Failed to read heap entry at offset 0x%" PFMT64x "\n", off);
break;
}
// Decode the entry
if (!rz_w32_decode_heap_entry(entry_buf, heap_info->encoding,
heap_info->encode_flag_mask, config)) {
// Invalid checksum - stop walking
break;
}
ut16 size_units = rz_read_le16(entry_buf + config->entry.size);
if (size_units == 0) {
// Size 0 marks the last (sentinel) entry
break;
}
RzWindowsHeapEntry *block = RZ_NEW0(RzWindowsHeapEntry);
if (!block) {
break;
}
rz_w32_extract_heap_entry(entry_buf, entry_va, block, config);
rz_list_append(list, block);
off += block->size;
}
RZ_FREE(entry_buf);
return list;
}

View file

@ -34,7 +34,6 @@ rz_core_sources = [
'cflag.c', 'cflag.c',
'cgraph.c', 'cgraph.c',
'chash.c', 'chash.c',
'cheap.c',
'cil.c', 'cil.c',
'cio.c', 'cio.c',
'clang.c', 'clang.c',
@ -60,6 +59,7 @@ rz_core_sources = [
'hack.c', 'hack.c',
'heap_glibc.c', 'heap_glibc.c',
'heap_jemalloc.c', 'heap_jemalloc.c',
'heap_windows.c',
'libs.c', 'libs.c',
'project.c', 'project.c',
'project_migrate.c', 'project_migrate.c',
@ -136,7 +136,7 @@ rz_core_sources = [
rz_core_inc = ['.'] rz_core_inc = ['.']
if host_machine.system() == 'windows' if host_machine.system() == 'windows'
rz_core_sources += 'windows_heap.c' rz_core_sources += 'windows_heap_live_debug.c'
endif endif
rz_core_inc = [platform_inc, 'cmd_descs'] rz_core_inc = [platform_inc, 'cmd_descs']

View file

@ -307,7 +307,7 @@ static bool GetHeapGlobalsOffset(RzDebug *dbg, HANDLE h_proc) {
RzDebugMap *map; RzDebugMap *map;
bool found = false; bool found = false;
rz_list_foreach (modules, it, map) { rz_list_foreach (modules, it, map) {
if (!strcmp(map->name, "ntdll.dll")) { if (RZ_STR_EQ(map->name, "ntdll.dll")) {
found = true; found = true;
break; break;
} }
@ -1450,18 +1450,18 @@ RZ_IPI RzList *rz_heap_blocks_list(RzCore *core) {
ut64 unusedBytes = block->extraInfo ? block->extraInfo->unusedBytes : 0; ut64 unusedBytes = block->extraInfo ? block->extraInfo->unusedBytes : 0;
// add blocks to list // add blocks to list
RzWindowsHeapBlock *heap_block = RZ_NEW0(RzWindowsHeapBlock); RzWindowsHeapEntry *heap_block = RZ_NEW0(RzWindowsHeapEntry);
if (!heap_block) { if (!heap_block) {
rz_list_free(blocks_list); rz_list_free(blocks_list);
RtlDestroyQueryDebugBuffer(db); RtlDestroyQueryDebugBuffer(db);
return NULL; return NULL;
} }
heap_block->headerAddress = address; heap_block->header_address = address;
heap_block->userAddress = (ut64)block->dwAddress; heap_block->user_address = (ut64)block->dwAddress;
heap_block->size = block->dwSize; heap_block->size = block->dwSize;
strcpy(heap_block->type, type); heap_block->flags = (ut8)block->dwFlags;
heap_block->unusedBytes = unusedBytes; heap_block->unused_bytes = (ut8)unusedBytes;
heap_block->granularity = granularity; heap_block->is_busy = (block->dwFlags & 0xFFFF) == LF32_FIXED;
rz_list_append(blocks_list, heap_block); rz_list_append(blocks_list, heap_block);
} while (GetNextHeapBlock(&heapInfo->heaps[i], block)); } while (GetNextHeapBlock(&heapInfo->heaps[i], block));
@ -1502,10 +1502,8 @@ RZ_IPI RzList *rz_heap_list(RzCore *core) {
RtlDestroyQueryDebugBuffer(db); RtlDestroyQueryDebugBuffer(db);
return NULL; return NULL;
} }
rzHeapInfo->base = (ut64)heap.Base; rzHeapInfo->base_address = (ut64)heap.Base;
rzHeapInfo->blockCount = (ut64)heap.BlockCount; rzHeapInfo->total_blocks = (ut32)heap.BlockCount;
rzHeapInfo->allocated = (ut64)heap.Allocated;
rzHeapInfo->committed = (ut64)heap.Committed;
rz_list_append(heaps_list, rzHeapInfo); rz_list_append(heaps_list, rzHeapInfo);

View file

@ -1020,8 +1020,7 @@ RZ_API void rz_core_sysenv_end(RzCore *core);
RZ_API void rz_core_recover_vars(RzCore *core, RzAnalysisFunction *fcn, bool argonly); RZ_API void rz_core_recover_vars(RzCore *core, RzAnalysisFunction *fcn, bool argonly);
/* cmd_windows_heap.c */ /* cmd_windows_heap.c */
RZ_API RZ_OWN RzList /*<RzWindowsHeapBlock *>*/ *rz_heap_windows_blocks_list(RzCore *core); RZ_API RZ_OWN RzList /*<RzWindowsHeapEntry *>*/ *rz_core_heap_windows_blocks_list(RzCore *core);
RZ_API RZ_OWN RzList /*<RzWindowsHeapInfo *>*/ *rz_heap_windows_heap_list(RzCore *core);
// XXX dupe from rz_bin.h // XXX dupe from rz_bin.h
/* bin.c */ /* bin.c */

View file

@ -1,30 +1,37 @@
// SPDX-FileCopyrightText: 2026 bubblepipe <bubblepipe42@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#ifndef RZ_WINDOWS_HEAP_H #ifndef RZ_WINDOWS_HEAP_H
#define RZ_WINDOWS_HEAP_H #define RZ_WINDOWS_HEAP_H
#include <rz_types.h> #include <rz_types.h>
#include <rz_list.h>
#include <rz_io.h>
#include "../../subprojects/rzheap/rz_windows/windows_heap_types.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
typedef struct rz_heap_block { #if __WINDOWS__
ut64 userAddress; /* windows_heap_live_debug.c */
ut64 headerAddress; RZ_IPI RzList *rz_heap_blocks_list(RzCore *core);
ut64 granularity; RZ_IPI RzList *rz_heap_list(RzCore *core);
ut64 unusedBytes; RZ_IPI void rz_heap_debug_block_win(RzCore *core, const char *addr, RzOutputMode mode, bool flag);
char type[100]; RZ_IPI void rz_heap_list_w32(RzCore *core, RzOutputMode mode);
ut64 size; #endif
} RzWindowsHeapBlock;
typedef struct rz_heap_info { void init_heap_config(RzCore *core, RzWindowsHeapConfig *config);
ut64 base; ut64 get_heap_base(RzIO *io, const RzWindowsHeapConfig *config);
ut64 blockCount;
ut64 allocated; RZ_OWN RzWindowsHeapInfo *rz_w32_heap_info_parse(RZ_NONNULL RzIO *io,
ut64 committed; ut64 heap_base, RZ_NONNULL const RzWindowsHeapConfig *config);
} RzWindowsHeapInfo;
RZ_OWN RzList /*<RzWindowsHeapEntry *>*/ *rz_w32_heap_blocks_list(RZ_NONNULL RzIO *io,
RZ_NONNULL const RzWindowsHeapInfo *heap_info, RZ_NONNULL const RzWindowsHeapConfig *config);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif // #endif /* RZ_WINDOWS_HEAP_H */

View file

@ -6,6 +6,15 @@ install_headers(
install_dir: join_paths(rzheap_incdir, 'rz_glibc'), install_dir: join_paths(rzheap_incdir, 'rz_glibc'),
) )
install_headers(
[
'rz_windows/windows_heap_versions.h',
'rz_windows/windows_heap_types.h',
'rz_windows/windows_heap_parser.h',
],
install_dir: join_paths(rzheap_incdir, 'rz_windows'),
)
rzheap_dep = declare_dependency( rzheap_dep = declare_dependency(
include_directories: include_directories('.', 'rz_jemalloc', 'rz_glibc', 'rz_windows'), include_directories: include_directories('.', 'rz_jemalloc', 'rz_glibc', 'rz_windows'),
) )

View file

@ -25,15 +25,15 @@
-What about the parsing functions? Alter its behaviour depending on version or create -What about the parsing functions? Alter its behaviour depending on version or create
one function for each version one function for each version
*/ */
#define EXTRA_FLAG (1ULL << (sizeof (size_t) * 8 - 1)) #define EXTRA_FLAG (1ULL << (sizeof(size_t) * 8 - 1))
#define SHIFT 16 #define SHIFT 16
#define LFH_BLOCK (1 << (SHIFT)) #define LFH_BLOCK (1 << (SHIFT))
#define LARGE_BLOCK (1 << (SHIFT + 1)) #define LARGE_BLOCK (1 << (SHIFT + 1))
#define NT_BLOCK (1 << (SHIFT + 2)) #define NT_BLOCK (1 << (SHIFT + 2))
#define SEGMENT_HEAP_BLOCK (1 << (SHIFT + 3)) #define SEGMENT_HEAP_BLOCK (1 << (SHIFT + 3))
#define VS_BLOCK (1 << (SHIFT + 4)) #define VS_BLOCK (1 << (SHIFT + 4))
#define BACKEND_BLOCK (1 << (SHIFT + 5)) #define BACKEND_BLOCK (1 << (SHIFT + 5))
typedef struct _HEAP_LOCAL_DATA *PHEAP_LOCAL_DATA; typedef struct _HEAP_LOCAL_DATA *PHEAP_LOCAL_DATA;
typedef struct _HEAP_SUBSEGMENT *PHEAP_SUBSEGMENT; typedef struct _HEAP_SUBSEGMENT *PHEAP_SUBSEGMENT;
@ -116,7 +116,7 @@ typedef struct _INTERLOCK_SEQ { // Is this right? NO!
typedef struct _HEAP_UNPACKED_ENTRY { typedef struct _HEAP_UNPACKED_ENTRY {
#if defined(_M_X64) #if defined(_M_X64)
PVOID PreviousBlockPrivateData; PVOID PreviousBlockPrivateData;
#endif #endif
union { union {
struct { struct {
@ -388,10 +388,10 @@ typedef struct _HEAP_VS_CHUNK_HEADER {
enum { enum {
PAGE_RANGE_FLAGS_LFH_SUBSEGMENT = 0x01, PAGE_RANGE_FLAGS_LFH_SUBSEGMENT = 0x01,
PAGE_RANGE_FLAGS_COMMITED = 0x02, PAGE_RANGE_FLAGS_COMMITED = 0x02,
PAGE_RANGE_FLAGS_ALLOCATED = 0x04, PAGE_RANGE_FLAGS_ALLOCATED = 0x04,
PAGE_RANGE_FLAGS_FIRST = 0x08, PAGE_RANGE_FLAGS_FIRST = 0x08,
PAGE_RANGE_FLAGS_VS_SUBSEGMENT = 0x20 // LIES PAGE_RANGE_FLAGS_VS_SUBSEGMENT = 0x20 // LIES
}; };
typedef struct _HEAP_PAGE_RANGE_DESCRIPTOR { typedef struct _HEAP_PAGE_RANGE_DESCRIPTOR {
@ -716,7 +716,7 @@ typedef struct _HEAP {
PHEAP_PSEUDO_TAG_ENTRY PseudoTagEntries; PHEAP_PSEUDO_TAG_ENTRY PseudoTagEntries;
LIST_ENTRY FreeLists; LIST_ENTRY FreeLists;
PHEAP_LOCK LockVariable; PHEAP_LOCK LockVariable;
LONG32 (WINAPI * CommitRoutine) (PVOID, PVOID *, WPARAM *); LONG32(WINAPI *CommitRoutine)(PVOID, PVOID *, WPARAM *);
RTL_RUN_ONCE StackTraceInitVar; RTL_RUN_ONCE StackTraceInitVar;
RTL_HEAP_MEMORY_LIMIT_DATA CommitLimitData; RTL_HEAP_MEMORY_LIMIT_DATA CommitLimitData;
PVOID FrontEndHeap; PVOID FrontEndHeap;
@ -815,7 +815,6 @@ typedef struct _HEAP_USERDATA_HEADER {
WPARAM BitmapData; WPARAM BitmapData;
} HEAP_USERDATA_HEADER, *PHEAP_USERDATA_HEADER; } HEAP_USERDATA_HEADER, *PHEAP_USERDATA_HEADER;
typedef struct _HEAP_SUBSEGMENT *PHEAP_SUBSEGMENT; typedef struct _HEAP_SUBSEGMENT *PHEAP_SUBSEGMENT;
typedef struct _HEAP_LOCAL_SEGMENT_INFO { typedef struct _HEAP_LOCAL_SEGMENT_INFO {
PHEAP_LOCAL_DATA LocalData; PHEAP_LOCAL_DATA LocalData;
@ -864,7 +863,7 @@ typedef struct _HEAP_LOCAL_DATA {
PLFH_BLOCK_ZONE CrtZone; PLFH_BLOCK_ZONE CrtZone;
PLFH_HEAP LowFragHeap; PLFH_HEAP LowFragHeap;
ULONG Sequence; ULONG Sequence;
//HEAP_LOCAL_SEGMENT_INFO SegmentInfo[128]; // Only on Win7 // HEAP_LOCAL_SEGMENT_INFO SegmentInfo[128]; // Only on Win7
} HEAP_LOCAL_DATA, *PHEAP_LOCAL_DATA; } HEAP_LOCAL_DATA, *PHEAP_LOCAL_DATA;
typedef struct _HEAP_BUCKET { typedef struct _HEAP_BUCKET {
@ -969,7 +968,6 @@ typedef struct _DEBUG_BUFFER {
PVOID Reserved[4]; PVOID Reserved[4];
} DEBUG_BUFFER, *PDEBUG_BUFFER; } DEBUG_BUFFER, *PDEBUG_BUFFER;
typedef struct _DEBUG_HEAP_INFORMATION { typedef struct _DEBUG_HEAP_INFORMATION {
PVOID Base; PVOID Base;
DWORD Flags; DWORD Flags;
@ -991,26 +989,22 @@ typedef struct _HeapInformation {
DEBUG_HEAP_INFORMATION heaps[/* count */]; DEBUG_HEAP_INFORMATION heaps[/* count */];
} HeapInformation, *PHeapInformation; } HeapInformation, *PHeapInformation;
PDEBUG_BUFFER (NTAPI *RtlCreateQueryDebugBuffer)( PDEBUG_BUFFER(NTAPI *RtlCreateQueryDebugBuffer)(
IN DWORD Size, IN DWORD Size,
IN BOOLEAN EventPair IN BOOLEAN EventPair);
);
NTSTATUS (NTAPI *RtlQueryProcessDebugInformation)( NTSTATUS(NTAPI *RtlQueryProcessDebugInformation)(
IN DWORD ProcessId, IN DWORD ProcessId,
IN DWORD DebugInfoClassMask, IN DWORD DebugInfoClassMask,
IN OUT PDEBUG_BUFFER DebugBuffer IN OUT PDEBUG_BUFFER DebugBuffer);
);
NTSTATUS (NTAPI *RtlDestroyQueryDebugBuffer)( NTSTATUS(NTAPI *RtlDestroyQueryDebugBuffer)(
IN PDEBUG_BUFFER DebugBuffer IN PDEBUG_BUFFER DebugBuffer);
);
__kernel_entry NTSTATUS (NTAPI *w32_NtQueryInformationProcess)( __kernel_entry NTSTATUS(NTAPI *w32_NtQueryInformationProcess)(
IN HANDLE ProcessHandle, IN HANDLE ProcessHandle,
IN PROCESSINFOCLASS ProcessInformationClass, IN PROCESSINFOCLASS ProcessInformationClass,
OUT PVOID ProcessInformation, OUT PVOID ProcessInformation,
IN ULONG ProcessInformationLength, IN ULONG ProcessInformationLength,
OUT PULONG ReturnLength OUT PULONG ReturnLength);
);
#endif #endif

View file

@ -0,0 +1,86 @@
// SPDX-FileCopyrightText: 2026 bubblepipe <bubblepipe42@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#ifndef RZ_WINDOWS_HEAP_PARSER_H
#define RZ_WINDOWS_HEAP_PARSER_H
#include <rz_io.h>
#include "windows_heap_types.h"
static inline ut64 rz_w32_read_ptr(const ut8 *buf, ut32 offset, ut8 ptr_size) {
if (ptr_size == 8) {
return rz_read_le64(buf + offset);
}
return (ut64)rz_read_le32(buf + offset);
}
static inline bool rz_w32_decode_heap_entry(ut8 *entry_buf, const ut8 *encoding,
ut32 encode_flag_mask, const RzWindowsHeapConfig *config) {
const RzW32HeapEntryLayout *el = &config->entry;
ut32 hdr = rz_read_le32(entry_buf + el->header_offset);
if (encode_flag_mask && (hdr & encode_flag_mask)) {
// XOR the header bytes with the encoding key
for (ut32 i = el->header_offset; i < el->struct_size; i++) {
entry_buf[i] ^= encoding[i];
}
}
// Size[0] ^ Size[1] ^ Flags ^ SmallTagIndex == 0
ut8 checksum = entry_buf[el->size] ^
entry_buf[el->size + 1] ^
entry_buf[el->flags] ^
entry_buf[el->small_tag_index];
return checksum == 0;
}
static inline void rz_w32_extract_heap_entry(const ut8 *entry_buf, ut64 entry_va,
RzWindowsHeapEntry *block, const RzWindowsHeapConfig *config) {
const RzW32HeapEntryLayout *el = &config->entry;
ut16 size_units = rz_read_le16(entry_buf + el->size);
ut8 flags = entry_buf[el->flags];
ut8 unused_bytes = entry_buf[el->unused_bytes];
block->header_address = entry_va;
block->user_address = entry_va + config->entry_granularity;
block->size = (ut64)size_units * config->entry_granularity;
block->flags = flags;
block->unused_bytes = unused_bytes;
block->is_busy = (flags & RZ_NT_HEAP_ENTRY_BUSY) != 0;
}
static inline bool rz_w32_read_heap_info(RzIO *io, ut64 addr,
RzWindowsHeapInfo *info, const RzWindowsHeapConfig *config) {
const RzW32HeapSegmentLayout *sl = &config->segment;
const RzW32HeapLayout *hl = &config->heap;
const RzW32HeapEntryLayout *el = &config->entry;
ut32 read_size = hl->struct_size;
ut8 *hdr = RZ_NEWS0(ut8, read_size);
if (!hdr) {
return false;
}
if (!rz_io_read_at_mapped(io, addr, hdr, read_size)) {
free(hdr);
return false;
}
info->segment_signature = rz_read_le32(hdr + sl->segment_signature);
info->base_address = rz_w32_read_ptr(hdr, sl->base_address, config->ptr_size);
info->number_of_pages = rz_read_le32(hdr + sl->number_of_pages);
info->first_entry = rz_w32_read_ptr(hdr, sl->first_entry, config->ptr_size);
info->last_valid_entry = rz_w32_read_ptr(hdr, sl->last_valid_entry, config->ptr_size);
info->flags = rz_read_le32(hdr + hl->flags);
info->encode_flag_mask = rz_read_le32(hdr + hl->encode_flag_mask);
info->heap_signature = rz_read_le32(hdr + hl->signature);
info->front_end_heap = rz_w32_read_ptr(hdr, hl->front_end_heap, config->ptr_size);
info->front_end_heap_type = hdr[hl->front_end_heap_type];
memcpy(info->encoding, hdr + hl->encoding, el->struct_size);
free(hdr);
return true;
}
#endif // RZ_WINDOWS_HEAP_PARSER_H

View file

@ -0,0 +1,68 @@
// SPDX-FileCopyrightText: 2026 bubblepipe <bubblepipe42@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#ifndef RZ_WINDOWS_HEAP_TYPES_H
#define RZ_WINDOWS_HEAP_TYPES_H
#include <rz_types.h>
#include <rz_list.h>
#include "windows_heap_versions.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct rz_w32_heap_config_t {
ut8 ptr_size;
bool is_big_endian;
int build_number;
RzW32HeapEntryLayout entry;
RzW32HeapSegmentLayout segment;
RzW32HeapLayout heap;
ut32 entry_granularity;
} RzWindowsHeapConfig;
typedef struct rz_w32_heap_block_t {
ut64 header_address;
ut64 user_address;
ut64 size;
ut8 flags;
ut8 unused_bytes;
bool is_busy;
} RzWindowsHeapEntry;
typedef struct rz_w32_heap_info_t {
ut64 base_address;
ut64 first_entry;
ut64 last_valid_entry;
ut32 segment_signature;
ut32 heap_signature;
ut32 flags;
ut32 encode_flag_mask;
ut8 encoding[16];
ut32 number_of_pages;
ut8 front_end_heap_type;
ut64 front_end_heap;
ut32 total_blocks;
ut32 busy_blocks;
ut32 free_blocks;
} RzWindowsHeapInfo;
static inline void rz_w32_heap_config_init(RzWindowsHeapConfig *config,
ut8 ptr_size, int build_number) {
config->ptr_size = ptr_size;
config->is_big_endian = false;
config->build_number = build_number;
config->entry = rz_w32_get_heap_entry_layout(ptr_size);
config->segment = rz_w32_get_heap_segment_layout(ptr_size);
config->heap = rz_w32_get_heap_layout(build_number, ptr_size);
config->entry_granularity = config->entry.struct_size;
}
#ifdef __cplusplus
}
#endif
#endif /* RZ_WINDOWS_HEAP_TYPES_H */

View file

@ -0,0 +1,267 @@
// SPDX-FileCopyrightText: 2026 bubblepipe <bubblepipe42@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#ifndef RZ_WINDOWS_HEAP_VERSIONS_H
#define RZ_WINDOWS_HEAP_VERSIONS_H
#include <rz_types.h>
#define RZ_W10_BUILD_UNKNOWN 0
#define RZ_W10_BUILD_1511 10586 /* 1511, Threshold 2 */
#define RZ_W10_BUILD_1607 14393 /* 1607, Redstone 1 */
#define RZ_W10_BUILD_21H1 19043 /* 21H1 */
#define RZ_NT_HEAP_SIGNATURE 0xffeeffee
#define RZ_SEGMENT_HEAP_SIGNATURE 0xddeeddee
#define RZ_NT_HEAP_ENTRY_BUSY 0x01
#define RZ_NT_HEAP_ENTRY_EXTRA 0x02
#define RZ_NT_HEAP_ENTRY_FILL 0x04
#define RZ_NT_HEAP_ENTRY_VIRTUAL 0x08
#define RZ_NT_HEAP_ENTRY_LAST 0x10
#define RZ_NT_HEAP_ENTRY_SETTABLE 0x20
static inline bool rz_w32_has_stack_trace_init_var(int build) {
return build >= RZ_W10_BUILD_1607;
}
static inline bool rz_w32_has_commit_limit_data(int build) {
return build >= RZ_W10_BUILD_21H1;
}
typedef struct rz_w32_heap_entry_layout_t {
ut32 previous_block_private_data;
ut32 size;
ut32 flags;
ut32 small_tag_index;
ut32 previous_size;
ut32 segment_offset;
ut32 unused_bytes;
ut32 struct_size;
ut32 header_offset;
} RzW32HeapEntryLayout;
typedef struct rz_w32_heap_segment_layout_t {
ut32 entry;
ut32 segment_signature;
ut32 segment_flags;
ut32 segment_list_entry;
ut32 heap_ptr;
ut32 base_address;
ut32 number_of_pages;
ut32 first_entry;
ut32 last_valid_entry;
ut32 struct_size;
} RzW32HeapSegmentLayout;
typedef struct rz_w32_heap_layout_t {
ut32 flags;
ut32 force_flags;
ut32 compatibility_flags;
ut32 encode_flag_mask;
ut32 encoding;
ut32 interceptor;
ut32 virtual_mem_thresh;
ut32 signature;
ut32 virtual_alloc_blocks;
ut32 segment_list;
ut32 front_end_heap;
ut32 front_end_heap_type;
ut32 counters;
ut32 tuning_parameters;
ut32 struct_size;
} RzW32HeapLayout;
static const RzW32HeapEntryLayout rz_w32_heap_entry_layout_64 = {
.previous_block_private_data = 0x00,
.size = 0x08,
.flags = 0x0A,
.small_tag_index = 0x0B,
.previous_size = 0x0C,
.segment_offset = 0x0E,
.unused_bytes = 0x0F,
.struct_size = 16,
.header_offset = 8,
};
static const RzW32HeapEntryLayout rz_w32_heap_entry_layout_32 = {
.previous_block_private_data = 0, /* not present on x86 */
.size = 0x00,
.flags = 0x02,
.small_tag_index = 0x03,
.previous_size = 0x04,
.segment_offset = 0x06,
.unused_bytes = 0x07,
.struct_size = 8,
.header_offset = 0,
};
static inline RzW32HeapEntryLayout rz_w32_get_heap_entry_layout(ut8 ptr_size) {
if (ptr_size == 8) {
return rz_w32_heap_entry_layout_64;
}
return rz_w32_heap_entry_layout_32;
}
static const RzW32HeapSegmentLayout rz_w32_heap_segment_layout_64 = {
.entry = 0x00,
.segment_signature = 0x10,
.segment_flags = 0x14,
.segment_list_entry = 0x18,
.heap_ptr = 0x28,
.base_address = 0x30,
.number_of_pages = 0x38,
.first_entry = 0x40,
.last_valid_entry = 0x48,
.struct_size = 0x70,
};
static const RzW32HeapSegmentLayout rz_w32_heap_segment_layout_32 = {
.entry = 0x00,
.segment_signature = 0x08,
.segment_flags = 0x0C,
.segment_list_entry = 0x10,
.heap_ptr = 0x18,
.base_address = 0x1C,
.number_of_pages = 0x20,
.first_entry = 0x24,
.last_valid_entry = 0x28,
.struct_size = 0x40,
};
static inline RzW32HeapSegmentLayout rz_w32_get_heap_segment_layout(ut8 ptr_size) {
if (ptr_size == 8) {
return rz_w32_heap_segment_layout_64;
}
return rz_w32_heap_segment_layout_32;
}
static const RzW32HeapLayout rz_w32_heap_layout_10586_64 = {
.flags = 0x70,
.force_flags = 0x74,
.compatibility_flags = 0x78,
.encode_flag_mask = 0x7C,
.encoding = 0x80,
.interceptor = 0x90,
.virtual_mem_thresh = 0x94,
.signature = 0x98,
.virtual_alloc_blocks = 0x110,
.segment_list = 0x120,
.front_end_heap = 0x170,
.front_end_heap_type = 0x17A,
.counters = 0x0210,
.tuning_parameters = 0x0288,
.struct_size = 0x0298,
};
static const RzW32HeapLayout rz_w32_heap_layout_10586_32 = {
.flags = 0x40,
.force_flags = 0x44,
.compatibility_flags = 0x48,
.encode_flag_mask = 0x4C,
.encoding = 0x50,
.interceptor = 0x58,
.virtual_mem_thresh = 0x5C,
.signature = 0x60,
.virtual_alloc_blocks = 0x9C,
.segment_list = 0xA4,
.front_end_heap = 0xD0,
.front_end_heap_type = 0xD6,
.counters = 0x01E0,
.tuning_parameters = 0x023C,
.struct_size = 0x0248,
};
static const RzW32HeapLayout rz_w32_heap_layout_14393_64 = {
.flags = 0x70,
.force_flags = 0x74,
.compatibility_flags = 0x78,
.encode_flag_mask = 0x7C,
.encoding = 0x80,
.interceptor = 0x90,
.virtual_mem_thresh = 0x94,
.signature = 0x98,
.virtual_alloc_blocks = 0x110,
.segment_list = 0x120,
.front_end_heap = 0x178,
.front_end_heap_type = 0x0182,
.counters = 0x0218,
.tuning_parameters = 0x0290,
.struct_size = 0x02A0,
};
static const RzW32HeapLayout rz_w32_heap_layout_14393_32 = {
.flags = 0x40,
.force_flags = 0x44,
.compatibility_flags = 0x48,
.encode_flag_mask = 0x4C,
.encoding = 0x50,
.interceptor = 0x58,
.virtual_mem_thresh = 0x5C,
.signature = 0x60,
.virtual_alloc_blocks = 0x9C,
.segment_list = 0xA4,
.front_end_heap = 0xD4,
.front_end_heap_type = 0xDA,
.counters = 0x01E4,
.tuning_parameters = 0x0240,
.struct_size = 0x0248,
};
static const RzW32HeapLayout rz_w32_heap_layout_19043_64 = {
.flags = 0x70,
.force_flags = 0x74,
.compatibility_flags = 0x78,
.encode_flag_mask = 0x7C,
.encoding = 0x80,
.interceptor = 0x90,
.virtual_mem_thresh = 0x94,
.signature = 0x98,
.virtual_alloc_blocks = 0x110,
.segment_list = 0x120,
.front_end_heap = 0x198,
.front_end_heap_type = 0x1A2,
.counters = 0x0238,
.tuning_parameters = 0x02B0,
.struct_size = 0x02C0,
};
static const RzW32HeapLayout rz_w32_heap_layout_19043_32 = {
.flags = 0x40,
.force_flags = 0x44,
.compatibility_flags = 0x48,
.encode_flag_mask = 0x4C,
.encoding = 0x50,
.interceptor = 0x58,
.virtual_mem_thresh = 0x5C,
.signature = 0x60,
.virtual_alloc_blocks = 0x9C,
.segment_list = 0xA4,
.front_end_heap = 0xE4,
.front_end_heap_type = 0xEA,
.counters = 0x01F4,
.tuning_parameters = 0x0250,
.struct_size = 0x0258,
};
static inline RzW32HeapLayout rz_w32_get_heap_layout(int build, ut8 ptr_size) {
if (ptr_size == 8) {
if (build >= RZ_W10_BUILD_21H1) {
return rz_w32_heap_layout_19043_64;
}
if (build >= RZ_W10_BUILD_1607) {
return rz_w32_heap_layout_14393_64;
}
return rz_w32_heap_layout_10586_64;
} else {
if (build >= RZ_W10_BUILD_21H1) {
return rz_w32_heap_layout_19043_32;
}
if (build >= RZ_W10_BUILD_1607) {
return rz_w32_heap_layout_14393_32;
}
return rz_w32_heap_layout_10586_32;
}
}
#endif /* RZ_WINDOWS_HEAP_VERSIONS_H */

View file

@ -22,6 +22,7 @@ dirlist = [
"subprojects/rzwinkd", "subprojects/rzwinkd",
"subprojects/rzheap/rz_jemalloc", "subprojects/rzheap/rz_jemalloc",
"subprojects/rzheap/rz_glibc", "subprojects/rzheap/rz_glibc",
"subprojects/rzheap/rz_windows",
"test/unit", "test/unit",
] ]

18
test/db/cmd/cmd_dmhw Normal file
View file

@ -0,0 +1,18 @@
NAME=dmhw / dmhwb / dmhwbf
FILE=bins/heap/multithreadheap.exe.bin
CMDS=<<EOF
e dbg.windows.version=1809
om 3 0x1f08dc50000 0x10000 0x0 rw- heap
dmhw~None
dmhwb~?BUSY
dmhwb~?FREE
dmhwbf
fl~alloc?
EOF
EXPECT=<<EOF
0x1f08dc50000 113 255 None
109
4
113
EOF
RUN