Refactor windows heap parser (#6014)
This commit is contained in:
parent
58a39e6411
commit
bb76233c2e
19 changed files with 903 additions and 148 deletions
|
|
@ -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)");
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
121
librz/core/heap_windows.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
@ -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']
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
|
||||||
|
|
@ -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'),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
86
subprojects/rzheap/rz_windows/windows_heap_parser.h
Normal file
86
subprojects/rzheap/rz_windows/windows_heap_parser.h
Normal 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
|
||||||
68
subprojects/rzheap/rz_windows/windows_heap_types.h
Normal file
68
subprojects/rzheap/rz_windows/windows_heap_types.h
Normal 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 */
|
||||||
267
subprojects/rzheap/rz_windows/windows_heap_versions.h
Normal file
267
subprojects/rzheap/rz_windows/windows_heap_versions.h
Normal 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 */
|
||||||
|
|
@ -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
18
test/db/cmd/cmd_dmhw
Normal 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
|
||||||
Loading…
Reference in a new issue