diff --git a/librz/arch/analysis.c b/librz/arch/analysis.c index b79b000e83..6c649fc9b4 100644 --- a/librz/arch/analysis.c +++ b/librz/arch/analysis.c @@ -164,8 +164,8 @@ RZ_API RzAnalysis *rz_analysis_new(RZ_NULLABLE const char *sdb_types_path) { } } analysis->ht_global_var = ht_sp_new(HT_STR_DUP, NULL, (HtSPFreeValue)rz_analysis_var_global_free); - analysis->ht_rop_semantics = NULL; - analysis->ht_rop = NULL; + analysis->ht_gadget_semantics = NULL; + analysis->ht_gadget = NULL; analysis->global_var_tree = NULL; analysis->il_vm = NULL; analysis->hash = rz_hash_new(); @@ -220,7 +220,7 @@ RZ_API void rz_analysis_free(RZ_NULLABLE RzAnalysis *a) { rz_list_free(a->imports); rz_str_constpool_fini(&a->constpool); ht_sp_free(a->ht_global_var); - ht_up_free(a->ht_rop_semantics); + ht_up_free(a->ht_gadget_semantics); ht_sp_free(a->plugins); rz_analysis_debug_info_free(a->debug_info); ht_sp_free(a->ht_virtual_xrefs); @@ -513,14 +513,14 @@ RZ_API void rz_analysis_set_xrefs_to(RZ_NONNULL RzAnalysis *analysis, HtUP *xref analysis->ht_xrefs_to = xrefs_to; } -RZ_API RZ_BORROW HtUP *rz_analysis_get_rop_semantics(RZ_NONNULL RzAnalysis *analysis) { +RZ_API RZ_BORROW HtUP *rz_analysis_get_gadget_semantics(RZ_NONNULL RzAnalysis *analysis) { rz_return_val_if_fail(analysis, NULL); - return analysis->ht_rop_semantics; + return analysis->ht_gadget_semantics; } -RZ_API void rz_analysis_set_rop_semantics(RZ_NONNULL RzAnalysis *analysis, HtUP *rop_semantics) { +RZ_API void rz_analysis_set_gadget_semantics(RZ_NONNULL RzAnalysis *analysis, HtUP *gadget_semantics) { rz_return_if_fail(analysis); - analysis->ht_rop_semantics = rop_semantics; + analysis->ht_gadget_semantics = gadget_semantics; } RZ_API RZ_BORROW RzAnalysisCallbacks *rz_analysis_get_callbacks(RZ_NONNULL RzAnalysis *analysis) { diff --git a/librz/arch/analysis_private.h b/librz/arch/analysis_private.h index a09628444e..9ad6111977 100644 --- a/librz/arch/analysis_private.h +++ b/librz/arch/analysis_private.h @@ -87,8 +87,8 @@ struct rz_analysis_t { RzPlatformTarget *arch_target; RzPlatformTargetIndex *platform_target; HtSP *ht_global_var; // global variables - HtUP *ht_rop_semantics; ///< cache rop gadget semantic information - HtUP *ht_rop; ///< cache rop gadget address list + HtUP *ht_gadget_semantics; ///< cache gadget semantic information + HtUP *ht_gadget; ///< cache gadget address list RBTree global_var_tree; // global variables by address. must not overlap RzHash *hash; RzAnalysisDebugInfo *debug_info; ///< store all debug info parsed from DWARF, etc.. diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index 9d7d401b50..4c41978b02 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -3632,12 +3632,12 @@ RZ_API int rz_core_config_init(RzCore *core) { SETDESC(n, "Set grep(~) as case smart/sensitive/insensitive"); SETOPTIONS(n, "smart", "sensitive", "insensitive", NULL); - /* rop */ - SETI("rop.len", 5, "Maximum ROP gadget length"); - SETBPREF("rop.cache", "false", "Cache rop gadget results(experimental)"); - SETBPREF("rop.subchains", "false", "Display every length gadget from rop.len=X to 2 in /Rl"); - SETBPREF("rop.conditional", "false", "Include conditional jump, calls and returns in ropsearch"); - SETBPREF("rop.comments", "false", "Display comments in rop search output"); + /* gadget */ + SETI("gadget.len", 5, "Maximum number of instructions per gadget"); + SETBPREF("gadget.cache", "false", "Cache gadget results(experimental)"); + SETBPREF("gadget.subchains", "false", "Display every length gadget from gadget.len=X to 2"); + SETBPREF("gadget.conditional", "false", "Include conditional jump, calls and returns in gadget search"); + SETBPREF("gadget.comments", "false", "Display comments in gadget search output"); /* io */ SETCB("io.cache", "false", &cb_io_cache, "Change both of io.cache.{read,write}"); diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index 8e26900ae7..1faae66de1 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -1,3 +1,4 @@ +// SPDX-FileCopyrightText: 2026 MrQuantum1915 // SPDX-FileCopyrightText: 2010-2021 pancake // SPDX-License-Identifier: LGPL-3.0-only @@ -9,7 +10,7 @@ #include #include -#include "cmd_search_rop.c" +#include "cmd_search_gadget.c" #include "rz_cons.h" #include #include @@ -44,19 +45,34 @@ struct search_parameters { bool regex_search; }; +static RzGadgetType gadget_type_from_cmd(const char *cmd_name) { + rz_return_val_if_fail(cmd_name && cmd_name[0] && cmd_name[1], RZ_GADGET_TYPE_ROP); + switch (cmd_name[1]) { + case 'J': + return RZ_GADGET_TYPE_JOP; + case 'C': + return RZ_GADGET_TYPE_COP; + case 'R': + default: + return RZ_GADGET_TYPE_ROP; + } +} + RZ_IPI RzCmdStatus rz_cmd_info_gadget_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { const char *input = argc > 1 ? argv[1] : ""; if (!input) { return RZ_CMD_STATUS_ERROR; } - RzRopSearchContext *context = rz_core_rop_search_context_new(core, argv[1], false, RZ_ROP_GADGET_PRINT, RZ_ROP_DETAIL_SEARCH_NON, state); - RzCmdStatus status = rz_core_rop_gadget_info(core, context); + RzGadgetType gadget_type = gadget_type_from_cmd(argv[0]); + + RzGadgetSearchContext *context = rz_core_gadget_search_context_new(core, gadget_type, input, false, RZ_GADGET_PRINT, RZ_GADGET_DETAIL_SEARCH_NON, state); + RzCmdStatus status = rz_core_gadget_info(core, context); return status; } RZ_IPI RzCmdStatus rz_cmd_query_gadget_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - RzPVector /**/ *constraints = rz_core_rop_constraint_map_parse(core, argc, argv); + RzPVector /**/ *constraints = rz_core_gadget_constraint_map_parse(core, argc, argv); if (!constraints) { return RZ_CMD_STATUS_ERROR; } @@ -65,15 +81,17 @@ RZ_IPI RzCmdStatus rz_cmd_query_gadget_handler(RzCore *core, int argc, const cha return RZ_CMD_STATUS_INVALID; } - RzRopSearchContext *context = rz_core_rop_search_context_new(core, NULL, false, - RZ_ROP_GADGET_PRINT | RZ_ROP_GADGET_ANALYZE, RZ_ROP_DETAIL_SEARCH_NON, state); + RzGadgetType gadget_type = gadget_type_from_cmd(argv[0]); + + RzGadgetSearchContext *context = rz_core_gadget_search_context_new(core, gadget_type, NULL, false, + RZ_GADGET_PRINT | RZ_GADGET_ANALYZE, RZ_GADGET_DETAIL_SEARCH_NON, state); if (!context) { rz_pvector_free(constraints); return RZ_CMD_STATUS_ERROR; } context->constraints = constraints; - const RzCmdStatus cmd_status = rz_core_rop_search(core, context); - rz_core_rop_search_context_free(context); + const RzCmdStatus cmd_status = rz_core_gadget_search(core, context); + rz_core_gadget_search_context_free(context); return cmd_status; } @@ -82,29 +100,39 @@ RZ_IPI RzCmdStatus rz_cmd_search_gadget_handler(RzCore *core, int argc, const ch if (!input) { return RZ_CMD_STATUS_ERROR; } - RzRopSearchContext *context = rz_core_rop_search_context_new(core, input, true, RZ_ROP_GADGET_PRINT, RZ_ROP_DETAIL_SEARCH_NON, state); - RzCmdStatus status = rz_core_rop_search(core, context); - rz_core_rop_search_context_free(context); + + RzGadgetType gadget_type = gadget_type_from_cmd(argv[0]); + + RzGadgetSearchContext *context = rz_core_gadget_search_context_new(core, gadget_type, input, true, RZ_GADGET_PRINT, RZ_GADGET_DETAIL_SEARCH_NON, state); + RzCmdStatus status = rz_core_gadget_search(core, context); + rz_core_gadget_search_context_free(context); return status; } RZ_IPI RzCmdStatus rz_cmd_detail_gadget_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { const char *input = argc > 1 ? argv[1] : ""; - RzRopSearchContext *context = rz_core_rop_search_context_new(core, input, false, RZ_ROP_GADGET_PRINT_DETAIL | RZ_ROP_GADGET_ANALYZE, RZ_ROP_DETAIL_SEARCH_NON, state); - RzCmdStatus status = rz_core_rop_search(core, context); - rz_core_rop_search_context_free(context); + + RzGadgetType gadget_type = gadget_type_from_cmd(argv[0]); + + RzGadgetSearchContext *context = rz_core_gadget_search_context_new(core, gadget_type, input, false, RZ_GADGET_PRINT_DETAIL | RZ_GADGET_ANALYZE, RZ_GADGET_DETAIL_SEARCH_NON, state); + RzCmdStatus status = rz_core_gadget_search(core, context); + rz_core_gadget_search_context_free(context); return status; } RZ_IPI RzCmdStatus rz_cmd_rop_search_stack_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - RzRopSearchContext *context = rz_core_rop_search_context_new(core, argv[1], false, RZ_ROP_GADGET_PRINT_DETAIL | RZ_ROP_GADGET_ANALYZE, RZ_ROP_DETAIL_SEARCH_STACK, state); - RzCmdStatus status = rz_core_rop_gadget_info(core, context); + RzGadgetType gadget_type = RZ_GADGET_TYPE_ROP; + RzGadgetSearchContext *context = rz_core_gadget_search_context_new(core, gadget_type, argv[1], false, RZ_GADGET_PRINT_DETAIL | RZ_GADGET_ANALYZE, RZ_GADGET_DETAIL_SEARCH_STACK, state); + RzCmdStatus status = rz_core_gadget_info(core, context); return status; } -RZ_IPI RzCmdStatus rz_cmd_rop_search_size_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - RzRopSearchContext *context = rz_core_rop_search_context_new(core, argv[1], false, RZ_ROP_GADGET_PRINT_DETAIL | RZ_ROP_GADGET_ANALYZE, RZ_ROP_DETAIL_SEARCH_SIZE, state); - RzCmdStatus status = rz_core_rop_gadget_info(core, context); +RZ_IPI RzCmdStatus rz_cmd_gadget_search_size_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + + RzGadgetType gadget_type = gadget_type_from_cmd(argv[0]); + + RzGadgetSearchContext *context = rz_core_gadget_search_context_new(core, gadget_type, argv[1], false, RZ_GADGET_PRINT_DETAIL | RZ_GADGET_ANALYZE, RZ_GADGET_DETAIL_SEARCH_SIZE, state); + RzCmdStatus status = rz_core_gadget_info(core, context); return status; } diff --git a/librz/core/cmd/cmd_search_rop.c b/librz/core/cmd/cmd_search_gadget.c similarity index 69% rename from librz/core/cmd/cmd_search_rop.c rename to librz/core/cmd/cmd_search_gadget.c index 8eed523051..949afa4456 100644 --- a/librz/core/cmd/cmd_search_rop.c +++ b/librz/core/cmd/cmd_search_gadget.c @@ -1,3 +1,4 @@ +// SPDX-FileCopyrightText: 2026 MrQuantum1915 // SPDX-FileCopyrightText: 2024 z3phyr // SPDX-FileCopyrightText: 2009-2016 Alexandru Caciulescu // SPDX-License-Identifier: LGPL-3.0-only @@ -7,7 +8,7 @@ #include "rz_core.h" #include "rz_list.h" #include "rz_types_base.h" -#include "rz_rop.h" +#include "rz_gadget.h" static void skip_whitespace(const char *str, ut64 *idx) { if (*idx >= strlen(str)) { @@ -194,8 +195,8 @@ static bool parse_il_op(const char *str, ut64 *idx, bool *is_compound_op, RzILOp return false; } -static bool rop_constraint_set_regs(RzRopConstraint *rc, - RzRopILInstructionType il_type, +static bool gadget_constraint_set_regs(RzGadgetConstraint *rc, + RzGadgetILInstructionType il_type, RZ_NONNULL const RzRegItem *dst, RZ_NONNULL const RzRegItem *src0, RZ_NULLABLE const RzRegItem *src1) { @@ -213,7 +214,7 @@ static bool rop_constraint_set_regs(RzRopConstraint *rc, return true; } -static bool rop_constraint_set_op(RzRopConstraint *rc, RzILOpPureCode op) { +static bool gadget_constraint_set_op(RzGadgetConstraint *rc, RzILOpPureCode op) { if (op >= RZ_IL_OP_PURE_MAX) { return false; } @@ -226,8 +227,8 @@ static bool rop_constraint_set_op(RzRopConstraint *rc, RzILOpPureCode op) { return true; } -static bool rop_constraint_set_const(RzRopConstraint *rc, - RzRopILInstructionType il_type, +static bool gadget_constraint_set_const(RzGadgetConstraint *rc, + RzGadgetILInstructionType il_type, RZ_NONNULL const RzRegItem *dst, RZ_NULLABLE const RzRegItem *src0, ut64 const_value) { @@ -245,7 +246,7 @@ static bool rop_constraint_set_const(RzRopConstraint *rc, return true; } -static bool parse_compound_op(const RzCore *core, const char *str, RzRopConstraint *rc) { +static bool parse_compound_op(const RzCore *core, const char *str, RzGadgetConstraint *gadget_constraint) { ut64 idx = 0; ut64 const_value = 0; bool inc_dec = false; @@ -284,14 +285,14 @@ static bool parse_compound_op(const RzCore *core, const char *str, RzRopConstrai if (constant_status && is_compound_op) { // dst = dst (math op) num - return rop_constraint_set_const(rc, MOV_OP_CONST, dst_reg, dst_reg, const_value) && - rop_constraint_set_op(rc, op); + return gadget_constraint_set_const(gadget_constraint, MOV_OP_CONST, dst_reg, dst_reg, const_value) && + gadget_constraint_set_op(gadget_constraint, op); } if (src_reg && is_compound_op) { // dst = dst (math op) src - return rop_constraint_set_regs(rc, MOV_OP_REG, dst_reg, dst_reg, src_reg) && - rop_constraint_set_op(rc, op); + return gadget_constraint_set_regs(gadget_constraint, MOV_OP_REG, dst_reg, dst_reg, src_reg) && + gadget_constraint_set_op(gadget_constraint, op); } if (!inc_dec) { @@ -301,11 +302,11 @@ static bool parse_compound_op(const RzCore *core, const char *str, RzRopConstrai const_value = 1; // dst (math op)= 1 - return rop_constraint_set_const(rc, MOV_OP_CONST, dst_reg, dst_reg, const_value) && - rop_constraint_set_op(rc, op); + return gadget_constraint_set_const(gadget_constraint, MOV_OP_CONST, dst_reg, dst_reg, const_value) && + gadget_constraint_set_op(gadget_constraint, op); } -static bool parse_reg_to_const(const RzCore *core, const char *str, RzRopConstraint *rc) { +static bool parse_reg_to_const(const RzCore *core, const char *str, RzGadgetConstraint *gadget_constraint) { ut64 idx = 0; ut64 const_value = 0; const RzRegItem *dst_reg = parse_register(core, str, &idx); @@ -317,10 +318,10 @@ static bool parse_reg_to_const(const RzCore *core, const char *str, RzRopConstra return false; } - return rop_constraint_set_const(rc, MOV_CONST, dst_reg, NULL, const_value); + return gadget_constraint_set_const(gadget_constraint, MOV_CONST, dst_reg, NULL, const_value); } -static bool parse_reg_to_reg(const RzCore *core, const char *str, RzRopConstraint *rc) { +static bool parse_reg_to_reg(const RzCore *core, const char *str, RzGadgetConstraint *gadget_constraint) { ut64 idx = 0; const RzRegItem *src_reg = NULL; const RzRegItem *dst_reg = parse_register(core, str, &idx); @@ -341,10 +342,10 @@ static bool parse_reg_to_reg(const RzCore *core, const char *str, RzRopConstrain return false; } - return rop_constraint_set_regs(rc, MOV_REG, dst_reg, src_reg, NULL); + return gadget_constraint_set_regs(gadget_constraint, MOV_REG, dst_reg, src_reg, NULL); } -static bool parse_reg_op_const(const RzCore *core, const char *str, RzRopConstraint *rc) { +static bool parse_reg_op_const(const RzCore *core, const char *str, RzGadgetConstraint *gadget_constraint) { ut64 idx = 0; ut64 const_value = 0; RzILOpPureCode op = RZ_IL_OP_PURE_MAX; @@ -360,14 +361,14 @@ static bool parse_reg_op_const(const RzCore *core, const char *str, RzRopConstra goto compound; } - return rop_constraint_set_const(rc, MOV_OP_CONST, dst_reg, src_reg, const_value) && - rop_constraint_set_op(rc, op); + return gadget_constraint_set_const(gadget_constraint, MOV_OP_CONST, dst_reg, src_reg, const_value) && + gadget_constraint_set_op(gadget_constraint, op); compound: - return parse_compound_op(core, str, rc); + return parse_compound_op(core, str, gadget_constraint); } -static bool parse_reg_op_reg(const RzCore *core, const char *str, RzRopConstraint *rc) { +static bool parse_reg_op_reg(const RzCore *core, const char *str, RzGadgetConstraint *gadget_constraint) { ut64 idx = 0; RzILOpPureCode op = RZ_IL_OP_PURE_MAX; const RzRegItem *src_reg0 = NULL; @@ -391,63 +392,65 @@ static bool parse_reg_op_reg(const RzCore *core, const char *str, RzRopConstrain goto compound; } - return rop_constraint_set_regs(rc, MOV_OP_REG, dst_reg, src_reg0, src_reg1) && - rop_constraint_set_op(rc, op); + return gadget_constraint_set_regs(gadget_constraint, MOV_OP_REG, dst_reg, src_reg0, src_reg1) && + gadget_constraint_set_op(gadget_constraint, op); compound: - return parse_compound_op(core, str, rc); + return parse_compound_op(core, str, gadget_constraint); } /** - * \brief Create a new RzRopSearchContext object. + * \brief Create a new RzGadgetSearchContext object. * \param core RZ_NONNULL Pointer to the RzCore structure containing configuration settings. * \param greparg RZ_NULLABLE Pointer to a string containing the grep argument. * \param regexp Flag specifying whether regular expressions should be used. - * \param mask ROP request mask specifying the ROP request parameters. - * \param detail_mask search ROP gadgets given details. + * \param mask Gadget request mask specifying the Gadget request parameters. + * \param detail_mask search gadgets given details. * \param state RZ_BORROW Pointer to the command state output structure. - * \return RZ_OUT A pointer to the newly created RzRopSearchContext object, or NULL if memory allocation fails. + * \return RZ_OUT A pointer to the newly created RzGadgetSearchContext object, or NULL if memory allocation fails. * - * This function allocates and initializes a new RzRopSearchContext object. + * This function allocates and initializes a new RzGadgetSearchContext object. */ -RZ_API RZ_OWN RzRopSearchContext *rz_core_rop_search_context_new(RZ_NONNULL const RzCore *core, RZ_NULLABLE const char *greparg, const bool regexp, - const RzRopRequestMask mask, const RzRopDetailSearchMask detail_mask, RZ_NULLABLE RZ_BORROW RzCmdStateOutput *state) { +RZ_API RZ_OWN RzGadgetSearchContext *rz_core_gadget_search_context_new(RZ_NONNULL const RzCore *core, const RzGadgetType gadget_type, RZ_NULLABLE const char *greparg, const bool regexp, + const RzGadgetRequestMask mask, const RzGadgetDetailSearchMask detail_mask, RZ_NULLABLE RZ_BORROW RzCmdStateOutput *state) { rz_return_val_if_fail(core, NULL); - RzRopSearchContext *context = RZ_NEW0(RzRopSearchContext); + RzGadgetSearchContext *context = RZ_NEW0(RzGadgetSearchContext); if (!context) { return NULL; } + context->type = gadget_type; context->greparg = rz_str_dup(greparg); context->arch = rz_config_get(core->config, "asm.arch"); context->regexp = regexp; context->mask = mask; context->detail_mask = detail_mask; context->state = state; - context->max_instr = rz_config_get_i(core->config, "rop.len"); + context->max_instr = rz_config_get_i(core->config, "gadget.len"); context->max_count = rz_config_get_i(core->config, "search.maxhits"); context->increment = 1; context->from = 0; context->to = 0; context->end_list = NULL; context->unique_hitlists = NULL; - context->crop = rz_config_get_i(core->config, "rop.conditional"); - context->subchain = rz_config_get_i(core->config, "rop.subchain"); - context->cache = rz_config_get_i(core->config, "rop.cache"); + context->allow_conditional = rz_config_get_b(core->config, "gadget.conditional"); + context->comments = rz_config_get_b(core->config, "gadget.comments"); + context->subchains = rz_config_get_b(core->config, "gadget.subchains"); + context->cache = rz_config_get_b(core->config, "gadget.cache"); context->ret_val = false; context->buf = NULL; return context; } /** - * \brief Free an RzRopSearchContext object. - * \param context RZ_NULLABLE Pointer to the RzRopSearchContext object to free. + * \brief Free an RzGadgetSearchContext object. + * \param context RZ_NULLABLE Pointer to the RzGadgetSearchContext object to free. * - * Frees the memory allocated for an RzRopSearchContext object. + * Frees the memory allocated for an RzGadgetSearchContext object. * Note: Other elements must be freed by the caller/callee. */ -RZ_API void rz_core_rop_search_context_free(RZ_NULLABLE RzRopSearchContext *context) { +RZ_API void rz_core_gadget_search_context_free(RZ_NULLABLE RzGadgetSearchContext *context) { if (!context) { return; } @@ -462,77 +465,77 @@ RZ_API void rz_core_rop_search_context_free(RZ_NULLABLE RzRopSearchContext *cont * \brief Analyze and parse a constraint string. * \param core Pointer to the RzCore object. * \param str The constraint string to analyze. - * \param rop_constraint Pointer to the RzRopConstraint object to store the parsed result. + * \param gadget_constraint Pointer to the RzGadgetConstraint object to store the parsed result. * \return true if the constraint string is successfully parsed, false otherwise. * * This function analyzes a given constraint string and attempts to parse it into - * the provided RzRopConstraint. It tries four different parsing methods: + * the provided RzGadgetConstraint. It tries four different parsing methods: * * The function returns true if any of these parsing methods succeed. */ -RZ_API bool rz_core_rop_analyze_constraint(const RZ_NONNULL RzCore *core, const RZ_NONNULL char *str, - RZ_NULLABLE RZ_OUT RzRopConstraint *rop_constraint) { +RZ_API bool rz_core_gadget_analyze_constraint(const RZ_NONNULL RzCore *core, const RZ_NONNULL char *str, + RZ_NULLABLE RZ_OUT RzGadgetConstraint *gadget_constraint) { rz_return_val_if_fail(core && str, false); - if (!rop_constraint) { + if (!gadget_constraint) { return false; } - return parse_reg_to_const(core, str, rop_constraint) || - parse_reg_to_reg(core, str, rop_constraint) || - parse_reg_op_const(core, str, rop_constraint) || - parse_reg_op_reg(core, str, rop_constraint); + return parse_reg_to_const(core, str, gadget_constraint) || + parse_reg_to_reg(core, str, gadget_constraint) || + parse_reg_op_const(core, str, gadget_constraint) || + parse_reg_op_reg(core, str, gadget_constraint); } /** - * \brief Parse the given token into a rop constraint + * \brief Parse the given token into a gadget constraint * \param core Pointer to the RzCore object. * \param token Input string in the form `key=value`(Eg: rbx=rdx, r12=1)` - * \return \p RzRopConstraint if parsing is successful else NULL + * \return \p RzGadgetConstraint if parsing is successful else NULL * - * The function parses the given token and parses according to the predefined ROP constriant type + * The function parses the given token and parses according to the predefined gadget constraint type */ -RZ_API RZ_OWN RzRopConstraint *rz_core_rop_constraint_parse_args(const RZ_NONNULL RzCore *core, const RZ_NONNULL char *token) { +RZ_API RZ_OWN RzGadgetConstraint *rz_core_gadget_constraint_parse_args(const RZ_NONNULL RzCore *core, const RZ_NONNULL char *token) { rz_return_val_if_fail(core && token, NULL); if (RZ_STR_ISEMPTY(token)) { return NULL; } - RzRopConstraint *rop_constraint = RZ_NEW0(RzRopConstraint); - if (!rop_constraint) { - free(rop_constraint); + RzGadgetConstraint *gadget_constraint = RZ_NEW0(RzGadgetConstraint); + if (!gadget_constraint) { + free(gadget_constraint); return NULL; } RzList *l = rz_str_split_duplist(token, "=", true); if (rz_list_empty(l)) { rz_list_free(l); - free(rop_constraint); + free(gadget_constraint); return NULL; } - if (!rz_core_rop_analyze_constraint(core, token, rop_constraint)) { - free(rop_constraint); + if (!rz_core_gadget_analyze_constraint(core, token, gadget_constraint)) { + free(gadget_constraint); rz_list_free(l); return NULL; } rz_list_free(l); - return rop_constraint; + return gadget_constraint; } /** - * \brief Parse rop constraint map + * \brief Parse gadget constraint map * \param core Pointer to the RzCore object. * \param argc Number of arguments. * \param argv Array of arguments. - * \return RzPVector of RzRopConstraint objects. + * \return RzPVector of RzGadgetConstraint objects. * - * This function parses a list of arguments into a RzPVector of RzRopConstraint objects. + * This function parses a list of arguments into a RzPVector of RzGadgetConstraint objects. */ -RZ_API RZ_OWN RzPVector /**/ *rz_core_rop_constraint_map_parse(const RZ_NONNULL RzCore *core, const int argc, const char **argv) { +RZ_API RZ_OWN RzPVector /**/ *rz_core_gadget_constraint_map_parse(const RZ_NONNULL RzCore *core, const int argc, const char **argv) { rz_return_val_if_fail(core && argv && RZ_STR_ISNOTEMPTY(argv[0]), false); - RzPVector *constr_map = rz_pvector_new((RzPVectorFree)rz_core_rop_constraint_free); + RzPVector *constr_map = rz_pvector_new((RzPVectorFree)rz_core_gadget_constraint_free); if (!constr_map) { return NULL; } @@ -548,11 +551,11 @@ RZ_API RZ_OWN RzPVector /**/ *rz_core_rop_constraint_map_pars RzListIter *it; char *token; rz_list_foreach (l, it, token) { - RzRopConstraint *rop_constraint = rz_core_rop_constraint_parse_args(core, token); - if (!rop_constraint) { + RzGadgetConstraint *gadget_constraint = rz_core_gadget_constraint_parse_args(core, token); + if (!gadget_constraint) { continue; } - rz_pvector_push(constr_map, rop_constraint); + rz_pvector_push(constr_map, gadget_constraint); } rz_list_free(l); } diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index 71ca15f891..443a2eb6ea 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -21,7 +21,7 @@ static const RzCmdDescDetail cmd_search_cryptographic_material_details[2]; static const RzCmdDescDetail cmd_search_file_details[2]; static const RzCmdDescDetail cmd_query_gadget_details[5]; static const RzCmdDescDetail cmd_rop_search_stack_details[2]; -static const RzCmdDescDetail cmd_rop_search_size_details[2]; +static const RzCmdDescDetail cmd_gadget_search_size_details[2]; static const RzCmdDescDetail cmd_search_value_details[3]; static const RzCmdDescDetail cmd_search_hex_details[2]; static const RzCmdDescDetail cmd_search_hex_regex_details[2]; @@ -163,7 +163,7 @@ static const RzCmdDescArg cmd_search_gadget_args[2]; static const RzCmdDescArg cmd_query_gadget_args[2]; static const RzCmdDescArg cmd_detail_gadget_args[2]; static const RzCmdDescArg cmd_rop_search_stack_args[2]; -static const RzCmdDescArg cmd_rop_search_size_args[2]; +static const RzCmdDescArg cmd_gadget_search_size_args[2]; static const RzCmdDescArg cmd_search_value_args[3]; static const RzCmdDescArg cmd_search_value_alias_v1_args[2]; static const RzCmdDescArg cmd_search_value_alias_v2_args[2]; @@ -2259,16 +2259,16 @@ static const RzCmdDescHelp cmd_rop_search_stack_help = { .args = cmd_rop_search_stack_args, }; -static const RzCmdDescDetailEntry cmd_rop_search_size_Usage_space_example_detail_entries[] = { +static const RzCmdDescDetailEntry cmd_gadget_search_size_Usage_space_example_detail_entries[] = { { .text = "Search ROP gadgets with the size less than 0x20", .arg_str = NULL, .comment = "/Rl \"<0x20\"" }, { .text = "Search ROP gadgets with the size 0x10", .arg_str = NULL, .comment = "/Rl =0x10" }, { 0 }, }; -static const RzCmdDescDetail cmd_rop_search_size_details[] = { - { .name = "Usage example", .entries = cmd_rop_search_size_Usage_space_example_detail_entries }, +static const RzCmdDescDetail cmd_gadget_search_size_details[] = { + { .name = "Usage example", .entries = cmd_gadget_search_size_Usage_space_example_detail_entries }, { 0 }, }; -static const RzCmdDescArg cmd_rop_search_size_args[] = { +static const RzCmdDescArg cmd_gadget_search_size_args[] = { { .name = "Gadget size", .type = RZ_CMD_ARG_TYPE_STRING, @@ -2278,10 +2278,10 @@ static const RzCmdDescArg cmd_rop_search_size_args[] = { }, { 0 }, }; -static const RzCmdDescHelp cmd_rop_search_size_help = { +static const RzCmdDescHelp cmd_gadget_search_size_help = { .summary = "Search rop gadgets given gadget size", - .details = cmd_rop_search_size_details, - .args = cmd_rop_search_size_args, + .details = cmd_gadget_search_size_details, + .args = cmd_gadget_search_size_args, }; static const RzCmdDescHelp slash_v_help = { @@ -21856,8 +21856,8 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) { RzCmdDesc *cmd_rop_search_stack_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_R_cd, "/Rs", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_rop_search_stack_handler, &cmd_rop_search_stack_help); rz_warn_if_fail(cmd_rop_search_stack_cd); - RzCmdDesc *cmd_rop_search_size_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_R_cd, "/Rl", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_rop_search_size_handler, &cmd_rop_search_size_help); - rz_warn_if_fail(cmd_rop_search_size_cd); + RzCmdDesc *cmd_gadget_search_size_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_R_cd, "/Rl", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_gadget_search_size_handler, &cmd_gadget_search_size_help); + rz_warn_if_fail(cmd_gadget_search_size_cd); RzCmdDesc *slash_v_cd = rz_cmd_desc_group_state_new(core->rcmd, slash__cd, "/v", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_value_handler, &cmd_search_value_help, &slash_v_help); rz_warn_if_fail(slash_v_cd); diff --git a/librz/core/cmd_descs/cmd_descs.h b/librz/core/cmd_descs/cmd_descs.h index 6e595bbc03..32025da433 100644 --- a/librz/core/cmd_descs/cmd_descs.h +++ b/librz/core/cmd_descs/cmd_descs.h @@ -152,7 +152,7 @@ RZ_IPI RzCmdStatus rz_cmd_detail_gadget_handler(RzCore *core, int argc, const ch // "/Rs" RZ_IPI RzCmdStatus rz_cmd_rop_search_stack_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "/Rl" -RZ_IPI RzCmdStatus rz_cmd_rop_search_size_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +RZ_IPI RzCmdStatus rz_cmd_gadget_search_size_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "/v" RZ_IPI RzCmdStatus rz_cmd_search_value_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "/v1" diff --git a/librz/core/cmd_descs/cmd_search.yaml b/librz/core/cmd_descs/cmd_search.yaml index ad6806b5b8..b221f1977c 100644 --- a/librz/core/cmd_descs/cmd_search.yaml +++ b/librz/core/cmd_descs/cmd_search.yaml @@ -583,7 +583,7 @@ commands: - text: "Search ROP gadgets with 0x100 stack changes" comment: "/Rs =0x100" - name: "/Rl" - cname: cmd_rop_search_size + cname: cmd_gadget_search_size summary: Search rop gadgets given gadget size type: RZ_CMD_DESC_TYPE_ARGV_STATE modes: diff --git a/librz/core/rop.c b/librz/core/gadget.c similarity index 66% rename from librz/core/rop.c rename to librz/core/gadget.c index 916330cf4f..3ede891403 100644 --- a/librz/core/rop.c +++ b/librz/core/gadget.c @@ -1,3 +1,4 @@ +// SPDX-FileCopyrightText: 2026 MrQuantum1915 // SPDX-FileCopyrightText: 2024 z3phyr // SPDX-License-Identifier: LGPL-3.0-only @@ -5,22 +6,10 @@ #include #include #include -#include +#include +#include "gadget_internal.h" -static bool is_cond_end_gadget(const RzAnalysisOp *aop) { - switch (aop->type) { - case RZ_ANALYSIS_OP_TYPE_CJMP: - case RZ_ANALYSIS_OP_TYPE_UCJMP: - case RZ_ANALYSIS_OP_TYPE_CCALL: - case RZ_ANALYSIS_OP_TYPE_UCCALL: - case RZ_ANALYSIS_OP_TYPE_CRET: - return true; - default: - return false; - } -} - -static bool is_ret_gadget(const RzCore *core, const RzCoreAsmHit *hit, const ut8 crop) { +static bool gadget_is_valid_terminator(const RzGadgetType gadget_type, const RzCore *core, const RzCoreAsmHit *hit, const bool allow_conditional) { rz_return_val_if_fail(core && core->analysis && hit, false); bool status = false; RzAnalysisOp aop = { 0 }; @@ -34,49 +23,34 @@ static bool is_ret_gadget(const RzCore *core, const RzCoreAsmHit *hit, const ut8 free(buf); return status; } - switch (aop.type) { - case RZ_ANALYSIS_OP_TYPE_RET: - if (crop) { - status = is_cond_end_gadget(&aop); - break; - } - status = true; + + switch (gadget_type) { + case RZ_GADGET_TYPE_ROP: + status = rz_gadget_rop_is_valid_terminator(&aop, allow_conditional); break; default: break; } + rz_analysis_op_fini(&aop); free(buf); return status; } -static bool is_end_gadget(const RzAnalysisOp *aop, const ut8 crop) { +static bool gadget_is_valid_end_gadget(const RzGadgetType gadget_type, const RzAnalysisOp *aop, const bool allow_conditional) { if (aop->family == RZ_ANALYSIS_OP_FAMILY_SECURITY) { return false; } - switch (aop->type) { - case RZ_ANALYSIS_OP_TYPE_TRAP: - case RZ_ANALYSIS_OP_TYPE_RET: - case RZ_ANALYSIS_OP_TYPE_UCALL: - case RZ_ANALYSIS_OP_TYPE_RCALL: - case RZ_ANALYSIS_OP_TYPE_ICALL: - case RZ_ANALYSIS_OP_TYPE_IRCALL: - case RZ_ANALYSIS_OP_TYPE_UJMP: - case RZ_ANALYSIS_OP_TYPE_RJMP: - case RZ_ANALYSIS_OP_TYPE_IJMP: - case RZ_ANALYSIS_OP_TYPE_IRJMP: - case RZ_ANALYSIS_OP_TYPE_JMP: - case RZ_ANALYSIS_OP_TYPE_CALL: - if (crop) { - return is_cond_end_gadget(aop); - } - return true; + + switch (gadget_type) { + case RZ_GADGET_TYPE_ROP: + return rz_gadget_rop_is_end_gadget(aop, allow_conditional); default: return false; } } -static bool rz_rop_process_asm_op(const RzCore *core, const RzCoreAsmHit *hit, RzAsmOp *asmop, RzAnalysisOp *aop, unsigned int *size, char **asmop_str, char **asmop_hex_str) { +static bool gadget_process_asm_op(const RzCore *core, const RzCoreAsmHit *hit, RzAsmOp *asmop, RzAnalysisOp *aop, unsigned int *size, char **asmop_str, char **asmop_hex_str) { ut8 *buf = malloc(hit->len); if (!buf) { return false; @@ -111,8 +85,8 @@ static bool rz_rop_process_asm_op(const RzCore *core, const RzCoreAsmHit *hit, R return true; } -static bool rz_rop_print_table_mode(const RzCore *core, const RzCoreAsmHit *hit, const RzList /**/ *hitlist, - ut32 *size, char **asmop_str, char **asmop_hex_str, RzRopSearchContext *context) { +static bool gadget_hitlist_print_table_mode(const RzCore *core, const RzCoreAsmHit *hit, const RzPVector /**/ *hitlist, + ut32 *size, char **asmop_str, char **asmop_hex_str, RzGadgetSearchContext *context) { rz_return_val_if_fail(core && hitlist, false); RzAnalysisOp aop = RZ_EMPTY; RzAsmOp *asmop = rz_asm_op_new(); @@ -120,25 +94,28 @@ static bool rz_rop_print_table_mode(const RzCore *core, const RzCoreAsmHit *hit, return false; } - if (!rz_rop_process_asm_op(core, hit, asmop, &aop, size, asmop_str, asmop_hex_str)) { + if (!gadget_process_asm_op(core, hit, asmop, &aop, size, asmop_str, asmop_hex_str)) { rz_asm_op_free(asmop); return false; } - const ut64 addr_last = ((RzCoreAsmHit *)rz_list_last_val(hitlist))->addr; - if (addr_last != hit->addr) { - *asmop_str = rz_str_append(*asmop_str, "; "); + size_t len = rz_pvector_len(hitlist); + if (len > 0) { + const RzCoreAsmHit *last_hit = rz_pvector_at(hitlist, len - 1); + if (last_hit->addr != hit->addr) { + *asmop_str = rz_str_append(*asmop_str, "; "); + } } rz_asm_op_free(asmop); rz_analysis_op_fini(&aop); return true; } -static bool rz_rop_prepare_asm_op(const RzCore *core, const RzCoreAsmHit *hit, RzAsmOp **asmop_out, RzAnalysisOp *aop, ut32 *size) { +static bool gadget_prepare_asm_op(const RzCore *core, const RzCoreAsmHit *hit, RzAsmOp **asmop_out, RzAnalysisOp *aop, ut32 *size) { RzAsmOp *asmop = rz_asm_op_new(); if (!asmop) { return false; } - if (!rz_rop_process_asm_op(core, hit, asmop, aop, size, NULL, NULL)) { + if (!gadget_process_asm_op(core, hit, asmop, aop, size, NULL, NULL)) { rz_asm_op_free(asmop); return false; } @@ -170,14 +147,14 @@ static RZ_OWN char *get_colored_asm(const RzCore *core, RzAsmOp *asmop, RzAnalys return ret_str_asm; } -static bool rz_rop_print_quiet_mode(const RzCore *core, const RzCoreAsmHit *hit, ut32 *size, RzRopSearchContext *context) { +static bool gadget_hitlist_print_quiet_mode(const RzCore *core, const RzCoreAsmHit *hit, ut32 *size, RzGadgetSearchContext *context) { if (!core || !context) { return false; } RzAnalysisOp aop = RZ_EMPTY; RzAsmOp *asmop = NULL; - if (!rz_rop_prepare_asm_op(core, hit, &asmop, &aop, size)) { + if (!gadget_prepare_asm_op(core, hit, &asmop, &aop, size)) { return false; } @@ -199,20 +176,19 @@ static bool rz_rop_print_quiet_mode(const RzCore *core, const RzCoreAsmHit *hit, return true; } -static bool rz_rop_print_standard_mode(const RzCore *core, const RzCoreAsmHit *hit, ut32 *size, RzRopSearchContext *context) { +static bool gadget_hitlist_print_standard_mode(const RzCore *core, const RzCoreAsmHit *hit, ut32 *size, RzGadgetSearchContext *context) { rz_return_val_if_fail(core && context, false); RzAnalysisOp aop = RZ_EMPTY; RzAsmOp *asmop = NULL; - if (!rz_rop_prepare_asm_op(core, hit, &asmop, &aop, size)) { + if (!gadget_prepare_asm_op(core, hit, &asmop, &aop, size)) { return false; } - const bool rop_comments = rz_config_get_i(core->config, "rop.comments"); const bool colorize = rz_config_get_i(core->config, "scr.color"); bool ret_val = context->ret_val; const char *comment = NULL; - if (rop_comments) { + if (context->comments) { comment = rz_meta_get_string(core->analysis, RZ_META_TYPE_COMMENT, hit->addr); } @@ -253,14 +229,14 @@ static bool rz_rop_print_standard_mode(const RzCore *core, const RzCoreAsmHit *h return true; } -static bool rz_rop_print_json_mode(const RzCore *core, const RzCoreAsmHit *hit, unsigned int *size, PJ *pj) { +static bool gadget_hitlist_print_json_mode(const RzCore *core, const RzCoreAsmHit *hit, unsigned int *size, PJ *pj) { rz_return_val_if_fail(core && hit && pj, false); RzAnalysisOp aop = RZ_EMPTY; RzAsmOp *asmop = rz_asm_op_new(); if (!asmop) { return false; } - if (!rz_rop_process_asm_op(core, hit, asmop, &aop, size, NULL, NULL)) { + if (!gadget_process_asm_op(core, hit, asmop, &aop, size, NULL, NULL)) { rz_asm_op_free(asmop); return false; } @@ -277,7 +253,7 @@ static bool rz_rop_print_json_mode(const RzCore *core, const RzCoreAsmHit *hit, return true; } -RZ_API void rz_core_rop_reg_info_free(RZ_NULLABLE RzRopRegInfo *reg_info) { +RZ_API void rz_core_gadget_reg_info_free(RZ_NULLABLE RzGadgetRegInfo *reg_info) { if (!reg_info) { return; } @@ -286,10 +262,10 @@ RZ_API void rz_core_rop_reg_info_free(RZ_NULLABLE RzRopRegInfo *reg_info) { free(reg_info); } -RZ_API RZ_OWN RzRopRegInfo *rz_core_rop_reg_info_new(RZ_NONNULL const RzCore *core, RZ_NONNULL const RzILEvent *evt, +RZ_API RZ_OWN RzGadgetRegInfo *rz_core_gadget_reg_info_new(RZ_NONNULL const RzCore *core, RZ_NONNULL const RzILEvent *evt, const ut64 init_val, const ut64 new_val) { rz_return_val_if_fail(core && evt, NULL); - RzRopRegInfo *reg_info = RZ_NEW0(RzRopRegInfo); + RzGadgetRegInfo *reg_info = RZ_NEW0(RzGadgetRegInfo); if (!reg_info) { return NULL; } @@ -328,14 +304,14 @@ RZ_API RZ_OWN RzRopRegInfo *rz_core_rop_reg_info_new(RZ_NONNULL const RzCore *co } /** - * \brief Create a new RzRopGadgetInfo object. - * \param address The address of the ROP gadget. - * \return RZ_OUT A pointer to the newly created RzRopGadgetInfo object, or NULL if memory allocation fails. + * \brief Create a new RzGadgetInfo object. + * \param address The address of the gadget. + * \return RZ_OUT A pointer to the newly created RzGadgetInfo object, or NULL if memory allocation fails. * - * This function allocates and initializes a new RzRopGadgetInfo object with the given address. + * This function allocates and initializes a new RzGadgetInfo object with the given address. */ -RZ_API RZ_OWN RzRopGadgetInfo *rz_core_rop_gadget_info_new(const ut64 address) { - RzRopGadgetInfo *gadget_info = RZ_NEW0(RzRopGadgetInfo); +RZ_API RZ_OWN RzGadgetInfo *rz_core_gadget_info_new(const ut64 address) { + RzGadgetInfo *gadget_info = RZ_NEW0(RzGadgetInfo); if (!gadget_info) { return NULL; } @@ -345,20 +321,20 @@ RZ_API RZ_OWN RzRopGadgetInfo *rz_core_rop_gadget_info_new(const ut64 address) { gadget_info->curr_pc_val = address; gadget_info->is_pc_write = false; gadget_info->is_syscall = false; - gadget_info->modified_registers = rz_pvector_new((RzPVectorFree)rz_core_rop_reg_info_free); - gadget_info->dependencies = rz_list_newf((RzListFree)rz_core_rop_reg_info_free); + gadget_info->modified_registers = rz_pvector_new((RzPVectorFree)rz_core_gadget_reg_info_free); + gadget_info->dependencies = rz_list_newf((RzListFree)rz_core_gadget_reg_info_free); gadget_info->analysis_cache = NULL; gadget_info->size = 0; return gadget_info; } /** - * \brief Free an RzRopGadgetInfo object. - * \param gadget_info RZ_NULLABLE Pointer to the RzRopGadgetInfo object to free. + * \brief Free an RzGadgetInfo object. + * \param gadget_info RZ_NULLABLE Pointer to the RzGadgetInfo object to free. * - * Frees the memory allocated for an RzRopGadgetInfo object, including its modified registers and dependencies. + * Frees the memory allocated for an RzGadgetInfo object, including its modified registers and dependencies. */ -RZ_API void rz_core_rop_gadget_info_free(RZ_NULLABLE RzRopGadgetInfo *gadget_info) { +RZ_API void rz_core_gadget_info_free(RZ_NULLABLE RzGadgetInfo *gadget_info) { if (!gadget_info) { return; } @@ -369,15 +345,15 @@ RZ_API void rz_core_rop_gadget_info_free(RZ_NULLABLE RzRopGadgetInfo *gadget_inf } /** - * \brief Add a register info to an RzRopGadgetInfo object. - * \param gadget_info RZ_NONNULL Pointer to the RzRopGadgetInfo object. - * \param reg_info RZ_NONNULL Pointer to the RzRopRegInfo object. + * \brief Add a register info to an RzGadgetInfo object. + * \param gadget_info RZ_NONNULL Pointer to the RzGadgetInfo object. + * \param reg_info RZ_NONNULL Pointer to the RzGadgetRegInfo object. * \param is_dependency Boolean indicating whether the register is a dependency. * - * Adds the given register info to the modified registers of the RzRopGadgetInfo object if it is not a dependency. + * Adds the given register info to the modified registers of the RzGadgetInfo object if it is not a dependency. */ -RZ_API void rz_core_rop_gadget_info_add_register(const RZ_NONNULL RZ_OUT RzRopGadgetInfo *gadget_info, - RZ_NONNULL RzRopRegInfo *reg_info, const bool is_dependency) { +RZ_API void rz_core_gadget_info_add_register(const RZ_NONNULL RZ_OUT RzGadgetInfo *gadget_info, + RZ_NONNULL RzGadgetRegInfo *reg_info, const bool is_dependency) { rz_return_if_fail(gadget_info); if (!is_dependency && reg_info) { @@ -387,18 +363,18 @@ RZ_API void rz_core_rop_gadget_info_add_register(const RZ_NONNULL RZ_OUT RzRopGa /** * \brief Get the modified register info by name. - * \param gadget_info RZ_NONNULL Pointer to the RzRopGadgetInfo object. + * \param gadget_info RZ_NONNULL Pointer to the RzGadgetInfo object. * \param name RZ_NONNULL Pointer to the name of the register. - * \return RZ_OUT A pointer to the RzRopRegInfo object if found, or NULL if not found or if gadget_info is NULL. + * \return RZ_OUT A pointer to the RzGadgetRegInfo object if found, or NULL if not found or if gadget_info is NULL. * - * Searches the modified registers in the RzRopGadgetInfo object for the register with the given name and returns its info. + * Searches the modified registers in the RzGadgetInfo object for the register with the given name and returns its info. */ -RZ_API RZ_BORROW RzRopRegInfo *rz_core_rop_gadget_info_get_modified_register(const RZ_NONNULL RzRopGadgetInfo *gadget_info, +RZ_API RZ_BORROW RzGadgetRegInfo *rz_core_gadget_info_get_modified_register(const RZ_NONNULL RzGadgetInfo *gadget_info, const RZ_NONNULL char *name) { rz_return_val_if_fail(gadget_info && name, NULL); void **it; rz_pvector_foreach (gadget_info->modified_registers, it) { - RzRopRegInfo *reg_info = *it; + RzGadgetRegInfo *reg_info = *it; if (RZ_STR_EQ(reg_info->name, name)) { return reg_info; } @@ -407,18 +383,18 @@ RZ_API RZ_BORROW RzRopRegInfo *rz_core_rop_gadget_info_get_modified_register(con } /** - * \brief Update a register info in the RzRopGadgetInfo object. - * \param gadget_info Pointer to the RzRopGadgetInfo object. - * \param new_reg_info Pointer to the new RzRopRegInfo object. + * \brief Update a register info in the RzGadgetInfo object. + * \param gadget_info Pointer to the RzGadgetInfo object. + * \param new_reg_info Pointer to the new RzGadgetRegInfo object. * \return void * - * Updates the register info in the RzRopGadgetInfo object with the values from the new register info. + * Updates the register info in the RzGadgetInfo object with the values from the new register info. * If the register is not already in the modified registers list, it is added. */ -RZ_API void rz_core_rop_gadget_info_update_register(const RZ_INOUT RzRopGadgetInfo *gadget_info, RZ_INOUT RZ_NONNULL RzRopRegInfo *new_reg_info) { +RZ_API void rz_core_gadget_info_update_register(const RZ_INOUT RzGadgetInfo *gadget_info, RZ_INOUT RZ_NONNULL RzGadgetRegInfo *new_reg_info) { rz_return_if_fail(gadget_info && new_reg_info); - RzRopRegInfo *existing_reg_info = rz_core_rop_gadget_info_get_modified_register(gadget_info, new_reg_info->name); + RzGadgetRegInfo *existing_reg_info = rz_core_gadget_info_get_modified_register(gadget_info, new_reg_info->name); if (existing_reg_info) { existing_reg_info->init_val = new_reg_info->init_val; existing_reg_info->new_val = new_reg_info->new_val; @@ -432,13 +408,13 @@ RZ_API void rz_core_rop_gadget_info_update_register(const RZ_INOUT RzRopGadgetIn } /** - * \brief Duplicate the RzRopRegInfo - * \param src Pointer to RzRopRegInfo - * \return RzRopRegInfo* on success, NULL on failure + * \brief Duplicate the RzGadgetRegInfo + * \param src Pointer to RzGadgetRegInfo + * \return RzGadgetRegInfo* on success, NULL on failure */ -RZ_API RZ_OWN RzRopRegInfo *rz_core_rop_reg_info_dup(RZ_BORROW RZ_NONNULL RzRopRegInfo *src) { +RZ_API RZ_OWN RzGadgetRegInfo *rz_core_gadget_reg_info_dup(RZ_BORROW RZ_NONNULL RzGadgetRegInfo *src) { rz_return_val_if_fail(src, NULL); - RzRopRegInfo *dup = RZ_NEW0(RzRopRegInfo); + RzGadgetRegInfo *dup = RZ_NEW0(RzGadgetRegInfo); if (!dup) { return NULL; } @@ -456,20 +432,20 @@ RZ_API RZ_OWN RzRopRegInfo *rz_core_rop_reg_info_dup(RZ_BORROW RZ_NONNULL RzRopR } /** - * \brief Find the ROP Register information for the given register - * \param gadget_info Pointer to the RzRopGadgetInfo + * \brief Find the Gadget Register information for the given register + * \param gadget_info Pointer to the RzGadgetInfo * \param name Register to filter the dependencies * - * \return Pvector of register rop information + * \return Pvector of register gadget information */ -RZ_API RZ_OWN RzPVector /**/ *rz_core_rop_reg_info_find(const RZ_NONNULL RzRopGadgetInfo *gadget_info, const RZ_NONNULL char *name) { +RZ_API RZ_OWN RzPVector /**/ *rz_core_gadget_reg_info_find(const RZ_NONNULL RzGadgetInfo *gadget_info, const RZ_NONNULL char *name) { rz_return_val_if_fail(gadget_info && name, NULL); - RzPVector * /**/ reg_info_v = rz_pvector_new((RzPVectorFree)rz_core_rop_reg_info_free); + RzPVector * /**/ reg_info_v = rz_pvector_new((RzPVectorFree)rz_core_gadget_reg_info_free); if (!reg_info_v) { return NULL; } RzListIter *iter; - RzRopRegInfo *reg_info; + RzGadgetRegInfo *reg_info; rz_list_foreach (gadget_info->dependencies, iter, reg_info) { if (RZ_STR_EQ(reg_info->name, name)) { rz_pvector_push(reg_info_v, reg_info); @@ -479,18 +455,18 @@ RZ_API RZ_OWN RzPVector /**/ *rz_core_rop_reg_info_find(const RZ } /** - * \brief Check if a register with a specific name exists in the modified registers of a RzRopGadgetInfo object. - * \param gadget_info RZ_NONNULL Pointer to the RzRopGadgetInfo object. + * \brief Check if a register with a specific name exists in the modified registers of a RzGadgetInfo object. + * \param gadget_info RZ_NONNULL Pointer to the RzGadgetInfo object. * \param name RZ_NONNULL Pointer to the name of the register. * \return true if a register with the given name exists, false otherwise. * - * Checks the modified registers in the RzRopGadgetInfo object to see if a register with the given name exists. + * Checks the modified registers in the RzGadgetInfo object to see if a register with the given name exists. */ -RZ_API bool rz_core_rop_gadget_info_has_register(const RZ_NONNULL RzRopGadgetInfo *gadget_info, const RZ_NONNULL char *name) { +RZ_API bool rz_core_gadget_info_has_register(const RZ_NONNULL RzGadgetInfo *gadget_info, const RZ_NONNULL char *name) { rz_return_val_if_fail(gadget_info && name, false); void **it; rz_pvector_foreach (gadget_info->modified_registers, it) { - const RzRopRegInfo *reg_info = *it; + const RzGadgetRegInfo *reg_info = *it; if (RZ_STR_EQ(reg_info->name, name)) { return true; } @@ -498,27 +474,27 @@ RZ_API bool rz_core_rop_gadget_info_has_register(const RZ_NONNULL RzRopGadgetInf return false; } -static inline bool is_var_read_event(const RzRopRegInfo *reg_info) { +static inline bool is_var_read_event(const RzGadgetRegInfo *reg_info) { return reg_info->is_var_read && !reg_info->is_mem_read && !reg_info->is_var_write && !reg_info->is_mem_write; } -static inline bool is_var_write_event(const RzRopRegInfo *reg_info) { +static inline bool is_var_write_event(const RzGadgetRegInfo *reg_info) { return reg_info->is_var_write; } -static inline bool is_mem_read_event(const RzRopRegInfo *reg_info) { +static inline bool is_mem_read_event(const RzGadgetRegInfo *reg_info) { return reg_info->is_mem_read; } -static inline bool is_mem_write_event(const RzRopRegInfo *reg_info) { +static inline bool is_mem_write_event(const RzGadgetRegInfo *reg_info) { return reg_info->is_mem_write; } -static inline bool is_pc_write_event(const RzRopRegInfo *reg_info) { +static inline bool is_pc_write_event(const RzGadgetRegInfo *reg_info) { return reg_info->is_pc_write; } -rz_rop_event_check_fn rz_rop_event_functions[RZ_ROP_EVENT_COUNT] = { +rz_gadget_event_check_fn rz_gadget_event_functions[RZ_GADGET_EVENT_COUNT] = { is_var_read_event, is_var_write_event, is_mem_read_event, @@ -528,27 +504,27 @@ rz_rop_event_check_fn rz_rop_event_functions[RZ_ROP_EVENT_COUNT] = { /** * \brief Check if a given event dependency is present for a register - * \param gadget_info RZ_NONNULL Pointer to the RzRopGadgetInfo object. - * \param event The RzRopEvent to check. + * \param gadget_info RZ_NONNULL Pointer to the RzGadgetInfo object. + * \param event The RzGadgetEvent to check. * \param reg_name Name of the register * \return True if there is an \p event which uses \p reg_name. False otherwise. */ -RZ_API bool rz_core_rop_gadget_reg_info_has_event(const RZ_NONNULL RzRopGadgetInfo *gadget_info, - const RzRopEvent event, const RZ_NULLABLE char *reg_name) { +RZ_API bool rz_core_gadget_reg_info_has_event(const RZ_NONNULL RzGadgetInfo *gadget_info, + const RzGadgetEvent event, const RZ_NULLABLE char *reg_name) { rz_return_val_if_fail(gadget_info, false); - if (event >= RZ_ROP_EVENT_COUNT) { + if (event >= RZ_GADGET_EVENT_COUNT) { return false; } RzListIter *iter; - RzRopRegInfo *reg_info; + RzGadgetRegInfo *reg_info; rz_list_foreach (gadget_info->dependencies, iter, reg_info) { if (RZ_STR_NE(reg_name, reg_info->name)) { continue; } - if (event == RZ_ROP_EVENT_COUNT) { + if (event == RZ_GADGET_EVENT_COUNT) { return true; } - if (rz_rop_event_functions[event](reg_info)) { + if (rz_gadget_event_functions[event](reg_info)) { return true; } } @@ -556,59 +532,59 @@ RZ_API bool rz_core_rop_gadget_reg_info_has_event(const RZ_NONNULL RzRopGadgetIn } /** - * \brief Find all dependencies based on a specific event in the dependencies of a RzRopGadgetInfo object. - * \param gadget_info RZ_NONNULL Pointer to the RzRopGadgetInfo object. - * \param event The RzRopEvent to check. - * \return RZ_OUT A pointer to a list of RzRopRegInfo objects matching the given event, or NULL if none are found or if gadget_info is NULL. + * \brief Find all dependencies based on a specific event in the dependencies of a RzGadgetInfo object. + * \param gadget_info RZ_NONNULL Pointer to the RzGadgetInfo object. + * \param event The RzGadgetEvent to check. + * \return RZ_OUT A pointer to a list of RzGadgetRegInfo objects matching the given event, or NULL if none are found or if gadget_info is NULL. */ -RZ_API RZ_OWN RzPVector /**/ *rz_core_rop_gadget_get_reg_info_by_event(const RZ_NONNULL RzRopGadgetInfo *gadget_info, - const RzRopEvent event) { +RZ_API RZ_OWN RzPVector /**/ *rz_core_gadget_get_reg_info_by_event(const RZ_NONNULL RzGadgetInfo *gadget_info, + const RzGadgetEvent event) { rz_return_val_if_fail(gadget_info, NULL); - if (event >= RZ_ROP_EVENT_COUNT) { + if (event >= RZ_GADGET_EVENT_COUNT) { return NULL; } - RzPVector *matches = rz_pvector_new((RzPVectorFree)rz_core_rop_reg_info_free); + RzPVector *matches = rz_pvector_new((RzPVectorFree)rz_core_gadget_reg_info_free); if (!matches) { return NULL; } RzListIter *iter; - RzRopRegInfo *reg_info; + RzGadgetRegInfo *reg_info; rz_list_foreach (gadget_info->dependencies, iter, reg_info) { - if (rz_rop_event_functions[event](reg_info)) { - rz_pvector_push(matches, rz_core_rop_reg_info_dup(reg_info)); + if (rz_gadget_event_functions[event](reg_info)) { + rz_pvector_push(matches, rz_core_gadget_reg_info_dup(reg_info)); } } return matches; } /** - * \brief Find all registers with specific names in the modified registers of a RzRopGadgetInfo object. - * \param gadget_info RZ_NONNULL Pointer to the RzRopGadgetInfo object. + * \brief Find all registers with specific names in the modified registers of a RzGadgetInfo object. + * \param gadget_info RZ_NONNULL Pointer to the RzGadgetInfo object. * \param registers RZ_NONNULL Pointer to a RzPvector of register names. - * \return RZ_OUT A pointer to a RzPvector of RzRopRegInfo objects matching the given names, or NULL if none are found or if gadget_info is NULL. + * \return RZ_OUT A pointer to a RzPvector of RzGadgetRegInfo objects matching the given names, or NULL if none are found or if gadget_info is NULL. * - * Searches the modified registers in the RzRopGadgetInfo object for all registers with the given registers and returns their info in a vector. + * Searches the modified registers in the RzGadgetInfo object for all registers with the given registers and returns their info in a vector. */ -RZ_API RZ_OWN RzPVector /**/ *rz_core_rop_get_reg_info_by_reg_names(const RZ_NONNULL RzRopGadgetInfo *gadget_info, +RZ_API RZ_OWN RzPVector /**/ *rz_core_gadget_get_reg_info_by_reg_names(const RZ_NONNULL RzGadgetInfo *gadget_info, const RZ_NONNULL RzPVector /**/ *registers) { rz_return_val_if_fail(gadget_info && registers, NULL); - RzPVector *result = rz_pvector_new((RzPVectorFree)rz_core_rop_reg_info_free); + RzPVector *result = rz_pvector_new((RzPVectorFree)rz_core_gadget_reg_info_free); if (!result) { return NULL; } void **it; rz_pvector_foreach (gadget_info->modified_registers, it) { - RzRopRegInfo *reg_info = *it; + RzGadgetRegInfo *reg_info = *it; void **reg_it; rz_pvector_foreach (registers, reg_it) { const char *reg = *reg_it; if (RZ_STR_EQ(reg_info->name, reg)) { - RzRopRegInfo *rop_reg_info_dup = rz_core_rop_reg_info_dup(reg_info); - if (!rop_reg_info_dup) { + RzGadgetRegInfo *gadget_reg_info_dup = rz_core_gadget_reg_info_dup(reg_info); + if (!gadget_reg_info_dup) { continue; } - rz_pvector_push(result, rop_reg_info_dup); + rz_pvector_push(result, gadget_reg_info_dup); break; } } @@ -622,14 +598,14 @@ RZ_API RZ_OWN RzPVector /**/ *rz_core_rop_get_reg_info_by_reg_na return result; } -static void rz_rop_gadget_info_add_dependency(const RzCore *core, RzRopGadgetInfo *gadget_info, const RzILEvent *evt, RzRopRegInfo *reg_info) { +static void gadget_info_add_dependency(const RzCore *core, RzGadgetInfo *gadget_info, const RzILEvent *evt, RzGadgetRegInfo *reg_info) { rz_return_if_fail(core && core->analysis); RzReg *rreg = rz_analysis_get_reg(core->analysis); if (!reg_info || !rreg) { return; } - RzRopRegInfo *reg_info_dup = rz_core_rop_reg_info_dup(reg_info); + RzGadgetRegInfo *reg_info_dup = rz_core_gadget_reg_info_dup(reg_info); if (!reg_info_dup) { return; } @@ -679,13 +655,13 @@ static void rz_rop_gadget_info_add_dependency(const RzCore *core, RzRopGadgetInf } static void var_read_add_reg_info(const RzCore *core, const RzILEvent *event, - const RzILEventVarRead *var_read, RZ_OUT RzRopRegInfo **reg_info) { + const RzILEventVarRead *var_read, RZ_OUT RzGadgetRegInfo **reg_info) { rz_return_if_fail(core && event && var_read && reg_info); RzBitVector *val = rz_il_value_to_bv(var_read->value); if (!val) { return; } - *reg_info = rz_core_rop_reg_info_new(core, event, rz_bv_to_ut64(val), rz_bv_to_ut64(val)); + *reg_info = rz_core_gadget_reg_info_new(core, event, rz_bv_to_ut64(val), rz_bv_to_ut64(val)); if (!*reg_info) { rz_bv_free(val); return; @@ -694,17 +670,17 @@ static void var_read_add_reg_info(const RzCore *core, const RzILEvent *event, } static bool is_handle_il_event_read(const RzCore *core, const RzILEventVarRead *var_read, - RzRopRegInfo *reg_info, RzRopGadgetInfo *gadget_info, const RzILEvent *event, const RzILEvent *curr_event) { - if (rz_core_rop_gadget_reg_info_has_event(gadget_info, RZ_ROP_EVENT_VAR_READ, event->data.var_read.variable)) { + RzGadgetRegInfo *reg_info, RzGadgetInfo *gadget_info, const RzILEvent *event, const RzILEvent *curr_event) { + if (rz_core_gadget_reg_info_has_event(gadget_info, RZ_GADGET_EVENT_VAR_READ, event->data.var_read.variable)) { return false; } var_read_add_reg_info(core, event, var_read, ®_info); - rz_rop_gadget_info_add_dependency(core, gadget_info, curr_event, reg_info); - rz_core_rop_reg_info_free(reg_info); + gadget_info_add_dependency(core, gadget_info, curr_event, reg_info); + rz_core_gadget_reg_info_free(reg_info); return true; } -static bool fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadget_info, const RzILEvent *curr_event, +static bool fill_gadget_info_from_events(RzCore *core, RzGadgetInfo *gadget_info, const RzILEvent *curr_event, RzILEvent *event, RzPVector /**/ *vec, const bool is_dependency) { rz_return_val_if_fail(core, false); if (!gadget_info) { @@ -718,9 +694,9 @@ static bool fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadg switch (event->type) { case RZ_IL_EVENT_VAR_READ: { const RzILEventVarRead *var_read = &event->data.var_read; - RzRopRegInfo *reg_info = rz_core_rop_gadget_info_get_modified_register(gadget_info, var_read->variable); + RzGadgetRegInfo *reg_info = rz_core_gadget_info_get_modified_register(gadget_info, var_read->variable); if (reg_info && !is_dependency) { - RzRopRegInfo *new_reg_info = rz_core_rop_reg_info_dup(reg_info); + RzGadgetRegInfo *new_reg_info = rz_core_gadget_reg_info_dup(reg_info); if (!new_reg_info) { break; } @@ -729,8 +705,8 @@ static bool fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadg break; } new_reg_info->new_val = rz_bv_to_ut64(val); - rz_core_rop_gadget_info_update_register(gadget_info, new_reg_info); - rz_core_rop_reg_info_free(new_reg_info); + rz_core_gadget_info_update_register(gadget_info, new_reg_info); + rz_core_gadget_reg_info_free(new_reg_info); rz_pvector_push(vec, event); rz_bv_free(val); break; @@ -750,9 +726,9 @@ static bool fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadg break; } } - rz_rop_gadget_info_add_dependency(core, gadget_info, curr_event, reg_info); + gadget_info_add_dependency(core, gadget_info, curr_event, reg_info); if (is_stack_evt) { - rz_core_rop_reg_info_free(reg_info); + rz_core_gadget_reg_info_free(reg_info); } break; } @@ -787,9 +763,9 @@ static bool fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadg } while (!rz_pvector_empty(vec)) { RzILEvent *evt = rz_pvector_pop(vec); - fill_rop_gadget_info_from_events(core, gadget_info, event, evt, vec, true); + fill_gadget_info_from_events(core, gadget_info, event, evt, vec, true); } - RzRopRegInfo *reg_info = rz_core_rop_gadget_info_get_modified_register(gadget_info, var_write->variable); + RzGadgetRegInfo *reg_info = rz_core_gadget_info_get_modified_register(gadget_info, var_write->variable); if (!reg_info) { RzBitVector *old_val = rz_il_value_to_bv(var_write->old_value); RzBitVector *new_val = rz_il_value_to_bv(var_write->new_value); @@ -798,9 +774,9 @@ static bool fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadg rz_bv_free(new_val); break; } - reg_info = rz_core_rop_reg_info_new(core, event, rz_bv_to_ut64(old_val), + reg_info = rz_core_gadget_reg_info_new(core, event, rz_bv_to_ut64(old_val), rz_bv_to_ut64(new_val)); - rz_core_rop_gadget_info_add_register(gadget_info, reg_info, is_dependency); + rz_core_gadget_info_add_register(gadget_info, reg_info, is_dependency); rz_bv_free(old_val); rz_bv_free(new_val); } @@ -808,13 +784,13 @@ static bool fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadg case RZ_IL_EVENT_MEM_READ: { while (!rz_pvector_empty(vec)) { RzILEvent *evt = rz_pvector_pop(vec); - fill_rop_gadget_info_from_events(core, gadget_info, event, evt, vec, true); + fill_gadget_info_from_events(core, gadget_info, event, evt, vec, true); } } break; case RZ_IL_EVENT_MEM_WRITE: { while (!rz_pvector_empty(vec)) { RzILEvent *evt = rz_pvector_pop(vec); - fill_rop_gadget_info_from_events(core, gadget_info, event, evt, vec, true); + fill_gadget_info_from_events(core, gadget_info, event, evt, vec, true); } } break; case RZ_IL_EVENT_PC_WRITE: { @@ -830,7 +806,7 @@ static bool fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadg return true; } -static bool analyze_gadget(RzCore *core, const RzCoreAsmHit *hit, RzRopGadgetInfo *rop_gadget_info) { +static bool analyze_gadget(RzCore *core, const RzCoreAsmHit *hit, RzGadgetInfo *gadget_info) { rz_return_val_if_fail(core && core->analysis, false); int ret = true; @@ -857,7 +833,7 @@ static bool analyze_gadget(RzCore *core, const RzCoreAsmHit *hit, RzRopGadgetInf rz_pvector_init(&vec, (RzPVectorFree)rz_il_event_free); rz_pvector_foreach (vm->events, it) { RzILEvent *evt = *it; - if (!fill_rop_gadget_info_from_events(core, rop_gadget_info, NULL, evt, + if (!fill_gadget_info_from_events(core, gadget_info, NULL, evt, &vec, false)) { break; } @@ -869,7 +845,7 @@ cleanup: return ret; } -static void rz_rop_gadget_print_standard_mode(const RzCore *core, const RzRopGadgetInfo *gadget_info) { +static void gadget_print_standard_mode(const RzCore *core, const RzGadgetInfo *gadget_info) { rz_return_if_fail(core && core->analysis && gadget_info); RzReg *rreg = rz_analysis_get_reg(core->analysis); if (!rreg) { @@ -881,7 +857,7 @@ static void rz_rop_gadget_print_standard_mode(const RzCore *core, const RzRopGad rz_cons_printf("Changed registers: "); void **it; - RzRopRegInfo *reg_info; + RzGadgetRegInfo *reg_info; rz_pvector_foreach (gadget_info->modified_registers, it) { reg_info = *it; rz_cons_printf("%s ", reg_info->name); @@ -912,7 +888,7 @@ static void rz_rop_gadget_print_standard_mode(const RzCore *core, const RzRopGad rz_cons_printf("\n"); } -static void rz_rop_gadget_print_json_mode(const RzCore *core, const RzRopGadgetInfo *gadget_info, PJ *pj) { +static void gadget_print_json_mode(const RzCore *core, const RzGadgetInfo *gadget_info, PJ *pj) { rz_return_if_fail(gadget_info && pj); RzReg *rreg = rz_analysis_get_reg(core->analysis); @@ -926,7 +902,7 @@ static void rz_rop_gadget_print_json_mode(const RzCore *core, const RzRopGadgetI pj_k(pj, "modified_registers"); pj_a(pj); void **it; - RzRopRegInfo *reg_info; + RzGadgetRegInfo *reg_info; rz_pvector_foreach (gadget_info->modified_registers, it) { reg_info = *it; pj_o(pj); @@ -963,13 +939,13 @@ static void rz_rop_gadget_print_json_mode(const RzCore *core, const RzRopGadgetI pj_end(pj); } -static void print_modified_reg(const RzRopGadgetInfo *gadget_info) { +static void print_modified_reg(const RzGadgetInfo *gadget_info) { rz_cons_printf("Modified regs: "); if (gadget_info->modified_registers) { void **it; bool first = true; rz_pvector_foreach (gadget_info->modified_registers, it) { - RzRopRegInfo *reg_info = (RzRopRegInfo *)*it; + RzGadgetRegInfo *reg_info = (RzGadgetRegInfo *)*it; if (!reg_info || !reg_info->name) { continue; } @@ -982,11 +958,11 @@ static void print_modified_reg(const RzRopGadgetInfo *gadget_info) { } } -static void print_rop_dependencies(const RzRopGadgetInfo *gadget_info) { +static void print_gadget_dependencies(const RzGadgetInfo *gadget_info) { rz_cons_printf("Dependencies: "); if (gadget_info->dependencies) { RzListIter *iter; - RzRopRegInfo *dep_info; + RzGadgetRegInfo *dep_info; bool first = true; rz_list_foreach (gadget_info->dependencies, iter, dep_info) { if (!dep_info || !dep_info->name) { @@ -1001,7 +977,7 @@ static void print_rop_dependencies(const RzRopGadgetInfo *gadget_info) { } } -static void print_rop_long_info(const RzRopGadgetInfo *gadget_info, RzVector /**/ *lens, RzVector /**/ *add, RzPVector /**/ *asm_strs, RzPVector /**/ *hex_strs, int high_pad, bool utf8, bool colorize) { +static void print_gadget_long_info(const RzGadgetInfo *gadget_info, RzVector /**/ *lens, RzVector /**/ *add, RzPVector /**/ *asm_strs, RzPVector /**/ *hex_strs, int high_pad, bool utf8, bool colorize) { ut32 size = gadget_info->size; size_t instr_count = 0; int pad = 0; @@ -1030,7 +1006,7 @@ static void print_rop_long_info(const RzRopGadgetInfo *gadget_info, RzVector /*< print_modified_reg(gadget_info); rz_cons_newline(); } else if (instr_count == 2) { - print_rop_dependencies(gadget_info); + print_gadget_dependencies(gadget_info); rz_cons_newline(); } else { rz_cons_newline(); @@ -1040,7 +1016,7 @@ static void print_rop_long_info(const RzRopGadgetInfo *gadget_info, RzVector /*< } } -static void rz_rop_gadget_print_long_mode(const RzCore *core, const RzRopGadgetInfo *gadget_info, const RzRopSearchContext *context) { +static void gadget_print_long_mode(const RzCore *core, const RzGadgetInfo *gadget_info, const RzGadgetSearchContext *context) { rz_return_if_fail(core && core->analysis); ut64 addr = gadget_info->address; @@ -1096,7 +1072,7 @@ static void rz_rop_gadget_print_long_mode(const RzCore *core, const RzRopGadgetI free(hex); rz_analysis_op_fini(&aop); } - print_rop_long_info(gadget_info, lens, add, asm_strs, hex_strs, high_pad, utf8, colorize); + print_gadget_long_info(gadget_info, lens, add, asm_strs, hex_strs, high_pad, utf8, colorize); free(rep_str); rz_asm_op_fini(&asmop); rz_vector_free(lens); @@ -1107,12 +1083,12 @@ static void rz_rop_gadget_print_long_mode(const RzCore *core, const RzRopGadgetI rz_cons_newline(); } -static void print_rop_gadget_info(const RzCore *core, const RzRopGadgetInfo *gadget_info, const RzRopSearchContext *context) { +static void print_gadget_info(const RzCore *core, const RzGadgetInfo *gadget_info, const RzGadgetSearchContext *context) { rz_return_if_fail(gadget_info && context); if (!context->state) { return; } - if (RZ_STR_NE(context->greparg, "") && !(context->detail_mask | RZ_ROP_DETAIL_SEARCH_NON)) { + if (RZ_STR_NE(context->greparg, "") && !(context->detail_mask | RZ_GADGET_DETAIL_SEARCH_NON)) { const ut64 addr = rz_num_math(core->num, context->greparg); if (!addr || gadget_info->address != addr) { return; @@ -1121,13 +1097,13 @@ static void print_rop_gadget_info(const RzCore *core, const RzRopGadgetInfo *gad switch (context->state->mode) { case RZ_OUTPUT_MODE_JSON: - rz_rop_gadget_print_json_mode(core, gadget_info, context->state->d.pj); + gadget_print_json_mode(core, gadget_info, context->state->d.pj); break; case RZ_OUTPUT_MODE_STANDARD: - rz_rop_gadget_print_standard_mode(core, gadget_info); + gadget_print_standard_mode(core, gadget_info); break; case RZ_OUTPUT_MODE_LONG: - rz_rop_gadget_print_long_mode(core, gadget_info, context); + gadget_print_long_mode(core, gadget_info, context); break; default: rz_warn_if_reached(); @@ -1135,14 +1111,14 @@ static void print_rop_gadget_info(const RzCore *core, const RzRopGadgetInfo *gad } } -static bool print_rop(const RzCore *core, RzList /**/ *hitlist, RzRopSearchContext *context) { +static bool print_gadget_hitlist(const RzCore *core, RzPVector /**/ *hitlist, size_t start_idx, RzGadgetSearchContext *context) { rz_return_val_if_fail(core && hitlist && context, false); RzCmdStateOutput *state = context->state; if (!state) { return false; } rz_cmd_state_output_set_columnsf(state, "XXs", "addr", "bytes", "disasm"); - RzCoreAsmHit *hit = (RzCoreAsmHit *)rz_list_first_val(hitlist); + RzCoreAsmHit *hit = (RzCoreAsmHit *)rz_pvector_at(hitlist, start_idx); if (!hit) { return false; } @@ -1160,32 +1136,34 @@ static bool print_rop(const RzCore *core, RzList /**/ *hitlist, bool result = 0; hit = NULL; - RzListIter *iter; ut32 size = 0; char *asmop_str = NULL, *asmop_hex_str = NULL; - rz_list_foreach (hitlist, iter, hit) { - switch (state->mode) { - case RZ_OUTPUT_MODE_JSON: - if (!state->d.pj) { + if (!rz_pvector_empty(hitlist)) { + for (size_t i = start_idx; i < rz_pvector_len(hitlist); i++) { + hit = rz_pvector_at(hitlist, i); + switch (state->mode) { + case RZ_OUTPUT_MODE_JSON: + if (!state->d.pj) { + break; + } + result = gadget_hitlist_print_json_mode(core, hit, &size, state->d.pj); + break; + case RZ_OUTPUT_MODE_QUIET: + result = gadget_hitlist_print_quiet_mode(core, hit, &size, context); + break; + case RZ_OUTPUT_MODE_STANDARD: + result = gadget_hitlist_print_standard_mode(core, hit, &size, context); + break; + case RZ_OUTPUT_MODE_TABLE: + result = gadget_hitlist_print_table_mode(core, hit, hitlist, &size, &asmop_str, &asmop_hex_str, context); + break; + default: + rz_warn_if_reached(); break; } - result = rz_rop_print_json_mode(core, hit, &size, state->d.pj); - break; - case RZ_OUTPUT_MODE_QUIET: - result = rz_rop_print_quiet_mode(core, hit, &size, context); - break; - case RZ_OUTPUT_MODE_STANDARD: - result = rz_rop_print_standard_mode(core, hit, &size, context); - break; - case RZ_OUTPUT_MODE_TABLE: - result = rz_rop_print_table_mode(core, hit, hitlist, &size, &asmop_str, &asmop_hex_str, context); - break; - default: - rz_warn_if_reached(); - break; - } - if (!result) { - return result; + if (!result) { + return result; + } } } switch (state->mode) { @@ -1232,11 +1210,11 @@ static bool print_rop(const RzCore *core, RzList /**/ *hitlist, return true; } -static bool handle_rop_list(RzStrBuf *sb, const RzRopSearchContext *context, - const RzRopEndListPair *end_gadget, RZ_OWN RzList /**/ *hitlist) { +static bool handle_gadget_list(RzStrBuf *sb, const RzGadgetSearchContext *context, + const RzGadgetEndListPair *end_gadget, RZ_OWN RzPVector /**/ *hitlist) { rz_return_val_if_fail(sb && context && context->unique_hitlists, false); - if (end_gadget->delay_size && rz_list_length(hitlist) < 1 + end_gadget->delay_size) { - rz_list_free(hitlist); + if (end_gadget->delay_size && rz_pvector_len(hitlist) < 1 + end_gadget->delay_size) { + rz_pvector_free(hitlist); return false; } @@ -1249,13 +1227,13 @@ static bool handle_rop_list(RzStrBuf *sb, const RzRopSearchContext *context, if (!is_found && asm_op_hex) { ht_su_insert(context->unique_hitlists, asm_op_hex, 1); } else { - rz_list_free(hitlist); + rz_pvector_free(hitlist); return false; } return true; } -static void init_grep_context(const RzRopSearchContext *context, char **grep_str, +static void init_grep_context(const RzGadgetSearchContext *context, char **grep_str, const char **start, const char **end, const RzList /**/ *rx_list, char **rx, int *count) { if (context->greparg) { *start = context->greparg; @@ -1271,7 +1249,7 @@ static void init_grep_context(const RzRopSearchContext *context, char **grep_str } } -static bool process_instruction(const RzCore *core, RzAnalysisOp *aop, const int addr, const ut8 *buf, const int buf_len, ut32 *end_gadget_cnt) { +static bool process_instruction(const RzGadgetType type, const RzCore *core, RzAnalysisOp *aop, const int addr, const ut8 *buf, const int buf_len, ut32 *end_gadget_cnt) { const int error = rz_analysis_op(core->analysis, aop, addr, buf, buf_len, RZ_ANALYSIS_OP_MASK_DISASM | RZ_ANALYSIS_OP_MASK_IL); if (!aop) { return false; @@ -1279,7 +1257,7 @@ static bool process_instruction(const RzCore *core, RzAnalysisOp *aop, const int if (error < 0 || (aop->type == RZ_ANALYSIS_OP_TYPE_NOP && aop->size == 0)) { return false; } - if (is_end_gadget(aop, 0)) { + if (gadget_is_valid_end_gadget(type, aop, 0)) { (*end_gadget_cnt)++; } return true; @@ -1292,7 +1270,7 @@ static bool is_invalid_instruction(const char *opst, const int end_gadget_cnt) { end_gadget_cnt > 1; } -static void update_search_context(const RzRopSearchContext *context, const char **start, const char **end, +static void update_search_context(const RzGadgetSearchContext *context, const char **start, const char **end, char **grep_str, const RzList /**/ *rx_list, char **rx, int *count) { if (*end && (*end)[0] == ';') { // fields are semicolon-separated *start = *end + 1; // skip the ; @@ -1314,18 +1292,18 @@ static void update_search_context(const RzRopSearchContext *context, const char } } -static RzList /**/ *construct_rop_gadget(RzCore *core, ut8 *buf, int idx, RzRopSearchContext *context, - RzList /**/ *rx_list, RzRopEndListPair *end_gadget) { +static RzPVector /**/ *construct_gadget(RzCore *core, ut8 *buf, int idx, RzGadgetSearchContext *context, + RzList /**/ *rx_list, RzGadgetEndListPair *end_gadget) { const char *start = NULL, *end = NULL; int count = 0; char *rx = NULL; char *grep_str = NULL; - bool is_greparg = !(context->mask & (RZ_ROP_GADGET_PRINT_DETAIL | RZ_ROP_GADGET_ANALYZE)) && !(context->detail_mask | RZ_ROP_DETAIL_SEARCH_NON) && context->greparg; + bool is_greparg = !(context->mask & (RZ_GADGET_PRINT_DETAIL | RZ_GADGET_ANALYZE)) && !(context->detail_mask | RZ_GADGET_DETAIL_SEARCH_NON) && context->greparg; if (is_greparg) { init_grep_context(context, &grep_str, &start, &end, rx_list, &rx, &count); } - RzList *hitlist = rz_core_asm_hit_list_new(); + RzPVector *hitlist = rz_pvector_new((RzPVectorFree)rz_core_asm_hit_free); if (!hitlist) { free(grep_str); return NULL; @@ -1341,7 +1319,7 @@ static RzList /**/ *construct_rop_gadget(RzCore *core, ut8 *buf, RzStrBuf *sb = rz_strbuf_new(""); while (nb_instr < context->max_instr) { rz_analysis_op_init(&aop); - if (idx >= delta || !process_instruction(core, &aop, addr, buf + idx, delta - idx, &end_gadget_cnt)) { + if (idx >= delta || !process_instruction(context->type, core, &aop, addr, buf + idx, delta - idx, &end_gadget_cnt)) { valid = false; goto cleanup; } @@ -1370,7 +1348,7 @@ static RzList /**/ *construct_rop_gadget(RzCore *core, ut8 *buf, char *asm_op_hex = rz_asm_op_get_hex(&asmop); rz_strbuf_append(sb, asm_op_hex); free(asm_op_hex); - rz_list_append(hitlist, hit); + rz_pvector_push(hitlist, hit); if (ret >= 0) { rz_asm_op_fini(&asmop); } @@ -1400,11 +1378,11 @@ cleanup: rz_analysis_op_fini(&aop); free(grep_str); if ((context->regexp && rx) || (!valid || (is_greparg && end))) { - rz_list_free(hitlist); + rz_pvector_free(hitlist); rz_strbuf_free(sb); return NULL; } - if (!handle_rop_list(sb, context, end_gadget, hitlist)) { + if (!handle_gadget_list(sb, context, end_gadget, hitlist)) { rz_strbuf_free(sb); return NULL; } @@ -1412,82 +1390,84 @@ cleanup: return hitlist; } -static RzRopGadgetInfo *perform_gadget_analysis(RzCore *core, const ut8 crop, const RzList /**/ *hitlist) { +static RzGadgetInfo *perform_gadget_analysis(const RzGadgetType type, RzCore *core, const bool allow_conditional, const RzPVector /**/ *hitlist) { rz_return_val_if_fail(core && core->analysis && hitlist, NULL); - RzRopGadgetInfo *rop_gadget_info = NULL; + RzGadgetInfo *gadget_info = NULL; - HtUP *ht_rop_semantics = rz_analysis_get_rop_semantics(core->analysis); - if (!ht_rop_semantics) { - ht_rop_semantics = ht_up_new(NULL, (HtUPFreeValue)rz_core_rop_gadget_info_free); - rz_analysis_set_rop_semantics(core->analysis, ht_rop_semantics); + HtUP *ht_gadget_semantics = rz_analysis_get_gadget_semantics(core->analysis); + if (!ht_gadget_semantics) { + ht_gadget_semantics = ht_up_new(NULL, (HtUPFreeValue)rz_core_gadget_info_free); + rz_analysis_set_gadget_semantics(core->analysis, ht_gadget_semantics); } - const RzCoreAsmHit *hit_last = (RzCoreAsmHit *)rz_list_last_val(hitlist); - if (!is_ret_gadget(core, hit_last, crop)) { - return rop_gadget_info; + const RzCoreAsmHit *hit_last = (RzCoreAsmHit *)rz_pvector_at(hitlist, rz_pvector_len(hitlist) - 1); + if (!gadget_is_valid_terminator(type, core, hit_last, allow_conditional)) { + return gadget_info; } - const ut64 addr_start = ((RzCoreAsmHit *)rz_list_first_val(hitlist))->addr; - rop_gadget_info = ht_up_find(ht_rop_semantics, addr_start, NULL); - if (rop_gadget_info) { - return rop_gadget_info; + const ut64 addr_start = ((RzCoreAsmHit *)rz_pvector_at(hitlist, 0))->addr; + gadget_info = ht_up_find(ht_gadget_semantics, addr_start, NULL); + if (gadget_info) { + return gadget_info; } - RzListIter *iter; + void **iter; RzCoreAsmHit *hit; - rop_gadget_info = rz_core_rop_gadget_info_new(addr_start); - if (!rop_gadget_info) { + gadget_info = rz_core_gadget_info_new(addr_start); + if (!gadget_info) { return NULL; } - ut32 rop_gadget_size = 0; - rz_list_foreach (hitlist, iter, hit) { - if (!analyze_gadget(core, hit, rop_gadget_info)) { + ut32 gadget_size = 0; + rz_pvector_foreach (hitlist, iter) { + hit = *iter; + if (!analyze_gadget(core, hit, gadget_info)) { RZ_LOG_WARN("Failed to analyze gadget at 0x%" PFMT64x "\n", hit->addr); } - rop_gadget_size += hit->len; + gadget_size += hit->len; } - rop_gadget_info->size = rop_gadget_size; - ht_up_insert(ht_rop_semantics, addr_start, rop_gadget_info); - return rop_gadget_info; + gadget_info->size = gadget_size; + ht_up_insert(ht_gadget_semantics, addr_start, gadget_info); + return gadget_info; } /** - * \brief Perform ROP operations based on the given \p context and \p hitlist. + * \brief Perform Gadget operations based on the given \p context and \p hitlist. * \param core Pointer to the RzCore structure. - * \param context Pointer to the RzRopSearchContext structure. - * \param hitlist Pointer to the RzList structure containing the ROP gadgets. + * \param context Pointer to the RzGadgetSearchContext structure. + * \param hitlist Pointer to the RzList structure containing the gadgets. * \return true if the operation was successful, false otherwise. * - * This function performs ROP operations based on the given \p context and \p hitlist. + * This function performs Gadget operations based on the given \p context and \p hitlist. */ -RZ_API bool rz_core_handle_rop_request_type(RZ_NONNULL RzCore *core, RZ_NONNULL RzRopSearchContext *context, - RZ_NONNULL RzList /**/ *hitlist) { +RZ_API bool rz_core_handle_gadget_request_type(RZ_NONNULL RzCore *core, RZ_NONNULL RzGadgetSearchContext *context, + RZ_NONNULL RzPVector /**/ *hitlist) { rz_return_val_if_fail(core && core->analysis && hitlist && context, false); - if (context->mask & RZ_ROP_GADGET_PRINT) { - if (context->subchain) { - do { - if (!print_rop(core, hitlist, context)) { + if (context->mask & RZ_GADGET_PRINT) { + if (context->subchains) { + const size_t len = rz_pvector_len(hitlist); + const size_t limit = (len > 1) ? (len - 1) : 1; + for (size_t i = 0; i < limit; i++) { + if (!print_gadget_hitlist(core, hitlist, i, context)) { return false; } - hitlist->head = hitlist->head->next; - } while (hitlist->head->next); + } } else { - if (!print_rop(core, hitlist, context)) { + if (!print_gadget_hitlist(core, hitlist, 0, context)) { return false; } } } - RzRopGadgetInfo *rop_gadget_info = NULL; + RzGadgetInfo *gadget_info = NULL; bool is_analysis = false; - if (context->mask & RZ_ROP_GADGET_ANALYZE) { - rop_gadget_info = perform_gadget_analysis(core, context->crop, hitlist); + if (context->mask & RZ_GADGET_ANALYZE) { + gadget_info = perform_gadget_analysis(context->type, core, context->allow_conditional, hitlist); is_analysis = true; } - if (context->mask & RZ_ROP_GADGET_PRINT_DETAIL) { - if (!rop_gadget_info && is_analysis) { + if (context->mask & RZ_GADGET_PRINT_DETAIL) { + if (!gadget_info && is_analysis) { return false; } - print_rop_gadget_info(core, rop_gadget_info, context); + print_gadget_info(core, gadget_info, context); } return true; } @@ -1516,8 +1496,8 @@ static bool fetch_search_itv(const RzCore *core, RzInterval *search_itv) { return true; } -static RzList /**/ *compute_end_gadget_list(const RzCore *core, const ut8 *buf, const RzRopSearchContext *context) { - RzList /**/ *end_list = rz_list_newf(free); +static RzList /**/ *compute_end_gadget_list(const RzCore *core, const ut8 *buf, const RzGadgetSearchContext *context) { + RzList /**/ *end_list = rz_list_newf(free); const int delta = context->to - context->from; for (int i = 0; i < delta; i += context->increment) { @@ -1530,8 +1510,8 @@ static RzList /**/ *compute_end_gadget_list(const RzCore *co continue; } - if (is_end_gadget(&end_gadget, context->crop)) { - RzRopEndListPair *epair = RZ_NEW0(RzRopEndListPair); + if (gadget_is_valid_end_gadget(context->type, &end_gadget, context->allow_conditional)) { + RzGadgetEndListPair *epair = RZ_NEW0(RzGadgetEndListPair); if (epair) { epair->instr_offset = i + (end_gadget.delay ? context->increment : 0); epair->delay_size = end_gadget.delay; @@ -1566,7 +1546,7 @@ static void set_increment_based_on_arch(const RzCore *core, const char *arch, in * * This function processes the provided grep argument string and returns a list of tokens. */ -RZ_API RZ_NULLABLE RZ_OWN RzList /**/ *rz_core_rop_handle_grep_args(RZ_NULLABLE const char *greparg, const bool regexp) { +RZ_API RZ_NULLABLE RZ_OWN RzList /**/ *rz_core_gadget_handle_grep_args(RZ_NULLABLE const char *greparg, const bool regexp) { if (!greparg || !regexp) { return NULL; } @@ -1600,10 +1580,10 @@ RZ_API RZ_NULLABLE RZ_OWN RzList /**/ *rz_core_rop_handle_grep_args(RZ_N return rx_list; } -static bool parse_detail_search_arg(RzCore *core, const char *str, RopDetailSearchCmpOp *op, st64 *value) { +static bool parse_detail_search_arg(RzCore *core, const char *str, RzGadgetDetailSearchCmpOp *op, st64 *value) { if (RZ_STR_ISEMPTY(str)) { - *op = ROP_DETAIL_CMP_EQ; + *op = RZ_GADGET_DETAIL_CMP_EQ; *value = 0; return true; } @@ -1615,31 +1595,31 @@ static bool parse_detail_search_arg(RzCore *core, const char *str, RopDetailSear } if (*p == '\0') { - *op = ROP_DETAIL_CMP_EQ; + *op = RZ_GADGET_DETAIL_CMP_EQ; *value = 0; return true; } if (rz_str_startswith(p, ">=")) { - *op = ROP_DETAIL_CMP_GE; + *op = RZ_GADGET_DETAIL_CMP_GE; p += 2; } else if (rz_str_startswith(p, "<=")) { - *op = ROP_DETAIL_CMP_LE; + *op = RZ_GADGET_DETAIL_CMP_LE; p += 2; } else if (rz_str_startswith(p, "==")) { - *op = ROP_DETAIL_CMP_EQ; + *op = RZ_GADGET_DETAIL_CMP_EQ; p += 2; } else if (p[0] == '>') { - *op = ROP_DETAIL_CMP_GT; + *op = RZ_GADGET_DETAIL_CMP_GT; p++; } else if (p[0] == '<') { - *op = ROP_DETAIL_CMP_LT; + *op = RZ_GADGET_DETAIL_CMP_LT; p++; } else if (p[0] == '=') { - *op = ROP_DETAIL_CMP_EQ; + *op = RZ_GADGET_DETAIL_CMP_EQ; p++; } else { - *op = ROP_DETAIL_CMP_EQ; + *op = RZ_GADGET_DETAIL_CMP_EQ; } // skip possible spaces between operator and number @@ -1656,23 +1636,23 @@ static bool parse_detail_search_arg(RzCore *core, const char *str, RopDetailSear return true; } -static bool match_detail_search(st64 gadget_val, RopDetailSearchCmpOp op, st64 target) { +static bool match_detail_search(st64 gadget_val, RzGadgetDetailSearchCmpOp op, st64 target) { switch (op) { - case ROP_DETAIL_CMP_EQ: + case RZ_GADGET_DETAIL_CMP_EQ: return gadget_val == target; - case ROP_DETAIL_CMP_GT: + case RZ_GADGET_DETAIL_CMP_GT: return gadget_val > target; - case ROP_DETAIL_CMP_GE: + case RZ_GADGET_DETAIL_CMP_GE: return gadget_val >= target; - case ROP_DETAIL_CMP_LT: + case RZ_GADGET_DETAIL_CMP_LT: return gadget_val < target; - case ROP_DETAIL_CMP_LE: + case RZ_GADGET_DETAIL_CMP_LE: return gadget_val <= target; } return false; } -static bool match_rop_constraint(const RzRopGadgetInfo *gadget_info, const RzRopConstraint *constraint) { +static bool match_gadget_constraint(const RzGadgetInfo *gadget_info, const RzGadgetConstraint *constraint) { if (!gadget_info || !constraint) { return false; } @@ -1682,7 +1662,7 @@ static bool match_rop_constraint(const RzRopGadgetInfo *gadget_info, const RzRop return false; } - RzRopRegInfo *reg_info = rz_core_rop_gadget_info_get_modified_register(gadget_info, dst_reg); + RzGadgetRegInfo *reg_info = rz_core_gadget_info_get_modified_register(gadget_info, dst_reg); if (!reg_info) { return false; } @@ -1701,7 +1681,7 @@ static bool match_rop_constraint(const RzRopGadgetInfo *gadget_info, const RzRop if (!src_reg) { return false; } - return rz_core_rop_gadget_reg_info_has_event(gadget_info, RZ_ROP_EVENT_VAR_READ, src_reg); + return rz_core_gadget_reg_info_has_event(gadget_info, RZ_GADGET_EVENT_VAR_READ, src_reg); } case MOV_OP_CONST: { const char *src_reg = constraint->args[SRC_REG]; @@ -1709,7 +1689,7 @@ static bool match_rop_constraint(const RzRopGadgetInfo *gadget_info, const RzRop if (!src_reg || !src_const) { return false; } - return rz_core_rop_gadget_reg_info_has_event(gadget_info, RZ_ROP_EVENT_VAR_READ, src_reg); + return rz_core_gadget_reg_info_has_event(gadget_info, RZ_GADGET_EVENT_VAR_READ, src_reg); } case MOV_OP_REG: { const char *src_reg = constraint->args[SRC_REG]; @@ -1717,31 +1697,31 @@ static bool match_rop_constraint(const RzRopGadgetInfo *gadget_info, const RzRop if (!src_reg || !src_reg_second) { return false; } - return rz_core_rop_gadget_reg_info_has_event(gadget_info, RZ_ROP_EVENT_VAR_READ, src_reg) && - rz_core_rop_gadget_reg_info_has_event(gadget_info, RZ_ROP_EVENT_VAR_READ, src_reg_second); + return rz_core_gadget_reg_info_has_event(gadget_info, RZ_GADGET_EVENT_VAR_READ, src_reg) && + rz_core_gadget_reg_info_has_event(gadget_info, RZ_GADGET_EVENT_VAR_READ, src_reg_second); } default: return false; } } -static bool match_constraints(const RzRopGadgetInfo *gadget_info, const RzPVector /**/ *constraints) { +static bool match_constraints(const RzGadgetInfo *gadget_info, const RzPVector /**/ *constraints) { if (!constraints || rz_pvector_empty(constraints)) { return true; } void **it; rz_pvector_foreach (constraints, it) { - RzRopConstraint *constraint = *it; - if (!match_rop_constraint(gadget_info, constraint)) { + RzGadgetConstraint *constraint = *it; + if (!match_gadget_constraint(gadget_info, constraint)) { return false; } } return true; } -static bool process_disassembly(RzCore *core, ut8 *buf, const int idx, RzRopSearchContext *context, - RzList /**/ *rx_list, RzRopEndListPair *end_gadget) { +static bool process_disassembly(RzCore *core, ut8 *buf, const int idx, RzGadgetSearchContext *context, + RzList /**/ *rx_list, RzGadgetEndListPair *end_gadget) { RzAsmOp *asmop = rz_asm_op_new(); bool status = false; const int ret = rz_asm_disassemble(core->rasm, asmop, buf + idx, context->to - context->from - idx); @@ -1750,48 +1730,48 @@ static bool process_disassembly(RzCore *core, ut8 *buf, const int idx, RzRopSear } rz_asm_set_pc(core->rasm, context->from + idx); - RzList *hitlist = construct_rop_gadget(core, buf, idx, context, rx_list, end_gadget); + RzPVector *hitlist = construct_gadget(core, buf, idx, context, rx_list, end_gadget); if (!hitlist) { goto fini; } if (context->constraints && !rz_pvector_empty(context->constraints)) { - RzRopGadgetInfo *rop_gadget_info = perform_gadget_analysis(core, context->crop, hitlist); - if (!rop_gadget_info || !match_constraints(rop_gadget_info, context->constraints)) { - rz_list_free(hitlist); + RzGadgetInfo *gadget_info = perform_gadget_analysis(context->type, core, context->allow_conditional, hitlist); + if (!gadget_info || !match_constraints(gadget_info, context->constraints)) { + rz_pvector_free(hitlist); goto fini; } } if (context->detail_mask) { - RzRopGadgetInfo *rop_gadget_info = perform_gadget_analysis(core, context->crop, hitlist); - if (!rop_gadget_info) { + RzGadgetInfo *gadget_info = perform_gadget_analysis(context->type, core, context->allow_conditional, hitlist); + if (!gadget_info) { goto fini; } - if (context->detail_mask & (RZ_ROP_DETAIL_SEARCH_STACK | RZ_ROP_DETAIL_SEARCH_SIZE)) { - RopDetailSearchCmpOp cmp_op; + if (context->detail_mask & (RZ_GADGET_DETAIL_SEARCH_STACK | RZ_GADGET_DETAIL_SEARCH_SIZE)) { + RzGadgetDetailSearchCmpOp cmp_op; st64 target; - // RZ_ROP_DETAIL_SEARCH_STACK -> stack_change, RZ_ROP_DETAIL_SEARCH_SIZE -> size - ut64 gadget_info = context->detail_mask & RZ_ROP_DETAIL_SEARCH_STACK ? rop_gadget_info->stack_change : rop_gadget_info->size; + // RZ_GADGET_DETAIL_SEARCH_STACK -> stack_change, RZ_GADGET_DETAIL_SEARCH_SIZE -> size + ut64 search_val = context->detail_mask & RZ_GADGET_DETAIL_SEARCH_STACK ? gadget_info->stack_change : gadget_info->size; if (!parse_detail_search_arg(core, context->greparg, &cmp_op, &target)) { goto fini; } - if (!match_detail_search(gadget_info, cmp_op, target)) { + if (!match_detail_search(search_val, cmp_op, target)) { goto fini; } } } if (core->search->align && (context->from + idx) % core->search->align != 0) { - rz_list_free(hitlist); + rz_pvector_free(hitlist); goto fini; } - if (!rz_core_handle_rop_request_type(core, context, hitlist)) { - rz_list_free(hitlist); + if (!rz_core_handle_gadget_request_type(core, context, hitlist)) { + rz_pvector_free(hitlist); goto fini; } - rz_list_free(hitlist); + rz_pvector_free(hitlist); if (context->max_count > 0) { context->max_count--; @@ -1805,7 +1785,7 @@ fini: return status; } -static bool update_end_gadget(int *i, const int ropdepth, RzRopEndListPair **end_gadget, const RzRopSearchContext *context) { +static bool update_end_gadget(int *i, const int gadget_depth, RzGadgetEndListPair **end_gadget, const RzGadgetSearchContext *context) { rz_return_val_if_fail(end_gadget && context, false); if (*i > (*end_gadget)->instr_offset) { // We've exhausted the first end-gadget section, @@ -1813,8 +1793,8 @@ static bool update_end_gadget(int *i, const int ropdepth, RzRopEndListPair **end free(*end_gadget); if (rz_list_get_n(context->end_list, 0)) { - *end_gadget = (RzRopEndListPair *)rz_list_pop(context->end_list); - *i = (*end_gadget)->instr_offset - ropdepth; + *end_gadget = (RzGadgetEndListPair *)rz_list_pop(context->end_list); + *i = (*end_gadget)->instr_offset - gadget_depth; if (*i < 0) { *i = 0; } @@ -1826,7 +1806,7 @@ static bool update_end_gadget(int *i, const int ropdepth, RzRopEndListPair **end return true; } -static int handle_rop_search_address(RzCore *core, RzRopSearchContext *context, RzList /**/ *rx_list) { +static int handle_gadget_search_address(RzCore *core, RzGadgetSearchContext *context, RzList /**/ *rx_list) { const ut64 delta = context->to - context->from; ut8 *buf = RZ_NEWS0(ut8, delta); if (!buf) { @@ -1846,14 +1826,14 @@ static int handle_rop_search_address(RzCore *core, RzRopSearchContext *context, } rz_list_reverse(context->end_list); const int max_inst_size_x86 = 15; - // Get the depth of rop search, should just be max_instr + // Get the depth of gadget search window, should just be max_instr // instructions, x86 and friends are weird length instructions, so // we'll just assume 15 byte instructions. - const int ropdepth = context->increment == 1 ? context->max_instr * max_inst_size_x86 /* wow, x86 is long */ : context->max_instr * context->increment; + const int gadget_depth = context->increment == 1 ? context->max_instr * max_inst_size_x86 /* wow, x86 is long */ : context->max_instr * context->increment; if (rz_cons_is_breaked()) { return -2; } - RzRopEndListPair *end_gadget = rz_list_pop(context->end_list); + RzGadgetEndListPair *end_gadget = rz_list_pop(context->end_list); // Start at just before the first end gadget. const int next = end_gadget->instr_offset; for (int i = 0; i < delta && context->max_count; i += context->increment) { @@ -1867,7 +1847,7 @@ static int handle_rop_search_address(RzCore *core, RzRopSearchContext *context, if (rz_cons_is_breaked()) { break; } - if (i > next && !update_end_gadget(&i, ropdepth, &end_gadget, context)) { + if (i > next && !update_end_gadget(&i, gadget_depth, &end_gadget, context)) { break; } if (process_disassembly(core, buf, i, context, rx_list, end_gadget)) { @@ -1881,17 +1861,17 @@ static int handle_rop_search_address(RzCore *core, RzRopSearchContext *context, } /** - * \brief Search for ROP gadgets. + * \brief Search for gadgets. * \param core Pointer to the RzCore object. - * \param context Pointer to the RzRopSearchContext object. + * \param context Pointer to the RzGadgetSearchContext object. * \return true if the search is successful, false otherwise. * - * Searches for ROP gadgets within the address range specified by configuration. - * Disassembles instructions, identifies end gadgets, constructs ROP gadgets, and + * Searches for gadgets within the address range specified by configuration. + * Disassembles instructions, identifies end gadgets, constructs gadgets, and * filters results based on the grep argument and request mask. Outputs results to * the provided state object. */ -RZ_API RzCmdStatus rz_core_rop_search(RZ_NONNULL RzCore *core, RZ_NONNULL RzRopSearchContext *context) { +RZ_API RzCmdStatus rz_core_gadget_search(RZ_NONNULL RzCore *core, RZ_NONNULL RzGadgetSearchContext *context) { rz_return_val_if_fail(core && core->search && context, RZ_CMD_STATUS_ERROR); RzInterval search_itv = { 0 }; @@ -1900,9 +1880,9 @@ RZ_API RzCmdStatus rz_core_rop_search(RZ_NONNULL RzCore *core, RZ_NONNULL RzRopS } if (context->max_instr <= 1) { - RZ_LOG_ERROR("core: ROP length (rop.len) must be greater than 1.\n"); + RZ_LOG_ERROR("core: Gadget length (gadget.len) must be greater than 1.\n"); if (context->max_instr == 1) { - RZ_LOG_ERROR("core: For rop.len = 1, use /c to search for single " + RZ_LOG_ERROR("core: For gadget.len = 1, use /c to search for single " "instructions. See /c? for help.\n"); } return RZ_CMD_STATUS_ERROR; @@ -1919,11 +1899,11 @@ RZ_API RzCmdStatus rz_core_rop_search(RZ_NONNULL RzCore *core, RZ_NONNULL RzRopS if (context->ret_val) { context->buf = rz_strbuf_new(NULL); } - RzList /**/ *rx_list = rz_core_rop_handle_grep_args(context->greparg, context->regexp); + RzList /**/ *rx_list = rz_core_gadget_handle_grep_args(context->greparg, context->regexp); int status = 0; - // If we need to know where to look, perform rop operations here. + // If specific address range is provided, scan that range for gadgets. if (context->to || context->from) { - status = handle_rop_search_address(core, context, rx_list); + status = handle_gadget_search_address(core, context, rx_list); goto cleanup; } @@ -1944,7 +1924,7 @@ RZ_API RzCmdStatus rz_core_rop_search(RZ_NONNULL RzCore *core, RZ_NONNULL RzRopS if (rz_cons_is_breaked()) { break; } - status = handle_rop_search_address(core, context, rx_list); + status = handle_gadget_search_address(core, context, rx_list); if (status == -2) { break; } @@ -1969,31 +1949,31 @@ cleanup: } /** - * \brief Display ROP gadget information. + * \brief Display gadget information. * \param core Pointer to the RzCore object. - * \param context Pointer to the RzRopSearchContext object. + * \param context Pointer to the RzGadgetSearchContext object. * \return RZ_CMD_STATUS_OK on success. * - * Displays ROP gadgets from the gadgetSdb. - * If unavailable, performs a ROP search with the input. + * Displays gadgets from the gadgetSdb. + * If unavailable, performs a gadget search with the input. */ -RZ_API RzCmdStatus rz_core_rop_gadget_info(RZ_NONNULL RzCore *core, RZ_NONNULL RZ_OWN RzRopSearchContext *context) { +RZ_API RzCmdStatus rz_core_gadget_info(RZ_NONNULL RzCore *core, RZ_NONNULL RZ_OWN RzGadgetSearchContext *context) { rz_return_val_if_fail(core && core->analysis && context, RZ_CMD_STATUS_ERROR); // TODO: resolve this logic later. - RzCmdStatus status = rz_core_rop_search(core, context); - rz_core_rop_search_context_free(context); + RzCmdStatus status = rz_core_gadget_search(core, context); + rz_core_gadget_search_context_free(context); return status; } /** - * \brief Free an RzRopConstraint object. - * \param data Pointer to the RzRopConstraint object to free. + * \brief Free an RzGadgetConstraint object. + * \param data Pointer to the RzGadgetConstraint object to free. * - * Frees the memory allocated for an RzRopConstraint object. + * Frees the memory allocated for an RzGadgetConstraint object. */ -RZ_API void rz_core_rop_constraint_free(RZ_NULLABLE void *data) { - RzRopConstraint *constraint = data; +RZ_API void rz_core_gadget_constraint_free(RZ_NULLABLE void *data) { + RzGadgetConstraint *constraint = data; if (!constraint) { return; } diff --git a/librz/core/gadget_internal.h b/librz/core/gadget_internal.h new file mode 100644 index 0000000000..2b66507565 --- /dev/null +++ b/librz/core/gadget_internal.h @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2026 MrQuantum1915 +// SPDX-License-Identifier: LGPL-3.0-only + +#ifndef RZ_GADGET_INTERNAL_H +#define RZ_GADGET_INTERNAL_H + +#include + +// ROP (Return-Oriented Programming) +RZ_IPI bool rz_gadget_rop_is_end_gadget(const RzAnalysisOp *aop, const bool allow_conditional); +RZ_IPI bool rz_gadget_rop_is_valid_terminator(const RzAnalysisOp *aop, const bool allow_conditional); + +#endif diff --git a/librz/core/gadget_rop.c b/librz/core/gadget_rop.c new file mode 100644 index 0000000000..f865ef3900 --- /dev/null +++ b/librz/core/gadget_rop.c @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2026 MrQuantum1915 +// SPDX-License-Identifier: LGPL-3.0-only + +#include "gadget_internal.h" + +static bool is_cond_end_gadget(const RzAnalysisOp *aop) { + switch (aop->type) { + case RZ_ANALYSIS_OP_TYPE_CJMP: + case RZ_ANALYSIS_OP_TYPE_UCJMP: + case RZ_ANALYSIS_OP_TYPE_CCALL: + case RZ_ANALYSIS_OP_TYPE_UCCALL: + case RZ_ANALYSIS_OP_TYPE_CRET: + return true; + default: + return false; + } +} + +RZ_IPI bool rz_gadget_rop_is_end_gadget(const RzAnalysisOp *aop, const bool allow_conditional) { + switch (aop->type) { + case RZ_ANALYSIS_OP_TYPE_TRAP: + case RZ_ANALYSIS_OP_TYPE_RET: + case RZ_ANALYSIS_OP_TYPE_UCALL: + case RZ_ANALYSIS_OP_TYPE_RCALL: + case RZ_ANALYSIS_OP_TYPE_ICALL: + case RZ_ANALYSIS_OP_TYPE_IRCALL: + case RZ_ANALYSIS_OP_TYPE_UJMP: + case RZ_ANALYSIS_OP_TYPE_RJMP: + case RZ_ANALYSIS_OP_TYPE_IJMP: + case RZ_ANALYSIS_OP_TYPE_IRJMP: + case RZ_ANALYSIS_OP_TYPE_JMP: + case RZ_ANALYSIS_OP_TYPE_CALL: + if (allow_conditional) { + return is_cond_end_gadget(aop); + } + return true; + default: + return false; + } +} + +RZ_IPI bool rz_gadget_rop_is_valid_terminator(const RzAnalysisOp *aop, const bool allow_conditional) { + switch (aop->type) { + case RZ_ANALYSIS_OP_TYPE_RET: + if (allow_conditional) { + return is_cond_end_gadget(aop); + } + return true; + default: + return false; + } +} diff --git a/librz/core/meson.build b/librz/core/meson.build index 6116fd25b1..4f0deed14a 100644 --- a/librz/core/meson.build +++ b/librz/core/meson.build @@ -63,7 +63,8 @@ rz_core_sources = [ 'libs.c', 'project.c', 'project_migrate.c', - 'rop.c', + 'gadget.c', + 'gadget_rop.c', 'rtr.c', #'rtr_http.c', #'rtr_shell.c', diff --git a/librz/core/project_migrate.c b/librz/core/project_migrate.c index 8fab21f84d..70e54ccf51 100644 --- a/librz/core/project_migrate.c +++ b/librz/core/project_migrate.c @@ -733,6 +733,27 @@ RZ_API bool rz_project_migrate_v20_v21(RzProject *prj, RzSerializeResultInfo *re return true; } +// -- +// Migration 21 -> 22 +// +// Changes from : +// Renamed ROP search configs to gadget search for generalization: +// - `rop.X` to `gadget.X` + +RZ_API bool rz_project_migrate_v21_v22(RzProject *prj, RzSerializeResultInfo *res) { + Sdb *core_db; + RZ_SERIALIZE_SUB(prj, core_db, res, "core", return false;); + Sdb *config_db; + RZ_SERIALIZE_SUB(core_db, config_db, res, "config", return false;); + sdb_rename(config_db, "rop.len", "gadget.len"); + sdb_rename(config_db, "rop.cache", "gadget.cache"); + sdb_rename(config_db, "rop.subchains", "gadget.subchains"); + sdb_rename(config_db, "rop.conditional", "gadget.conditional"); + sdb_rename(config_db, "rop.comments", "gadget.comments"); + + return true; +} + static bool (*const migrations[])(RzProject *prj, RzSerializeResultInfo *res) = { rz_project_migrate_v1_v2, rz_project_migrate_v2_v3, @@ -754,6 +775,7 @@ static bool (*const migrations[])(RzProject *prj, RzSerializeResultInfo *res) = rz_project_migrate_v18_v19, rz_project_migrate_v19_v20, rz_project_migrate_v20_v21, + rz_project_migrate_v21_v22, }; /// Migrate the given project to the current version in-place diff --git a/librz/include/meson.build b/librz/include/meson.build index 5d64356e29..9feee80cd6 100644 --- a/librz/include/meson.build +++ b/librz/include/meson.build @@ -40,7 +40,7 @@ include_files = [ 'rz_platform.h', 'rz_project.h', 'rz_reg.h', - 'rz_rop.h', + 'rz_gadget.h', 'rz_search.h', 'rz_sign.h', 'rz_skiplist.h', diff --git a/librz/include/rz_analysis.h b/librz/include/rz_analysis.h index c200e745c2..6ce0b649db 100644 --- a/librz/include/rz_analysis.h +++ b/librz/include/rz_analysis.h @@ -1370,8 +1370,8 @@ RZ_API RZ_BORROW HtUP *rz_analysis_get_xrefs_from(RZ_NONNULL RzAnalysis *analysi RZ_API void rz_analysis_set_xrefs_from(RZ_NONNULL RzAnalysis *analysis, HtUP *xrefs_from); RZ_API RZ_BORROW HtUP *rz_analysis_get_xrefs_to(RZ_NONNULL RzAnalysis *analysis); RZ_API void rz_analysis_set_xrefs_to(RZ_NONNULL RzAnalysis *analysis, HtUP *xrefs_to); -RZ_API RZ_BORROW HtUP *rz_analysis_get_rop_semantics(RZ_NONNULL RzAnalysis *analysis); -RZ_API void rz_analysis_set_rop_semantics(RZ_NONNULL RzAnalysis *analysis, HtUP *rop_semantics); +RZ_API RZ_BORROW HtUP *rz_analysis_get_gadget_semantics(RZ_NONNULL RzAnalysis *analysis); +RZ_API void rz_analysis_set_gadget_semantics(RZ_NONNULL RzAnalysis *analysis, HtUP *rop_semantics); RZ_API RZ_BORROW RzAnalysisCallbacks *rz_analysis_get_callbacks(RZ_NONNULL RzAnalysis *analysis); RZ_API void rz_analysis_set_os(RZ_NONNULL RzAnalysis *analysis, RZ_NULLABLE const char *os); RZ_API const char *rz_analysis_get_os(RZ_NONNULL RzAnalysis *analysis); diff --git a/librz/include/rz_gadget.h b/librz/include/rz_gadget.h new file mode 100644 index 0000000000..fcc03c3858 --- /dev/null +++ b/librz/include/rz_gadget.h @@ -0,0 +1,222 @@ +// SPDX-FileCopyrightText: 2026 MrQuantum1915 +// SPDX-FileCopyrightText: 2024 z3phyr +// SPDX-License-Identifier: LGPL-3.0-only + +#ifndef RZ_GADGET_H +#define RZ_GADGET_H + +/** + * \file rz_gadget.h + * \brief Gadget (ROP, JOP, COP) related APIs and structures. + * + * This file contains definitions, structures, and function prototypes for handling ROP, JOP and COP gadgets and constraints. + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Information about a register. + */ +typedef struct rz_gadget_reg_info_t { + char *name; + bool is_mem_read; ///< Register involved in Memory read. + bool is_pc_write; ///< PC write flag. + bool is_var_read; ///< Register involved in Variable read. + bool is_var_write; ///< Register involved in Variable write. + bool is_mem_write; ///< Register involved in Memory write. + ut64 init_val; + ut64 new_val; + ut64 bits; ///< Register bits for capturing cast + RzILOpPure *value_transformations; ///< TODO: Captures Value transformations. +} RzGadgetRegInfo; + +/** + * \brief Information about a gadget. + */ +typedef struct rz_gadget_info_t { + ut64 address; ///< Gadget address. + ut64 stack_change; ///< Stack change. + ut64 curr_pc_val; ///< Current PC value. + ut32 size; ///< Gadget size. + bool is_pc_write; ///< PC write flag. + bool is_syscall; ///< Syscall flag. + RzIterator /*RzAnalysisBytes *>*/ *analysis_cache; ///< Stores \p RzAnalysisBytes for the gadget. + RzPVector /**/ *modified_registers; ///< Modified registers. + RzList /**/ *dependencies; ///< Dependencies. +} RzGadgetInfo; + +/** + * \brief Type of gadget to search for. + */ +typedef enum { + RZ_GADGET_TYPE_ROP, ///< Return-Oriented Programming. + RZ_GADGET_TYPE_JOP, ///< Jump-Oriented Programming. + RZ_GADGET_TYPE_COP, ///< Call-Oriented Programming. +} RzGadgetType; + +/** + * \brief Types of IL instructions for Gadget constraints. + */ +typedef enum rz_gadget_il_instr_type { + MOV_CONST, ///< reg <- const + MOV_REG, ///< reg <- reg + MOV_OP_CONST, ///< reg <- reg OP const + MOV_OP_REG, ///< reg <- reg OP reg + SYSCALL, ///< syscall +} RzGadgetILInstructionType; + +/** + * \brief Argument types for Gadget constraints. + */ +typedef enum { + SRC_REG, + DST_REG, + SRC_CONST, + SRC_REG_SECOND, + OP, + NUM_ARGS +} RzGadgetArgType; + +/** + * \brief Gadget request mask for filtering gadgets. + */ +typedef enum { + RZ_GADGET_PRINT = 1 << 0, ///< Print Gadget. + RZ_GADGET_PRINT_DETAIL = 1 << 1, ///< Detailed Gadget. + RZ_GADGET_ANALYZE = 1 << 2, ///< Detailed Gadget. + RZ_GADGET_ALL = RZ_GADGET_PRINT | RZ_GADGET_PRINT_DETAIL | RZ_GADGET_ANALYZE ///< All Gadget requests. +} RzGadgetRequestMask; + +/** + * \brief Gadget search mask for filtering gadgets given details. + */ +typedef enum { + RZ_GADGET_DETAIL_SEARCH_NON = 0, + RZ_GADGET_DETAIL_SEARCH_STACK = 1 << 0, ///< Search gadgets by stack changes. + RZ_GADGET_DETAIL_SEARCH_SIZE = 1 << 1, ///< Search gadgets by gadget sizes. + // RZ_GADGET_DETAIL_SEARCH_WRITE = 1 << 2, ///< Search gadgets by written registers. + // RZ_GADGET_DETAIL_SEARCH_READ = 1 << 3, ///< Search gadgets by read registers. +} RzGadgetDetailSearchMask; + +/** + * \brief Filter conditions while searching gadgets by stack changes. + */ +typedef enum { + RZ_GADGET_DETAIL_CMP_EQ = 1, ///< == + RZ_GADGET_DETAIL_CMP_GT = 1 << 1, ///< > + RZ_GADGET_DETAIL_CMP_GE = RZ_GADGET_DETAIL_CMP_GT | RZ_GADGET_DETAIL_CMP_EQ, ///< >= + RZ_GADGET_DETAIL_CMP_LT = 1 << 2, ///< < + RZ_GADGET_DETAIL_CMP_LE = RZ_GADGET_DETAIL_CMP_LT | RZ_GADGET_DETAIL_CMP_EQ, ///< <= +} RzGadgetDetailSearchCmpOp; + +/** + * \brief Pair representing an end gadget with instruction offset and delay size. + */ +typedef struct rz_gadget_endlist_pair_t { + int instr_offset; ///< Instruction offset. + int delay_size; ///< Delay size. +} RzGadgetEndListPair; + +/** + * \brief Structure representing a Gadget constraint. + */ +typedef struct rz_gadget_constraint_t { + RzGadgetILInstructionType type; ///< IL instruction type. + char *args[NUM_ARGS]; ///< Arguments. +} RzGadgetConstraint; + +/** + * \brief Structure representing a Gadget search context. + */ +typedef struct rz_gadget_search_context_t { + RzGadgetType type; ///< Type of gadget to search for. + ut8 max_instr; ///< Gadget search max length. + bool subchains; ///< Display every length gadget from gadget.len=X to 2. + bool allow_conditional; ///< Include conditional jump, calls and returns in gadget search. + bool comments; ///< Display comments in gadget search output. + char *greparg; ///< Grep argument string. + const char *arch; ///< Architecture of the binary. + bool regexp; ///< Regular expression argument flag. + bool cache; ///< Cache the search results. + RzGadgetRequestMask mask; ///< Mask for kind of gadget request operation. + RzGadgetDetailSearchMask detail_mask; ///< Mask for searching gadgets given details. + RzCmdStateOutput *state; ///< Command state output. + int increment; ///< Gadget search increment value. + ut64 max_count; ///< Maximum number of hits (0: no limit). + ut64 from; ///< Start address to start gadget search. + ut64 to; ///< End address to stop gadget search. + RzList /**/ *end_list; ///< List of end gadgets. + HtSU *unique_hitlists; ///< Cache unique gadget hitlists. + bool ret_val; ///< Flag to indicate return the search results. + RzStrBuf *buf; ///< String buffer for storing search results. + RzPVector /**/ *constraints; ///< User constraints for filtering. +} RzGadgetSearchContext; + +/** + * \brief Enum for different Gadget register events. + */ +typedef enum { + RZ_GADGET_EVENT_VAR_READ, + RZ_GADGET_EVENT_VAR_WRITE, + RZ_GADGET_EVENT_MEM_READ, + RZ_GADGET_EVENT_MEM_WRITE, + RZ_GADGET_EVENT_PC_WRITE, + RZ_GADGET_EVENT_COUNT ///< This should always be the last element. +} RzGadgetEvent; + +/** + * \brief Function pointer type for event check functions. + */ +typedef bool (*rz_gadget_event_check_fn)(const RzGadgetRegInfo *); + +/** + * \brief Array of event check functions. + */ +extern rz_gadget_event_check_fn rz_gadget_event_functions[RZ_GADGET_EVENT_COUNT]; + +// Command APIs +RZ_API RzCmdStatus rz_core_gadget_search(RZ_NONNULL RzCore *core, RZ_NONNULL RzGadgetSearchContext *context); +RZ_API RzCmdStatus rz_core_gadget_info(RZ_NONNULL RzCore *core, RZ_NONNULL RZ_OWN RzGadgetSearchContext *context); +RZ_API bool rz_core_gadget_analyze_constraint(const RZ_NONNULL RzCore *core, const RZ_NONNULL char *str, + RZ_NULLABLE RZ_OUT RzGadgetConstraint *gadget_constraint); +RZ_API RZ_OWN RzPVector /**/ *rz_core_gadget_constraint_map_parse(const RZ_NONNULL RzCore *core, int argc, const char **argv); +RZ_API bool rz_core_handle_gadget_request_type(RZ_NONNULL RzCore *core, RZ_NONNULL RzGadgetSearchContext *context, RZ_NONNULL RzPVector /**/ *hitlist); +RZ_API RZ_NULLABLE RZ_OWN RzList /**/ *rz_core_gadget_handle_grep_args(RZ_NULLABLE const char *greparg, const bool regexp); + +// Gadget Search Context APIs +RZ_API RZ_OWN RzGadgetSearchContext *rz_core_gadget_search_context_new(RZ_NONNULL const RzCore *core, const RzGadgetType gadget_type, RZ_NULLABLE const char *greparg, bool regexp, + RzGadgetRequestMask mask, RzGadgetDetailSearchMask detail_mask, RZ_NULLABLE RZ_BORROW RzCmdStateOutput *state); +RZ_API void rz_core_gadget_search_context_free(RZ_NULLABLE RzGadgetSearchContext *context); + +// Gadget Constraint APIs +RZ_API void rz_core_gadget_constraint_free(RZ_NULLABLE void *data); +RZ_API RZ_OWN RzGadgetConstraint *rz_core_gadget_constraint_parse_args(const RZ_NONNULL RzCore *core, const RZ_NONNULL char *token); + +// Gadget Info APIs +RZ_API void rz_core_gadget_info_free(RZ_NULLABLE RzGadgetInfo *gadget_info); +RZ_API void rz_core_gadget_info_add_register(const RZ_NONNULL RZ_OUT RzGadgetInfo *gadget_info, + RZ_NONNULL RzGadgetRegInfo *reg_info, bool is_dependency); +RZ_API void rz_core_gadget_info_update_register(const RZ_INOUT RzGadgetInfo *gadget_info, RZ_INOUT RZ_NONNULL RzGadgetRegInfo *new_reg_info); +RZ_API RZ_OWN RzGadgetInfo *rz_core_gadget_info_new(ut64 address); +RZ_API RZ_OWN RzGadgetRegInfo *rz_core_gadget_reg_info_dup(RZ_BORROW RZ_NONNULL RzGadgetRegInfo *src); +RZ_API void rz_core_gadget_reg_info_free(RZ_NULLABLE RzGadgetRegInfo *reg_info); +RZ_API RZ_OWN RzGadgetRegInfo *rz_core_gadget_reg_info_new(RZ_NONNULL const RzCore *core, RZ_NONNULL const RzILEvent *evt, + ut64 init_val, ut64 new_val); +RZ_API RZ_BORROW RzGadgetRegInfo *rz_core_gadget_info_get_modified_register(const RZ_NONNULL RzGadgetInfo *gadget_info, + const RZ_NONNULL char *name); +RZ_API bool rz_core_gadget_info_has_register(const RZ_NONNULL RzGadgetInfo *gadget_info, const RZ_NONNULL char *name); +RZ_API RZ_OWN RzPVector /**/ *rz_core_gadget_get_reg_info_by_event(const RZ_NONNULL RzGadgetInfo *gadget_info, RzGadgetEvent event); +RZ_API RZ_OWN RzPVector /**/ *rz_core_gadget_get_reg_info_by_reg_names(const RZ_NONNULL RzGadgetInfo *gadget_info, RZ_NONNULL const RzPVector /**/ *registers); +RZ_API bool rz_core_gadget_reg_info_has_event(const RZ_NONNULL RzGadgetInfo *gadget_info, + RzGadgetEvent event, const RZ_NULLABLE char *reg_name); +RZ_API RZ_OWN RzPVector /**/ *rz_core_gadget_reg_info_find(const RZ_NONNULL RzGadgetInfo *gadget_info, const RZ_NONNULL char *name); + +#ifdef __cplusplus +} +#endif +#endif // RZ_GADGET_H diff --git a/librz/include/rz_project.h b/librz/include/rz_project.h index 52b5a90ceb..ae4fc9c81e 100644 --- a/librz/include/rz_project.h +++ b/librz/include/rz_project.h @@ -12,7 +12,7 @@ extern "C" { #endif -#define RZ_PROJECT_VERSION 21 +#define RZ_PROJECT_VERSION 22 typedef Sdb RzProject; @@ -66,6 +66,7 @@ RZ_API bool rz_project_migrate_v17_v18(RzProject *prj, RzSerializeResultInfo *re RZ_API bool rz_project_migrate_v18_v19(RzProject *prj, RzSerializeResultInfo *res); RZ_API bool rz_project_migrate_v19_v20(RzProject *prj, RzSerializeResultInfo *res); RZ_API bool rz_project_migrate_v20_v21(RzProject *prj, RzSerializeResultInfo *res); +RZ_API bool rz_project_migrate_v21_v22(RzProject *prj, RzSerializeResultInfo *res); RZ_API bool rz_project_migrate(RzProject *prj, unsigned long version, RzSerializeResultInfo *res); #ifdef __cplusplus diff --git a/librz/include/rz_rop.h b/librz/include/rz_rop.h deleted file mode 100644 index a00af56384..0000000000 --- a/librz/include/rz_rop.h +++ /dev/null @@ -1,210 +0,0 @@ -// SPDX-FileCopyrightText: 2024 z3phyr -// SPDX-License-Identifier: LGPL-3.0-only - -#ifndef RZ_ROP_H -#define RZ_ROP_H - -/** - * \file rz_rop.h - * \brief Return-Oriented Programming (ROP) related APIs and structures.. - * - * This file contains definitions, structures, and function prototypes for handling ROP gadgets and constraints. - */ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief Information about a register. - */ -typedef struct rz_rop_reg_info_t { - char *name; - bool is_mem_read; ///< Register involved in Memory read. - bool is_pc_write; ///< PC write flag. - bool is_var_read; ///< Register involved in Variable read. - bool is_var_write; ///< Register involved in Variable write. - bool is_mem_write; ///< Register involved in Memory write. - ut64 init_val; - ut64 new_val; - ut64 bits; ///< Register bits for capturing cast - RzILOpPure *value_transformations; ///< TODO: Captures Value transformations. -} RzRopRegInfo; - -/** - * \brief Information about a ROP gadget. - */ -typedef struct rz_rop_gadget_info_t { - ut64 address; ///< Gadget address. - ut64 stack_change; ///< Stack change. - ut64 curr_pc_val; ///< Current PC value. - ut32 size; ///< Gadget size. - bool is_pc_write; ///< PC write flag. - bool is_syscall; ///< Syscall flag. - RzIterator /*RzAnalysisBytes *>*/ *analysis_cache; ///< Stores \p RzAnalysisBytes for the gadget. - RzPVector /**/ *modified_registers; ///< Modified registers. - RzList /**/ *dependencies; ///< Dependencies. -} RzRopGadgetInfo; - -/** - * \brief Types of IL instructions for ROP constraints. - */ -typedef enum rz_rop_il_instr_type { - MOV_CONST, ///< reg <- const - MOV_REG, ///< reg <- reg - MOV_OP_CONST, ///< reg <- reg OP const - MOV_OP_REG, ///< reg <- reg OP reg - SYSCALL, ///< syscall -} RzRopILInstructionType; - -/** - * \brief Argument types for ROP constraints. - */ -typedef enum { - SRC_REG, - DST_REG, - SRC_CONST, - SRC_REG_SECOND, - OP, - NUM_ARGS -} RzRopArgType; - -/** - * \brief ROP request mask for filtering gadgets. - */ -typedef enum { - RZ_ROP_GADGET_PRINT = 1 << 0, ///< Print ROP gadgets. - RZ_ROP_GADGET_PRINT_DETAIL = 1 << 1, ///< Detailed ROP gadgets. - RZ_ROP_GADGET_ANALYZE = 1 << 2, ///< Detailed ROP gadgets. - RZ_ROP_GADGET_ALL = RZ_ROP_GADGET_PRINT | RZ_ROP_GADGET_PRINT_DETAIL | RZ_ROP_GADGET_ANALYZE ///< All ROP gadgets requests. -} RzRopRequestMask; - -/** - * \brief ROP search mask for filtering gadgets given details. - */ -typedef enum { - RZ_ROP_DETAIL_SEARCH_NON = 0, - RZ_ROP_DETAIL_SEARCH_STACK = 1 << 0, ///< Search ROP gadgets by stack changes. - RZ_ROP_DETAIL_SEARCH_SIZE = 1 << 1, ///< Search ROP gadgets by gadget sizes. - // RZ_ROP_DETAIL_SEARCH_WRITE = 1 << 2, ///< Search ROP gadgets by written registers. - // RZ_ROP_DETAIL_SEARCH_READ = 1 << 3, ///< Search ROP gadgets by read registers. -} RzRopDetailSearchMask; - -/** - * \brief Filter conditions while searching ROP gadgets by stack changes. - */ -typedef enum { - ROP_DETAIL_CMP_EQ = 1, // == - ROP_DETAIL_CMP_GT = 1 << 1, // > - ROP_DETAIL_CMP_GE = ROP_DETAIL_CMP_GT | ROP_DETAIL_CMP_EQ, // >= - ROP_DETAIL_CMP_LT = 1 << 2, // < - ROP_DETAIL_CMP_LE = ROP_DETAIL_CMP_LT | ROP_DETAIL_CMP_EQ, // <= -} RopDetailSearchCmpOp; - -/** - * \brief Pair representing an end gadget with instruction offset and delay size. - */ -typedef struct rz_rop_endlist_pair_t { - int instr_offset; ///< Instruction offset. - int delay_size; ///< Delay size. -} RzRopEndListPair; - -/** - * \brief Structure representing a ROP constraint. - */ -typedef struct rz_rop_constraint_t { - RzRopILInstructionType type; ///< IL instruction type. - char *args[NUM_ARGS]; ///< Arguments. -} RzRopConstraint; - -/** - * \brief Structure representing a ROP search context. - */ -typedef struct rz_rop_search_context_t { - ut8 max_instr; ///< Rop search max length. - ut8 subchain; ///< Display every length gadget from rop.len=X to 2 in /Rl. - ut8 crop; ///< Include conditional jump, calls and returns in ropsearch. - char *greparg; ///< Grep argument string. - const char *arch; ///< Architecture of the binary. - bool regexp; ///< Regular expression argument flag. - bool cache; ///< Cache the search results. - RzRopRequestMask mask; ///< Mask for kind of rop request operation. - RzRopDetailSearchMask detail_mask; ///< Mask for searching gadgets given details. - RzCmdStateOutput *state; ///< Command state output. - int increment; ///< ROP search increment value. - ut64 max_count; ///< Maximum number of hits (0: no limit). - ut64 from; ///< Start address to start rop search. - ut64 to; ///< End address to stop rop search. - RzList /**/ *end_list; ///< List of end gadgets. - HtSU *unique_hitlists; ///< Cache unique ROP hitlists. - bool ret_val; ///< Flag to indicate return the search results. - RzStrBuf *buf; ///< String buffer for storing search results. - RzPVector /**/ *constraints; ///< User constraints for filtering. -} RzRopSearchContext; - -/** - * \brief Enum for different ROP register events. - */ -typedef enum { - RZ_ROP_EVENT_VAR_READ, - RZ_ROP_EVENT_VAR_WRITE, - RZ_ROP_EVENT_MEM_READ, - RZ_ROP_EVENT_MEM_WRITE, - RZ_ROP_EVENT_PC_WRITE, - RZ_ROP_EVENT_COUNT // This should always be the last element -} RzRopEvent; - -/** - * \brief Function pointer type for event check functions. - */ -typedef bool (*rz_rop_event_check_fn)(const RzRopRegInfo *); - -/** - * \brief Array of event check functions. - */ -extern rz_rop_event_check_fn rz_rop_event_functions[RZ_ROP_EVENT_COUNT]; - -// Command APIs -RZ_API RzCmdStatus rz_core_rop_search(RZ_NONNULL RzCore *core, RZ_NONNULL RzRopSearchContext *context); -RZ_API RzCmdStatus rz_core_rop_gadget_info(RZ_NONNULL RzCore *core, RZ_NONNULL RZ_OWN RzRopSearchContext *context); -RZ_API bool rz_core_rop_analyze_constraint(const RZ_NONNULL RzCore *core, const RZ_NONNULL char *str, - RZ_NULLABLE RZ_OUT RzRopConstraint *rop_constraint); -RZ_API RZ_OWN RzPVector /**/ *rz_core_rop_constraint_map_parse(const RZ_NONNULL RzCore *core, int argc, const char **argv); -RZ_API bool rz_core_handle_rop_request_type(RZ_NONNULL RzCore *core, RZ_NONNULL RzRopSearchContext *context, RZ_NONNULL RzList /**/ *hitlist); -RZ_API RZ_NULLABLE RZ_OWN RzList /**/ *rz_core_rop_handle_grep_args(RZ_NULLABLE const char *greparg, const bool regexp); - -// ROP Search Context APIs -RZ_API RZ_OWN RzRopSearchContext *rz_core_rop_search_context_new(RZ_NONNULL const RzCore *core, RZ_NULLABLE const char *greparg, bool regexp, - RzRopRequestMask mask, RzRopDetailSearchMask detail_mask, RZ_NULLABLE RZ_BORROW RzCmdStateOutput *state); -RZ_API void rz_core_rop_search_context_free(RZ_NULLABLE RzRopSearchContext *context); - -// ROP Constraint APIs -RZ_API void rz_core_rop_constraint_free(RZ_NULLABLE void *data); -RZ_API RZ_OWN RzRopConstraint *rz_core_rop_constraint_parse_args(const RZ_NONNULL RzCore *core, const RZ_NONNULL char *token); - -// ROP Gadget Info APIs -RZ_API void rz_core_rop_gadget_info_free(RZ_NULLABLE RzRopGadgetInfo *gadget_info); -RZ_API void rz_core_rop_gadget_info_add_register(const RZ_NONNULL RZ_OUT RzRopGadgetInfo *gadget_info, - RZ_NONNULL RzRopRegInfo *reg_info, bool is_dependency); -RZ_API void rz_core_rop_gadget_info_update_register(const RZ_INOUT RzRopGadgetInfo *gadget_info, RZ_INOUT RZ_NONNULL RzRopRegInfo *new_reg_info); -RZ_API RZ_OWN RzRopGadgetInfo *rz_core_rop_gadget_info_new(ut64 address); -RZ_API RZ_OWN RzRopRegInfo *rz_core_rop_reg_info_dup(RZ_BORROW RZ_NONNULL RzRopRegInfo *src); -RZ_API void rz_core_rop_reg_info_free(RZ_NULLABLE RzRopRegInfo *reg_info); -RZ_API RZ_OWN RzRopRegInfo *rz_core_rop_reg_info_new(RZ_NONNULL const RzCore *core, RZ_NONNULL const RzILEvent *evt, - ut64 init_val, ut64 new_val); -RZ_API RZ_BORROW RzRopRegInfo *rz_core_rop_gadget_info_get_modified_register(const RZ_NONNULL RzRopGadgetInfo *gadget_info, - const RZ_NONNULL char *name); -RZ_API bool rz_core_rop_gadget_info_has_register(const RZ_NONNULL RzRopGadgetInfo *gadget_info, const RZ_NONNULL char *name); -RZ_API RZ_OWN RzPVector /**/ *rz_core_rop_gadget_get_reg_info_by_event(const RZ_NONNULL RzRopGadgetInfo *gadget_info, RzRopEvent event); -RZ_API RZ_OWN RzPVector /**/ *rz_core_rop_get_reg_info_by_reg_names(const RZ_NONNULL RzRopGadgetInfo *gadget_info, RZ_NONNULL const RzPVector /**/ *registers); -RZ_API bool rz_core_rop_gadget_reg_info_has_event(const RZ_NONNULL RzRopGadgetInfo *gadget_info, - RzRopEvent event, const RZ_NULLABLE char *reg_name); -RZ_API RZ_OWN RzPVector /**/ *rz_core_rop_reg_info_find(const RZ_NONNULL RzRopGadgetInfo *gadget_info, const RZ_NONNULL char *name); - -#ifdef __cplusplus -} -#endif -#endif // RZ_ROP_H diff --git a/test/db/cmd/cmd_rop b/test/db/cmd/cmd_rop index 2093da4041..e831ca5aa0 100644 --- a/test/db/cmd/cmd_rop +++ b/test/db/cmd/cmd_rop @@ -318,7 +318,7 @@ NAME=search rop gadgets with another end gadget as part of it. FILE=bins/elf/analysis/unoriginal CMDS=<v21 migrate success"); + + // actual test + bool s_21_22 = rz_project_migrate_v21_v22(prj, res); + mu_assert_true(s_21_22, "v21->v22 migrate success"); + + Sdb *core_db = sdb_ns(prj, "core", false); + Sdb *config_db = sdb_ns(core_db, "config", false); + + mu_assert_null(sdb_get(config_db, "rop.len"), "old rop.len deleted"); + mu_assert_streq_free(sdb_get(config_db, "gadget.len"), "5", "new gadget.len added"); + + mu_assert_null(sdb_get(config_db, "rop.cache"), "old rop.cache deleted"); + mu_assert_streq_free(sdb_get(config_db, "gadget.cache"), "false", "new gadget.cache added"); + + mu_assert_null(sdb_get(config_db, "rop.subchains"), "old rop.subchains deleted"); + mu_assert_streq_free(sdb_get(config_db, "gadget.subchains"), "false", "new gadget.subchains added"); + + mu_assert_null(sdb_get(config_db, "rop.conditional"), "old rop.conditional deleted"); + mu_assert_streq_free(sdb_get(config_db, "gadget.conditional"), "false", "new gadget.conditional added"); + + mu_assert_null(sdb_get(config_db, "rop.comments"), "old rop.comments deleted"); + mu_assert_streq_free(sdb_get(config_db, "gadget.comments"), "false", "new gadget.comments added"); + + rz_serialize_result_info_free(res); + rz_project_free(prj); + mu_end; +} + /// Load project of given version from file into core and check the log for migration success messages #define BEGIN_LOAD_TEST(core, version, file) \ do { \ @@ -1055,6 +1091,18 @@ static bool test_load_v17() { mu_end; } +static bool test_load_v22_gadget_config() { + RzCore *core = rz_core_new(); + BEGIN_LOAD_TEST(core, 17, "prj/v17-rop-config.rzdb"); + mu_assert_eq(rz_config_get_i(core->config, "gadget.len"), 5, "gadget.len"); + mu_assert_eq(rz_config_get_b(core->config, "gadget.cache"), false, "gadget.cache"); + mu_assert_eq(rz_config_get_b(core->config, "gadget.subchains"), false, "gadget.subchains"); + mu_assert_eq(rz_config_get_b(core->config, "gadget.conditional"), false, "gadget.conditional"); + mu_assert_eq(rz_config_get_b(core->config, "gadget.comments"), false, "gadget.comments"); + rz_core_free(core); + mu_end; +} + int all_tests() { mu_run_test(test_migrate_v1_v2_noreturn); mu_run_test(test_migrate_v1_v2_noreturn_empty); @@ -1078,6 +1126,7 @@ int all_tests() { mu_run_test(test_migrate_v17_v18_rop_config); mu_run_test(test_migrate_v18_v19_str_config); mu_run_test(test_migrate_v20_v21_debase64); + mu_run_test(test_migrate_v21_v22_gadget_config); mu_run_test(test_load_v1_noreturn); mu_run_test(test_load_v1_noreturn_empty); mu_run_test(test_load_v1_unknown_type); @@ -1101,6 +1150,7 @@ int all_tests() { mu_run_test(test_load_v15_19_str_config); mu_run_test(test_load_v16); mu_run_test(test_load_v17); + mu_run_test(test_load_v22_gadget_config); return tests_passed != tests_run; } diff --git a/test/unit/test_rop.c b/test/unit/test_rop.c index da2844c1db..2062180df8 100644 --- a/test/unit/test_rop.c +++ b/test/unit/test_rop.c @@ -1,10 +1,10 @@ +// SPDX-FileCopyrightText: 2026 MrQuantum1915 // SPDX-FileCopyrightText: 2024 z3phyr // SPDX-License-Identifier: LGPL-3.0-only #include "minunit.h" #include -#include "analysis_private.h" -#include +#include // Only one gadget is added once for each test case. #define ROP_GADGET_MAX_SIZE 16 @@ -34,7 +34,7 @@ static RzCoreAsmHit *setup_rop_hitasm(RzCore *core, int addr, ut8 *buf_str, int return hit; } -static RzList /**/ * +static RzPVector /**/ * setup_rop_hitlist(RzCore *core, ut8 *buf_str, int addr, int len, HtUP *ht_rop_analysis) { RzAnalysisOp aop = { 0 }; rz_analysis_op_init(&aop); @@ -47,23 +47,23 @@ setup_rop_hitlist(RzCore *core, ut8 *buf_str, int addr, int len, HtUP *ht_rop_an return NULL; } - RzList /**/ *hitlist = rz_list_newf(rz_core_asm_hit_free); + RzPVector /**/ *hitlist = rz_pvector_new(rz_core_asm_hit_free); if (!hitlist) { return NULL; } RzCoreAsmHit *hit = setup_rop_hitasm(core, addr, buf_str, len - 1, ht_rop_analysis); if (!hit) { - rz_list_free(hitlist); + rz_pvector_free(hitlist); return NULL; } - rz_list_append(hitlist, hit); + rz_pvector_push(hitlist, hit); hit = setup_rop_hitasm(core, addr + len - 1, buf_str, 1, ht_rop_analysis); if (!hit) { - rz_list_free(hitlist); + rz_pvector_free(hitlist); return NULL; } - rz_list_append(hitlist, hit); + rz_pvector_push(hitlist, hit); rz_analysis_op_fini(&aop); return hitlist; } @@ -86,7 +86,7 @@ static void cleanup_test(RzCore *core, HtUP *ht_rop_analysis) { static bool rop_gadget_info_cb(void *user, const ut64 k, const void *v) { HtUP *ht_rop_analysis = (HtUP *)user; - RzRopGadgetInfo *gadget_info = (RzRopGadgetInfo *)v; + RzGadgetInfo *gadget_info = (RzGadgetInfo *)v; mu_assert_eq(k, gadget_info->address, "ROP gadget address mismatch"); RzAnalysisOp *aop = ht_up_find(ht_rop_analysis, k, NULL); mu_assert_notnull(aop, "ROP gadget analysis op is NULL"); @@ -95,16 +95,16 @@ static bool rop_gadget_info_cb(void *user, const ut64 k, const void *v) { mu_assert_notnull(src, "ROP gadget analysis op src is NULL"); RzRegItem *reg_item = aop->dst->reg; mu_assert_notnull(reg_item, "ROP gadget register item is NULL"); - RzRopRegInfo *reg_info = rz_core_rop_gadget_info_get_modified_register(gadget_info, aop->dst->reg->name); + RzGadgetRegInfo *reg_info = rz_core_gadget_info_get_modified_register(gadget_info, aop->dst->reg->name); mu_assert_notnull(reg_info, "ROP gadget modified register is NULL"); mu_assert_streq(reg_info->name, reg_item->name, "ROP gadget modified register name mismatch"); if (src[0].type == RZ_ANALYSIS_VAL_IMM) { mu_assert_eq(src->imm, reg_info->new_val - reg_info->init_val, "ROP gadget modified register value mismatch"); } else if (src[0].type == RZ_ANALYSIS_VAL_REG) { - RzPVector /**/ *reg_info_vector = rz_core_rop_gadget_get_reg_info_by_event(gadget_info, RZ_ROP_EVENT_VAR_READ); + RzPVector /**/ *reg_info_vector = rz_core_gadget_get_reg_info_by_event(gadget_info, RZ_GADGET_EVENT_VAR_READ); mu_assert_notnull(reg_info_vector, "ROP gadget register item is NULL"); mu_assert_eq(rz_pvector_len(reg_info_vector), 2, "ROP gadget register item count mismatch"); - RzRopRegInfo *reg_info_analysis_reg = rz_pvector_at(reg_info_vector, 0); + RzGadgetRegInfo *reg_info_analysis_reg = rz_pvector_at(reg_info_vector, 0); mu_assert_streq(src->reg->name, reg_info_analysis_reg->name, "ROP gadget modified register value mismatch"); rz_pvector_free(reg_info_vector); } @@ -117,28 +117,28 @@ bool test_rz_direct_solver() { mu_assert_notnull(core, "setup_rz_core failed"); int size = sizeof(x86_64_buf_str) / sizeof(x86_64_buf_str[0]); int addr = 0; - RzRopSearchContext *context = rz_core_rop_search_context_new( - core, NULL, false, RZ_ROP_GADGET_PRINT_DETAIL | RZ_ROP_GADGET_ANALYZE, RZ_ROP_DETAIL_SEARCH_NON, + RzGadgetSearchContext *context = rz_core_gadget_search_context_new( + core, RZ_GADGET_TYPE_ROP, NULL, false, RZ_GADGET_PRINT_DETAIL | RZ_GADGET_ANALYZE, RZ_GADGET_DETAIL_SEARCH_NON, NULL); - mu_assert_notnull(context, "rz_core_rop_search_context_new failed"); + mu_assert_notnull(context, "rz_core_gadget_search_context_new failed"); HtUP *ht_rop_analysis = ht_up_new(NULL, (HtUPFreeValue)rz_analysis_op_free); for (int i = 0; i < size; i++) { ut8 buf[ROP_GADGET_MAX_SIZE] = { 0 }; int len = rz_hex_str2bin(x86_64_buf_str[i], buf); rz_io_write_at(core->io, addr, buf, len); - RzList /**/ *hitlist = + RzPVector /**/ *hitlist = setup_rop_hitlist(core, buf, addr, len, ht_rop_analysis); mu_assert_notnull(hitlist, "setup_rop_hitlist failed"); - rz_core_handle_rop_request_type(core, context, hitlist); + rz_core_handle_gadget_request_type(core, context, hitlist); addr += len + 1; - rz_list_free(hitlist); + rz_pvector_free(hitlist); } - HtUP *rop_semantics = core->analysis->ht_rop_semantics; + HtUP *rop_semantics = rz_analysis_get_gadget_semantics(core->analysis); mu_assert_notnull(rop_semantics, "ROP semantics hashtable is NULL"); mu_assert_eq(ht_up_size(rop_semantics), 2, "ROP semantics hashtable count is not 2"); ht_up_foreach(rop_semantics, rop_gadget_info_cb, ht_rop_analysis); - rz_core_rop_search_context_free(context); + rz_core_gadget_search_context_free(context); cleanup_test(core, ht_rop_analysis); mu_end; } diff --git a/test/unit/test_rop_constraint.c b/test/unit/test_rop_constraint.c index 757b9f2ca7..ae05f49ac7 100644 --- a/test/unit/test_rop_constraint.c +++ b/test/unit/test_rop_constraint.c @@ -1,10 +1,10 @@ +// SPDX-FileCopyrightText: 2026 MrQuantum1915 // SPDX-FileCopyrightText: 2024 z3phyr // SPDX-License-Identifier: LGPL-3.0-only #include #include "minunit.h" -#include -#include "analysis_private.h" +#include // Define the register profile string for your architecture #define REGISTER_PROFILE_STRING \ @@ -35,7 +35,8 @@ static void setup_rz_core(RzCore *core) { rz_config_set(core->config, "analysis.arch", "x86"); rz_analysis_set_bits(core->analysis, 64); - rz_reg_set_profile_string(core->analysis->reg, REGISTER_PROFILE_STRING); + RzReg *reg = rz_analysis_get_reg(core->analysis); + rz_reg_set_profile_string(reg, REGISTER_PROFILE_STRING); } bool test_parse_reg_to_const(void) { @@ -45,19 +46,19 @@ bool test_parse_reg_to_const(void) { // Test case 1: Valid register to constant char str1[] = " eax = 123 "; - RzRopConstraint *rop_constraint = rz_core_rop_constraint_parse_args(core, str1); + RzGadgetConstraint *rop_constraint = rz_core_gadget_constraint_parse_args(core, str1); mu_assert_notnull(rop_constraint, "parse_reg_constraints failed on valid input"); mu_assert_eq(rop_constraint->type, MOV_CONST, "Invalid constraint type"); mu_assert_streq(rop_constraint->args[DST_REG], "eax", "Invalid destination register"); mu_assert_null(rop_constraint->args[SRC_REG], "Source register should be NULL"); mu_assert_streq(rop_constraint->args[SRC_CONST], "123", "Invalid constant value"); - rz_core_rop_constraint_free(rop_constraint); + rz_core_gadget_constraint_free(rop_constraint); // Test case 2: Invalid format char str2[] = "eax ="; - rop_constraint = rz_core_rop_constraint_parse_args(core, str2); + rop_constraint = rz_core_gadget_constraint_parse_args(core, str2); mu_assert_null(rop_constraint, "parse_reg_constraints failed on invalid input"); - rz_core_rop_constraint_free(rop_constraint); + rz_core_gadget_constraint_free(rop_constraint); rz_core_free(core); mu_end; @@ -70,18 +71,18 @@ bool test_parse_reg_to_reg(void) { // Test case 1: Valid register to register char str1[] = "eax = ebx "; - RzRopConstraint *rop_constraint = rz_core_rop_constraint_parse_args(core, str1); + RzGadgetConstraint *rop_constraint = rz_core_gadget_constraint_parse_args(core, str1); mu_assert_notnull(rop_constraint, "parse_reg_constraints failed on valid input"); mu_assert_eq(rop_constraint->type, MOV_REG, "Invalid constraint type"); mu_assert_streq(rop_constraint->args[DST_REG], "eax", "Invalid destination register"); mu_assert_streq(rop_constraint->args[SRC_REG], "ebx", "Invalid source register"); - rz_core_rop_constraint_free(rop_constraint); + rz_core_gadget_constraint_free(rop_constraint); // Test case 2: Invalid format char str2[] = "eax ="; - rop_constraint = rz_core_rop_constraint_parse_args(core, str2); + rop_constraint = rz_core_gadget_constraint_parse_args(core, str2); mu_assert_null(rop_constraint, "parse_reg_constraints failed on invalid input"); - rz_core_rop_constraint_free(rop_constraint); + rz_core_gadget_constraint_free(rop_constraint); rz_core_free(core); mu_end; @@ -94,53 +95,53 @@ bool test_parse_reg_op_const(void) { // Test case 1: Valid register operation with constant char str1[] = "eax=eax+3"; - RzRopConstraint *rop_constraint = rz_core_rop_constraint_parse_args(core, str1); + RzGadgetConstraint *rop_constraint = rz_core_gadget_constraint_parse_args(core, str1); mu_assert_notnull(rop_constraint, "parse_reg_constraints failed on valid input"); mu_assert_eq(rop_constraint->type, MOV_OP_CONST, "Invalid constraint type"); mu_assert_streq(rop_constraint->args[DST_REG], "eax", "Invalid destination register"); mu_assert_streq(rop_constraint->args[SRC_REG], "eax", "Invalid source register"); mu_assert_streq(rop_constraint->args[OP], "add", "Invalid operator"); mu_assert_streq(rop_constraint->args[SRC_CONST], "3", "Invalid constant value"); - rz_core_rop_constraint_free(rop_constraint); + rz_core_gadget_constraint_free(rop_constraint); // Test case 2: Invalid format char str2[] = "eax=eax+"; - rop_constraint = rz_core_rop_constraint_parse_args(core, str2); + rop_constraint = rz_core_gadget_constraint_parse_args(core, str2); mu_assert_null(rop_constraint, "parse_reg_constraints failed on invalid input"); - rz_core_rop_constraint_free(rop_constraint); + rz_core_gadget_constraint_free(rop_constraint); // Test case 3: Valid register operation with increment operator char str3[] = "eax++"; - rop_constraint = rz_core_rop_constraint_parse_args(core, str3); + rop_constraint = rz_core_gadget_constraint_parse_args(core, str3); mu_assert_notnull(rop_constraint, "parse_reg_constraints failed on valid input"); mu_assert_eq(rop_constraint->type, MOV_OP_CONST, "Invalid constraint type"); mu_assert_streq(rop_constraint->args[DST_REG], "eax", "Invalid destination register"); mu_assert_streq(rop_constraint->args[SRC_REG], "eax", "Invalid source register"); mu_assert_streq(rop_constraint->args[OP], "add", "Invalid operator"); mu_assert_streq(rop_constraint->args[SRC_CONST], "1", "Invalid constant value"); - rz_core_rop_constraint_free(rop_constraint); + rz_core_gadget_constraint_free(rop_constraint); // Test case 4: Valid register operation with decrement operator char str4[] = "eax--"; - rop_constraint = rz_core_rop_constraint_parse_args(core, str4); + rop_constraint = rz_core_gadget_constraint_parse_args(core, str4); mu_assert_notnull(rop_constraint, "parse_reg_constraints failed on valid input"); mu_assert_eq(rop_constraint->type, MOV_OP_CONST, "Invalid constraint type"); mu_assert_streq(rop_constraint->args[DST_REG], "eax", "Invalid destination register"); mu_assert_streq(rop_constraint->args[SRC_REG], "eax", "Invalid source register"); mu_assert_streq(rop_constraint->args[OP], "sub", "Invalid operator"); mu_assert_streq(rop_constraint->args[SRC_CONST], "1", "Invalid constant value"); - rz_core_rop_constraint_free(rop_constraint); + rz_core_gadget_constraint_free(rop_constraint); // Test case 5: Valid register operation with compound operator char str5[] = "eax *= 1"; - rop_constraint = rz_core_rop_constraint_parse_args(core, str5); + rop_constraint = rz_core_gadget_constraint_parse_args(core, str5); mu_assert_notnull(rop_constraint, "parse_reg_constraints failed on valid input"); mu_assert_eq(rop_constraint->type, MOV_OP_CONST, "Invalid constraint type"); mu_assert_streq(rop_constraint->args[DST_REG], "eax", "Invalid destination register"); mu_assert_streq(rop_constraint->args[SRC_REG], "eax", "Invalid source register"); mu_assert_streq(rop_constraint->args[OP], "mul", "Invalid operator"); mu_assert_streq(rop_constraint->args[SRC_CONST], "1", "Invalid constant value"); - rz_core_rop_constraint_free(rop_constraint); + rz_core_gadget_constraint_free(rop_constraint); rz_core_free(core); mu_end; @@ -153,31 +154,31 @@ bool test_parse_reg_op_reg(void) { // Test case 1: Valid register operation with register char str1[] = "eax=ebx-ecx"; - RzRopConstraint *rop_constraint = rz_core_rop_constraint_parse_args(core, str1); + RzGadgetConstraint *rop_constraint = rz_core_gadget_constraint_parse_args(core, str1); mu_assert_notnull(rop_constraint, "parse_reg_constraints failed on valid input"); mu_assert_eq(rop_constraint->type, MOV_OP_REG, "Invalid constraint type"); mu_assert_streq(rop_constraint->args[DST_REG], "eax", "Invalid destination register"); mu_assert_streq(rop_constraint->args[SRC_REG], "ebx", "Invalid source register"); mu_assert_streq(rop_constraint->args[OP], "sub", "Invalid operator"); mu_assert_streq(rop_constraint->args[SRC_REG_SECOND], "ecx", "Invalid destination constant register"); - rz_core_rop_constraint_free(rop_constraint); + rz_core_gadget_constraint_free(rop_constraint); // Test case 2: Invalid format char str2[] = "eax = eax+ "; - rop_constraint = rz_core_rop_constraint_parse_args(core, str2); + rop_constraint = rz_core_gadget_constraint_parse_args(core, str2); mu_assert_null(rop_constraint, "parse_reg_constraints failed on invalid input"); - rz_core_rop_constraint_free(rop_constraint); + rz_core_gadget_constraint_free(rop_constraint); // Test case 3: Valid register operation with register char str3[] = "eax += ebx"; - rop_constraint = rz_core_rop_constraint_parse_args(core, str3); + rop_constraint = rz_core_gadget_constraint_parse_args(core, str3); mu_assert_notnull(rop_constraint, "parse_reg_constraints failed on valid input"); mu_assert_eq(rop_constraint->type, MOV_OP_REG, "Invalid constraint type"); mu_assert_streq(rop_constraint->args[DST_REG], "eax", "Invalid destination register"); mu_assert_streq(rop_constraint->args[SRC_REG], "eax", "Invalid source register"); mu_assert_streq(rop_constraint->args[SRC_REG_SECOND], "ebx", "Invalid destination constant register"); mu_assert_streq(rop_constraint->args[OP], "add", "Invalid operator"); - rz_core_rop_constraint_free(rop_constraint); + rz_core_gadget_constraint_free(rop_constraint); rz_core_free(core); mu_end;