core/rop: refactor and grep ROP info (#4569)

This commit is contained in:
z3phyr 2024-07-31 08:50:50 -05:00 committed by GitHub
parent 6d45cbddb5
commit c02c0b744e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 450 additions and 169 deletions

View file

@ -8,7 +8,6 @@
#include <rz_util/rz_path.h>
#include <rz_arch.h>
#include <rz_lib.h>
#include <rz_rop.h>
/**
* \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);

View file

@ -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 /*<RzILOpPureCode *>*/ *constraints = rop_constraint_list_parse(core, argc, argv);
RzPVector /*<RzRopConstraint *>*/ *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) {

View file

@ -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 /*<RzILOpPureCode *>*/ *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 /*<RzRopConstraint *>*/ *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 /*<RzILOpPureCode *>*/ *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;
}

View file

@ -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);

View file

@ -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

View file

@ -7,6 +7,49 @@
#include <rz_util/rz_regex.h>
#include <rz_rop.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) {
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;
/**
* \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;
}
}
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");
}
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 /*<RzRopRegInfo *>*/ *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 /*<RzRopRegInfo *>*/ *rz_core_rop_get_reg_info_by_reg_names(const RZ_NONNULL RzRopGadgetInfo *gadget_info,
RZ_NONNULL const RzPVector /*<char *>*/ *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;
}
const RzILEventVarWrite *var_write = &event->data.var_write;
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;
}
}
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);
}
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) {
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);
break;
}
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,34 +714,109 @@ cleanup:
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;
if (reg_info->is_var_write) {
rz_cons_printf("%s ", reg_info->name);
}
rz_cons_printf("%s ", reg_info->name);
}
rz_cons_printf("\n");
rz_cons_printf("\nRegister dependencies:\n");
rz_cons_printf("Register dependencies:\n");
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;
}
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);
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 %llu\n", reg_info->name, reg_info->new_val);
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 %llu %llu\n", reg_info->name, reg_info->init_val, reg_info->new_val);
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("\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 (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) {
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) {
pj_ks(pj, "type", "mem_read");
pj_kn(pj, "new_val", reg_info->new_val);
} else if (reg_info->is_mem_write) {
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;
}
}
static int print_rop(const RzCore *core, const RzList /*<RzCoreAsmHit *>*/ *hitlist, RzCmdStateOutput *state) {
@ -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 /*<RzCoreAsmHit *>*/ *construct_rop_gadget(RzCore *core, ut8 *buf, int idx, RzRopSearchContext *context,
RzList /*<char *>*/ *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 /*<RzCoreAsmHit *>*/ *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 /*<RzCoreAsmHit *>*/ *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 /*<RzCoreAsmHit *>*/ *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 /*<RzCoreAsmHit *>*/ *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 /*<RzCoreAsmHit *>*/ *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 @@ cleanup:
return hitlist;
}
static int handle_rop_request_type(RzCore *core, RzRopSearchContext *context, RzList /*<RzCoreAsmHit *>*/ *hitlist) {
static RzRopGadgetInfo *perform_gadget_analysis(RzCore *core, const RzRopSearchContext *context, const RzList /*<RzCoreAsmHit *>*/ *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 /*<RzCoreAsmHit *>*/ *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 /*<char *>*/ *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 /*<char *>*/ *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 /*<RzRopConstraint *>*/ *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 /*<RzRopConstraint *>*/ *rz_core_rop_constraint_map_new(void) {
RzPVector *list = rz_pvector_new((RzPVectorFree)rz_core_rop_constraint_free);
if (!list) {
return NULL;
}
return list;
}

View file

@ -194,4 +194,4 @@ RZ_API RZ_OWN RzILEvent *rz_il_event_var_write_new(RZ_NONNULL const char *name,
}
return evt;
}
}

View file

@ -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..

View file

@ -5,6 +5,8 @@
#ifndef RZ_IL_VM_EVENTS_H
#define RZ_IL_VM_EVENTS_H
#include "rz_il_opcodes.h"
#include <rz_il/definitions/definitions.h>
#ifdef __cplusplus

View file

@ -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);

View file

@ -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 /*<RzRegInfo *>*/ *modified_registers; ///< Modified registers.
RzList /*<RzRegInfo *>*/ *dependencies; ///< Dependencies.
RzPVector /*<RzRopRegInfo *>*/ *modified_registers; ///< Modified registers.
RzList /*<RzRopRegInfo *>*/ *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 /*<RzRopEndListPair *>*/ *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 /*<RzRopConstraint *>*/ *rz_rop_constraint_list_new(void);
RZ_OWN RZ_API RzPVector /*<RzRopConstraint *>*/ *rz_core_rop_constraint_map_new(void);
RZ_API RzPVector /*<RzRopConstraint *>*/ *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 /*<RzRopRegInfo *>*/ *rz_core_rop_gadget_get_reg_info_by_event(const RZ_NONNULL RzRopGadgetInfo *gadget_info, RzRopEvent event);
RZ_API RzPVector /*<RzRopRegInfo *>*/ *rz_core_rop_get_reg_info_by_reg_names(const RZ_NONNULL RzRopGadgetInfo *gadget_info, RZ_NONNULL const RzPVector /*<char *>*/ *registers);
#ifdef __cplusplus
}

View file

@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: 2009-2020 pancake <pancake@nopcode.org>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_core.h>
#include <rz_list.h>
#include <rz_reg.h>
#include <rz_util.h>
@ -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];
}