diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index c91f3c8928..cfdc1479fe 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -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)"); diff --git a/librz/core/cheap.c b/librz/core/cheap.c deleted file mode 100644 index 989c57ddd2..0000000000 --- a/librz/core/cheap.c +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-FileCopyrightText: 2021 Pulak Malhotra -// SPDX-License-Identifier: LGPL-3.0-only - -#include -#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 /**/ *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 /**/ *rz_heap_windows_heap_list(RzCore *core) { - return rz_heap_list(core); -} -#else - -RZ_API RZ_OWN RzList /**/ *rz_heap_windows_blocks_list(RzCore *core) { - return NULL; -} - -RZ_API RZ_OWN RzList /**/ *rz_heap_windows_heap_list(RzCore *core) { - return NULL; -} - -#endif diff --git a/librz/core/cmd/cmd_windows_heap.c b/librz/core/cmd/cmd_windows_heap.c index a154bd6c4b..f0465d15a7 100644 --- a/librz/core/cmd/cmd_windows_heap.c +++ b/librz/core/cmd/cmd_windows_heap.c @@ -1,43 +1,262 @@ // SPDX-FileCopyrightText: 2021 Pulak Malhotra +// SPDX-FileCopyrightText: 2026 bubblepipe // SPDX-License-Identifier: LGPL-3.0-only +#include "analysis_private.h" #include -#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 #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); - 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; +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, 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; +} diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index 789953cbda..71ca15f891 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -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); diff --git a/librz/core/cmd_descs/cmd_descs.h b/librz/core/cmd_descs/cmd_descs.h index d6ef2afcfa..6e595bbc03 100644 --- a/librz/core/cmd_descs/cmd_descs.h +++ b/librz/core/cmd_descs/cmd_descs.h @@ -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" diff --git a/librz/core/cmd_descs/cmd_heap.yaml b/librz/core/cmd_descs/cmd_heap.yaml index aa334b02c6..b48838a39c 100644 --- a/librz/core/cmd_descs/cmd_heap.yaml +++ b/librz/core/cmd_descs/cmd_heap.yaml @@ -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 diff --git a/librz/core/core_private.h b/librz/core/core_private.h index 301f3a6e88..6caf9a598e 100644 --- a/librz/core/core_private.h +++ b/librz/core/core_private.h @@ -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) { diff --git a/librz/core/heap_windows.c b/librz/core/heap_windows.c new file mode 100644 index 0000000000..4b2a3c6999 --- /dev/null +++ b/librz/core/heap_windows.c @@ -0,0 +1,121 @@ +// SPDX-FileCopyrightText: 2026 bubblepipe +// SPDX-License-Identifier: LGPL-3.0-only + +#include +#include +#include + +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 /**/ *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 /**/ *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; +} diff --git a/librz/core/meson.build b/librz/core/meson.build index 0c1b3dce09..6116fd25b1 100644 --- a/librz/core/meson.build +++ b/librz/core/meson.build @@ -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'] diff --git a/librz/core/windows_heap.c b/librz/core/windows_heap_live_debug.c similarity index 98% rename from librz/core/windows_heap.c rename to librz/core/windows_heap_live_debug.c index 269d31a6de..6f4f1d1265 100644 --- a/librz/core/windows_heap.c +++ b/librz/core/windows_heap_live_debug.c @@ -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); diff --git a/librz/include/rz_core.h b/librz/include/rz_core.h index 8b2171c088..aeea2f5d05 100644 --- a/librz/include/rz_core.h +++ b/librz/include/rz_core.h @@ -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 /**/ *rz_heap_windows_blocks_list(RzCore *core); -RZ_API RZ_OWN RzList /**/ *rz_heap_windows_heap_list(RzCore *core); +RZ_API RZ_OWN RzList /**/ *rz_core_heap_windows_blocks_list(RzCore *core); // XXX dupe from rz_bin.h /* bin.c */ diff --git a/librz/include/rz_windows_heap.h b/librz/include/rz_windows_heap.h index 1fccf60745..5de29aeacc 100644 --- a/librz/include/rz_windows_heap.h +++ b/librz/include/rz_windows_heap.h @@ -1,30 +1,37 @@ +// SPDX-FileCopyrightText: 2026 bubblepipe +// SPDX-License-Identifier: LGPL-3.0-only + #ifndef RZ_WINDOWS_HEAP_H #define RZ_WINDOWS_HEAP_H #include +#include +#include +#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 /**/ *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 */ diff --git a/subprojects/rzheap/meson.build b/subprojects/rzheap/meson.build index 2622d7382e..99a37712c9 100644 --- a/subprojects/rzheap/meson.build +++ b/subprojects/rzheap/meson.build @@ -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'), ) diff --git a/subprojects/rzheap/rz_windows/windows_heap.h b/subprojects/rzheap/rz_windows/windows_heap.h index 64c1fc629b..a6e53465e7 100644 --- a/subprojects/rzheap/rz_windows/windows_heap.h +++ b/subprojects/rzheap/rz_windows/windows_heap.h @@ -25,15 +25,15 @@ -What about the parsing functions? Alter its behaviour depending on version or create 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 LFH_BLOCK (1 << (SHIFT)) -#define LARGE_BLOCK (1 << (SHIFT + 1)) -#define NT_BLOCK (1 << (SHIFT + 2)) -#define SEGMENT_HEAP_BLOCK (1 << (SHIFT + 3)) -#define VS_BLOCK (1 << (SHIFT + 4)) -#define BACKEND_BLOCK (1 << (SHIFT + 5)) +#define SHIFT 16 +#define LFH_BLOCK (1 << (SHIFT)) +#define LARGE_BLOCK (1 << (SHIFT + 1)) +#define NT_BLOCK (1 << (SHIFT + 2)) +#define SEGMENT_HEAP_BLOCK (1 << (SHIFT + 3)) +#define VS_BLOCK (1 << (SHIFT + 4)) +#define BACKEND_BLOCK (1 << (SHIFT + 5)) typedef struct _HEAP_LOCAL_DATA *PHEAP_LOCAL_DATA; typedef struct _HEAP_SUBSEGMENT *PHEAP_SUBSEGMENT; @@ -116,7 +116,7 @@ typedef struct _INTERLOCK_SEQ { // Is this right? NO! typedef struct _HEAP_UNPACKED_ENTRY { #if defined(_M_X64) - PVOID PreviousBlockPrivateData; + PVOID PreviousBlockPrivateData; #endif union { struct { @@ -388,10 +388,10 @@ typedef struct _HEAP_VS_CHUNK_HEADER { enum { PAGE_RANGE_FLAGS_LFH_SUBSEGMENT = 0x01, - PAGE_RANGE_FLAGS_COMMITED = 0x02, - PAGE_RANGE_FLAGS_ALLOCATED = 0x04, - PAGE_RANGE_FLAGS_FIRST = 0x08, - PAGE_RANGE_FLAGS_VS_SUBSEGMENT = 0x20 // LIES + PAGE_RANGE_FLAGS_COMMITED = 0x02, + PAGE_RANGE_FLAGS_ALLOCATED = 0x04, + PAGE_RANGE_FLAGS_FIRST = 0x08, + PAGE_RANGE_FLAGS_VS_SUBSEGMENT = 0x20 // LIES }; typedef struct _HEAP_PAGE_RANGE_DESCRIPTOR { @@ -716,7 +716,7 @@ typedef struct _HEAP { PHEAP_PSEUDO_TAG_ENTRY PseudoTagEntries; LIST_ENTRY FreeLists; PHEAP_LOCK LockVariable; - LONG32 (WINAPI * CommitRoutine) (PVOID, PVOID *, WPARAM *); + LONG32(WINAPI *CommitRoutine)(PVOID, PVOID *, WPARAM *); RTL_RUN_ONCE StackTraceInitVar; RTL_HEAP_MEMORY_LIMIT_DATA CommitLimitData; PVOID FrontEndHeap; @@ -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; @@ -864,7 +863,7 @@ typedef struct _HEAP_LOCAL_DATA { PLFH_BLOCK_ZONE CrtZone; PLFH_HEAP LowFragHeap; 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; typedef struct _HEAP_BUCKET { @@ -969,7 +968,6 @@ typedef struct _DEBUG_BUFFER { PVOID Reserved[4]; } DEBUG_BUFFER, *PDEBUG_BUFFER; - typedef struct _DEBUG_HEAP_INFORMATION { PVOID Base; DWORD Flags; @@ -991,26 +989,22 @@ typedef struct _HeapInformation { DEBUG_HEAP_INFORMATION heaps[/* count */]; } HeapInformation, *PHeapInformation; -PDEBUG_BUFFER (NTAPI *RtlCreateQueryDebugBuffer)( +PDEBUG_BUFFER(NTAPI *RtlCreateQueryDebugBuffer)( IN DWORD Size, - IN BOOLEAN EventPair -); + IN BOOLEAN EventPair); -NTSTATUS (NTAPI *RtlQueryProcessDebugInformation)( +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 -); +NTSTATUS(NTAPI *RtlDestroyQueryDebugBuffer)( + 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 -); +__kernel_entry NTSTATUS(NTAPI *w32_NtQueryInformationProcess)( + IN HANDLE ProcessHandle, + IN PROCESSINFOCLASS ProcessInformationClass, + OUT PVOID ProcessInformation, + IN ULONG ProcessInformationLength, + OUT PULONG ReturnLength); #endif diff --git a/subprojects/rzheap/rz_windows/windows_heap_parser.h b/subprojects/rzheap/rz_windows/windows_heap_parser.h new file mode 100644 index 0000000000..0dbae3cc2b --- /dev/null +++ b/subprojects/rzheap/rz_windows/windows_heap_parser.h @@ -0,0 +1,86 @@ +// SPDX-FileCopyrightText: 2026 bubblepipe +// SPDX-License-Identifier: LGPL-3.0-only + +#ifndef RZ_WINDOWS_HEAP_PARSER_H +#define RZ_WINDOWS_HEAP_PARSER_H + +#include +#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 diff --git a/subprojects/rzheap/rz_windows/windows_heap_types.h b/subprojects/rzheap/rz_windows/windows_heap_types.h new file mode 100644 index 0000000000..d594093e71 --- /dev/null +++ b/subprojects/rzheap/rz_windows/windows_heap_types.h @@ -0,0 +1,68 @@ +// SPDX-FileCopyrightText: 2026 bubblepipe +// SPDX-License-Identifier: LGPL-3.0-only + +#ifndef RZ_WINDOWS_HEAP_TYPES_H +#define RZ_WINDOWS_HEAP_TYPES_H + +#include +#include +#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 */ diff --git a/subprojects/rzheap/rz_windows/windows_heap_versions.h b/subprojects/rzheap/rz_windows/windows_heap_versions.h new file mode 100644 index 0000000000..4abf3761b9 --- /dev/null +++ b/subprojects/rzheap/rz_windows/windows_heap_versions.h @@ -0,0 +1,267 @@ +// SPDX-FileCopyrightText: 2026 bubblepipe +// SPDX-License-Identifier: LGPL-3.0-only + +#ifndef RZ_WINDOWS_HEAP_VERSIONS_H +#define RZ_WINDOWS_HEAP_VERSIONS_H + +#include + +#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 */ diff --git a/sys/clang-format.py b/sys/clang-format.py index b989d61c93..5c0353380f 100755 --- a/sys/clang-format.py +++ b/sys/clang-format.py @@ -22,6 +22,7 @@ dirlist = [ "subprojects/rzwinkd", "subprojects/rzheap/rz_jemalloc", "subprojects/rzheap/rz_glibc", + "subprojects/rzheap/rz_windows", "test/unit", ] diff --git a/test/db/cmd/cmd_dmhw b/test/db/cmd/cmd_dmhw new file mode 100644 index 0000000000..1ffedae9bb --- /dev/null +++ b/test/db/cmd/cmd_dmhw @@ -0,0 +1,18 @@ +NAME=dmhw / dmhwb / dmhwbf +FILE=bins/heap/multithreadheap.exe.bin +CMDS=<