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')");
|
||||
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");
|
||||
SETPREF("esil.fillstack", "", "Initialize ESIL stack with (random, debrujn, sequence, zeros, ...)");
|
||||
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: 2026 bubblepipe <bubblepipe42@gmail.com>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
#include "analysis_private.h"
|
||||
#include <rz_core.h>
|
||||
#include "../core_private.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;
|
||||
#include <rz_windows_heap.h>
|
||||
|
||||
#if __WINDOWS__
|
||||
RZ_IPI RzCmdStatus rz_cmd_debug_process_heaps_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
||||
rz_heap_list_w32(core, mode);
|
||||
bool is_windows_live_debug(RzCore *core) {
|
||||
return core->dbg && core->dbg->cur && !rz_debug_is_dead(core->dbg);
|
||||
}
|
||||
#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, RzOutputMode mode) {
|
||||
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], mode, false);
|
||||
rz_heap_debug_block_win(core, argv[1], state->mode, false);
|
||||
} else {
|
||||
rz_heap_debug_block_win(core, NULL, mode, false);
|
||||
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;
|
||||
}
|
||||
|
||||
#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
|
||||
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);
|
||||
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);
|
||||
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_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);
|
||||
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"
|
||||
RZ_IPI RzCmdStatus rz_cmd_heap_tcache_print_handler(RzCore *core, int argc, const char **argv);
|
||||
// "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"
|
||||
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"
|
||||
RZ_IPI RzCmdStatus rz_cmd_debug_heap_block_flag_handler(RzCore *core, int argc, const char **argv);
|
||||
// "dmhja"
|
||||
|
|
|
|||
|
|
@ -93,16 +93,20 @@ commands:
|
|||
- name: dmhw
|
||||
summary: List process heaps
|
||||
cname: cmd_debug_process_heaps
|
||||
type: RZ_CMD_DESC_TYPE_ARGV_STATE
|
||||
modes:
|
||||
- RZ_OUTPUT_MODE_STANDARD
|
||||
- RZ_OUTPUT_MODE_TABLE
|
||||
- RZ_OUTPUT_MODE_JSON
|
||||
default_mode: RZ_OUTPUT_MODE_TABLE
|
||||
args: []
|
||||
- name: dmhwb
|
||||
summary: List allocated heap blocks
|
||||
cname: cmd_debug_process_heap_block
|
||||
type: RZ_CMD_DESC_TYPE_ARGV_STATE
|
||||
modes:
|
||||
- RZ_OUTPUT_MODE_STANDARD
|
||||
- RZ_OUTPUT_MODE_TABLE
|
||||
- RZ_OUTPUT_MODE_JSON
|
||||
default_mode: RZ_OUTPUT_MODE_TABLE
|
||||
args:
|
||||
- name: addr
|
||||
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
|
||||
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);
|
||||
|
||||
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',
|
||||
'cgraph.c',
|
||||
'chash.c',
|
||||
'cheap.c',
|
||||
'cil.c',
|
||||
'cio.c',
|
||||
'clang.c',
|
||||
|
|
@ -60,6 +59,7 @@ rz_core_sources = [
|
|||
'hack.c',
|
||||
'heap_glibc.c',
|
||||
'heap_jemalloc.c',
|
||||
'heap_windows.c',
|
||||
'libs.c',
|
||||
'project.c',
|
||||
'project_migrate.c',
|
||||
|
|
@ -136,7 +136,7 @@ rz_core_sources = [
|
|||
|
||||
rz_core_inc = ['.']
|
||||
if host_machine.system() == 'windows'
|
||||
rz_core_sources += 'windows_heap.c'
|
||||
rz_core_sources += 'windows_heap_live_debug.c'
|
||||
endif
|
||||
rz_core_inc = [platform_inc, 'cmd_descs']
|
||||
|
||||
|
|
|
|||
|
|
@ -307,7 +307,7 @@ static bool GetHeapGlobalsOffset(RzDebug *dbg, HANDLE h_proc) {
|
|||
RzDebugMap *map;
|
||||
bool found = false;
|
||||
rz_list_foreach (modules, it, map) {
|
||||
if (!strcmp(map->name, "ntdll.dll")) {
|
||||
if (RZ_STR_EQ(map->name, "ntdll.dll")) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1450,18 +1450,18 @@ RZ_IPI RzList *rz_heap_blocks_list(RzCore *core) {
|
|||
ut64 unusedBytes = block->extraInfo ? block->extraInfo->unusedBytes : 0;
|
||||
|
||||
// add blocks to list
|
||||
RzWindowsHeapBlock *heap_block = RZ_NEW0(RzWindowsHeapBlock);
|
||||
RzWindowsHeapEntry *heap_block = RZ_NEW0(RzWindowsHeapEntry);
|
||||
if (!heap_block) {
|
||||
rz_list_free(blocks_list);
|
||||
RtlDestroyQueryDebugBuffer(db);
|
||||
return NULL;
|
||||
}
|
||||
heap_block->headerAddress = address;
|
||||
heap_block->userAddress = (ut64)block->dwAddress;
|
||||
heap_block->header_address = address;
|
||||
heap_block->user_address = (ut64)block->dwAddress;
|
||||
heap_block->size = block->dwSize;
|
||||
strcpy(heap_block->type, type);
|
||||
heap_block->unusedBytes = unusedBytes;
|
||||
heap_block->granularity = granularity;
|
||||
heap_block->flags = (ut8)block->dwFlags;
|
||||
heap_block->unused_bytes = (ut8)unusedBytes;
|
||||
heap_block->is_busy = (block->dwFlags & 0xFFFF) == LF32_FIXED;
|
||||
|
||||
rz_list_append(blocks_list, heap_block);
|
||||
} while (GetNextHeapBlock(&heapInfo->heaps[i], block));
|
||||
|
|
@ -1502,10 +1502,8 @@ RZ_IPI RzList *rz_heap_list(RzCore *core) {
|
|||
RtlDestroyQueryDebugBuffer(db);
|
||||
return NULL;
|
||||
}
|
||||
rzHeapInfo->base = (ut64)heap.Base;
|
||||
rzHeapInfo->blockCount = (ut64)heap.BlockCount;
|
||||
rzHeapInfo->allocated = (ut64)heap.Allocated;
|
||||
rzHeapInfo->committed = (ut64)heap.Committed;
|
||||
rzHeapInfo->base_address = (ut64)heap.Base;
|
||||
rzHeapInfo->total_blocks = (ut32)heap.BlockCount;
|
||||
|
||||
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);
|
||||
|
||||
/* cmd_windows_heap.c */
|
||||
RZ_API RZ_OWN RzList /*<RzWindowsHeapBlock *>*/ *rz_heap_windows_blocks_list(RzCore *core);
|
||||
RZ_API RZ_OWN RzList /*<RzWindowsHeapInfo *>*/ *rz_heap_windows_heap_list(RzCore *core);
|
||||
RZ_API RZ_OWN RzList /*<RzWindowsHeapEntry *>*/ *rz_core_heap_windows_blocks_list(RzCore *core);
|
||||
|
||||
// XXX dupe from rz_bin.h
|
||||
/* 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
|
||||
#define RZ_WINDOWS_HEAP_H
|
||||
|
||||
#include <rz_types.h>
|
||||
#include <rz_list.h>
|
||||
#include <rz_io.h>
|
||||
#include "../../subprojects/rzheap/rz_windows/windows_heap_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct rz_heap_block {
|
||||
ut64 userAddress;
|
||||
ut64 headerAddress;
|
||||
ut64 granularity;
|
||||
ut64 unusedBytes;
|
||||
char type[100];
|
||||
ut64 size;
|
||||
} RzWindowsHeapBlock;
|
||||
#if __WINDOWS__
|
||||
/* windows_heap_live_debug.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
|
||||
|
||||
typedef struct rz_heap_info {
|
||||
ut64 base;
|
||||
ut64 blockCount;
|
||||
ut64 allocated;
|
||||
ut64 committed;
|
||||
} RzWindowsHeapInfo;
|
||||
void init_heap_config(RzCore *core, RzWindowsHeapConfig *config);
|
||||
ut64 get_heap_base(RzIO *io, const RzWindowsHeapConfig *config);
|
||||
|
||||
RZ_OWN RzWindowsHeapInfo *rz_w32_heap_info_parse(RZ_NONNULL RzIO *io,
|
||||
ut64 heap_base, RZ_NONNULL const RzWindowsHeapConfig *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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //
|
||||
#endif /* RZ_WINDOWS_HEAP_H */
|
||||
|
|
|
|||
|
|
@ -6,6 +6,15 @@ install_headers(
|
|||
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(
|
||||
include_directories: include_directories('.', 'rz_jemalloc', 'rz_glibc', 'rz_windows'),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -815,7 +815,6 @@ typedef struct _HEAP_USERDATA_HEADER {
|
|||
WPARAM BitmapData;
|
||||
} HEAP_USERDATA_HEADER, *PHEAP_USERDATA_HEADER;
|
||||
|
||||
|
||||
typedef struct _HEAP_SUBSEGMENT *PHEAP_SUBSEGMENT;
|
||||
typedef struct _HEAP_LOCAL_SEGMENT_INFO {
|
||||
PHEAP_LOCAL_DATA LocalData;
|
||||
|
|
@ -969,7 +968,6 @@ typedef struct _DEBUG_BUFFER {
|
|||
PVOID Reserved[4];
|
||||
} DEBUG_BUFFER, *PDEBUG_BUFFER;
|
||||
|
||||
|
||||
typedef struct _DEBUG_HEAP_INFORMATION {
|
||||
PVOID Base;
|
||||
DWORD Flags;
|
||||
|
|
@ -993,24 +991,20 @@ typedef struct _HeapInformation {
|
|||
|
||||
PDEBUG_BUFFER(NTAPI *RtlCreateQueryDebugBuffer)(
|
||||
IN DWORD Size,
|
||||
IN BOOLEAN EventPair
|
||||
);
|
||||
IN BOOLEAN EventPair);
|
||||
|
||||
NTSTATUS(NTAPI *RtlQueryProcessDebugInformation)(
|
||||
IN DWORD ProcessId,
|
||||
IN DWORD DebugInfoClassMask,
|
||||
IN OUT PDEBUG_BUFFER DebugBuffer
|
||||
);
|
||||
IN OUT PDEBUG_BUFFER DebugBuffer);
|
||||
|
||||
NTSTATUS(NTAPI *RtlDestroyQueryDebugBuffer)(
|
||||
IN PDEBUG_BUFFER DebugBuffer
|
||||
);
|
||||
IN PDEBUG_BUFFER DebugBuffer);
|
||||
|
||||
__kernel_entry NTSTATUS(NTAPI *w32_NtQueryInformationProcess)(
|
||||
IN HANDLE ProcessHandle,
|
||||
IN PROCESSINFOCLASS ProcessInformationClass,
|
||||
OUT PVOID ProcessInformation,
|
||||
IN ULONG ProcessInformationLength,
|
||||
OUT PULONG ReturnLength
|
||||
);
|
||||
OUT PULONG ReturnLength);
|
||||
#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/rzheap/rz_jemalloc",
|
||||
"subprojects/rzheap/rz_glibc",
|
||||
"subprojects/rzheap/rz_windows",
|
||||
"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