diff --git a/librz/arch/analysis.c b/librz/arch/analysis.c index 8414332e76a..8c32fae42d5 100644 --- a/librz/arch/analysis.c +++ b/librz/arch/analysis.c @@ -8,7 +8,6 @@ #include #include #include -#include /** * \brief Returns the default size byte width of memory access operations. @@ -130,7 +129,9 @@ RZ_API RzAnalysis *rz_analysis_new(void) { } } 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->is_rop_analysis = false; analysis->global_var_tree = NULL; analysis->il_vm = NULL; analysis->hash = rz_hash_new(); @@ -187,7 +188,7 @@ RZ_API RzAnalysis *rz_analysis_free(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); + ht_up_free(a->ht_rop_semantics); rz_list_free(a->plugins); rz_analysis_debug_info_free(a->debug_info); free(a); diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index e0c0ab9f0de..f39a13e743d 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -230,18 +230,18 @@ RZ_IPI RzCmdStatus rz_cmd_info_gadget_handler(RzCore *core, int argc, const char } RZ_IPI RzCmdStatus rz_cmd_query_gadget_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - RzList /**/ *constraints = rop_constraint_list_parse(core, argc, argv); + RzPVector /**/ *constraints = rop_constraint_map_parse(core, argc, argv); if (!constraints) { return RZ_CMD_STATUS_ERROR; } - if (rz_list_empty(constraints)) { - rz_list_free(constraints); + if (rz_pvector_empty(constraints)) { + rz_pvector_fini(constraints); return RZ_CMD_STATUS_INVALID; } RzRopSearchContext *context = rz_core_rop_search_context_new(core, argv[1], false, RZ_ROP_GADGET_PRINT, state); const RzCmdStatus cmd_status = rz_core_rop_search(core, context); - rz_list_free(constraints); + rz_pvector_fini(constraints); return cmd_status; } @@ -256,10 +256,8 @@ RZ_IPI RzCmdStatus rz_cmd_search_gadget_handler(RzCore *core, int argc, const ch 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, true, RZ_ROP_GADGET_PRINT_DETAIL | RZ_ROP_GADGET_ANALYZE, state); + RzRopSearchContext *context = rz_core_rop_search_context_new(core, input, false, RZ_ROP_GADGET_PRINT_DETAIL | RZ_ROP_GADGET_ANALYZE, state); return rz_core_rop_search(core, context); - ; } static void cmd_search_bin(RzCore *core, RzInterval itv) { diff --git a/librz/core/cmd/cmd_search_rop.c b/librz/core/cmd/cmd_search_rop.c index 7b88c5f114b..40fc93b1f24 100644 --- a/librz/core/cmd/cmd_search_rop.c +++ b/librz/core/cmd/cmd_search_rop.c @@ -298,6 +298,8 @@ RZ_OWN RZ_API RzRopSearchContext *rz_core_rop_search_context_new(RZ_NONNULL cons } context->greparg = greparg ? strdup(greparg) : NULL; + context->mode_str = rz_config_get(core->config, "search.in"); + context->arch = rz_config_get(core->config, "asm.arch"); context->regexp = regexp; context->mask = mask; context->state = state; @@ -310,6 +312,7 @@ RZ_OWN RZ_API RzRopSearchContext *rz_core_rop_search_context_new(RZ_NONNULL cons 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"); return context; } @@ -401,7 +404,7 @@ static bool parse_reg_op_reg(const RzCore *core, const char *str, RzRopConstrain * * The function returns true if any of these parsing methods succeed. */ -RZ_API bool rz_core_rop_analyze_constraint(RzCore *core, const char *str, RzRopConstraint *rop_constraint) { +RZ_API bool rz_core_rop_analyze_constraint(RZ_NONNULL RzCore *core, const char *str, RzRopConstraint *rop_constraint) { rz_return_val_if_fail(core, false); return parse_reg_to_const(core, str, rop_constraint) || parse_reg_to_reg(core, str, rop_constraint) || @@ -433,16 +436,28 @@ static RzRopConstraint *rop_constraint_parse_args(RzCore *core, char *token) { return rop_constraint; } -static RzList /**/ *rop_constraint_list_parse(RzCore *core, const int argc, const char **argv) { - RzList *constr_list = rz_rop_constraint_list_new(); +/** + * \brief Parse rop constraint map + * \param core Pointer to the RzCore object. + * \param argc Number of arguments. + * \param argv Array of arguments. + * \return RzPVector of RzRopConstraint objects. + * + * This function parses a list of arguments into a RzPVector of RzRopConstraint objects. + */ +RZ_API RzPVector /**/ *rop_constraint_map_parse(RZ_NONNULL RzCore *core, const int argc, const char **argv) { + RzPVector *constr_map = rz_core_rop_constraint_map_new(); + if (!constr_map) { + return NULL; + } for (int i = 1; i < argc; i++) { RzList *l = rz_str_split_duplist_n(argv[i], ",", 1, false); if (!l) { - return constr_list; + return constr_map; } size_t llen = rz_list_length(l); if (!llen) { - return constr_list; + return constr_map; } RzListIter *it; char *token; @@ -451,9 +466,9 @@ static RzList /**/ *rop_constraint_list_parse(RzCore *core, co if (!rop_constraint) { continue; } - rz_list_append(constr_list, rop_constraint); + rz_pvector_push(constr_map, rop_constraint); } rz_list_free(l); } - return constr_list; + return constr_map; } \ No newline at end of file diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index 38454b5d69a..7c49d03b6e9 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -19247,7 +19247,7 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) { rz_warn_if_fail(cmd_query_gadget_cd); rz_cmd_desc_set_default_mode(cmd_query_gadget_cd, RZ_OUTPUT_MODE_STANDARD); - RzCmdDesc *cmd_detail_gadget_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_R_cd, "/Rg", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_detail_gadget_handler, &cmd_detail_gadget_help); + RzCmdDesc *cmd_detail_gadget_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_R_cd, "/Rg", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_detail_gadget_handler, &cmd_detail_gadget_help); rz_warn_if_fail(cmd_detail_gadget_cd); rz_cmd_desc_set_default_mode(cmd_detail_gadget_cd, RZ_OUTPUT_MODE_STANDARD); diff --git a/librz/core/cmd_descs/cmd_search.yaml b/librz/core/cmd_descs/cmd_search.yaml index 9d964e866ef..4cb3f3777eb 100644 --- a/librz/core/cmd_descs/cmd_search.yaml +++ b/librz/core/cmd_descs/cmd_search.yaml @@ -57,8 +57,6 @@ commands: modes: - RZ_OUTPUT_MODE_STANDARD - RZ_OUTPUT_MODE_JSON - - RZ_OUTPUT_MODE_QUIET - - RZ_OUTPUT_MODE_TABLE args: - name: Gadget address type: RZ_CMD_ARG_TYPE_STRING diff --git a/librz/core/rop.c b/librz/core/rop.c index 78bb850e4a2..3cbc7a4e222 100644 --- a/librz/core/rop.c +++ b/librz/core/rop.c @@ -7,6 +7,49 @@ #include #include +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) { + rz_return_val_if_fail(core && core->analysis && hit, false); + bool status = false; + RzAnalysisOp aop = { 0 }; + ut8 *buf = malloc(hit->len); + if (rz_io_nread_at(core->io, hit->addr, buf, hit->len) < 0) { + free(buf); + return status; + } + rz_analysis_op_init(&aop); + if (rz_analysis_op(core->analysis, &aop, hit->addr, buf, hit->len, RZ_ANALYSIS_OP_MASK_DISASM) < 0) { + free(buf); + return status; + } + switch (aop.type) { + case RZ_ANALYSIS_OP_TYPE_RET: + if (crop) { + status = is_cond_end_gadget(&aop); + break; + } + status = true; + break; + default: + break; + } + rz_analysis_op_fini(&aop); + free(buf); + return status; +} + static bool is_end_gadget(const RzAnalysisOp *aop, const ut8 crop) { if (aop->family == RZ_ANALYSIS_OP_FAMILY_SECURITY) { return false; @@ -24,20 +67,9 @@ static bool is_end_gadget(const RzAnalysisOp *aop, const ut8 crop) { case RZ_ANALYSIS_OP_TYPE_IRJMP: case RZ_ANALYSIS_OP_TYPE_JMP: case RZ_ANALYSIS_OP_TYPE_CALL: - return true; - default: - return false; - } - - if (!crop) { - return false; - } - 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: + if (crop) { + return is_cond_end_gadget(aop); + } return true; default: return false; @@ -197,11 +229,16 @@ RZ_IPI void rz_core_rop_reg_info_free(RzRopRegInfo *reg_info) { return; } free(reg_info->name); + free(reg_info->value_transformations); free(reg_info); } RZ_IPI RzRopRegInfo *rz_core_rop_reg_info_new(const RzCore *core, 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); + if (!reg_info) { + return NULL; + } const char *name = NULL; if (evt->type == RZ_IL_EVENT_VAR_READ) { reg_info->is_var_read = true; @@ -210,9 +247,6 @@ RZ_IPI RzRopRegInfo *rz_core_rop_reg_info_new(const RzCore *core, const RzILEven reg_info->is_var_write = true; name = evt->data.var_write.variable; } - if (!reg_info) { - return NULL; - } const RzList *head = rz_reg_get_list(core->analysis->reg, RZ_REG_TYPE_GPR); if (!head) { free(reg_info); @@ -233,6 +267,8 @@ RZ_IPI RzRopRegInfo *rz_core_rop_reg_info_new(const RzCore *core, const RzILEven } reg_info->init_val = init_val; reg_info->new_val = new_val; + reg_info->bits = core->analysis->bits; + reg_info->value_transformations = NULL; // Fill this as you need return reg_info; } @@ -284,9 +320,9 @@ RZ_API void rz_core_rop_gadget_info_free(RZ_NULLABLE RzRopGadgetInfo *gadget_inf */ 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_return_if_fail(gadget_info && reg_info); + rz_return_if_fail(gadget_info); - if (!is_dependency) { + if (!is_dependency && reg_info) { rz_pvector_push(gadget_info->modified_registers, reg_info); } } @@ -358,42 +394,110 @@ RZ_IPI RzRopRegInfo *rz_core_rop_reg_info_dup(RzRopRegInfo *src) { return dup; } -static bool is_stack_pointer(const RzCore *core, const char *name) { - RzRegItem *reg_item = rz_reg_get(core->analysis->reg, name, RZ_REG_TYPE_GPR); - if (!reg_item) { - return false; - } - if (core->analysis->bits == 32 && RZ_STR_EQ(core->analysis->cpu, "x86")) { - return !strcmp(reg_item->name, "esp"); - } - if (core->analysis->bits == 64) { - return !strcmp(reg_item->name, "rsp") || !strcmp(reg_item->name, "esp"); - } - if (core->analysis->bits == 64 && !strcmp(core->analysis->cpu, "arm")) { - return !strcmp(reg_item->name, "r13"); +/** + * \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. + * \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. + */ +RZ_API bool rz_core_rop_gadget_info_has_register(const RZ_NONNULL RzRopGadgetInfo *gadget_info, RZ_NONNULL const 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; + if (RZ_STR_EQ(reg_info->name, name)) { + return true; + } } - return reg_item->name; + return false; } -static bool is_base_pointer(const RzCore *core, const char *name) { - RzRegItem *reg_item = rz_reg_get(core->analysis->reg, name, RZ_REG_TYPE_GPR); - if (!reg_item) { - return false; +static bool is_var_write_event(const RzRopRegInfo *reg_info) { + return reg_info->is_var_write; +} + +static bool is_mem_read_event(const RzRopRegInfo *reg_info) { + return reg_info->is_mem_read; +} + +static bool is_mem_write_event(const RzRopRegInfo *reg_info) { + return reg_info->is_mem_write; +} + +static bool is_pc_write_event(const RzRopRegInfo *reg_info) { + return reg_info->is_pc_write; +} + +rz_rop_event_check_fn rz_rop_event_functions[RZ_ROP_EVENT_COUNT] = { + is_var_write_event, + is_mem_read_event, + is_mem_write_event, + is_pc_write_event, +}; + +/** + * \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. + */ +RZ_API RzPVector /**/ *rz_core_rop_gadget_get_reg_info_by_event(const RZ_NONNULL RzRopGadgetInfo *gadget_info, const RzRopEvent event) { + rz_return_val_if_fail(gadget_info, NULL); + if (event < 0 || event >= RZ_ROP_EVENT_COUNT) { + return NULL; } - if (core->analysis->bits == 32 && RZ_STR_EQ(core->analysis->cpu, "x86")) { - return RZ_STR_EQ(reg_item->name, "ebp"); + RzPVector *matches = rz_pvector_new((RzPVectorFree)rz_core_rop_reg_info_free); + RzListIter *iter; + RzRopRegInfo *reg_info; + rz_list_foreach (gadget_info->dependencies, iter, reg_info) { + if (rz_rop_event_functions[event](reg_info)) { + rz_pvector_push(matches, reg_info); + } } - if (core->analysis->bits == 64) { - return RZ_STR_EQ(reg_item->name, "rbp") || RZ_STR_EQ(reg_item->name, "ebp"); + 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. + * \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. + * + * Searches the modified registers in the RzRopGadgetInfo object for all registers with the given registers and returns their info in a vector. + */ +RZ_API RzPVector /**/ *rz_core_rop_get_reg_info_by_reg_names(const RZ_NONNULL RzRopGadgetInfo *gadget_info, + RZ_NONNULL const RzPVector /**/ *registers) { + rz_return_val_if_fail(gadget_info && registers, NULL); + + RzPVector *result = rz_pvector_new((RzPVectorFree)rz_core_rop_reg_info_free); + void **it; + rz_pvector_foreach (gadget_info->modified_registers, it) { + RzRopRegInfo *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)) { + rz_pvector_push(result, rz_core_rop_reg_info_dup(reg_info)); + break; + } + } } - if (core->analysis->bits == 64 && !strcmp(core->analysis->cpu, "arm")) { - return RZ_STR_EQ(reg_item->name, "r11"); + + if (rz_pvector_empty(result)) { + rz_pvector_free(result); + return NULL; } - return reg_item->name; + + return result; } static void rz_rop_gadget_info_add_dependency(const RzCore *core, RzRopGadgetInfo *gadget_info, const RzILEvent *evt, RzRopRegInfo *reg_info) { - + rz_return_if_fail(core && core->analysis && core->analysis->reg); + if (!reg_info) { + return; + } RzRopRegInfo *reg_info_dup = rz_core_rop_reg_info_dup(reg_info); if (!reg_info_dup) { return; @@ -401,16 +505,16 @@ static void rz_rop_gadget_info_add_dependency(const RzCore *core, RzRopGadgetInf switch (evt->type) { case RZ_IL_EVENT_MEM_READ: { const RzILEventMemRead *mem_read = &evt->data.mem_read; - reg_info->is_mem_read = true; - reg_info->is_mem_write = false; - reg_info->is_var_write = false; + reg_info_dup->is_mem_read = true; + reg_info_dup->is_mem_write = false; + reg_info_dup->is_var_write = false; reg_info_dup->new_val = rz_bv_to_ut64(mem_read->address); break; } case RZ_IL_EVENT_MEM_WRITE: { - reg_info->is_mem_write = true; - reg_info->is_mem_read = false; - reg_info->is_var_write = false; + reg_info_dup->is_mem_write = true; + reg_info_dup->is_mem_read = false; + reg_info_dup->is_var_write = false; const RzILEventMemWrite *mem_write = &evt->data.mem_write; reg_info_dup->init_val = rz_bv_to_ut64(mem_write->old_value); reg_info_dup->new_val = rz_bv_to_ut64(mem_write->new_value); @@ -429,8 +533,8 @@ static void rz_rop_gadget_info_add_dependency(const RzCore *core, RzRopGadgetInf break; } reg_info_dup->new_val = rz_bv_to_ut64(new_val); - if (is_stack_pointer(core, reg_info->name)) { - gadget_info->stack_change += rz_bv_to_ut64(new_val) - reg_info->new_val; + if (rz_reg_is_role(core->analysis->reg, reg_info->name, RZ_REG_NAME_SP)) { + gadget_info->stack_change += rz_bv_to_ut64(new_val) - rz_bv_to_ut64(init_val); } rz_bv_free(init_val); rz_bv_free(new_val); @@ -448,6 +552,10 @@ static int fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadge if (!gadget_info) { return -1; } + const RzList *head = rz_reg_get_list(core->analysis->reg, RZ_REG_TYPE_GPR); + if (!head) { + return -1; + } switch (event->type) { case RZ_IL_EVENT_VAR_READ: { const RzILEventVarRead *var_read = &event->data.var_read; @@ -471,11 +579,27 @@ static int fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadge break; } if (is_dependency && curr_event) { - // shouldn't take this path if it is a dependency + bool is_stack_evt = false; if (curr_event->type == RZ_IL_EVENT_VAR_READ) { break; } + // Stack reads during pop, push + if (rz_reg_is_role(core->analysis->reg, var_read->variable, RZ_REG_NAME_SP)) { + is_stack_evt = true; + RzBitVector *val = rz_il_value_to_bv(var_read->value); + if (!val) { + break; + } + reg_info = rz_core_rop_reg_info_new(core, event, rz_bv_to_ut64(val), rz_bv_to_ut64(val)); + if (!reg_info) { + break; + } + rz_bv_free(val); + } rz_rop_gadget_info_add_dependency(core, gadget_info, curr_event, reg_info); + if (is_stack_evt) { + rz_core_rop_reg_info_free(reg_info); + } break; } if (reg_info) { @@ -485,40 +609,33 @@ static int fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadge if (!val) { break; } - reg_info = rz_core_rop_reg_info_new(core, event, rz_bv_to_ut64(val), rz_bv_to_ut64(val)); - rz_core_rop_gadget_info_add_register(gadget_info, reg_info, is_dependency); if (!is_dependency) { rz_pvector_push(vec, event); } rz_bv_free(val); } break; case RZ_IL_EVENT_VAR_WRITE: { + RzListIter *iter_dst; + RzRegItem *item_dst; if (is_dependency) { break; } - while (!rz_pvector_empty(vec)) { - RzILEvent *evt = rz_pvector_pop(vec); - fill_rop_gadget_info_from_events(core, gadget_info, event, evt, vec, true); - } const RzILEventVarWrite *var_write = &event->data.var_write; - RzRopRegInfo *reg_info = rz_core_rop_gadget_info_get_modified_register(gadget_info, var_write->variable); - if (reg_info && !is_dependency) { - RzRopRegInfo *new_reg_info = rz_core_rop_reg_info_dup(reg_info); - if (!new_reg_info) { + bool is_reg = false; + rz_list_foreach (head, iter_dst, item_dst) { + if (RZ_STR_EQ(var_write->variable, item_dst->name) && item_dst->type == RZ_REG_TYPE_GPR) { + is_reg = true; break; } - RzBitVector *old_val = rz_il_value_to_bv(var_write->old_value); - RzBitVector *new_val = rz_il_value_to_bv(var_write->old_value); - if (old_val && new_val) { - new_reg_info->new_val = rz_bv_to_ut64(new_val); - new_reg_info->is_mem_write = true; - rz_core_rop_gadget_info_update_register(gadget_info, new_reg_info); - } - rz_bv_free(old_val); - rz_bv_free(new_val); + } + if (!is_reg) { break; } - + while (!rz_pvector_empty(vec)) { + RzILEvent *evt = rz_pvector_pop(vec); + fill_rop_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); 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); @@ -549,6 +666,8 @@ static int fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadge case RZ_IL_EVENT_PC_WRITE: { if (!gadget_info->is_pc_write) { gadget_info->is_pc_write = true; + } else { + gadget_info->is_syscall = true; } } break; default: @@ -582,7 +701,8 @@ static int analyze_gadget(RzCore *core, const RzCoreAsmHit *hit, RzRopGadgetInfo rz_pvector_init(&vec, (RzPVectorFree)rz_il_event_free); rz_pvector_foreach (vm->events, it) { RzILEvent *evt = *it; - ret = fill_rop_gadget_info_from_events(core, rop_gadget_info, NULL, evt, &vec, false); + ret = fill_rop_gadget_info_from_events(core, rop_gadget_info, NULL, evt, + &vec, false); if (ret < 0) { break; } @@ -594,33 +714,108 @@ static int analyze_gadget(RzCore *core, const RzCoreAsmHit *hit, RzRopGadgetInfo return ret; } -static void print_rop_gadget_info(const RzCore *core, const RzRopGadgetInfo *gadget_info) { - rz_cons_printf("\nGadget 0x%" PFMT64x "\n", gadget_info->address); +static void rz_rop_gadget_print_standard_mode(const RzCore *core, const RzRopGadgetInfo *gadget_info) { + rz_return_if_fail(core && core->analysis && core->analysis->reg && gadget_info); + + rz_cons_printf("Gadget 0x%" PFMT64x "\n", gadget_info->address); rz_cons_printf("Stack change: 0x%" PFMT64x "\n", gadget_info->stack_change); rz_cons_printf("Changed registers: "); - RzRopRegInfo *reg_info; void **it; + RzRopRegInfo *reg_info; rz_pvector_foreach (gadget_info->modified_registers, it) { reg_info = *it; + rz_cons_printf("%s ", reg_info->name); + } + rz_cons_printf("\n"); + + rz_cons_printf("Register dependencies:\n"); + RzListIter *iter; + rz_list_foreach (gadget_info->dependencies, iter, reg_info) { + if (rz_reg_is_role(core->analysis->reg, reg_info->name, RZ_REG_NAME_SP) || + rz_reg_is_role(core->analysis->reg, reg_info->name, RZ_REG_NAME_BP)) { + continue; + } if (reg_info->is_var_write) { - rz_cons_printf("%s ", reg_info->name); + rz_cons_printf("Var write: %s Initial value: %llu New Value: %llu\n", reg_info->name, reg_info->init_val, reg_info->new_val); + } else if (reg_info->is_mem_read) { + rz_cons_printf("Memory Read: %s Value: %llu\n", reg_info->name, reg_info->new_val); + } else if (reg_info->is_mem_write) { + rz_cons_printf("Memory Write: %s Initial Value: %llu New Value: %llu\n", reg_info->name, reg_info->init_val, reg_info->new_val); } } - rz_cons_printf("\nRegister dependencies:\n"); + rz_cons_printf("\n"); +} + +static void rz_rop_gadget_print_json_mode(const RzCore *core, const RzRopGadgetInfo *gadget_info, PJ *pj) { + rz_return_if_fail(gadget_info && pj); + + pj_o(pj); + pj_kn(pj, "address", gadget_info->address); + pj_kn(pj, "stack_change", gadget_info->stack_change); + + pj_k(pj, "modified_registers"); + pj_a(pj); + void **it; + RzRopRegInfo *reg_info; + rz_pvector_foreach (gadget_info->modified_registers, it) { + reg_info = *it; + pj_o(pj); + pj_ks(pj, "name", reg_info->name); + pj_ks(pj, "type", "var_write"); + pj_end(pj); + } + pj_end(pj); + + pj_k(pj, "dependencies"); + pj_a(pj); RzListIter *iter; rz_list_foreach (gadget_info->dependencies, iter, reg_info) { - if (is_stack_pointer(core, reg_info->name) || is_base_pointer(core, reg_info->name)) { + if (rz_reg_is_role(core->analysis->reg, reg_info->name, RZ_REG_NAME_SP) || + rz_reg_is_role(core->analysis->reg, reg_info->name, RZ_REG_NAME_BP)) { continue; } + pj_o(pj); + pj_ks(pj, "name", reg_info->name); if (reg_info->is_var_write) { - rz_cons_printf("Var write: %s %llu %llu\n", reg_info->name, reg_info->init_val, reg_info->new_val); + pj_ks(pj, "type", "var_write"); + pj_kn(pj, "init_val", reg_info->init_val); + pj_kn(pj, "new_val", reg_info->new_val); } else if (reg_info->is_mem_read) { - rz_cons_printf("Memory Read: %s %llu\n", reg_info->name, reg_info->new_val); + pj_ks(pj, "type", "mem_read"); + pj_kn(pj, "new_val", reg_info->new_val); } else if (reg_info->is_mem_write) { - rz_cons_printf("Memory Write: %s %llu %llu\n", reg_info->name, reg_info->init_val, reg_info->new_val); + pj_ks(pj, "type", "mem_write"); + pj_kn(pj, "init_val", reg_info->init_val); + pj_kn(pj, "new_val", reg_info->new_val); } + pj_end(pj); + } + pj_end(pj); + + pj_end(pj); +} + +static void print_rop_gadget_info(const RzCore *core, const RzRopGadgetInfo *gadget_info, const RzRopSearchContext *context) { + rz_return_if_fail(gadget_info && context && context->state); + if (RZ_STR_NE(context->greparg, "")) { + const ut64 addr = rz_num_math(core->num, context->greparg); + if (!addr || gadget_info->address != addr) { + return; + } + } + + switch (context->state->mode) { + case RZ_OUTPUT_MODE_JSON: + rz_rop_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); + break; + default: + rz_warn_if_reached(); + break; } } @@ -734,7 +929,10 @@ 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) { - const int error = rz_analysis_op(core->analysis, aop, addr, buf, buf_len, RZ_ANALYSIS_OP_MASK_DISASM); + 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; + } if (error < 0 || (aop->type == RZ_ANALYSIS_OP_TYPE_NOP && aop->size == 0)) { return false; } @@ -745,6 +943,7 @@ static bool process_instruction(const RzCore *core, RzAnalysisOp *aop, const int } static bool is_invalid_instruction(const char *opst, const int end_gadget_cnt) { + rz_return_val_if_fail(opst, false); return !rz_str_ncasecmp(opst, "invalid", strlen("invalid")) || !rz_str_ncasecmp(opst, ".byte", strlen(".byte")) || end_gadget_cnt > 1; @@ -774,20 +973,19 @@ 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) { - int endaddr = end_gadget->instr_offset; const char *start = NULL, *end = NULL; - char *grep_str = NULL; - RzCoreAsmHit *hit = NULL; - bool valid = false; - char *rx = NULL; int count = 0; - - RzStrBuf *sb = rz_strbuf_new(""); - init_grep_context(context, &grep_str, &start, &end, rx_list, &rx, &count); + char *rx = NULL; + char *grep_str = NULL; + bool is_greparg = !(context->mask & (RZ_ROP_GADGET_PRINT_DETAIL | RZ_ROP_GADGET_ANALYZE)) && 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(); if (!hitlist) { - goto cleanup; + free(grep_str); + return NULL; } ut8 nb_instr = 0; @@ -796,6 +994,8 @@ static RzList /**/ *construct_rop_gadget(RzCore *core, ut8 *buf, ut32 end_gadget_cnt = 0; RzAnalysisOp aop = { 0 }; + bool valid = false; + 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)) { @@ -805,7 +1005,7 @@ static RzList /**/ *construct_rop_gadget(RzCore *core, ut8 *buf, char *opst = aop.mnemonic; RzAsmOp asmop = RZ_EMPTY; - int ret = rz_asm_disassemble(core->rasm, &asmop, buf + idx, delta - idx) < 0; + int ret = rz_asm_disassemble(core->rasm, &asmop, buf + idx, delta - idx); if (ret < 0) { valid = false; goto cleanup; @@ -816,7 +1016,7 @@ static RzList /**/ *construct_rop_gadget(RzCore *core, ut8 *buf, goto cleanup; } - hit = rz_core_asm_hit_new(); + RzCoreAsmHit *hit = rz_core_asm_hit_new(); if (!hit) { valid = false; goto cleanup; @@ -838,15 +1038,15 @@ static RzList /**/ *construct_rop_gadget(RzCore *core, ut8 *buf, if (rx) { int grep_find = rz_regex_contains(rx, opst, RZ_REGEX_ZERO_TERMINATED, RZ_REGEX_EXTENDED, RZ_REGEX_DEFAULT); search_hit = end && context->greparg && grep_find; - } else { + } else if (is_greparg) { search_hit = end && context->greparg && strstr(opst, grep_str); } if (search_hit) { update_search_context(context, &start, &end, &grep_str, rx_list, &rx, &count); } - if (endaddr <= idx - aop.size) { - valid = endaddr == idx - aop.size; + if (end_gadget->instr_offset <= idx - aop.size) { + valid = end_gadget->instr_offset == idx - aop.size; goto cleanup; } rz_analysis_op_fini(&aop); @@ -856,7 +1056,7 @@ static RzList /**/ *construct_rop_gadget(RzCore *core, ut8 *buf, cleanup: rz_analysis_op_fini(&aop); free(grep_str); - if ((context->regexp && rx) || (!valid || (context->greparg && end))) { + if ((context->regexp && rx) || (!valid || (is_greparg && end))) { rz_list_free(hitlist); rz_strbuf_free(sb); return NULL; @@ -869,7 +1069,37 @@ static RzList /**/ *construct_rop_gadget(RzCore *core, ut8 *buf, return hitlist; } -static int handle_rop_request_type(RzCore *core, RzRopSearchContext *context, RzList /**/ *hitlist) { +static RzRopGadgetInfo *perform_gadget_analysis(RzCore *core, const RzRopSearchContext *context, const RzList /**/ *hitlist) { + RzRopGadgetInfo *rop_gadget_info = NULL; + + if (!core->analysis->ht_rop_semantics) { + core->analysis->ht_rop_semantics = ht_up_new(NULL, (HtUPFreeValue)rz_core_rop_gadget_info_free); + } + const RzCoreAsmHit *hit_last = (RzCoreAsmHit *)rz_list_last(hitlist); + if (!is_ret_gadget(core, hit_last, context->crop)) { + return rop_gadget_info; + } + const ut64 addr_start = ((RzCoreAsmHit *)rz_list_first(hitlist))->addr; + rop_gadget_info = ht_up_find(core->analysis->ht_rop_semantics, addr_start, NULL); + if (!rop_gadget_info) { + RzListIter *iter; + RzCoreAsmHit *hit; + rop_gadget_info = rz_core_rop_gadget_info_new(addr_start); + const bool is_rop_analysis = core->analysis->is_rop_analysis; + core->analysis->is_rop_analysis = true; + rz_list_foreach (hitlist, iter, hit) { + if (analyze_gadget(core, hit, rop_gadget_info) < 0) { + RZ_LOG_WARN("Failed to analyze gadget at 0x%" PFMT64x "\n", hit->addr); + } + } + core->analysis->is_rop_analysis = is_rop_analysis; + ht_up_insert(core->analysis->ht_rop_semantics, addr_start, rop_gadget_info); + } + + return rop_gadget_info; +} + +static int handle_rop_request_type(RzCore *core, const RzRopSearchContext *context, RzList /**/ *hitlist) { rz_return_val_if_fail(core && core->analysis, -1); if (context->mask & RZ_ROP_GADGET_PRINT) { if (context->subchain) { @@ -881,28 +1111,19 @@ static int handle_rop_request_type(RzCore *core, RzRopSearchContext *context, Rz print_rop(core, hitlist, context->state); } } - if (rz_config_get_i(core->config, "rop.cache") && !core->analysis->ht_rop) { - core->analysis->ht_rop = ht_up_new(NULL, (HtUPFreeValue)rz_core_rop_gadget_info_free); - } - RzRopGadgetInfo *rop_gadget_info = NULL; + RzRopGadgetInfo *rop_gadget_info = NULL; + bool is_analysis = false; if (context->mask & RZ_ROP_GADGET_ANALYZE) { - RzListIter *iter; - RzCoreAsmHit *hit; - if (!core->analysis->ht_rop) { - core->analysis->ht_rop = ht_up_new(NULL, (HtUPFreeValue)rz_core_rop_gadget_info_free); - } - const ut64 addr_start = ((RzCoreAsmHit *)rz_list_first(hitlist))->addr; - rop_gadget_info = rz_core_rop_gadget_info_new(addr_start); - rz_list_foreach (hitlist, iter, hit) { - if (analyze_gadget(core, hit, rop_gadget_info) < 0) { - RZ_LOG_WARN("Failed to analyze gadget at 0x%" PFMT64x "\n", hit->addr); - } - } - ht_up_insert(core->analysis->ht_rop, addr_start, rop_gadget_info); + rop_gadget_info = perform_gadget_analysis(core, context, hitlist); + is_analysis = true; } + if (context->mask & RZ_ROP_GADGET_PRINT_DETAIL) { - print_rop_gadget_info(core, rop_gadget_info); + if (!rop_gadget_info && is_analysis) { + return 0; + } + print_rop_gadget_info(core, rop_gadget_info, context); } return 0; } @@ -972,7 +1193,7 @@ static void set_increment_based_on_arch(const RzCore *core, const char *arch, in } static RzList /**/ *handle_grep_args(const char *greparg, const bool regexp) { - if (!greparg && !regexp) { + if (!greparg || !regexp) { return NULL; } @@ -1016,7 +1237,6 @@ 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); - if (!hitlist) { goto fini; } @@ -1075,7 +1295,7 @@ RZ_BORROW static int update_end_gadget(int *i, const int ropdepth, RzRopEndListP * filters results based on the grep argument and request mask. Outputs results to * the provided state object. */ -RZ_API RzCmdStatus rz_core_rop_search(RzCore *core, RZ_OWN RzRopSearchContext *context) { +RZ_API RzCmdStatus rz_core_rop_search(RZ_NONNULL RzCore *core, RZ_OWN RzRopSearchContext *context) { rz_return_val_if_fail(core && core->search, RZ_CMD_STATUS_ERROR); int result = -1; @@ -1093,23 +1313,19 @@ RZ_API RzCmdStatus rz_core_rop_search(RzCore *core, RZ_OWN RzRopSearchContext *c } return -1; } - const char *arch = rz_config_get(core->config, "asm.arch"); - set_increment_based_on_arch(core, arch, &context->increment); + set_increment_based_on_arch(core, context->arch, &context->increment); RzList /**/ *rx_list = handle_grep_args(context->greparg, context->regexp); rz_cmd_state_output_array_start(context->state); rz_cons_break_push(NULL, NULL); - const char *mode_str = rz_config_get(core->config, "search.in"); - RzList *boundaries = rz_core_get_boundaries_prot(core, -1, mode_str, "search"); + RzList *boundaries = rz_core_get_boundaries_prot(core, -1, context->mode_str, "search"); if (!boundaries) { rz_cmd_state_output_array_end(context->state); } - context->max_count = rz_config_get_i(core->config, "search.maxhits"); if (context->max_count == 0) { context->max_count = -1; } context->unique_hitlists = ht_su_new(HT_STR_DUP); RzListIter *itermap; - context->subchain = rz_config_get_i(core->config, "rop.subchains"); RzIOMap *map; rz_list_foreach (boundaries, itermap, map) { if (!rz_itv_overlap(search_itv, map->itv)) { @@ -1195,10 +1411,10 @@ RZ_API RzCmdStatus rz_core_rop_search(RzCore *core, RZ_OWN RzRopSearchContext *c * Displays ROP gadgets from the gadgetSdb. * If unavailable, performs a ROP search with the input. */ -RZ_API RzCmdStatus rz_core_rop_gadget_info(RzCore *core, RZ_OWN RzRopSearchContext *context) { +RZ_API RzCmdStatus rz_core_rop_gadget_info(RZ_NONNULL RzCore *core, RZ_OWN RzRopSearchContext *context) { rz_return_val_if_fail(core && core->analysis, RZ_CMD_STATUS_ERROR); - if (!core->analysis->ht_rop) { + if (!core->analysis->ht_rop_semantics) { // TODO: resolve this logic later. } return rz_core_rop_search(core, context); @@ -1229,10 +1445,10 @@ RZ_API void rz_core_rop_constraint_free(RZ_NULLABLE void *data) { * * Creates a new RzList for RzRopConstraint object. */ -RZ_OWN RZ_API RzList /**/ *rz_rop_constraint_list_new(void) { - RzList *list = rz_list_new(); - if (list) { - list->free = &rz_core_rop_constraint_free; +RZ_OWN RZ_API RzPVector /**/ *rz_core_rop_constraint_map_new(void) { + RzPVector *list = rz_pvector_new((RzPVectorFree)rz_core_rop_constraint_free); + if (!list) { + return NULL; } return list; } \ No newline at end of file diff --git a/librz/il/il_events.c b/librz/il/il_events.c index df4271b2b7c..97c6bf29528 100644 --- a/librz/il/il_events.c +++ b/librz/il/il_events.c @@ -194,4 +194,4 @@ RZ_API RZ_OWN RzILEvent *rz_il_event_var_write_new(RZ_NONNULL const char *name, } return evt; -} +} \ No newline at end of file diff --git a/librz/include/rz_analysis.h b/librz/include/rz_analysis.h index ffa34e46eb5..6cecc953918 100644 --- a/librz/include/rz_analysis.h +++ b/librz/include/rz_analysis.h @@ -528,7 +528,9 @@ typedef struct rz_analysis_t { RzPlatformTarget *arch_target; RzPlatformTargetIndex *platform_target; HtSP *ht_global_var; // global variables - HtUP *ht_rop; ///< store rop gadget address. + HtUP *ht_rop_semantics; ///< cache rop gadget semantic information + HtUP *ht_rop; ///< cache rop gadget address list + bool is_rop_analysis; 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/include/rz_il/rz_il_events.h b/librz/include/rz_il/rz_il_events.h index 6cb182d9d42..72607d0ed32 100644 --- a/librz/include/rz_il/rz_il_events.h +++ b/librz/include/rz_il/rz_il_events.h @@ -5,6 +5,8 @@ #ifndef RZ_IL_VM_EVENTS_H #define RZ_IL_VM_EVENTS_H +#include "rz_il_opcodes.h" + #include #ifdef __cplusplus diff --git a/librz/include/rz_reg.h b/librz/include/rz_reg.h index e060b5b14a6..4d9cc451567 100644 --- a/librz/include/rz_reg.h +++ b/librz/include/rz_reg.h @@ -185,10 +185,11 @@ RZ_API ut64 rz_reg_getv(RzReg *reg, const char *name); RZ_API ut64 rz_reg_getv_by_role_or_name(RzReg *reg, const char *name); RZ_API ut64 rz_reg_setv(RzReg *reg, const char *name, ut64 val); RZ_API const char *rz_reg_32_to_64(RzReg *reg, const char *rreg32); +RZ_API bool rz_reg_is_role(const RzReg *reg, const char *name, RzRegisterId id); RZ_API const char *rz_reg_64_to_32(RzReg *reg, const char *rreg64); RZ_API const char *rz_reg_get_name_by_type(RzReg *reg, const char *name); RZ_API const char *rz_reg_get_type(int idx); -RZ_API const char *rz_reg_get_name(RzReg *reg, int kind); +RZ_API const char *rz_reg_get_name(const RzReg *reg, int kind); RZ_API RzRegItem *rz_reg_get_by_role(RzReg *reg, RzRegisterId role); RZ_API const char *rz_reg_get_role(int role); RZ_API int rz_reg_role_by_name(RZ_NONNULL const char *str); diff --git a/librz/include/rz_rop.h b/librz/include/rz_rop.h index 4d1f7c61ee5..6195406e1e9 100644 --- a/librz/include/rz_rop.h +++ b/librz/include/rz_rop.h @@ -29,6 +29,8 @@ typedef struct rz_rop_reg_info_t { 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; /** @@ -40,8 +42,8 @@ typedef struct rz_rop_gadget_info_t { ut64 curr_pc_val; ///< Current PC value. bool is_pc_write; ///< PC write flag. bool is_syscall; ///< Syscall flag. - RzPVector /**/ *modified_registers; ///< Modified registers. - RzList /**/ *dependencies; ///< Dependencies. + RzPVector /**/ *modified_registers; ///< Modified registers. + RzList /**/ *dependencies; ///< Dependencies. } RzRopGadgetInfo; /** @@ -101,21 +103,46 @@ typedef struct rz_rop_search_context_t { ut8 subchain; ut8 crop; char *greparg; + const char *mode_str; + const char *arch; bool regexp; - int max_count; - int increment; + bool cache; RzRopRequestMask mask; RzCmdStateOutput *state; + int increment; + int max_count; ut64 from; ut64 to; RzList /**/ *end_list; HtSU *unique_hitlists; } RzRopSearchContext; +/** + * \brief Enum for different ROP register events. + */ +typedef enum { + RZ_ROP_EVENT_VAR_WRITE, + RZ_ROP_EVENT_MEM_READ, + RZ_ROP_EVENT_MEM_WRITE, + RZ_ROP_EVENT_PC_WRITE, + // Event can be to filter pure operations as needed. + 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(RzCore *core, RZ_OWN RzRopSearchContext *context); -RZ_API RzCmdStatus rz_core_rop_gadget_info(RzCore *core, RZ_OWN RzRopSearchContext *context); -RZ_API bool rz_core_rop_analyze_constraint(RzCore *core, const char *str, RzRopConstraint *rop_constraint); +RZ_API RzCmdStatus rz_core_rop_search(RZ_NONNULL RzCore *core, RZ_OWN RzRopSearchContext *context); +RZ_API RzCmdStatus rz_core_rop_gadget_info(RZ_NONNULL RzCore *core, RZ_OWN RzRopSearchContext *context); +RZ_API bool rz_core_rop_analyze_constraint(RZ_NONNULL RzCore *core, const char *str, RzRopConstraint *rop_constraint); // ROP Search Context APIs RZ_OWN RZ_API RzRopSearchContext *rz_core_rop_search_context_new(RZ_NONNULL const RzCore *core, RZ_NULLABLE const char *greparg, @@ -124,18 +151,21 @@ RZ_API void rz_core_rop_search_context_free(RZ_NULLABLE RzRopSearchContext *cont // ROP Constraint APIs RZ_API void rz_core_rop_constraint_free(RZ_NULLABLE void *data); -RZ_OWN RZ_API RzList /**/ *rz_rop_constraint_list_new(void); +RZ_OWN RZ_API RzPVector /**/ *rz_core_rop_constraint_map_new(void); +RZ_API RzPVector /**/ *rop_constraint_map_parse(RZ_NONNULL RzCore *core, int argc, const char **argv); // 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_add_register(const RZ_NONNULL RZ_OUT RzRopGadgetInfo *gadget_info, RZ_NONNULL RzRopRegInfo *reg_info, bool is_dependency); RZ_API int rz_core_rop_gadget_info_update_register(RZ_INOUT RzRopGadgetInfo *gadget_info, RZ_NONNULL RzRopRegInfo *new_reg_info); RZ_API RZ_OWN RzRopGadgetInfo *rz_core_rop_gadget_info_new(ut64 address); RZ_IPI RzRopRegInfo *rz_core_rop_reg_info_dup(RzRopRegInfo *src); RZ_IPI void rz_core_rop_reg_info_free(RzRopRegInfo *reg_info); RZ_IPI RzRopRegInfo *rz_core_rop_reg_info_new(const RzCore *core, const RzILEvent *evt, ut64 init_val, ut64 new_val); RZ_BORROW RZ_API RzRopRegInfo *rz_core_rop_gadget_info_get_modified_register(const RZ_NONNULL RzRopGadgetInfo *gadget_info, RZ_NONNULL const char *name); +RZ_API bool rz_core_rop_gadget_info_has_register(const RZ_NONNULL RzRopGadgetInfo *gadget_info, RZ_NONNULL const char *name); +RZ_API RzPVector /**/ *rz_core_rop_gadget_get_reg_info_by_event(const RZ_NONNULL RzRopGadgetInfo *gadget_info, RzRopEvent event); +RZ_API RzPVector /**/ *rz_core_rop_get_reg_info_by_reg_names(const RZ_NONNULL RzRopGadgetInfo *gadget_info, RZ_NONNULL const RzPVector /**/ *registers); #ifdef __cplusplus } diff --git a/librz/reg/reg.c b/librz/reg/reg.c index b3876b38524..eda7ca577e7 100644 --- a/librz/reg/reg.c +++ b/librz/reg/reg.c @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2009-2020 pancake // SPDX-License-Identifier: LGPL-3.0-only +#include #include #include #include @@ -11,6 +12,23 @@ static const char *types[RZ_REG_TYPE_LAST + 1] = { "gpr", "drx", "fpu", "mmx", "xmm", "ymm", "flg", "seg", "sys", "sec", "vc", "vcc", "ctr", NULL }; +/** + * \brief Check if the given register has the given RegisterId. + * + * \param reg const RzReg Pointer + * \param name Register name. + * \param id RegisterId to check. + * \return true if the register has the given RegisterId, false otherwise. + */ +RZ_API bool rz_reg_is_role(const RzReg *reg, const char *name, const RzRegisterId id) { + rz_return_val_if_fail(reg && name, false); + const char *sp = rz_reg_get_name(reg, id); + if (!sp) { + return false; + } + return RZ_STR_EQ(sp, name); +} + // Take the 32bits name of a register, and return the 64 bit name of it. // If there is no equivalent 64 bit register return NULL. // SLOW @@ -147,7 +165,7 @@ RZ_API bool rz_reg_set_name(RZ_NONNULL RzReg *reg, RzRegisterId role, RZ_NONNULL return false; } -RZ_API const char *rz_reg_get_name(RzReg *reg, int role) { +RZ_API const char *rz_reg_get_name(const RzReg *reg, const int role) { if (reg && role >= 0 && role < RZ_REG_NAME_LAST) { return reg->name[role]; }