From c3ff18353af16867fe30b3392d7904406ed4e635 Mon Sep 17 00:00:00 2001 From: Giridhar Prasath R Date: Thu, 13 Jun 2024 18:03:57 -0400 Subject: [PATCH 01/30] Ropchain constraint syntax parser - Parse the rop constraints - Update esil output to rzil sdb - Add /Rg gadget command --- librz/core/cmd/cmd_search.c | 49 +++- librz/core/cmd/cmd_search_rop.c | 389 +++++++++++++++++++++++++++ librz/core/cmd_descs/cmd_descs.c | 25 +- librz/core/cmd_descs/cmd_descs.h | 2 + librz/core/cmd_descs/cmd_search.yaml | 19 +- librz/core/meson.build | 1 + librz/core/rop.c | 2 + librz/include/meson.build | 1 + librz/include/rz_rop.h | 31 +++ 9 files changed, 508 insertions(+), 11 deletions(-) create mode 100644 librz/core/rop.c create mode 100644 librz/include/rz_rop.h diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index f2aa8a31cc2..64349b45776 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -256,7 +256,6 @@ RZ_IPI RzCmdStatus rz_cmd_info_gadget_handler(RzCore *core, int argc, const char const char *s = sdbkv_value(kv); ut64 addr; int opsz; - do { RzCoreAsmHit *hit = rz_core_asm_hit_new(); if (!hit) { @@ -278,8 +277,13 @@ 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) { - const char *input = argc > 1 ? argv[1] : ""; - rop_kuery(core, input, state); + RzList *constraints = rop_constraint_list_parse(core, argc, argv); + if (!constraints) { + return RZ_CMD_STATUS_ERROR; + } + rop_constraint_analysis(core, constraints); + rz_list_free(constraints); + // rop_kuery(core, input, state); return RZ_CMD_STATUS_OK; } @@ -292,6 +296,15 @@ RZ_IPI RzCmdStatus rz_cmd_search_gadget_handler(RzCore *core, int argc, const ch return RZ_CMD_STATUS_OK; } +RZ_IPI RzCmdStatus rz_cmd_detail_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; + } + // Add logic + return RZ_CMD_STATUS_OK; +} + static void cmd_search_bin(RzCore *core, RzInterval itv) { ut64 from = itv.addr, to = rz_itv_end(itv); int size; // , sz = sizeof (buf); @@ -1050,7 +1063,9 @@ static bool insert_into(void *user, const ut64 k, const ut64 v) { } // TODO: follow unconditional jumps -static RzList /**/ *construct_rop_gadget(RzCore *core, ut64 addr, ut8 *buf, int buflen, int idx, const char *grep, int regex, RzList /**/ *rx_list, struct endlist_pair *end_gadget, HtUU *badstart) { +static RzList /**/ *construct_rop_gadget(RzCore *core, ut64 addr, ut8 *buf, int buflen, + int idx, const char *grep, int regex, RzList /**/ *rx_list, + struct endlist_pair *end_gadget, HtUU *badstart, int delta) { int endaddr = end_gadget->instr_offset; int branch_delay = end_gadget->delay_size; RzAnalysisOp aop = { 0 }; @@ -1093,6 +1108,10 @@ static RzList /**/ *construct_rop_gadget(RzCore *core, ut64 addr while (nb_instr < max_instr) { ht_uu_insert(localbadstart, idx, 1); rz_analysis_op_init(&aop); + if (idx >= delta) { + valid = false; + goto ret; + } int error = rz_analysis_op(core->analysis, &aop, addr, buf + idx, buflen - idx, RZ_ANALYSIS_OP_MASK_DISASM); if (error < 0 || (nb_instr == 0 && (is_end_gadget(&aop, 0) || aop.type == RZ_ANALYSIS_OP_TYPE_NOP))) { valid = false; @@ -1389,6 +1408,22 @@ static void print_rop(RzCore *core, RzList /**/ *hitlist, RzCmdS rz_cons_printf("Gadget size: %d\n", (int)size); const char *key = rz_strf(tmpbuf, "0x%08" PFMT64x, addr); rop_classify(core, db, ropList, key, size); + buf = malloc(size + 1); + hit = rz_list_first(hitlist); + if (!buf) { + goto cleanup; + } + RzAsmOp *asmop = rz_asm_op_new(); + buf[size] = 0; + rz_io_read_at(core->io, hit->addr, buf, size); + rz_asm_set_pc(core->rasm, hit->addr); + rz_asm_disassemble(core->rasm, asmop, buf, size); + rz_analysis_op_init(&aop); + RzStrBuf sb = { 0 }; + rz_analysis_op(core->analysis, &aop, hit->addr, buf, size, RZ_ANALYSIS_OP_MASK_IL); + rz_il_op_effect_stringify(aop.il_op, &sb, true); + rz_analysis_op_fini(&aop); + rz_asm_op_free(asmop); } rz_cons_newline(); break; @@ -1517,7 +1552,7 @@ static int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzC (void)rz_io_read_at(core->io, from, buf, delta); // Find the end gadgets. - for (i = 0; i + 32 < delta; i += increment) { + for (i = 0; i < delta; i += increment) { RzAnalysisOp end_gadget = RZ_EMPTY; // Disassemble one. rz_analysis_op_init(&end_gadget); @@ -1570,7 +1605,7 @@ static int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzC next = end_gadget->instr_offset; prev = 0; // Start at just before the first end gadget. - for (i = next - ropdepth; i < (delta - max_inst_size_x86) && max_count; i += increment) { + for (i = 0; i < delta && max_count; i += increment) { if (increment == 1) { // give in-boundary instructions a shot if (i < prev - max_inst_size_x86) { @@ -1614,7 +1649,7 @@ static int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzC rz_asm_set_pc(core->rasm, from + i); RzList *hitlist = construct_rop_gadget(core, from + i, buf, delta, i, greparg, regexp, - rx_list, end_gadget, badstart); + rx_list, end_gadget, badstart, delta); if (!hitlist) { rz_asm_op_free(asmop); asmop = NULL; diff --git a/librz/core/cmd/cmd_search_rop.c b/librz/core/cmd/cmd_search_rop.c index 89d64e135e4..8ed2c3b88b6 100644 --- a/librz/core/cmd/cmd_search_rop.c +++ b/librz/core/cmd/cmd_search_rop.c @@ -7,6 +7,9 @@ #include "rz_io.h" #include "rz_list.h" #include "rz_types_base.h" +#include "rz_rop.h" + +#include static RzList /**/ *parse_list(const char *str) { char *line, *data, *str_n; @@ -727,3 +730,389 @@ static void rop_classify(RzCore *core, Sdb *db, RzList /**/ *ropList, co free(str); } + +RZ_API void rz_rop_constraint_free(void *data) { + RzRopConstraint *constraint = data; + if (constraint) { + for (int i = 0; i < NUM_ARGS; i++) { + if (constraint->args[i]) { + free(constraint->args[i]); + } + } + free(constraint); + } +} + +static RzList /**/ *rz_rop_constraint_list_new(void) { + RzList *list = rz_list_new(); + if (list) { + list->free = &rz_rop_constraint_free; + } + return list; +} + +static void skip_whitespace(const char *str, int *idx) { + while (str[*idx] == ' ' || str[*idx] == '\t' || str[*idx] == '\n' || str[*idx] == '\r') { + (*idx)++; + } +} + +static bool parse_eof(const char *str, int idx) { + skip_whitespace(str, &idx); + return str[idx] == '\0'; +} + +static bool parse_il_equal(char *str, int *idx) { + skip_whitespace(str, idx); + if (*idx >= strlen(str)) + return false; + if (str[*idx] == '=') { + (*idx)++; + return true; + } + return false; +} + +static char *parse_register(char *str, int *idx) { + char reg[256] = { 0 }; + int reg_idx = 0; + + skip_whitespace(str, idx); + + while (isalnum(str[*idx]) || str[*idx] == '_') { + reg[reg_idx++] = str[*idx]; + (*idx)++; + } + + // Check if the register is correct for the given architecture. + if (reg_idx == 0) { + return NULL; + } + + return strdup(reg); +} + +static bool parse_constant(const char *str, int *idx, unsigned long long *value) { + int base = 10; + int neg = 0; + char num_str[256] = { 0 }; + int num_idx = 0; + + skip_whitespace(str, idx); + + if (str[*idx] == '-') { + neg = 1; + (*idx)++; + } + + skip_whitespace(str, idx); + + if (str[*idx] == '0' && (str[*idx + 1] == 'x' || str[*idx + 1] == 'X')) { + base = 16; + *idx += 2; + } + + while (isdigit(str[*idx]) || (base == 16 && isxdigit(str[*idx]))) { + num_str[num_idx++] = str[*idx]; + (*idx)++; + } + + if (num_idx == 0) { + return false; + } + + *value = strtoull(num_str, NULL, base); + if (neg) { + *value = -*value; + } + + return true; +} + +static bool parse_reg_to_const(RzCore *core, char *str, RzRopConstraint *rop_constraint) { + int idx = 0; + char *dst_reg = parse_register(str, &idx); + if (!dst_reg) { + return false; + } + + if (!parse_il_equal(str, &idx)) { + free(dst_reg); + return false; + } + + unsigned long long const_value; + if (!parse_constant(str, &idx, &const_value)) { + free(dst_reg); + return false; + } + + if (!parse_eof(str, idx)) { + free(dst_reg); + return false; + } + + rop_constraint->type = MOV_CONST; + rop_constraint->args[DST_REG] = dst_reg; + rop_constraint->args[SRC_REG] = NULL; + char value_str[256]; + sprintf(value_str, "%llu", const_value); + rop_constraint->args[DST_CONST] = strdup(value_str); + return true; +} + +static bool parse_reg_to_reg(RzCore *core, char *str, RzRopConstraint *rop_constraint) { + int idx = 0; + char *dst_reg = parse_register(str, &idx); + if (!dst_reg) { + return false; + } + + if (!parse_il_equal(str, &idx)) { + free(dst_reg); + return false; + } + + char *src_reg = parse_register(str, &idx); + if (!src_reg) { + free(dst_reg); + return false; + } + + if (!parse_eof(str, idx)) { + free(dst_reg); + return false; + } + + rop_constraint->type = MOV_REG; + rop_constraint->args[DST_REG] = dst_reg; + rop_constraint->args[SRC_REG] = src_reg; + return true; +} + +static bool parse_il_op(RzList *args, const char *str, int *idx) { + RzILOpPureCode res = RZ_IL_OP_VAR; + + skip_whitespace(str, idx); + if (*idx >= strlen(str)) { + return false; + } + + switch (str[*idx]) { + case '+': + (*idx)++; + res = RZ_IL_OP_ADD; + break; + case '/': + (*idx)++; + res = RZ_IL_OP_DIV; + break; + case '*': + (*idx)++; + res = RZ_IL_OP_MUL; + break; + case '^': + (*idx)++; + res = RZ_IL_OP_XOR; + break; + case '&': + (*idx)++; + res = RZ_IL_OP_AND; + break; + case '|': + (*idx)++; + res = RZ_IL_OP_OR; + break; + case '%': + (*idx)++; + res = RZ_IL_OP_MOD; + break; + default: break; + } + if (res == RZ_IL_OP_VAR) { + if (strncmp(&str[*idx], "<<", 2) == 0) { + *idx += 2; + res = RZ_IL_OP_SHIFTL; + } else if (strncmp(&str[*idx], ">>", 2) == 0) { + *idx += 2; + res = RZ_IL_OP_SHIFTR; + } else { + return false; + } + } + + RzILOpPureCode *op_ptr = (RzILOpPureCode *)malloc(sizeof(RzILOpPureCode)); + if (!op_ptr) { + return false; + } + *op_ptr = res; + rz_list_append(args, op_ptr); + + return true; +} + +static bool parse_reg_op_const(RzCore *core, char *str, RzRopConstraint *rop_constraint) { + int idx = 0; + char *dst_reg = parse_register(str, &idx); + if (!dst_reg) { + return false; + } + + if (!parse_il_equal(str, &idx)) { + free(dst_reg); + return false; + } + + char *src_reg = parse_register(str, &idx); + if (!src_reg) { + free(dst_reg); + return false; + } + RzList *args = rz_list_new(); + if (!parse_il_op(args, str, &idx)) { + free(dst_reg); + free(src_reg); + rz_list_free(args); + return false; + } + + ut64 const_value; + if (!parse_constant(str, &idx, &const_value)) { + free(dst_reg); + free(src_reg); + return false; + } + + if (!parse_eof(str, idx)) { + free(dst_reg); + free(src_reg); + rz_list_free(args); + return false; + } + + rop_constraint->type = MOV_OP_CONST; + rop_constraint->args[DST_REG] = dst_reg; + rop_constraint->args[SRC_REG] = src_reg; + RzILOpPureCode *op = rz_list_get_n(args, 0); + char op_str[3]; + snprintf(op_str, sizeof(op_str), "%s", rz_il_op_pure_code_stringify(*op)); + rop_constraint->args[OP] = strdup(op_str); + char value_str[256]; + sprintf(value_str, "%llu", const_value); + rop_constraint->args[DST_CONST] = strdup(value_str); + return true; +} + +static bool parse_reg_op_reg(RzCore *core, char *str, RzRopConstraint *rop_constraint) { + int idx = 0; + char *dst_reg = parse_register(str, &idx); + if (!dst_reg) { + return false; + } + + if (!parse_il_equal(str, &idx)) { + free(dst_reg); + return false; + } + + char *src_reg1 = parse_register(str, &idx); + if (!src_reg1) { + free(dst_reg); + return false; + } + + RzList *args = rz_list_new(); + if (!parse_il_op(args, str, &idx)) { + free(dst_reg); + free(src_reg1); + rz_list_free(args); + return false; + } + + char *src_reg2 = parse_register(str, &idx); + if (!src_reg2) { + free(dst_reg); + free(src_reg1); + return false; + } + + if (!parse_eof(str, idx)) { + free(dst_reg); + free(src_reg1); + free(src_reg2); + rz_list_free(args); + return false; + } + + rop_constraint->type = MOV_OP_REG; + rop_constraint->args[DST_REG] = dst_reg; + rop_constraint->args[SRC_REG] = src_reg1; + RzILOpPureCode *op = rz_list_get_n(args, 0); + char op_str[16]; + snprintf(op_str, sizeof(op_str), "%s", rz_il_op_pure_code_stringify(*op)); + rop_constraint->args[OP] = strdup(op_str); + rop_constraint->args[DST_CONST] = src_reg2; + return true; +} + +static bool parse_instruction(RzCore *core, char *str, RzRopConstraint *rop_constraint) { + 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); +} + +static void rop_constraint_analysis(RzCore *core, const RzList *constraint_list) { + RzListIter *it; + RzRopConstraint *token; + rz_list_foreach (constraint_list, it, token) { + } +} + +static RzRopConstraint *rop_constraint_kv(RzCore *core, char *token) { + RzRopConstraint *rop_constraint = RZ_NEW0(RzRopConstraint); + RzList *l = rz_str_split_duplist_n(token, "=", 1, false); + char *key = rz_list_get_n(l, 0); + char *value = rz_list_get_n(l, 1); + if (RZ_STR_ISEMPTY(key) || RZ_STR_ISEMPTY(value)) { + RZ_LOG_ERROR("core: Make sure to use the format = without spaces.\n"); + rz_list_free(l); + return NULL; + } + if (!rop_constraint) { + rz_list_free(l); + return NULL; + } + if (!parse_instruction(core, token, rop_constraint)) { + free(rop_constraint); + return NULL; + } + + rz_list_free(l); + return rop_constraint; +} + +static RzList *rop_constraint_list_parse(RzCore *core, int argc, const char **argv) { + RzList *constr_list = rz_rop_constraint_list_new(); + for (int i = 1; i < argc; i++) { + RzList *l = rz_str_split_duplist_n(argv[i], ",", 1, false); + if (!l) { + return constr_list; + } + size_t llen = rz_list_length(l); + if (!llen) { + return constr_list; + } + RzListIter *it; + char *token; + rz_list_foreach (l, it, token) { + RzRopConstraint *rop_constraint = rop_constraint_kv(core, token); + if (!rop_constraint) { + continue; + } + rz_list_append(constr_list, rop_constraint); + } + rz_list_free(l); + } + return constr_list; +} \ 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 3020a2a8189..0b66e01bd26 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -104,6 +104,7 @@ static const RzCmdDescArg interpret_macro_multiple_args[4]; static const RzCmdDescArg cmd_info_gadget_args[2]; 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 remote_args[3]; static const RzCmdDescArg remote_send_args[3]; static const RzCmdDescArg remote_add_args[2]; @@ -1388,7 +1389,7 @@ static const RzCmdDescHelp cmd_search_gadget_help = { static const RzCmdDescArg cmd_query_gadget_args[] = { { - .name = "nop|mov|arithm", + .name = "key=value", .type = RZ_CMD_ARG_TYPE_STRING, .flags = RZ_CMD_ARG_FLAG_LAST, .optional = false, @@ -1397,10 +1398,26 @@ static const RzCmdDescArg cmd_query_gadget_args[] = { { 0 }, }; static const RzCmdDescHelp cmd_query_gadget_help = { - .summary = "Query ROP Gadgets", + .summary = "Query ROP Gadgets by providing constraints", + .args_str = " [=] [[=] ...]]", .args = cmd_query_gadget_args, }; +static const RzCmdDescArg cmd_detail_gadget_args[] = { + { + .name = "Gadget address", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + .optional = false, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_detail_gadget_help = { + .summary = "Gadget detail info", + .args = cmd_detail_gadget_args, +}; + static const RzCmdDescHelp R_help = { .summary = "Connect with other instances of rizin", }; @@ -19230,6 +19247,10 @@ 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); + rz_warn_if_fail(cmd_detail_gadget_cd); + rz_cmd_desc_set_default_mode(cmd_detail_gadget_cd, RZ_OUTPUT_MODE_STANDARD); + RzCmdDesc *R_cd = rz_cmd_desc_group_new(core->rcmd, root_cd, "R", rz_remote_handler, &remote_help, &R_help); rz_warn_if_fail(R_cd); RzCmdDesc *remote_send_cd = rz_cmd_desc_argv_new(core->rcmd, R_cd, "R<", rz_remote_send_handler, &remote_send_help); diff --git a/librz/core/cmd_descs/cmd_descs.h b/librz/core/cmd_descs/cmd_descs.h index a5458c81481..8dcaad5f3b4 100644 --- a/librz/core/cmd_descs/cmd_descs.h +++ b/librz/core/cmd_descs/cmd_descs.h @@ -67,6 +67,8 @@ RZ_IPI RzCmdStatus rz_cmd_info_gadget_handler(RzCore *core, int argc, const char RZ_IPI RzCmdStatus rz_cmd_search_gadget_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "/Rk" RZ_IPI RzCmdStatus rz_cmd_query_gadget_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/Rg" +RZ_IPI RzCmdStatus rz_cmd_detail_gadget_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "/" RZ_IPI int rz_cmd_search(void *data, const char *input); // "R" diff --git a/librz/core/cmd_descs/cmd_search.yaml b/librz/core/cmd_descs/cmd_search.yaml index 291967326de..297be4085ca 100644 --- a/librz/core/cmd_descs/cmd_search.yaml +++ b/librz/core/cmd_descs/cmd_search.yaml @@ -36,7 +36,7 @@ commands: optional: true - name: "/Rk" cname: cmd_query_gadget - summary: Query ROP Gadgets + summary: Query ROP Gadgets by providing constraints type: RZ_CMD_DESC_TYPE_ARGV_STATE default_mode: RZ_OUTPUT_MODE_STANDARD modes: @@ -44,7 +44,22 @@ commands: - RZ_OUTPUT_MODE_JSON - RZ_OUTPUT_MODE_QUIET - RZ_OUTPUT_MODE_TABLE + args_str: " [=] [[=] ...]]" args: - - name: nop|mov|arithm + - name: key=value + type: RZ_CMD_ARG_TYPE_STRING + optional: false + - name: "/Rg" + cname: cmd_detail_gadget + summary: Gadget detail info + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + 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 optional: false \ No newline at end of file diff --git a/librz/core/meson.build b/librz/core/meson.build index 9ab6628ec36..bb6b7f6e107 100644 --- a/librz/core/meson.build +++ b/librz/core/meson.build @@ -54,6 +54,7 @@ rz_core_sources = [ 'libs.c', 'linux_heap_glibc.c', 'linux_heap_glibc64.c', + 'rop.c', 'project.c', 'project_migrate.c', 'rtr.c', diff --git a/librz/core/rop.c b/librz/core/rop.c new file mode 100644 index 00000000000..ce1af3afda2 --- /dev/null +++ b/librz/core/rop.c @@ -0,0 +1,2 @@ +// SPDX-FileCopyrightText: 2010-2021 z3phyr +// SPDX-License-Identifier: LGPL-3.0-only diff --git a/librz/include/meson.build b/librz/include/meson.build index 686641c8e2c..ee9930380e9 100644 --- a/librz/include/meson.build +++ b/librz/include/meson.build @@ -54,6 +54,7 @@ include_files = [ 'rz_vector.h', 'rz_windows.h', 'rz_windows_heap.h', + 'rz_rop.h', ] install_headers(include_files, install_dir: rizin_incdir) diff --git a/librz/include/rz_rop.h b/librz/include/rz_rop.h new file mode 100644 index 00000000000..2584d0bc3a7 --- /dev/null +++ b/librz/include/rz_rop.h @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: 2020-2021 z3phyr +// SPDX-License-Identifier: LGPL-3.0-only + +#ifndef RZ_ROP_H +#define RZ_ROP_H + +#endif // RZ_ROP_H + +typedef enum rzil_instr_type { + // Register to register + MOV_CONST, // reg <- const + MOV_REG, // reg <- reg + MOV_OP_CONST, // reg <- reg OP const + MOV_OP_REG, // reg <- reg OP reg + // Call functions + SYSCALL, +} RzILInstructionType; + +typedef enum { + SRC_REG, + DST_REG, + OP, + DST_CONST, + DST_REG_SECOND, + NUM_ARGS +} RzRopArgType; + +typedef struct rz_rop_constraint { + RzILInstructionType type; + char *args[NUM_ARGS]; +} RzRopConstraint; \ No newline at end of file From 0c3e27be51c55c8ab0030cfc2f12fd04387c14b5 Mon Sep 17 00:00:00 2001 From: Giridhar Prasath R Date: Fri, 14 Jun 2024 05:54:50 -0400 Subject: [PATCH 02/30] Refactor cmd_search.c and add unit tc --- librz/core/cmd/cmd_search.c | 761 +------------------------------ librz/core/cmd/cmd_search_rop.c | 116 ++--- librz/core/rop.c | 772 ++++++++++++++++++++++++++++++++ librz/include/rz_rop.h | 26 +- test/unit/meson.build | 1 + test/unit/test_rop_constraint.c | 142 ++++++ 6 files changed, 1006 insertions(+), 812 deletions(-) create mode 100644 test/unit/test_rop_constraint.c diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index 64349b45776..370475a16fd 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -1,12 +1,10 @@ // SPDX-FileCopyrightText: 2010-2021 pancake // SPDX-License-Identifier: LGPL-3.0-only -#include #include #include #include #include -#include #include #include "../core_private.h" @@ -17,10 +15,6 @@ #define AES_SEARCH_LENGTH 40 #define PRIVATE_KEY_SEARCH_LENGTH 11 -static int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzCmdStateOutput *state); -static void rop_kuery(void *data, const char *input, RzCmdStateOutput *state); -static void print_rop(RzCore *core, RzList /**/ *hitlist, RzCmdStateOutput *state); - static const char *help_msg_search_esil[] = { "/E", " [esil-expr]", "search offsets matching a specific esil expression", "/Ej", " [esil-expr]", "same as above but using the given magic file", @@ -153,11 +147,6 @@ struct search_parameters { bool privkey_search; }; -struct endlist_pair { - int instr_offset; - int delay_size; -}; - static int search_hash(RzCore *core, const char *hashname, const char *hashstr, ut32 minlen, ut32 maxlen, struct search_parameters *param) { RzIOMap *map; ut8 *buf; @@ -236,44 +225,7 @@ RZ_IPI RzCmdStatus rz_cmd_info_gadget_handler(RzCore *core, int argc, const char return RZ_CMD_STATUS_ERROR; } - Sdb *gadgetSdb = sdb_ns(core->sdb, "gadget_sdb", false); - - if (!gadgetSdb) { - rz_core_search_rop(core, argv[1], 0, state); - return RZ_CMD_STATUS_OK; - } - void **iter; - RzPVector *items = sdb_get_items(gadgetSdb, true); - - rz_cmd_state_output_array_start(state); - rz_pvector_foreach (items, iter) { - SdbKv *kv = *iter; - RzList *hitlist = rz_core_asm_hit_list_new(); - if (!hitlist) { - break; - } - - const char *s = sdbkv_value(kv); - ut64 addr; - int opsz; - do { - RzCoreAsmHit *hit = rz_core_asm_hit_new(); - if (!hit) { - rz_list_free(hitlist); - break; - } - sscanf(s, "%" PFMT64x "(%" PFMT32d ")", &addr, &opsz); - hit->addr = addr; - hit->len = opsz; - rz_list_append(hitlist, hit); - } while (*(s = strchr(s, ')') + 1) != '\0'); - - print_rop(core, hitlist, state); - rz_list_free(hitlist); - } - rz_pvector_free(items); - rz_cmd_state_output_array_end(state); - return RZ_CMD_STATUS_OK; + return rz_core_rop_gadget_info(core, input, state); } RZ_IPI RzCmdStatus rz_cmd_query_gadget_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { @@ -281,9 +233,11 @@ RZ_IPI RzCmdStatus rz_cmd_query_gadget_handler(RzCore *core, int argc, const cha if (!constraints) { return RZ_CMD_STATUS_ERROR; } - rop_constraint_analysis(core, constraints); + if (rz_list_empty(constraints)) { + rz_list_free(constraints); + return RZ_CMD_STATUS_INVALID; + } rz_list_free(constraints); - // rop_kuery(core, input, state); return RZ_CMD_STATUS_OK; } @@ -1024,711 +978,6 @@ RZ_API RZ_OWN RzList /**/ *rz_core_get_boundaries_prot(RzCore *core, return list; } -static bool is_end_gadget(const RzAnalysisOp *aop, const ut8 crop) { - 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: - return true; - } - if (crop) { // if conditional jumps, calls and returns should be used for the gadget-search too - 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; - } - } - return false; -} - -static bool insert_into(void *user, const ut64 k, const ut64 v) { - HtUU *ht = (HtUU *)user; - ht_uu_insert(ht, k, v); - return true; -} - -// TODO: follow unconditional jumps -static RzList /**/ *construct_rop_gadget(RzCore *core, ut64 addr, ut8 *buf, int buflen, - int idx, const char *grep, int regex, RzList /**/ *rx_list, - struct endlist_pair *end_gadget, HtUU *badstart, int delta) { - int endaddr = end_gadget->instr_offset; - int branch_delay = end_gadget->delay_size; - RzAnalysisOp aop = { 0 }; - const char *start = NULL, *end = NULL; - char *grep_str = NULL; - RzCoreAsmHit *hit = NULL; - RzList *hitlist = rz_core_asm_hit_list_new(); - ut8 nb_instr = 0; - const ut8 max_instr = rz_config_get_i(core->config, "rop.len"); - bool valid = false; - int grep_find; - int search_hit; - char *rx = NULL; - HtUUOptions opt = { 0 }; - HtUU *localbadstart = ht_uu_new_opt(&opt); - int count = 0; - - if (grep) { - start = grep; - end = strchr(grep, ';'); - if (!end) { // We filter on a single opcode, so no ";" - end = start + strlen(grep); - } - grep_str = calloc(1, end - start + 1); - strncpy(grep_str, start, end - start); - if (regex) { - // get the first regexp. - if (rz_list_length(rx_list) > 0) { - rx = rz_list_get_n(rx_list, count++); - } - } - } - - bool found; - ht_uu_find(badstart, idx, &found); - if (found) { - valid = false; - goto ret; - } - while (nb_instr < max_instr) { - ht_uu_insert(localbadstart, idx, 1); - rz_analysis_op_init(&aop); - if (idx >= delta) { - valid = false; - goto ret; - } - int error = rz_analysis_op(core->analysis, &aop, addr, buf + idx, buflen - idx, RZ_ANALYSIS_OP_MASK_DISASM); - if (error < 0 || (nb_instr == 0 && (is_end_gadget(&aop, 0) || aop.type == RZ_ANALYSIS_OP_TYPE_NOP))) { - valid = false; - goto ret; - } - - const int opsz = aop.size; - // opsz = rz_strbuf_length (asmop.buf); - char *opst = aop.mnemonic; - if (!opst) { - RZ_LOG_WARN("Analysis plugin %s did not return disassembly\n", core->analysis->cur->name); - RzAsmOp asmop; - rz_asm_set_pc(core->rasm, addr); - if (rz_asm_disassemble(core->rasm, &asmop, buf + idx, buflen - idx) < 0) { - valid = false; - goto ret; - } - opst = strdup(rz_asm_op_get_asm(&asmop)); - rz_asm_op_fini(&asmop); - } - if (!rz_str_ncasecmp(opst, "invalid", strlen("invalid")) || - !rz_str_ncasecmp(opst, ".byte", strlen(".byte"))) { - valid = false; - goto ret; - } - - hit = rz_core_asm_hit_new(); - if (hit) { - hit->addr = addr; - hit->len = opsz; - rz_list_append(hitlist, hit); - } - - // Move on to the next instruction - idx += opsz; - addr += opsz; - if (rx) { - grep_find = rz_regex_contains(rx, opst, RZ_REGEX_ZERO_TERMINATED, RZ_REGEX_EXTENDED, RZ_REGEX_DEFAULT); - search_hit = (end && grep && grep_find); - } else { - search_hit = (end && grep && strstr(opst, grep_str)); - } - - // Handle (possible) grep - if (search_hit) { - if (end[0] == ';') { // fields are semicolon-separated - start = end + 1; // skip the ; - end = strchr(start, ';'); - end = end ? end : start + strlen(start); // latest field? - free(grep_str); - grep_str = calloc(1, end - start + 1); - if (grep_str) { - strncpy(grep_str, start, end - start); - } - } else { - end = NULL; - } - if (regex) { - rx = rz_list_get_n(rx_list, count++); - } - } - if (endaddr <= (idx - opsz)) { - valid = (endaddr == idx - opsz); - goto ret; - } - rz_analysis_op_fini(&aop); - nb_instr++; - } -ret: - rz_analysis_op_fini(&aop); - free(grep_str); - if (regex && rx) { - rz_list_free(hitlist); - ht_uu_free(localbadstart); - return NULL; - } - if (!valid || (grep && end)) { - rz_list_free(hitlist); - ht_uu_free(localbadstart); - return NULL; - } - ht_uu_foreach(localbadstart, insert_into, badstart); - ht_uu_free(localbadstart); - // If our arch has bds then we better be including them - if (branch_delay && rz_list_length(hitlist) < (1 + branch_delay)) { - rz_list_free(hitlist); - return NULL; - } - return hitlist; -} - -static void print_rop(RzCore *core, RzList /**/ *hitlist, RzCmdStateOutput *state) { - RzCoreAsmHit *hit = NULL; - RzListIter *iter; - RzList *ropList = NULL; - unsigned int size = 0; - char *asmop_str = NULL, *asmop_hex_str = NULL; - RzAnalysisOp aop = RZ_EMPTY; - const char *comment = NULL; - Sdb *db = NULL; - const bool colorize = rz_config_get_i(core->config, "scr.color"); - const bool rop_comments = rz_config_get_i(core->config, "rop.comments"); - const bool esil = rz_config_get_i(core->config, "asm.esil"); - const bool rop_db = rz_config_get_i(core->config, "rop.db"); - char tmpbuf[16]; - ut8 *buf = NULL; - RzStrBuf *colored_asm = NULL, *bw_str = NULL; - if (rop_db) { - db = sdb_ns(core->sdb, "rop", true); - ropList = rz_list_newf(free); - if (!db) { - RZ_LOG_ERROR("core: Could not create SDB 'rop' namespace\n"); - rz_list_free(ropList); - return; - } - } - - rz_cmd_state_output_set_columnsf(state, "XXs", "addr", "bytes", "disasm"); - if (state->mode == RZ_OUTPUT_MODE_JSON) { - pj_o(state->d.pj); - pj_ka(state->d.pj, "opcodes"); - } else if (state->mode == RZ_OUTPUT_MODE_QUIET) { - rz_cons_printf("0x%08" PFMT64x ":", ((RzCoreAsmHit *)rz_list_first(hitlist))->addr); - } - const ut64 addr = ((RzCoreAsmHit *)rz_list_first(hitlist))->addr; - - rz_list_foreach (hitlist, iter, hit) { - RzAsmOp *asmop = rz_asm_op_new(); - switch (state->mode) { - case RZ_OUTPUT_MODE_JSON: - buf = malloc(hit->len); - if (!buf) { - goto cleanup; - } - rz_io_read_at(core->io, hit->addr, buf, hit->len); - rz_asm_set_pc(core->rasm, hit->addr); - rz_asm_disassemble(core->rasm, asmop, buf, hit->len); - rz_analysis_op_init(&aop); - rz_analysis_op(core->analysis, &aop, hit->addr, buf, hit->len, RZ_ANALYSIS_OP_MASK_ESIL); - size += hit->len; - if (aop.type != RZ_ANALYSIS_OP_TYPE_RET) { - char *opstr_n = rz_str_newf(" %s", RZ_STRBUF_SAFEGET(&aop.esil)); - rz_list_append(ropList, opstr_n); - } - pj_o(state->d.pj); - pj_kn(state->d.pj, "offset", hit->addr); - pj_ki(state->d.pj, "size", hit->len); - pj_ks(state->d.pj, "opcode", rz_asm_op_get_asm(asmop)); - pj_ks(state->d.pj, "type", rz_analysis_optype_to_string(aop.type)); - pj_end(state->d.pj); - free(buf); - rz_analysis_op_fini(&aop); - break; - case RZ_OUTPUT_MODE_QUIET: - // Print gadgets in a 'linear manner', each sequence on one line. - buf = malloc(hit->len); - if (!buf) { - goto cleanup; - } - rz_io_read_at(core->io, hit->addr, buf, hit->len); - rz_asm_set_pc(core->rasm, hit->addr); - rz_asm_disassemble(core->rasm, asmop, buf, hit->len); - rz_analysis_op_init(&aop); - rz_analysis_op(core->analysis, &aop, hit->addr, buf, hit->len, RZ_ANALYSIS_OP_MASK_BASIC); - size += hit->len; - const char *opstr = RZ_STRBUF_SAFEGET(&aop.esil); - if (aop.type != RZ_ANALYSIS_OP_TYPE_RET) { - rz_list_append(ropList, rz_str_newf(" %s", opstr)); - } - if (esil) { - rz_cons_printf("%s\n", opstr); - } else if (colorize) { - bw_str = rz_strbuf_new(rz_asm_op_get_asm(asmop)); - RzAsmParseParam *param = rz_asm_get_parse_param(core->analysis->reg, aop.type); - colored_asm = rz_asm_colorize_asm_str(bw_str, core->print, param, asmop->asm_toks); - rz_asm_parse_param_free(param); - rz_cons_printf(" %s%s;", colored_asm ? rz_strbuf_get(colored_asm) : "", Color_RESET); - rz_strbuf_free(colored_asm); - rz_strbuf_free(bw_str); - } else { - rz_cons_printf(" %s;", rz_asm_op_get_asm(asmop)); - } - free(buf); - rz_analysis_op_fini(&aop); - break; - case RZ_OUTPUT_MODE_STANDARD: - // Print gadgets with new instruction on a new line. - comment = rop_comments ? rz_meta_get_string(core->analysis, RZ_META_TYPE_COMMENT, hit->addr) : NULL; - if (hit->len < 0) { - RZ_LOG_ERROR("core: Invalid hit length here\n"); - continue; - } - buf = malloc(1 + hit->len); - if (!buf) { - break; - } - buf[hit->len] = 0; - rz_io_read_at(core->io, hit->addr, buf, hit->len); - rz_asm_set_pc(core->rasm, hit->addr); - rz_asm_disassemble(core->rasm, asmop, buf, hit->len); - rz_analysis_op_init(&aop); - rz_analysis_op(core->analysis, &aop, hit->addr, buf, hit->len, RZ_ANALYSIS_OP_MASK_ESIL); - size += hit->len; - if (aop.type != RZ_ANALYSIS_OP_TYPE_RET) { - char *opstr_n = rz_str_newf(" %s", RZ_STRBUF_SAFEGET(&aop.esil)); - rz_list_append(ropList, opstr_n); - } - char *asm_op_hex = rz_asm_op_get_hex(asmop); - if (colorize) { - bw_str = rz_strbuf_new(rz_asm_op_get_asm(asmop)); - RzAsmParseParam *param = rz_asm_get_parse_param(core->analysis->reg, aop.type); - colored_asm = rz_asm_colorize_asm_str(bw_str, core->print, param, asmop->asm_toks); - rz_asm_parse_param_free(param); - if (comment) { - rz_cons_printf(" 0x%08" PFMT64x " %18s %s%s ; %s\n", - hit->addr, asm_op_hex, colored_asm ? rz_strbuf_get(colored_asm) : "", Color_RESET, comment); - } else { - rz_cons_printf(" 0x%08" PFMT64x " %18s %s%s\n", - hit->addr, asm_op_hex, colored_asm ? rz_strbuf_get(colored_asm) : "", Color_RESET); - } - rz_strbuf_free(colored_asm); - rz_strbuf_free(bw_str); - } else { - if (comment) { - rz_cons_printf(" 0x%08" PFMT64x " %18s %s ; %s\n", - hit->addr, asm_op_hex, rz_asm_op_get_asm(asmop), comment); - } else { - rz_cons_printf(" 0x%08" PFMT64x " %18s %s\n", - hit->addr, asm_op_hex, rz_asm_op_get_asm(asmop)); - } - } - free(asm_op_hex); - free(buf); - rz_analysis_op_fini(&aop); - comment = NULL; - break; - case RZ_OUTPUT_MODE_TABLE: - buf = malloc(hit->len); - if (!buf) { - goto cleanup; - } - rz_io_read_at(core->io, hit->addr, buf, hit->len); - rz_asm_set_pc(core->rasm, hit->addr); - rz_asm_disassemble(core->rasm, asmop, buf, hit->len); - rz_analysis_op_init(&aop); - rz_analysis_op(core->analysis, &aop, hit->addr, buf, hit->len, RZ_ANALYSIS_OP_MASK_BASIC); - size += hit->len; - if (asmop_str) { - asmop_str = rz_str_append(asmop_str, rz_asm_op_get_asm(asmop)); - const ut64 addr_last = ((RzCoreAsmHit *)rz_list_last(hitlist))->addr; - if (addr_last != hit->addr) { - asmop_str = rz_str_append(asmop_str, "; "); - } - } else { - asmop_str = rz_str_newf("%s; ", rz_asm_op_get_asm(asmop)); - } - char *asmop_hex_str_dup = NULL; - if (asmop_hex_str) { - asmop_hex_str_dup = rz_asm_op_get_hex(asmop); - asmop_hex_str = rz_str_append(asmop_hex_str, asmop_hex_str_dup); - } else { - asmop_hex_str_dup = rz_asm_op_get_hex(asmop); - asmop_hex_str = rz_str_newf("%s", asmop_hex_str_dup); - } - free(asmop_hex_str_dup); - free(buf); - rz_analysis_op_fini(&aop); - break; - default: - rz_warn_if_reached(); - break; - } - rz_asm_op_free(asmop); - } - switch (state->mode) { - case RZ_OUTPUT_MODE_JSON: - pj_end(state->d.pj); - if (db && hit) { - const char *key = rz_strf(tmpbuf, "0x%08" PFMT64x, addr); - rop_classify(core, db, ropList, key, size); - } - if (hit) { - pj_kn(state->d.pj, "retaddr", hit->addr); - pj_ki(state->d.pj, "size", size); - } - pj_end(state->d.pj); - break; - case RZ_OUTPUT_MODE_QUIET: - rz_cons_newline(); - break; - // fallthrough - case RZ_OUTPUT_MODE_STANDARD: - if (db && hit) { - rz_cons_printf("Gadget size: %d\n", (int)size); - const char *key = rz_strf(tmpbuf, "0x%08" PFMT64x, addr); - rop_classify(core, db, ropList, key, size); - buf = malloc(size + 1); - hit = rz_list_first(hitlist); - if (!buf) { - goto cleanup; - } - RzAsmOp *asmop = rz_asm_op_new(); - buf[size] = 0; - rz_io_read_at(core->io, hit->addr, buf, size); - rz_asm_set_pc(core->rasm, hit->addr); - rz_asm_disassemble(core->rasm, asmop, buf, size); - rz_analysis_op_init(&aop); - RzStrBuf sb = { 0 }; - rz_analysis_op(core->analysis, &aop, hit->addr, buf, size, RZ_ANALYSIS_OP_MASK_IL); - rz_il_op_effect_stringify(aop.il_op, &sb, true); - rz_analysis_op_fini(&aop); - rz_asm_op_free(asmop); - } - rz_cons_newline(); - break; - case RZ_OUTPUT_MODE_TABLE: - rz_table_add_rowf(state->d.t, "Xss", addr, asmop_hex_str, asmop_str); - free(asmop_str); - free(asmop_hex_str); - break; - default: - rz_warn_if_reached(); - } -cleanup: - rz_list_free(ropList); -} - -static int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzCmdStateOutput *state) { - const ut8 crop = rz_config_get_i(core->config, "rop.conditional"); // decide if cjmp, cret, and ccall should be used too for the gadget-search - const ut8 subchain = rz_config_get_i(core->config, "rop.subchains"); - const ut8 max_instr = rz_config_get_i(core->config, "rop.len"); - const char *arch = rz_config_get(core->config, "asm.arch"); - int max_count = rz_config_get_i(core->config, "search.maxhits"); - int i = 0, end = 0, increment = 1, ret, result = true; - RzList /**/ *end_list = rz_list_newf(free); - RzList /**/ *rx_list = NULL; - int align = core->search->align; - RzListIter *itermap = NULL; - char *grep_arg = NULL; - char *tok, *gregexp = NULL; - char *rx = NULL; - RzAsmOp *asmop = NULL; - RzList *boundaries = NULL; - int delta = 0; - ut8 *buf; - RzIOMap *map; - - const ut64 search_from = rz_config_get_i(core->config, "search.from"), - search_to = rz_config_get_i(core->config, "search.to"); - if (search_from > search_to && search_to) { - RZ_LOG_ERROR("core: search.from > search.to is not supported\n"); - ret = false; - goto bad; - } - // {.addr = UT64_MAX, .size = 0} means search range is unspecified - RzInterval search_itv = { search_from, search_to - search_from }; - bool empty_search_itv = search_from == search_to && search_from != UT64_MAX; - if (empty_search_itv) { - RZ_LOG_ERROR("core: `from` address is equal `to`\n"); - ret = false; - goto bad; - } - // TODO full address cannot be represented, shrink 1 byte to [0, UT64_MAX) - if (search_from == UT64_MAX && search_to == UT64_MAX) { - search_itv.addr = 0; - search_itv.size = UT64_MAX; - } - - Sdb *gadgetSdb = NULL; - if (rz_config_get_i(core->config, "rop.sdb")) { - if (!(gadgetSdb = sdb_ns(core->sdb, "gadget_sdb", false))) { - gadgetSdb = sdb_ns(core->sdb, "gadget_sdb", true); - } - } - if (max_count == 0) { - max_count = -1; - } - if (max_instr <= 1) { - rz_list_free(end_list); - RZ_LOG_ERROR("core: ROP length (rop.len) must be greater than 1.\n"); - if (max_instr == 1) { - RZ_LOG_ERROR("core: For rop.len = 1, use /c to search for single " - "instructions. See /c? for help.\n"); - } - return false; - } - - if (!strcmp(arch, "mips")) { // MIPS has no jump-in-the-middle - increment = 4; - } else if (!strcmp(arch, "arm")) { // ARM has no jump-in-the-middle - increment = rz_config_get_i(core->config, "asm.bits") == 16 ? 2 : 4; - } else if (!strcmp(arch, "avr")) { // AVR is halfword aligned. - increment = 2; - } - - if (greparg) { - grep_arg = strdup(greparg); - grep_arg = rz_str_replace(grep_arg, ",,", ";", true); - } - - // Deal with the grep guy. - if (grep_arg && regexp) { - if (!rx_list) { - rx_list = rz_list_newf(free); - } - gregexp = strdup(grep_arg); - tok = strtok(gregexp, ";"); - while (tok) { - rx = strdup(tok); - rz_list_append(rx_list, rx); - tok = strtok(NULL, ";"); - } - } - rz_cmd_state_output_array_start(state); - rz_cons_break_push(NULL, NULL); - const char *mode_str = rz_config_get(core->config, "search.in"); - boundaries = rz_core_get_boundaries_prot(core, -1, mode_str, "search"); - if (!boundaries) { - rz_cmd_state_output_array_end(state); - } - rz_list_foreach (boundaries, itermap, map) { - HtUUOptions opt = { 0 }; - HtUU *badstart = ht_uu_new_opt(&opt); - if (!rz_itv_overlap(search_itv, map->itv)) { - continue; - } - RzInterval itv = rz_itv_intersect(search_itv, map->itv); - ut64 from = itv.addr, to = rz_itv_end(itv); - if (rz_cons_is_breaked()) { - break; - } - delta = to - from; - buf = calloc(1, delta); - if (!buf) { - result = false; - goto bad; - } - (void)rz_io_read_at(core->io, from, buf, delta); - - // Find the end gadgets. - for (i = 0; i < delta; i += increment) { - RzAnalysisOp end_gadget = RZ_EMPTY; - // Disassemble one. - rz_analysis_op_init(&end_gadget); - if (rz_analysis_op(core->analysis, &end_gadget, from + i, buf + i, - delta - i, RZ_ANALYSIS_OP_MASK_BASIC) < 1) { - rz_analysis_op_fini(&end_gadget); - continue; - } - if (is_end_gadget(&end_gadget, crop)) { -#if 0 - if (search->maxhits && rz_list_length (end_list) >= search->maxhits) { - // limit number of high level rop gadget results - rz_analysis_op_fini (&end_gadget); - break; - } -#endif - struct endlist_pair *epair = RZ_NEW0(struct endlist_pair); - if (epair) { - // If this arch has branch delay slots, add the next instr as well - if (end_gadget.delay) { - epair->instr_offset = i + increment; - epair->delay_size = end_gadget.delay; - } else { - epair->instr_offset = (intptr_t)i; - epair->delay_size = end_gadget.delay; - } - rz_list_append(end_list, (void *)(intptr_t)epair); - } - } - rz_analysis_op_fini(&end_gadget); - if (rz_cons_is_breaked()) { - break; - } - // Right now we have a list of all of the end/stop gadgets. - // We can just construct gadgets from a little bit before them. - } - rz_list_reverse(end_list); - // If we have no end gadgets, just skip all of this search nonsense. - if (!rz_list_empty(end_list)) { - int prev, next, ropdepth; - const int max_inst_size_x86 = 15; - // Get the depth of rop search, should just be max_instr - // instructions, x86 and friends are weird length instructions, so - // we'll just assume 15 byte instructions. - ropdepth = increment == 1 ? max_instr * max_inst_size_x86 /* wow, x86 is long */ : max_instr * increment; - if (rz_cons_is_breaked()) { - break; - } - struct endlist_pair *end_gadget = (struct endlist_pair *)rz_list_pop(end_list); - next = end_gadget->instr_offset; - prev = 0; - // Start at just before the first end gadget. - for (i = 0; i < delta && max_count; i += increment) { - if (increment == 1) { - // give in-boundary instructions a shot - if (i < prev - max_inst_size_x86) { - i = prev - max_inst_size_x86; - } - } else { - if (i < prev) { - i = prev; - } - } - if (i < 0) { - i = 0; - } - if (rz_cons_is_breaked()) { - break; - } - if (i >= next) { - // We've exhausted the first end-gadget section, - // move to the next one. - free(end_gadget); - if (rz_list_get_n(end_list, 0)) { - prev = i; - end_gadget = (struct endlist_pair *)rz_list_pop(end_list); - next = end_gadget->instr_offset; - i = next - ropdepth; - if (i < 0) { - i = 0; - } - } else { - break; - } - } - if (i >= end) { // read by chunk of 4k - rz_io_read_at(core->io, from + i, buf + i, - RZ_MIN((delta - i), 4096)); - end = i + 2048; - } - asmop = rz_asm_op_new(); - ret = rz_asm_disassemble(core->rasm, asmop, buf + i, delta - i); - if (ret) { - rz_asm_set_pc(core->rasm, from + i); - RzList *hitlist = construct_rop_gadget(core, - from + i, buf, delta, i, greparg, regexp, - rx_list, end_gadget, badstart, delta); - if (!hitlist) { - rz_asm_op_free(asmop); - asmop = NULL; - continue; - } - if (align && 0 != (from + i) % align) { - rz_asm_op_free(asmop); - asmop = NULL; - continue; - } - if (gadgetSdb) { - RzListIter *iter; - - RzCoreAsmHit *hit = rz_list_first(hitlist); - char *headAddr = rz_str_newf("%" PFMT64x, hit->addr); - if (!headAddr) { - result = false; - free(buf); - ht_uu_free(badstart); - goto bad; - } - - rz_list_foreach (hitlist, iter, hit) { - char *addr = rz_str_newf("%" PFMT64x "(%" PFMT32d ")", hit->addr, hit->len); - if (!addr) { - free(headAddr); - result = false; - free(buf); - ht_uu_free(badstart); - goto bad; - } - sdb_concat(gadgetSdb, headAddr, addr); - free(addr); - } - free(headAddr); - } - - if (subchain) { - do { - print_rop(core, hitlist, state); - hitlist->head = hitlist->head->next; - } while (hitlist->head->next); - } else { - print_rop(core, hitlist, state); - } - rz_list_free(hitlist); - if (max_count > 0) { - max_count--; - if (max_count < 1) { - break; - } - } - } - if (increment != 1) { - i = next; - } - rz_asm_op_free(asmop); - asmop = NULL; - } - } - free(buf); - ht_uu_free(badstart); - } - if (rz_cons_is_breaked()) { - eprintf("\n"); - } - -bad: - rz_cmd_state_output_array_end(state); - rz_cons_break_pop(); - rz_asm_op_free(asmop); - rz_list_free(rx_list); - rz_list_free(end_list); - rz_list_free(boundaries); - free(grep_arg); - free(gregexp); - return result; -} - static bool esil_addrinfo(RzAnalysisEsil *esil) { RzCore *core = (RzCore *)esil->cb.user; ut64 num = 0; diff --git a/librz/core/cmd/cmd_search_rop.c b/librz/core/cmd/cmd_search_rop.c index 8ed2c3b88b6..f232990cca7 100644 --- a/librz/core/cmd/cmd_search_rop.c +++ b/librz/core/cmd/cmd_search_rop.c @@ -731,26 +731,6 @@ static void rop_classify(RzCore *core, Sdb *db, RzList /**/ *ropList, co free(str); } -RZ_API void rz_rop_constraint_free(void *data) { - RzRopConstraint *constraint = data; - if (constraint) { - for (int i = 0; i < NUM_ARGS; i++) { - if (constraint->args[i]) { - free(constraint->args[i]); - } - } - free(constraint); - } -} - -static RzList /**/ *rz_rop_constraint_list_new(void) { - RzList *list = rz_list_new(); - if (list) { - list->free = &rz_rop_constraint_free; - } - return list; -} - static void skip_whitespace(const char *str, int *idx) { while (str[*idx] == ' ' || str[*idx] == '\t' || str[*idx] == '\n' || str[*idx] == '\r') { (*idx)++; @@ -764,8 +744,9 @@ static bool parse_eof(const char *str, int idx) { static bool parse_il_equal(char *str, int *idx) { skip_whitespace(str, idx); - if (*idx >= strlen(str)) + if (*idx >= strlen(str)) { return false; + } if (str[*idx] == '=') { (*idx)++; return true; @@ -773,7 +754,14 @@ static bool parse_il_equal(char *str, int *idx) { return false; } -static char *parse_register(char *str, int *idx) { +static bool is_reg_in_profile(const char *reg_profile, const char *str) { + if (strstr(reg_profile, str) != NULL) { + return true; + } + return false; +} + +static char *parse_register(RzCore *core, char *str, int *idx) { char reg[256] = { 0 }; int reg_idx = 0; @@ -784,12 +772,23 @@ static char *parse_register(char *str, int *idx) { (*idx)++; } - // Check if the register is correct for the given architecture. if (reg_idx == 0) { return NULL; } - return strdup(reg); + char *reg_prof = rz_analysis_get_reg_profile(core->analysis); + if (!reg_prof) { + return NULL; + } + + // Check if the register is correct for the given architecture. + if (is_reg_in_profile(reg_prof, reg)) { + free(reg_prof); + return strdup(reg); + } + + free(reg_prof); + return NULL; } static bool parse_constant(const char *str, int *idx, unsigned long long *value) { @@ -831,7 +830,7 @@ static bool parse_constant(const char *str, int *idx, unsigned long long *value) static bool parse_reg_to_const(RzCore *core, char *str, RzRopConstraint *rop_constraint) { int idx = 0; - char *dst_reg = parse_register(str, &idx); + char *dst_reg = parse_register(core, str, &idx); if (!dst_reg) { return false; } @@ -856,14 +855,14 @@ static bool parse_reg_to_const(RzCore *core, char *str, RzRopConstraint *rop_con rop_constraint->args[DST_REG] = dst_reg; rop_constraint->args[SRC_REG] = NULL; char value_str[256]; - sprintf(value_str, "%llu", const_value); - rop_constraint->args[DST_CONST] = strdup(value_str); + snprintf(value_str, sizeof(value_str), "%llu", const_value); + rop_constraint->args[SRC_CONST] = strdup(value_str); return true; } static bool parse_reg_to_reg(RzCore *core, char *str, RzRopConstraint *rop_constraint) { int idx = 0; - char *dst_reg = parse_register(str, &idx); + char *dst_reg = parse_register(core, str, &idx); if (!dst_reg) { return false; } @@ -873,7 +872,7 @@ static bool parse_reg_to_reg(RzCore *core, char *str, RzRopConstraint *rop_const return false; } - char *src_reg = parse_register(str, &idx); + char *src_reg = parse_register(core, str, &idx); if (!src_reg) { free(dst_reg); return false; @@ -927,6 +926,9 @@ static bool parse_il_op(RzList *args, const char *str, int *idx) { (*idx)++; res = RZ_IL_OP_MOD; break; + case '-': + (*idx)++; + res = RZ_IL_OP_SUB; default: break; } if (res == RZ_IL_OP_VAR) { @@ -941,7 +943,7 @@ static bool parse_il_op(RzList *args, const char *str, int *idx) { } } - RzILOpPureCode *op_ptr = (RzILOpPureCode *)malloc(sizeof(RzILOpPureCode)); + RzILOpPureCode *op_ptr = malloc(sizeof(RzILOpPureCode)); if (!op_ptr) { return false; } @@ -953,7 +955,7 @@ static bool parse_il_op(RzList *args, const char *str, int *idx) { static bool parse_reg_op_const(RzCore *core, char *str, RzRopConstraint *rop_constraint) { int idx = 0; - char *dst_reg = parse_register(str, &idx); + char *dst_reg = parse_register(core, str, &idx); if (!dst_reg) { return false; } @@ -963,7 +965,7 @@ static bool parse_reg_op_const(RzCore *core, char *str, RzRopConstraint *rop_con return false; } - char *src_reg = parse_register(str, &idx); + char *src_reg = parse_register(core, str, &idx); if (!src_reg) { free(dst_reg); return false; @@ -994,18 +996,25 @@ static bool parse_reg_op_const(RzCore *core, char *str, RzRopConstraint *rop_con rop_constraint->args[DST_REG] = dst_reg; rop_constraint->args[SRC_REG] = src_reg; RzILOpPureCode *op = rz_list_get_n(args, 0); - char op_str[3]; + if (!op) { + free(dst_reg); + free(src_reg); + rz_list_free(args); + return false; + } + + char op_str[16]; snprintf(op_str, sizeof(op_str), "%s", rz_il_op_pure_code_stringify(*op)); rop_constraint->args[OP] = strdup(op_str); char value_str[256]; - sprintf(value_str, "%llu", const_value); - rop_constraint->args[DST_CONST] = strdup(value_str); + snprintf(value_str, sizeof(value_str), "%llu", const_value); + rop_constraint->args[SRC_CONST] = strdup(value_str); return true; } static bool parse_reg_op_reg(RzCore *core, char *str, RzRopConstraint *rop_constraint) { int idx = 0; - char *dst_reg = parse_register(str, &idx); + char *dst_reg = parse_register(core, str, &idx); if (!dst_reg) { return false; } @@ -1015,7 +1024,7 @@ static bool parse_reg_op_reg(RzCore *core, char *str, RzRopConstraint *rop_const return false; } - char *src_reg1 = parse_register(str, &idx); + char *src_reg1 = parse_register(core, str, &idx); if (!src_reg1) { free(dst_reg); return false; @@ -1029,8 +1038,8 @@ static bool parse_reg_op_reg(RzCore *core, char *str, RzRopConstraint *rop_const return false; } - char *src_reg2 = parse_register(str, &idx); - if (!src_reg2) { + char *dst_reg2 = parse_register(core, str, &idx); + if (!dst_reg2) { free(dst_reg); free(src_reg1); return false; @@ -1039,7 +1048,7 @@ static bool parse_reg_op_reg(RzCore *core, char *str, RzRopConstraint *rop_const if (!parse_eof(str, idx)) { free(dst_reg); free(src_reg1); - free(src_reg2); + free(dst_reg2); rz_list_free(args); return false; } @@ -1048,28 +1057,30 @@ static bool parse_reg_op_reg(RzCore *core, char *str, RzRopConstraint *rop_const rop_constraint->args[DST_REG] = dst_reg; rop_constraint->args[SRC_REG] = src_reg1; RzILOpPureCode *op = rz_list_get_n(args, 0); + if (!op) { + free(dst_reg); + free(src_reg1); + free(dst_reg2); + rz_list_free(args); + return false; + } + char op_str[16]; snprintf(op_str, sizeof(op_str), "%s", rz_il_op_pure_code_stringify(*op)); rop_constraint->args[OP] = strdup(op_str); - rop_constraint->args[DST_CONST] = src_reg2; + rop_constraint->args[SRC_CONST] = dst_reg2; return true; } -static bool parse_instruction(RzCore *core, char *str, RzRopConstraint *rop_constraint) { +RZ_API bool analyze_constraint(RzCore *core, char *str, RzRopConstraint *rop_constraint) { + rz_return_val_if_fail(core, NULL); 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); } -static void rop_constraint_analysis(RzCore *core, const RzList *constraint_list) { - RzListIter *it; - RzRopConstraint *token; - rz_list_foreach (constraint_list, it, token) { - } -} - -static RzRopConstraint *rop_constraint_kv(RzCore *core, char *token) { +static RzRopConstraint *rop_constraint_parse_args(RzCore *core, char *token) { RzRopConstraint *rop_constraint = RZ_NEW0(RzRopConstraint); RzList *l = rz_str_split_duplist_n(token, "=", 1, false); char *key = rz_list_get_n(l, 0); @@ -1083,8 +1094,9 @@ static RzRopConstraint *rop_constraint_kv(RzCore *core, char *token) { rz_list_free(l); return NULL; } - if (!parse_instruction(core, token, rop_constraint)) { + if (!analyze_constraint(core, token, rop_constraint)) { free(rop_constraint); + rz_list_free(l); return NULL; } @@ -1106,7 +1118,7 @@ static RzList *rop_constraint_list_parse(RzCore *core, int argc, const char **ar RzListIter *it; char *token; rz_list_foreach (l, it, token) { - RzRopConstraint *rop_constraint = rop_constraint_kv(core, token); + RzRopConstraint *rop_constraint = rop_constraint_parse_args(core, token); if (!rop_constraint) { continue; } diff --git a/librz/core/rop.c b/librz/core/rop.c index ce1af3afda2..f2b2217d147 100644 --- a/librz/core/rop.c +++ b/librz/core/rop.c @@ -1,2 +1,774 @@ // SPDX-FileCopyrightText: 2010-2021 z3phyr // SPDX-License-Identifier: LGPL-3.0-only + +#include +#include +#include +#include +#include + +static bool is_end_gadget(const RzAnalysisOp *aop, const ut8 crop) { + 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: + return true; + } + if (crop) { // if conditional jumps, calls and returns should be used for the gadget-search too + 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; + } + } + return false; +} + +static void print_rop(RzCore *core, RzList /**/ *hitlist, RzCmdStateOutput *state) { + RzCoreAsmHit *hit = NULL; + RzListIter *iter; + RzList *ropList = NULL; + unsigned int size = 0; + char *asmop_str = NULL, *asmop_hex_str = NULL; + RzAnalysisOp aop = RZ_EMPTY; + const char *comment = NULL; + Sdb *db = NULL; + const bool colorize = rz_config_get_i(core->config, "scr.color"); + const bool rop_comments = rz_config_get_i(core->config, "rop.comments"); + const bool esil = rz_config_get_i(core->config, "asm.esil"); + const bool rop_db = rz_config_get_i(core->config, "rop.db"); + ut8 *buf = NULL; + RzStrBuf *colored_asm = NULL, *bw_str = NULL; + if (rop_db) { + db = sdb_ns(core->sdb, "rop", true); + ropList = rz_list_newf(free); + if (!db) { + RZ_LOG_ERROR("core: Could not create SDB 'rop' namespace\n"); + rz_list_free(ropList); + return; + } + } + + rz_cmd_state_output_set_columnsf(state, "XXs", "addr", "bytes", "disasm"); + if (state->mode == RZ_OUTPUT_MODE_JSON) { + pj_o(state->d.pj); + pj_ka(state->d.pj, "opcodes"); + } else if (state->mode == RZ_OUTPUT_MODE_QUIET) { + rz_cons_printf("0x%08" PFMT64x ":", ((RzCoreAsmHit *)rz_list_first(hitlist))->addr); + } + const ut64 addr = ((RzCoreAsmHit *)rz_list_first(hitlist))->addr; + + rz_list_foreach (hitlist, iter, hit) { + RzAsmOp *asmop = rz_asm_op_new(); + switch (state->mode) { + case RZ_OUTPUT_MODE_JSON: + buf = malloc(hit->len); + if (!buf) { + goto cleanup; + } + rz_io_read_at(core->io, hit->addr, buf, hit->len); + rz_asm_set_pc(core->rasm, hit->addr); + rz_asm_disassemble(core->rasm, asmop, buf, hit->len); + rz_analysis_op_init(&aop); + rz_analysis_op(core->analysis, &aop, hit->addr, buf, hit->len, RZ_ANALYSIS_OP_MASK_ESIL); + size += hit->len; + if (aop.type != RZ_ANALYSIS_OP_TYPE_RET) { + char *opstr_n = rz_str_newf(" %s", RZ_STRBUF_SAFEGET(&aop.esil)); + rz_list_append(ropList, opstr_n); + } + pj_o(state->d.pj); + pj_kn(state->d.pj, "offset", hit->addr); + pj_ki(state->d.pj, "size", hit->len); + pj_ks(state->d.pj, "opcode", rz_asm_op_get_asm(asmop)); + pj_ks(state->d.pj, "type", rz_analysis_optype_to_string(aop.type)); + pj_end(state->d.pj); + free(buf); + rz_analysis_op_fini(&aop); + break; + case RZ_OUTPUT_MODE_QUIET: + // Print gadgets in a 'linear manner', each sequence on one line. + buf = malloc(hit->len); + if (!buf) { + goto cleanup; + } + rz_io_read_at(core->io, hit->addr, buf, hit->len); + rz_asm_set_pc(core->rasm, hit->addr); + rz_asm_disassemble(core->rasm, asmop, buf, hit->len); + rz_analysis_op_init(&aop); + rz_analysis_op(core->analysis, &aop, hit->addr, buf, hit->len, RZ_ANALYSIS_OP_MASK_BASIC); + size += hit->len; + const char *opstr = RZ_STRBUF_SAFEGET(&aop.esil); + if (aop.type != RZ_ANALYSIS_OP_TYPE_RET) { + rz_list_append(ropList, rz_str_newf(" %s", opstr)); + } + if (esil) { + rz_cons_printf("%s\n", opstr); + } else if (colorize) { + bw_str = rz_strbuf_new(rz_asm_op_get_asm(asmop)); + RzAsmParseParam *param = rz_asm_get_parse_param(core->analysis->reg, aop.type); + colored_asm = rz_asm_colorize_asm_str(bw_str, core->print, param, asmop->asm_toks); + rz_asm_parse_param_free(param); + rz_cons_printf(" %s%s;", colored_asm ? rz_strbuf_get(colored_asm) : "", Color_RESET); + rz_strbuf_free(colored_asm); + rz_strbuf_free(bw_str); + } else { + rz_cons_printf(" %s;", rz_asm_op_get_asm(asmop)); + } + free(buf); + rz_analysis_op_fini(&aop); + break; + case RZ_OUTPUT_MODE_STANDARD: + // Print gadgets with new instruction on a new line. + comment = rop_comments ? rz_meta_get_string(core->analysis, RZ_META_TYPE_COMMENT, hit->addr) : NULL; + if (hit->len < 0) { + RZ_LOG_ERROR("core: Invalid hit length here\n"); + continue; + } + buf = malloc(1 + hit->len); + if (!buf) { + break; + } + buf[hit->len] = 0; + rz_io_read_at(core->io, hit->addr, buf, hit->len); + rz_asm_set_pc(core->rasm, hit->addr); + rz_asm_disassemble(core->rasm, asmop, buf, hit->len); + rz_analysis_op_init(&aop); + rz_analysis_op(core->analysis, &aop, hit->addr, buf, hit->len, RZ_ANALYSIS_OP_MASK_ESIL); + size += hit->len; + if (aop.type != RZ_ANALYSIS_OP_TYPE_RET) { + char *opstr_n = rz_str_newf(" %s", RZ_STRBUF_SAFEGET(&aop.esil)); + rz_list_append(ropList, opstr_n); + } + char *asm_op_hex = rz_asm_op_get_hex(asmop); + if (colorize) { + bw_str = rz_strbuf_new(rz_asm_op_get_asm(asmop)); + RzAsmParseParam *param = rz_asm_get_parse_param(core->analysis->reg, aop.type); + colored_asm = rz_asm_colorize_asm_str(bw_str, core->print, param, asmop->asm_toks); + rz_asm_parse_param_free(param); + if (comment) { + rz_cons_printf(" 0x%08" PFMT64x " %18s %s%s ; %s\n", + hit->addr, asm_op_hex, colored_asm ? rz_strbuf_get(colored_asm) : "", Color_RESET, comment); + } else { + rz_cons_printf(" 0x%08" PFMT64x " %18s %s%s\n", + hit->addr, asm_op_hex, colored_asm ? rz_strbuf_get(colored_asm) : "", Color_RESET); + } + rz_strbuf_free(colored_asm); + rz_strbuf_free(bw_str); + } else { + if (comment) { + rz_cons_printf(" 0x%08" PFMT64x " %18s %s ; %s\n", + hit->addr, asm_op_hex, rz_asm_op_get_asm(asmop), comment); + } else { + rz_cons_printf(" 0x%08" PFMT64x " %18s %s\n", + hit->addr, asm_op_hex, rz_asm_op_get_asm(asmop)); + } + } + free(asm_op_hex); + free(buf); + rz_analysis_op_fini(&aop); + comment = NULL; + break; + case RZ_OUTPUT_MODE_TABLE: + buf = malloc(hit->len); + if (!buf) { + goto cleanup; + } + rz_io_read_at(core->io, hit->addr, buf, hit->len); + rz_asm_set_pc(core->rasm, hit->addr); + rz_asm_disassemble(core->rasm, asmop, buf, hit->len); + rz_analysis_op_init(&aop); + rz_analysis_op(core->analysis, &aop, hit->addr, buf, hit->len, RZ_ANALYSIS_OP_MASK_BASIC); + size += hit->len; + if (asmop_str) { + asmop_str = rz_str_append(asmop_str, rz_asm_op_get_asm(asmop)); + const ut64 addr_last = ((RzCoreAsmHit *)rz_list_last(hitlist))->addr; + if (addr_last != hit->addr) { + asmop_str = rz_str_append(asmop_str, "; "); + } + } else { + asmop_str = rz_str_newf("%s; ", rz_asm_op_get_asm(asmop)); + } + char *asmop_hex_str_dup = NULL; + if (asmop_hex_str) { + asmop_hex_str_dup = rz_asm_op_get_hex(asmop); + asmop_hex_str = rz_str_append(asmop_hex_str, asmop_hex_str_dup); + } else { + asmop_hex_str_dup = rz_asm_op_get_hex(asmop); + asmop_hex_str = rz_str_newf("%s", asmop_hex_str_dup); + } + free(asmop_hex_str_dup); + free(buf); + rz_analysis_op_fini(&aop); + break; + default: + rz_warn_if_reached(); + break; + } + rz_asm_op_free(asmop); + } + switch (state->mode) { + case RZ_OUTPUT_MODE_JSON: + pj_end(state->d.pj); + if (db && hit) { + // const char *key = rz_strf(tmpbuf, "0x%08" PFMT64x, addr); + // rop_classify(core, db, ropList, key, size); + } + if (hit) { + pj_kn(state->d.pj, "retaddr", hit->addr); + pj_ki(state->d.pj, "size", size); + } + pj_end(state->d.pj); + break; + case RZ_OUTPUT_MODE_QUIET: + rz_cons_newline(); + break; + // fallthrough + case RZ_OUTPUT_MODE_STANDARD: + if (db && hit) { + rz_cons_printf("Gadget size: %d\n", (int)size); + // rop_classify(core, db, ropList, key, size); + buf = malloc(size + 1); + hit = rz_list_first(hitlist); + if (!buf) { + goto cleanup; + } + RzAsmOp *asmop = rz_asm_op_new(); + buf[size] = 0; + rz_io_read_at(core->io, hit->addr, buf, size); + rz_asm_set_pc(core->rasm, hit->addr); + rz_asm_disassemble(core->rasm, asmop, buf, size); + rz_analysis_op_init(&aop); + rz_analysis_op(core->analysis, &aop, hit->addr, buf, size, RZ_ANALYSIS_OP_MASK_IL); + rz_analysis_op_fini(&aop); + rz_asm_op_free(asmop); + free(buf); + } + rz_cons_newline(); + break; + case RZ_OUTPUT_MODE_TABLE: + rz_table_add_rowf(state->d.t, "Xss", addr, asmop_hex_str, asmop_str); + free(asmop_str); + free(asmop_hex_str); + break; + default: + rz_warn_if_reached(); + } +cleanup: + rz_list_free(ropList); +} + +static bool insert_into(void *user, const ut64 k, const ut64 v) { + HtUU *ht = (HtUU *)user; + ht_uu_insert(ht, k, v); + return true; +} + +// TODO: follow unconditional jumps +static RzList /**/ *construct_rop_gadget(RzCore *core, ut64 addr, ut8 *buf, int buflen, + int idx, const char *grep, int regex, RzList /**/ *rx_list, + RzRopEndListPair *end_gadget, HtUU *badstart, int delta) { + int endaddr = end_gadget->instr_offset; + int branch_delay = end_gadget->delay_size; + RzAnalysisOp aop = { 0 }; + const char *start = NULL, *end = NULL; + char *grep_str = NULL; + RzCoreAsmHit *hit = NULL; + RzList *hitlist = rz_core_asm_hit_list_new(); + ut8 nb_instr = 0; + const ut8 max_instr = rz_config_get_i(core->config, "rop.len"); + bool valid = false; + int grep_find; + int search_hit; + char *rx = NULL; + HtUUOptions opt = { 0 }; + HtUU *localbadstart = ht_uu_new_opt(&opt); + int count = 0; + + if (grep) { + start = grep; + end = strchr(grep, ';'); + if (!end) { // We filter on a single opcode, so no ";" + end = start + strlen(grep); + } + grep_str = calloc(1, end - start + 1); + strncpy(grep_str, start, end - start); + if (regex) { + // get the first regexp. + if (rz_list_length(rx_list) > 0) { + rx = rz_list_get_n(rx_list, count++); + } + } + } + + bool found; + ht_uu_find(badstart, idx, &found); + if (found) { + valid = false; + goto ret; + } + while (nb_instr < max_instr) { + ht_uu_insert(localbadstart, idx, 1); + rz_analysis_op_init(&aop); + if (idx >= delta) { + valid = false; + goto ret; + } + int error = rz_analysis_op(core->analysis, &aop, addr, buf + idx, buflen - idx, RZ_ANALYSIS_OP_MASK_DISASM); + if (error < 0 || (nb_instr == 0 && (is_end_gadget(&aop, 0) || aop.type == RZ_ANALYSIS_OP_TYPE_NOP))) { + valid = false; + goto ret; + } + + const int opsz = aop.size; + // opsz = rz_strbuf_length (asmop.buf); + char *opst = aop.mnemonic; + if (!opst) { + RZ_LOG_WARN("Analysis plugin %s did not return disassembly\n", core->analysis->cur->name); + RzAsmOp asmop; + rz_asm_set_pc(core->rasm, addr); + if (rz_asm_disassemble(core->rasm, &asmop, buf + idx, buflen - idx) < 0) { + valid = false; + goto ret; + } + opst = strdup(rz_asm_op_get_asm(&asmop)); + rz_asm_op_fini(&asmop); + } + if (!rz_str_ncasecmp(opst, "invalid", strlen("invalid")) || + !rz_str_ncasecmp(opst, ".byte", strlen(".byte"))) { + valid = false; + goto ret; + } + + hit = rz_core_asm_hit_new(); + if (hit) { + hit->addr = addr; + hit->len = opsz; + rz_list_append(hitlist, hit); + } + + // Move on to the next instruction + idx += opsz; + addr += opsz; + if (rx) { + grep_find = rz_regex_contains(rx, opst, RZ_REGEX_ZERO_TERMINATED, RZ_REGEX_EXTENDED, RZ_REGEX_DEFAULT); + search_hit = (end && grep && grep_find); + } else { + search_hit = (end && grep && strstr(opst, grep_str)); + } + + // Handle (possible) grep + if (search_hit) { + if (end[0] == ';') { // fields are semicolon-separated + start = end + 1; // skip the ; + end = strchr(start, ';'); + end = end ? end : start + strlen(start); // latest field? + free(grep_str); + grep_str = calloc(1, end - start + 1); + if (grep_str) { + strncpy(grep_str, start, end - start); + } + } else { + end = NULL; + } + if (regex) { + rx = rz_list_get_n(rx_list, count++); + } + } + if (endaddr <= (idx - opsz)) { + valid = (endaddr == idx - opsz); + goto ret; + } + rz_analysis_op_fini(&aop); + nb_instr++; + } +ret: + rz_analysis_op_fini(&aop); + free(grep_str); + if (regex && rx) { + rz_list_free(hitlist); + ht_uu_free(localbadstart); + return NULL; + } + if (!valid || (grep && end)) { + rz_list_free(hitlist); + ht_uu_free(localbadstart); + return NULL; + } + ht_uu_foreach(localbadstart, insert_into, badstart); + ht_uu_free(localbadstart); + // If our arch has bds then we better be including them + if (branch_delay && rz_list_length(hitlist) < (1 + branch_delay)) { + rz_list_free(hitlist); + return NULL; + } + return hitlist; +} + +RZ_API int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzCmdStateOutput *state) { + const ut8 crop = rz_config_get_i(core->config, "rop.conditional"); // decide if cjmp, cret, and ccall should be used too for the gadget-search + const ut8 subchain = rz_config_get_i(core->config, "rop.subchains"); + const ut8 max_instr = rz_config_get_i(core->config, "rop.len"); + const char *arch = rz_config_get(core->config, "asm.arch"); + int max_count = rz_config_get_i(core->config, "search.maxhits"); + int i = 0, end = 0, increment = 1, ret, result = true; + RzList /**/ *end_list = rz_list_newf(free); + RzList /**/ *rx_list = NULL; + int align = core->search->align; + RzListIter *itermap = NULL; + char *grep_arg = NULL; + char *tok, *gregexp = NULL; + char *rx = NULL; + RzAsmOp *asmop = NULL; + RzList *boundaries = NULL; + int delta = 0; + ut8 *buf; + RzIOMap *map; + + const ut64 search_from = rz_config_get_i(core->config, "search.from"), + search_to = rz_config_get_i(core->config, "search.to"); + if (search_from > search_to && search_to) { + RZ_LOG_ERROR("core: search.from > search.to is not supported\n"); + ret = false; + goto bad; + } + // {.addr = UT64_MAX, .size = 0} means search range is unspecified + RzInterval search_itv = { search_from, search_to - search_from }; + bool empty_search_itv = search_from == search_to && search_from != UT64_MAX; + if (empty_search_itv) { + RZ_LOG_ERROR("core: `from` address is equal `to`\n"); + ret = false; + goto bad; + } + // TODO full address cannot be represented, shrink 1 byte to [0, UT64_MAX) + if (search_from == UT64_MAX && search_to == UT64_MAX) { + search_itv.addr = 0; + search_itv.size = UT64_MAX; + } + + Sdb *gadgetSdb = NULL; + if (rz_config_get_i(core->config, "rop.sdb")) { + if (!(gadgetSdb = sdb_ns(core->sdb, "gadget_sdb", false))) { + gadgetSdb = sdb_ns(core->sdb, "gadget_sdb", true); + } + } + if (max_count == 0) { + max_count = -1; + } + if (max_instr <= 1) { + rz_list_free(end_list); + RZ_LOG_ERROR("core: ROP length (rop.len) must be greater than 1.\n"); + if (max_instr == 1) { + RZ_LOG_ERROR("core: For rop.len = 1, use /c to search for single " + "instructions. See /c? for help.\n"); + } + return false; + } + + if (!strcmp(arch, "mips")) { // MIPS has no jump-in-the-middle + increment = 4; + } else if (!strcmp(arch, "arm")) { // ARM has no jump-in-the-middle + increment = rz_config_get_i(core->config, "asm.bits") == 16 ? 2 : 4; + } else if (!strcmp(arch, "avr")) { // AVR is halfword aligned. + increment = 2; + } + + if (greparg) { + grep_arg = strdup(greparg); + grep_arg = rz_str_replace(grep_arg, ",,", ";", true); + } + + // Deal with the grep guy. + if (grep_arg && regexp) { + if (!rx_list) { + rx_list = rz_list_newf(free); + } + gregexp = strdup(grep_arg); + tok = strtok(gregexp, ";"); + while (tok) { + rx = strdup(tok); + rz_list_append(rx_list, rx); + tok = strtok(NULL, ";"); + } + } + rz_cmd_state_output_array_start(state); + rz_cons_break_push(NULL, NULL); + const char *mode_str = rz_config_get(core->config, "search.in"); + boundaries = rz_core_get_boundaries_prot(core, -1, mode_str, "search"); + if (!boundaries) { + rz_cmd_state_output_array_end(state); + } + rz_list_foreach (boundaries, itermap, map) { + HtUUOptions opt = { 0 }; + HtUU *badstart = ht_uu_new_opt(&opt); + if (!rz_itv_overlap(search_itv, map->itv)) { + continue; + } + RzInterval itv = rz_itv_intersect(search_itv, map->itv); + ut64 from = itv.addr, to = rz_itv_end(itv); + if (rz_cons_is_breaked()) { + break; + } + delta = to - from; + buf = calloc(1, delta); + if (!buf) { + result = false; + goto bad; + } + (void)rz_io_read_at(core->io, from, buf, delta); + + // Find the end gadgets. + for (i = 0; i < delta; i += increment) { + RzAnalysisOp end_gadget = RZ_EMPTY; + // Disassemble one. + rz_analysis_op_init(&end_gadget); + if (rz_analysis_op(core->analysis, &end_gadget, from + i, buf + i, + delta - i, RZ_ANALYSIS_OP_MASK_BASIC) < 1) { + rz_analysis_op_fini(&end_gadget); + continue; + } + if (is_end_gadget(&end_gadget, crop)) { +#if 0 + if (search->maxhits && rz_list_length (end_list) >= search->maxhits) { + // limit number of high level rop gadget results + rz_analysis_op_fini (&end_gadget); + break; + } +#endif + RzRopEndListPair *epair = RZ_NEW0(RzRopEndListPair); + if (epair) { + // If this arch has branch delay slots, add the next instr as well + if (end_gadget.delay) { + epair->instr_offset = i + increment; + epair->delay_size = end_gadget.delay; + } else { + epair->instr_offset = (intptr_t)i; + epair->delay_size = end_gadget.delay; + } + rz_list_append(end_list, (void *)(intptr_t)epair); + } + } + rz_analysis_op_fini(&end_gadget); + if (rz_cons_is_breaked()) { + break; + } + // Right now we have a list of all of the end/stop gadgets. + // We can just construct gadgets from a little bit before them. + } + rz_list_reverse(end_list); + // If we have no end gadgets, just skip all of this search nonsense. + if (!rz_list_empty(end_list)) { + int prev, next, ropdepth; + const int max_inst_size_x86 = 15; + // Get the depth of rop search, should just be max_instr + // instructions, x86 and friends are weird length instructions, so + // we'll just assume 15 byte instructions. + ropdepth = increment == 1 ? max_instr * max_inst_size_x86 /* wow, x86 is long */ : max_instr * increment; + if (rz_cons_is_breaked()) { + break; + } + RzRopEndListPair *end_gadget = rz_list_pop(end_list); + next = end_gadget->instr_offset; + prev = 0; + // Start at just before the first end gadget. + for (i = 0; i < delta && max_count; i += increment) { + if (increment == 1) { + // give in-boundary instructions a shot + if (i < prev - max_inst_size_x86) { + i = prev - max_inst_size_x86; + } + } else { + if (i < prev) { + i = prev; + } + } + if (i < 0) { + i = 0; + } + if (rz_cons_is_breaked()) { + break; + } + if (i >= next) { + // We've exhausted the first end-gadget section, + // move to the next one. + free(end_gadget); + if (rz_list_get_n(end_list, 0)) { + prev = i; + end_gadget = (RzRopEndListPair *)rz_list_pop(end_list); + next = end_gadget->instr_offset; + i = next - ropdepth; + if (i < 0) { + i = 0; + } + } else { + end_gadget = NULL; + break; + } + } + if (i >= end) { // read by chunk of 4k + rz_io_read_at(core->io, from + i, buf + i, + RZ_MIN((delta - i), 4096)); + end = i + 2048; + } + asmop = rz_asm_op_new(); + ret = rz_asm_disassemble(core->rasm, asmop, buf + i, delta - i); + if (ret) { + rz_asm_set_pc(core->rasm, from + i); + RzList *hitlist = construct_rop_gadget(core, + from + i, buf, delta, i, greparg, regexp, + rx_list, end_gadget, badstart, delta); + if (!hitlist) { + rz_asm_op_free(asmop); + asmop = NULL; + continue; + } + if (align && 0 != (from + i) % align) { + rz_asm_op_free(asmop); + asmop = NULL; + continue; + } + if (gadgetSdb) { + RzListIter *iter; + + RzCoreAsmHit *hit = rz_list_first(hitlist); + char *headAddr = rz_str_newf("%" PFMT64x, hit->addr); + if (!headAddr) { + result = false; + free(buf); + ht_uu_free(badstart); + goto bad; + } + + rz_list_foreach (hitlist, iter, hit) { + char *addr = rz_str_newf("%" PFMT64x "(%" PFMT32d ")", hit->addr, hit->len); + if (!addr) { + free(headAddr); + result = false; + free(buf); + ht_uu_free(badstart); + goto bad; + } + sdb_concat(gadgetSdb, headAddr, addr); + free(addr); + } + free(headAddr); + } + + if (subchain) { + do { + print_rop(core, hitlist, state); + hitlist->head = hitlist->head->next; + } while (hitlist->head->next); + } else { + print_rop(core, hitlist, state); + } + rz_list_free(hitlist); + if (max_count > 0) { + max_count--; + if (max_count < 1) { + break; + } + } + } + if (increment != 1) { + i = next; + } + rz_asm_op_free(asmop); + asmop = NULL; + } + free(end_gadget); + } + free(buf); + ht_uu_free(badstart); + } + if (rz_cons_is_breaked()) { + eprintf("\n"); + } + +bad: + rz_cmd_state_output_array_end(state); + rz_cons_break_pop(); + rz_asm_op_free(asmop); + rz_list_free(rx_list); + rz_list_free(end_list); + rz_list_free(boundaries); + free(grep_arg); + free(gregexp); + return result; +} + +RZ_API RzCmdStatus rz_core_rop_gadget_info(RzCore *core, const char *input, RzCmdStateOutput *state) { + Sdb *gadgetSdb = sdb_ns(core->sdb, "gadget_sdb", false); + + if (!gadgetSdb) { + rz_core_search_rop(core, input, 0, state); + return RZ_CMD_STATUS_OK; + } + void **iter; + RzPVector *items = sdb_get_items(gadgetSdb, true); + + rz_cmd_state_output_array_start(state); + rz_pvector_foreach (items, iter) { + SdbKv *kv = *iter; + RzList *hitlist = rz_core_asm_hit_list_new(); + if (!hitlist) { + break; + } + + const char *s = sdbkv_value(kv); + ut64 addr; + int opsz; + do { + RzCoreAsmHit *hit = rz_core_asm_hit_new(); + if (!hit) { + rz_list_free(hitlist); + break; + } + sscanf(s, "%" PFMT64x "(%" PFMT32d ")", &addr, &opsz); + hit->addr = addr; + hit->len = opsz; + rz_list_append(hitlist, hit); + } while (*(s = strchr(s, ')') + 1) != '\0'); + + print_rop(core, hitlist, state); + rz_list_free(hitlist); + } + rz_pvector_free(items); + rz_cmd_state_output_array_end(state); + return RZ_CMD_STATUS_OK; +} + +RZ_API void rz_rop_constraint_free(RZ_NULLABLE void *data) { + RzRopConstraint *constraint = data; + if (!constraint) { + return; + } + for (int i = 0; i < NUM_ARGS; i++) { + if (constraint->args[i]) { + free(constraint->args[i]); + } + } + free(constraint); +} + +RZ_API RzList /**/ *rz_rop_constraint_list_new(void) { + RzList *list = rz_list_new(); + if (list) { + list->free = &rz_rop_constraint_free; + } + return list; +} diff --git a/librz/include/rz_rop.h b/librz/include/rz_rop.h index 2584d0bc3a7..4ddbed007e2 100644 --- a/librz/include/rz_rop.h +++ b/librz/include/rz_rop.h @@ -19,13 +19,31 @@ typedef enum rzil_instr_type { typedef enum { SRC_REG, DST_REG, - OP, - DST_CONST, + SRC_CONST, DST_REG_SECOND, + OP, NUM_ARGS } RzRopArgType; -typedef struct rz_rop_constraint { +typedef struct rz_rop_endlist_pair_t { + int instr_offset; + int delay_size; +} RzRopEndListPair; + +typedef struct rz_rop_constraint_t { RzILInstructionType type; char *args[NUM_ARGS]; -} RzRopConstraint; \ No newline at end of file +} RzRopConstraint; + +typedef struct rz_rop_gadget_analysis_t { + ut64 addr; +} RzRopGadgetAnalysis; + +// Command APIs +RZ_API int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzCmdStateOutput *state); +RZ_API RzCmdStatus rz_core_rop_gadget_info(RzCore *core, const char *input, RzCmdStateOutput *state); +RZ_API bool analyze_constraint(RzCore *core, char *str, RzRopConstraint *rop_constraint); + +// ROP Constraint APIs +RZ_API void rz_rop_constraint_free(RZ_NULLABLE void *data); +RZ_API RzList /**/ *rz_rop_constraint_list_new(void); \ No newline at end of file diff --git a/test/unit/meson.build b/test/unit/meson.build index c5ca0883b74..99d44094b20 100644 --- a/test/unit/meson.build +++ b/test/unit/meson.build @@ -76,6 +76,7 @@ if get_option('enable_tests') 'rbtree', 'reg', 'regex', + 'rop_constraint', 'run', 'rz_test', 'sdb_array', diff --git a/test/unit/test_rop_constraint.c b/test/unit/test_rop_constraint.c new file mode 100644 index 00000000000..d274bdef730 --- /dev/null +++ b/test/unit/test_rop_constraint.c @@ -0,0 +1,142 @@ +// SPDX-FileCopyrightText: 2021 z3phyr +// SPDX-License-Identifier: LGPL-3.0-only + +#include +#include "minunit.h" +#include + +// Define the register profile string for your architecture +#define REGISTER_PROFILE_STRING \ + "=PC trip\n" \ + "=SP rsp\n" \ + "=BP rbp\n" \ + "=A0 rdi\n" \ + "=A1 rsi\n" \ + "=A2 rdx\n" \ + "=A3 rcx\n" \ + "=A4 r8\n" \ + "=A5 r9\n" \ + "=A6 r10\n" \ + "=A7 r11\n" \ + "=SN rax\n" \ + "gpr rax .64 80 0\n" \ + "gpr eax .32 80 0\n" \ + "gpr ax .16 80 0\n" \ + "gpr al .8 80 0\n" \ + "gpr ah .8 81 0\n" \ + "gpr rbx .64 40 0\n" \ + "gpr ebx .32 40 0\n" \ + "gpr bx .16 40 0\n" \ + "gpr bl .8 40 0\n" \ + "gpr bh .8 41 0\n" + +void setup_rzcore(RzCore *core) { + rz_reg_set_profile_string(core->analysis->reg, REGISTER_PROFILE_STRING); +} + +bool test_parse_reg_to_const(void) { + RzCore *core = rz_core_new(); + mu_assert_notnull(core, "new RzCore instance"); + setup_rzcore(core); + RzRopConstraint rop_constraint = { 0 }; + + // Test case 1: Valid register to constant + char str1[] = " eax = 123 "; + mu_assert("parse_reg_to_const failed on valid input", analyze_constraint(core, str1, &rop_constraint)); + mu_assert_eq(strcmp(rop_constraint.args[DST_REG], "eax"), 0, "Invalid destination register"); + mu_assert("Source register should be NULL", rop_constraint.args[SRC_REG] == NULL); + mu_assert_eq(strcmp(rop_constraint.args[SRC_CONST], "123"), 0, "Invalid constant value"); + + free(rop_constraint.args[DST_REG]); + free(rop_constraint.args[SRC_CONST]); + + // Test case 2: Invalid format + char str2[] = "eax ="; + mu_assert("parse_reg_to_const should fail on invalid input", !analyze_constraint(core, str2, &rop_constraint)); + + mu_end; +} + +bool test_parse_reg_to_reg(void) { + RzCore *core = rz_core_new(); + mu_assert_notnull(core, "new RzCore instance"); + setup_rzcore(core); + RzRopConstraint rop_constraint = { 0 }; + + // Test case 1: Valid register to register + char str1[] = "eax = ebx "; + mu_assert("parse_reg_to_reg failed on valid input", analyze_constraint(core, str1, &rop_constraint)); + mu_assert_eq(strcmp(rop_constraint.args[DST_REG], "eax"), 0, "Invalid destination register"); + mu_assert_eq(strcmp(rop_constraint.args[SRC_REG], "ebx"), 0, "Invalid source register"); + + free(rop_constraint.args[DST_REG]); + free(rop_constraint.args[SRC_REG]); + + // Test case 2: Invalid format + char str2[] = "eax ="; + mu_assert("parse_reg_to_reg should fail on invalid input", !analyze_constraint(core, str2, &rop_constraint)); + + mu_end; +} + +bool test_parse_reg_op_const(void) { + RzCore *core = rz_core_new(); + mu_assert_notnull(core, "new RzCore instance"); + setup_rzcore(core); + RzRopConstraint rop_constraint = { 0 }; + + // Test case 1: Valid register operation with constant + char str1[] = "eax=eax+3"; + mu_assert("parse_reg_op_const failed on valid input", analyze_constraint(core, str1, &rop_constraint)); + mu_assert_eq(strcmp(rop_constraint.args[DST_REG], "eax"), 0, "Invalid destination register"); + mu_assert_eq(strcmp(rop_constraint.args[SRC_REG], "eax"), 0, "Invalid source register"); + mu_assert_eq(strcmp(rop_constraint.args[OP], "add"), 0, "Invalid operator"); + mu_assert_eq(strcmp(rop_constraint.args[SRC_CONST], "3"), 0, "Invalid constant value"); + + free(rop_constraint.args[DST_REG]); + free(rop_constraint.args[SRC_REG]); + free(rop_constraint.args[OP]); + free(rop_constraint.args[SRC_CONST]); + + // Test case 2: Invalid format + char str2[] = "eax=eax+"; + mu_assert("parse_reg_op_const should fail on invalid input", !analyze_constraint(core, str2, &rop_constraint)); + + mu_end; +} + +bool test_parse_reg_op_reg(void) { + RzCore *core = rz_core_new(); + mu_assert_notnull(core, "new RzCore instance"); + setup_rzcore(core); + RzRopConstraint rop_constraint = { 0 }; + + // Test case 1: Valid register operation with register + char str1[] = "eax=eax-ebx"; + mu_assert("parse_reg_op_reg failed on valid input", analyze_constraint(core, str1, &rop_constraint)); + mu_assert_eq(strcmp(rop_constraint.args[DST_REG], "eax"), 0, "Invalid destination register"); + mu_assert_eq(strcmp(rop_constraint.args[SRC_REG], "eax"), 0, "Invalid source register"); + mu_assert_eq(strcmp(rop_constraint.args[OP], "sub"), 0, "Invalid operator"); + mu_assert_eq(strcmp(rop_constraint.args[SRC_CONST], "ebx"), 0, "Invalid destination constant register"); + + free(rop_constraint.args[DST_REG]); + free(rop_constraint.args[SRC_REG]); + free(rop_constraint.args[OP]); + free(rop_constraint.args[SRC_CONST]); + + // Test case 2: Invalid format + char str2[] = "eax = eax+ "; + mu_assert("parse_reg_op_reg should fail on invalid input", !analyze_constraint(core, str2, &rop_constraint)); + + mu_end; +} + +bool all_tests(void) { + mu_run_test(test_parse_reg_to_const); + mu_run_test(test_parse_reg_to_reg); + mu_run_test(test_parse_reg_op_const); + mu_run_test(test_parse_reg_op_reg); + return tests_passed != tests_run; +} + +mu_main(all_tests) From 15d55cae4078a85842070015cd9639c05f22b0b1 Mon Sep 17 00:00:00 2001 From: Giridhar Prasath R Date: Mon, 17 Jun 2024 07:17:20 -0400 Subject: [PATCH 03/30] Initial commit for RzILOpEffect rop APIs - This only adds the list of modified registers to a Structure - TODO: move the APis to a separate file under il/ and add support for all the Effect and Pure --- librz/core/rop.c | 121 ++++++++++++++++++++++++++++++++++++++++- librz/include/rz_rop.h | 13 +++++ 2 files changed, 133 insertions(+), 1 deletion(-) diff --git a/librz/core/rop.c b/librz/core/rop.c index f2b2217d147..0f03ea44963 100644 --- a/librz/core/rop.c +++ b/librz/core/rop.c @@ -7,6 +7,120 @@ #include #include +RzRopGadgetInfo *create_gadget_info(ut64 address); + +static void add_string_to_list(RzList *list, const char *str) { + if (!str) { + return; + } + char *copy = strdup(str); + if (rz_list_contains(list, str)) { + free(copy); + return; + } + rz_list_append(list, copy); +} + +RZ_API void populate_gadget_info(RzRopGadgetInfo *info, RzILOpEffect *effect) { + if (!effect) { + return; + } + switch (effect->code) { + case RZ_IL_OP_SET: + add_string_to_list(info->modified_registers, effect->op.set.v); + break; + case RZ_IL_OP_STORE: + add_string_to_list(info->memory_write.dependencies, (const char *)effect->op.store.key); + add_string_to_list(info->memory_write.stored_in_regs, (const char *)effect->op.store.value); + break; + case RZ_IL_OP_SEQ: + populate_gadget_info(info, effect->op.seq.x); + populate_gadget_info(info, effect->op.seq.y); + break; + case RZ_IL_OP_BRANCH: + populate_gadget_info(info, effect->op.branch.true_eff); + populate_gadget_info(info, effect->op.branch.false_eff); + break; + case RZ_IL_OP_JMP: + add_string_to_list(info->modified_registers, "rip"); + break; + case RZ_IL_OP_NOP: + // NOP does not change any state or register + break; + default: + break; + } +} + +RzRopGadgetInfo *create_gadget_info(ut64 address) { + RzRopGadgetInfo *info = RZ_NEW0(RzRopGadgetInfo); + if (!info) { + return NULL; + } + info->address = address; + info->stack_change = 0x8; + info->modified_registers = rz_list_new(); + info->memory_write.dependencies = rz_list_new(); + info->memory_write.stored_in_regs = rz_list_new(); + info->memory_read.dependencies = rz_list_new(); + info->memory_read.stored_in_regs = rz_list_new(); + return info; +} + +void free_gadget_info(RzRopGadgetInfo *info) { + if (!info) { + return; + } + rz_list_free(info->modified_registers); + rz_list_free(info->memory_write.dependencies); + rz_list_free(info->memory_write.stored_in_regs); + rz_list_free(info->memory_read.dependencies); + rz_list_free(info->memory_read.stored_in_regs); + + free(info); +} + +static void update_gadget_info_stack_change(RzRopGadgetInfo *info, ut64 change) { + info->stack_change += change; +} + +static void add_memory_dependency(RzRopGadgetInfo *info, const char *register_name) { + add_string_to_list(info->memory_write.dependencies, register_name); + add_string_to_list(info->memory_read.dependencies, register_name); +} + +static void set_memory_read_register(RzRopGadgetInfo *info, const char *register_name) { + add_string_to_list(info->memory_read.stored_in_regs, register_name); +} + +void merge_gadget_info(RzRopGadgetInfo *dest, RzRopGadgetInfo *src) { + RzListIter *iter; + char *data; + rz_list_foreach (src->modified_registers, iter, data) { + add_string_to_list(dest->modified_registers, data); + } + rz_list_foreach (src->memory_write.dependencies, iter, data) { + add_string_to_list(dest->memory_write.dependencies, data); + } + rz_list_foreach (src->memory_write.stored_in_regs, iter, data) { + add_string_to_list(dest->memory_write.stored_in_regs, data); + } + rz_list_foreach (src->memory_read.dependencies, iter, data) { + add_string_to_list(dest->memory_read.dependencies, data); + } + rz_list_foreach (src->memory_read.stored_in_regs, iter, data) { + add_string_to_list(dest->memory_read.stored_in_regs, data); + } + dest->stack_change += src->stack_change; +} + +RZ_API void process_gadget(RzCore *core, RzRopGadgetInfo *gadget_info, RzILOpEffect *effects, ut64 addr) { + RzRopGadgetInfo *temp_info = create_gadget_info(addr); + populate_gadget_info(temp_info, effects); + merge_gadget_info(gadget_info, temp_info); + free_gadget_info(temp_info); +} + static bool is_end_gadget(const RzAnalysisOp *aop, const ut8 crop) { if (aop->family == RZ_ANALYSIS_OP_FAMILY_SECURITY) { return false; @@ -254,6 +368,11 @@ static void print_rop(RzCore *core, RzList /**/ *hitlist, RzCmdS rz_asm_disassemble(core->rasm, asmop, buf, size); rz_analysis_op_init(&aop); rz_analysis_op(core->analysis, &aop, hit->addr, buf, size, RZ_ANALYSIS_OP_MASK_IL); + RzRopGadgetInfo *rop_gadget_info = create_gadget_info(hit->addr); + // TODO: Remove this + RzStrBuf sb = { 0 }; + rz_il_op_effect_stringify(aop.il_op, &sb, false); + process_gadget(core, rop_gadget_info, aop.il_op, hit->addr); rz_analysis_op_fini(&aop); rz_asm_op_free(asmop); free(buf); @@ -771,4 +890,4 @@ RZ_API RzList /**/ *rz_rop_constraint_list_new(void) { list->free = &rz_rop_constraint_free; } return list; -} +} \ No newline at end of file diff --git a/librz/include/rz_rop.h b/librz/include/rz_rop.h index 4ddbed007e2..6f7a0e34e7c 100644 --- a/librz/include/rz_rop.h +++ b/librz/include/rz_rop.h @@ -6,6 +6,19 @@ #endif // RZ_ROP_H +typedef struct { + RzList *dependencies; + RzList *stored_in_regs; +} RzRopMemoryOp; + +typedef struct { + ut64 address; + ut64 stack_change; + RzList *modified_registers; + RzRopMemoryOp memory_write; + RzRopMemoryOp memory_read; +} RzRopGadgetInfo; + typedef enum rzil_instr_type { // Register to register MOV_CONST, // reg <- const From 0d2c19040ae5ab15a3d2f9eed76f27552b45d94b Mon Sep 17 00:00:00 2001 From: Giridhar Prasath R Date: Tue, 18 Jun 2024 04:58:38 -0400 Subject: [PATCH 04/30] WIP: Add RzILOpEffect ROP gadget analysis APIs - Refactor code in rop.c - fix memory leaks - Add APIs for storing the information of a given gadget - fix tc --- librz/arch/analysis.c | 16 ++ librz/core/cmd/cmd_search_rop.c | 17 +- librz/core/rop.c | 352 ++++++++++++++------------------ librz/il/il_rop_gadget.c | 342 +++++++++++++++++++++++++++++++ librz/il/meson.build | 1 + librz/include/rz_analysis.h | 1 + librz/include/rz_rop.h | 12 +- test/db/cmd/cmd_rop | 7 + 8 files changed, 532 insertions(+), 216 deletions(-) create mode 100644 librz/il/il_rop_gadget.c diff --git a/librz/arch/analysis.c b/librz/arch/analysis.c index ecb90e58e53..8c3d388170e 100644 --- a/librz/arch/analysis.c +++ b/librz/arch/analysis.c @@ -240,6 +240,22 @@ RZ_API char *rz_analysis_get_reg_profile(RzAnalysis *analysis) { : NULL; } +RZ_API bool rz_analysis_is_reg_in_profile(RzAnalysis *analysis, const char *str) { + rz_return_val_if_fail(analysis, false); + + char *reg_prof = rz_analysis_get_reg_profile(analysis); + if (!reg_prof) { + return false; + } + + if (strstr(reg_prof, str) != NULL) { + free(reg_prof); + return true; + } + free(reg_prof); + return false; +} + RZ_API bool rz_analysis_set_reg_profile(RzAnalysis *analysis) { bool ret = false; char *p = rz_analysis_get_reg_profile(analysis); diff --git a/librz/core/cmd/cmd_search_rop.c b/librz/core/cmd/cmd_search_rop.c index f232990cca7..7736f1cd711 100644 --- a/librz/core/cmd/cmd_search_rop.c +++ b/librz/core/cmd/cmd_search_rop.c @@ -4,7 +4,6 @@ #include #include "rz_core.h" -#include "rz_io.h" #include "rz_list.h" #include "rz_types_base.h" #include "rz_rop.h" @@ -754,13 +753,6 @@ static bool parse_il_equal(char *str, int *idx) { return false; } -static bool is_reg_in_profile(const char *reg_profile, const char *str) { - if (strstr(reg_profile, str) != NULL) { - return true; - } - return false; -} - static char *parse_register(RzCore *core, char *str, int *idx) { char reg[256] = { 0 }; int reg_idx = 0; @@ -776,18 +768,11 @@ static char *parse_register(RzCore *core, char *str, int *idx) { return NULL; } - char *reg_prof = rz_analysis_get_reg_profile(core->analysis); - if (!reg_prof) { - return NULL; - } - // Check if the register is correct for the given architecture. - if (is_reg_in_profile(reg_prof, reg)) { - free(reg_prof); + if (rz_analysis_is_reg_in_profile(core->analysis, reg)) { return strdup(reg); } - free(reg_prof); return NULL; } diff --git a/librz/core/rop.c b/librz/core/rop.c index 0f03ea44963..7aa1425ff7a 100644 --- a/librz/core/rop.c +++ b/librz/core/rop.c @@ -9,49 +9,6 @@ RzRopGadgetInfo *create_gadget_info(ut64 address); -static void add_string_to_list(RzList *list, const char *str) { - if (!str) { - return; - } - char *copy = strdup(str); - if (rz_list_contains(list, str)) { - free(copy); - return; - } - rz_list_append(list, copy); -} - -RZ_API void populate_gadget_info(RzRopGadgetInfo *info, RzILOpEffect *effect) { - if (!effect) { - return; - } - switch (effect->code) { - case RZ_IL_OP_SET: - add_string_to_list(info->modified_registers, effect->op.set.v); - break; - case RZ_IL_OP_STORE: - add_string_to_list(info->memory_write.dependencies, (const char *)effect->op.store.key); - add_string_to_list(info->memory_write.stored_in_regs, (const char *)effect->op.store.value); - break; - case RZ_IL_OP_SEQ: - populate_gadget_info(info, effect->op.seq.x); - populate_gadget_info(info, effect->op.seq.y); - break; - case RZ_IL_OP_BRANCH: - populate_gadget_info(info, effect->op.branch.true_eff); - populate_gadget_info(info, effect->op.branch.false_eff); - break; - case RZ_IL_OP_JMP: - add_string_to_list(info->modified_registers, "rip"); - break; - case RZ_IL_OP_NOP: - // NOP does not change any state or register - break; - default: - break; - } -} - RzRopGadgetInfo *create_gadget_info(ut64 address) { RzRopGadgetInfo *info = RZ_NEW0(RzRopGadgetInfo); if (!info) { @@ -59,11 +16,11 @@ RzRopGadgetInfo *create_gadget_info(ut64 address) { } info->address = address; info->stack_change = 0x8; - info->modified_registers = rz_list_new(); - info->memory_write.dependencies = rz_list_new(); - info->memory_write.stored_in_regs = rz_list_new(); - info->memory_read.dependencies = rz_list_new(); - info->memory_read.stored_in_regs = rz_list_new(); + info->modified_registers = rz_list_newf(free); + info->memory_write.dependencies = rz_list_newf(free); + info->memory_write.stored_in_regs = rz_list_newf(free); + info->memory_read.dependencies = rz_list_newf(free); + info->memory_read.stored_in_regs = rz_list_newf(free); return info; } @@ -80,44 +37,31 @@ void free_gadget_info(RzRopGadgetInfo *info) { free(info); } -static void update_gadget_info_stack_change(RzRopGadgetInfo *info, ut64 change) { - info->stack_change += change; -} - -static void add_memory_dependency(RzRopGadgetInfo *info, const char *register_name) { - add_string_to_list(info->memory_write.dependencies, register_name); - add_string_to_list(info->memory_read.dependencies, register_name); -} - -static void set_memory_read_register(RzRopGadgetInfo *info, const char *register_name) { - add_string_to_list(info->memory_read.stored_in_regs, register_name); -} - -void merge_gadget_info(RzRopGadgetInfo *dest, RzRopGadgetInfo *src) { +void merge_gadget_info(RzCore *core, RzRopGadgetInfo *dest, RzRopGadgetInfo *src) { RzListIter *iter; char *data; rz_list_foreach (src->modified_registers, iter, data) { - add_string_to_list(dest->modified_registers, data); + add_reg_to_list(core, dest->modified_registers, data); } rz_list_foreach (src->memory_write.dependencies, iter, data) { - add_string_to_list(dest->memory_write.dependencies, data); + add_reg_to_list(core, dest->memory_write.dependencies, data); } rz_list_foreach (src->memory_write.stored_in_regs, iter, data) { - add_string_to_list(dest->memory_write.stored_in_regs, data); + add_reg_to_list(core, dest->memory_write.stored_in_regs, data); } rz_list_foreach (src->memory_read.dependencies, iter, data) { - add_string_to_list(dest->memory_read.dependencies, data); + add_reg_to_list(core, dest->memory_read.dependencies, data); } rz_list_foreach (src->memory_read.stored_in_regs, iter, data) { - add_string_to_list(dest->memory_read.stored_in_regs, data); + add_reg_to_list(core, dest->memory_read.stored_in_regs, data); } dest->stack_change += src->stack_change; } RZ_API void process_gadget(RzCore *core, RzRopGadgetInfo *gadget_info, RzILOpEffect *effects, ut64 addr) { RzRopGadgetInfo *temp_info = create_gadget_info(addr); - populate_gadget_info(temp_info, effects); - merge_gadget_info(gadget_info, temp_info); + populate_gadget_info(core, temp_info, effects); + merge_gadget_info(core, gadget_info, temp_info); free_gadget_info(temp_info); } @@ -153,21 +97,147 @@ static bool is_end_gadget(const RzAnalysisOp *aop, const ut8 crop) { return false; } +static int rz_rop_process_asm_op(RzCore *core, RzCoreAsmHit *hit, RzAsmOp *asmop, RzAnalysisOp *aop, unsigned int *size, char **asmop_str, char **asmop_hex_str) { + ut8 *buf = malloc(hit->len); + if (!buf) { + return -1; + } + rz_io_read_at(core->io, hit->addr, buf, hit->len); + rz_asm_set_pc(core->rasm, hit->addr); + rz_asm_disassemble(core->rasm, asmop, buf, hit->len); + rz_analysis_op_init(aop); + rz_analysis_op(core->analysis, aop, hit->addr, buf, hit->len, RZ_ANALYSIS_OP_MASK_ESIL); + *size += hit->len; + + // Append assembly operation string + if (asmop_str) { + *asmop_str = rz_str_append(*asmop_str, rz_asm_op_get_asm(asmop)); + *asmop_str = rz_str_append(*asmop_str, "; "); + } + + // Append hex string of assembly operation + if (asmop_hex_str) { + char *asmop_hex = rz_asm_op_get_hex(asmop); + *asmop_hex_str = rz_str_append(*asmop_hex_str, asmop_hex); + free(asmop_hex); + } + + free(buf); + return 0; +} + +static int rz_rop_print_table_mode(RzCore *core, RzCoreAsmHit *hit, RzList *hitlist, RzAsmOp *asmop, unsigned int *size, char **asmop_str, char **asmop_hex_str) { + RzAnalysisOp aop = RZ_EMPTY; + if (rz_rop_process_asm_op(core, hit, asmop, &aop, size, asmop_str, asmop_hex_str) != 0) { + return -1; + } + const ut64 addr_last = ((RzCoreAsmHit *)rz_list_last(hitlist))->addr; + if (addr_last != hit->addr) { + *asmop_str = rz_str_append(*asmop_str, "; "); + } + rz_analysis_op_fini(&aop); + return 0; +} + +static int rz_rop_print_quiet_mode(RzCore *core, RzCoreAsmHit *hit, RzList *ropList, RzAsmOp *asmop, unsigned int *size, bool esil, bool colorize) { + RzAnalysisOp aop = RZ_EMPTY; + if (rz_rop_process_asm_op(core, hit, asmop, &aop, size, NULL, NULL) != 0) { + return -1; + } + const char *opstr = RZ_STRBUF_SAFEGET(&aop.esil); + if (aop.type != RZ_ANALYSIS_OP_TYPE_RET) { + rz_list_append(ropList, rz_str_newf(" %s", opstr)); + } + if (esil) { + rz_cons_printf("%s\n", opstr); + } else if (colorize) { + RzStrBuf *bw_str = rz_strbuf_new(rz_asm_op_get_asm(asmop)); + RzAsmParseParam *param = rz_asm_get_parse_param(core->analysis->reg, aop.type); + RzStrBuf *colored_asm = rz_asm_colorize_asm_str(bw_str, core->print, param, asmop->asm_toks); + rz_asm_parse_param_free(param); + rz_cons_printf(" %s%s;", colored_asm ? rz_strbuf_get(colored_asm) : "", Color_RESET); + rz_strbuf_free(colored_asm); + rz_strbuf_free(bw_str); + } else { + rz_cons_printf(" %s;", rz_asm_op_get_asm(asmop)); + } + rz_analysis_op_fini(&aop); + return 0; +} + +static int rz_rop_print_standard_mode(RzCore *core, RzCoreAsmHit *hit, RzList *ropList, RzAsmOp *asmop, unsigned int *size, bool rop_comments, bool colorize) { + RzAnalysisOp aop = RZ_EMPTY; + if (rz_rop_process_asm_op(core, hit, asmop, &aop, size, NULL, NULL) != 0) { + return -1; + } + const char *comment = rop_comments ? rz_meta_get_string(core->analysis, RZ_META_TYPE_COMMENT, hit->addr) : NULL; + if (aop.type != RZ_ANALYSIS_OP_TYPE_RET) { + char *opstr_n = rz_str_newf(" %s", RZ_STRBUF_SAFEGET(&aop.esil)); + rz_list_append(ropList, opstr_n); + } + char *asm_op_hex = rz_asm_op_get_hex(asmop); + if (colorize) { + RzStrBuf *bw_str = rz_strbuf_new(rz_asm_op_get_asm(asmop)); + RzAsmParseParam *param = rz_asm_get_parse_param(core->analysis->reg, aop.type); + RzStrBuf *colored_asm = rz_asm_colorize_asm_str(bw_str, core->print, param, asmop->asm_toks); + rz_asm_parse_param_free(param); + if (comment) { + rz_cons_printf(" 0x%08" PFMT64x " %18s %s%s ; %s\n", + hit->addr, asm_op_hex, colored_asm ? rz_strbuf_get(colored_asm) : "", Color_RESET, comment); + } else { + rz_cons_printf(" 0x%08" PFMT64x " %18s %s%s\n", + hit->addr, asm_op_hex, colored_asm ? rz_strbuf_get(colored_asm) : "", Color_RESET); + } + rz_strbuf_free(colored_asm); + rz_strbuf_free(bw_str); + } else { + if (comment) { + rz_cons_printf(" 0x%08" PFMT64x " %18s %s ; %s\n", + hit->addr, asm_op_hex, rz_asm_op_get_asm(asmop), comment); + } else { + rz_cons_printf(" 0x%08" PFMT64x " %18s %s\n", + hit->addr, asm_op_hex, rz_asm_op_get_asm(asmop)); + } + } + free(asm_op_hex); + rz_analysis_op_fini(&aop); + return 0; +} + +static int rz_rop_print_json_mode(RzCore *core, RzCoreAsmHit *hit, RzList *ropList, RzCmdStateOutput *state, RzAsmOp *asmop, unsigned int *size) { + RzAnalysisOp aop = RZ_EMPTY; + + if (rz_rop_process_asm_op(core, hit, asmop, &aop, size, NULL, NULL) != 0) { + return -1; + } + + if (aop.type != RZ_ANALYSIS_OP_TYPE_RET) { + char *opstr_n = rz_str_newf(" %s", RZ_STRBUF_SAFEGET(&aop.esil)); + rz_list_append(ropList, opstr_n); + } + + pj_o(state->d.pj); + pj_kn(state->d.pj, "offset", hit->addr); + pj_ki(state->d.pj, "size", hit->len); + pj_ks(state->d.pj, "opcode", rz_asm_op_get_asm(asmop)); + pj_ks(state->d.pj, "type", rz_analysis_optype_to_string(aop.type)); + pj_end(state->d.pj); + + rz_analysis_op_fini(&aop); + return 0; +} + static void print_rop(RzCore *core, RzList /**/ *hitlist, RzCmdStateOutput *state) { RzCoreAsmHit *hit = NULL; RzListIter *iter; - RzList *ropList = NULL; unsigned int size = 0; + RzList *ropList = NULL; char *asmop_str = NULL, *asmop_hex_str = NULL; - RzAnalysisOp aop = RZ_EMPTY; - const char *comment = NULL; Sdb *db = NULL; const bool colorize = rz_config_get_i(core->config, "scr.color"); const bool rop_comments = rz_config_get_i(core->config, "rop.comments"); const bool esil = rz_config_get_i(core->config, "asm.esil"); const bool rop_db = rz_config_get_i(core->config, "rop.db"); - ut8 *buf = NULL; - RzStrBuf *colored_asm = NULL, *bw_str = NULL; if (rop_db) { db = sdb_ns(core->sdb, "rop", true); ropList = rz_list_newf(free); @@ -191,143 +261,24 @@ static void print_rop(RzCore *core, RzList /**/ *hitlist, RzCmdS RzAsmOp *asmop = rz_asm_op_new(); switch (state->mode) { case RZ_OUTPUT_MODE_JSON: - buf = malloc(hit->len); - if (!buf) { + if (rz_rop_print_json_mode(core, hit, ropList, state, asmop, &size) != 0) { goto cleanup; } - rz_io_read_at(core->io, hit->addr, buf, hit->len); - rz_asm_set_pc(core->rasm, hit->addr); - rz_asm_disassemble(core->rasm, asmop, buf, hit->len); - rz_analysis_op_init(&aop); - rz_analysis_op(core->analysis, &aop, hit->addr, buf, hit->len, RZ_ANALYSIS_OP_MASK_ESIL); - size += hit->len; - if (aop.type != RZ_ANALYSIS_OP_TYPE_RET) { - char *opstr_n = rz_str_newf(" %s", RZ_STRBUF_SAFEGET(&aop.esil)); - rz_list_append(ropList, opstr_n); - } - pj_o(state->d.pj); - pj_kn(state->d.pj, "offset", hit->addr); - pj_ki(state->d.pj, "size", hit->len); - pj_ks(state->d.pj, "opcode", rz_asm_op_get_asm(asmop)); - pj_ks(state->d.pj, "type", rz_analysis_optype_to_string(aop.type)); - pj_end(state->d.pj); - free(buf); - rz_analysis_op_fini(&aop); break; case RZ_OUTPUT_MODE_QUIET: - // Print gadgets in a 'linear manner', each sequence on one line. - buf = malloc(hit->len); - if (!buf) { + if (rz_rop_print_quiet_mode(core, hit, ropList, asmop, &size, esil, colorize) != 0) { goto cleanup; } - rz_io_read_at(core->io, hit->addr, buf, hit->len); - rz_asm_set_pc(core->rasm, hit->addr); - rz_asm_disassemble(core->rasm, asmop, buf, hit->len); - rz_analysis_op_init(&aop); - rz_analysis_op(core->analysis, &aop, hit->addr, buf, hit->len, RZ_ANALYSIS_OP_MASK_BASIC); - size += hit->len; - const char *opstr = RZ_STRBUF_SAFEGET(&aop.esil); - if (aop.type != RZ_ANALYSIS_OP_TYPE_RET) { - rz_list_append(ropList, rz_str_newf(" %s", opstr)); - } - if (esil) { - rz_cons_printf("%s\n", opstr); - } else if (colorize) { - bw_str = rz_strbuf_new(rz_asm_op_get_asm(asmop)); - RzAsmParseParam *param = rz_asm_get_parse_param(core->analysis->reg, aop.type); - colored_asm = rz_asm_colorize_asm_str(bw_str, core->print, param, asmop->asm_toks); - rz_asm_parse_param_free(param); - rz_cons_printf(" %s%s;", colored_asm ? rz_strbuf_get(colored_asm) : "", Color_RESET); - rz_strbuf_free(colored_asm); - rz_strbuf_free(bw_str); - } else { - rz_cons_printf(" %s;", rz_asm_op_get_asm(asmop)); - } - free(buf); - rz_analysis_op_fini(&aop); break; case RZ_OUTPUT_MODE_STANDARD: - // Print gadgets with new instruction on a new line. - comment = rop_comments ? rz_meta_get_string(core->analysis, RZ_META_TYPE_COMMENT, hit->addr) : NULL; - if (hit->len < 0) { - RZ_LOG_ERROR("core: Invalid hit length here\n"); - continue; - } - buf = malloc(1 + hit->len); - if (!buf) { - break; - } - buf[hit->len] = 0; - rz_io_read_at(core->io, hit->addr, buf, hit->len); - rz_asm_set_pc(core->rasm, hit->addr); - rz_asm_disassemble(core->rasm, asmop, buf, hit->len); - rz_analysis_op_init(&aop); - rz_analysis_op(core->analysis, &aop, hit->addr, buf, hit->len, RZ_ANALYSIS_OP_MASK_ESIL); - size += hit->len; - if (aop.type != RZ_ANALYSIS_OP_TYPE_RET) { - char *opstr_n = rz_str_newf(" %s", RZ_STRBUF_SAFEGET(&aop.esil)); - rz_list_append(ropList, opstr_n); - } - char *asm_op_hex = rz_asm_op_get_hex(asmop); - if (colorize) { - bw_str = rz_strbuf_new(rz_asm_op_get_asm(asmop)); - RzAsmParseParam *param = rz_asm_get_parse_param(core->analysis->reg, aop.type); - colored_asm = rz_asm_colorize_asm_str(bw_str, core->print, param, asmop->asm_toks); - rz_asm_parse_param_free(param); - if (comment) { - rz_cons_printf(" 0x%08" PFMT64x " %18s %s%s ; %s\n", - hit->addr, asm_op_hex, colored_asm ? rz_strbuf_get(colored_asm) : "", Color_RESET, comment); - } else { - rz_cons_printf(" 0x%08" PFMT64x " %18s %s%s\n", - hit->addr, asm_op_hex, colored_asm ? rz_strbuf_get(colored_asm) : "", Color_RESET); - } - rz_strbuf_free(colored_asm); - rz_strbuf_free(bw_str); - } else { - if (comment) { - rz_cons_printf(" 0x%08" PFMT64x " %18s %s ; %s\n", - hit->addr, asm_op_hex, rz_asm_op_get_asm(asmop), comment); - } else { - rz_cons_printf(" 0x%08" PFMT64x " %18s %s\n", - hit->addr, asm_op_hex, rz_asm_op_get_asm(asmop)); - } + if (rz_rop_print_standard_mode(core, hit, ropList, asmop, &size, rop_comments, colorize) != 0) { + goto cleanup; } - free(asm_op_hex); - free(buf); - rz_analysis_op_fini(&aop); - comment = NULL; break; case RZ_OUTPUT_MODE_TABLE: - buf = malloc(hit->len); - if (!buf) { + if (rz_rop_print_table_mode(core, hit, hitlist, asmop, &size, &asmop_str, &asmop_hex_str) != 0) { goto cleanup; } - rz_io_read_at(core->io, hit->addr, buf, hit->len); - rz_asm_set_pc(core->rasm, hit->addr); - rz_asm_disassemble(core->rasm, asmop, buf, hit->len); - rz_analysis_op_init(&aop); - rz_analysis_op(core->analysis, &aop, hit->addr, buf, hit->len, RZ_ANALYSIS_OP_MASK_BASIC); - size += hit->len; - if (asmop_str) { - asmop_str = rz_str_append(asmop_str, rz_asm_op_get_asm(asmop)); - const ut64 addr_last = ((RzCoreAsmHit *)rz_list_last(hitlist))->addr; - if (addr_last != hit->addr) { - asmop_str = rz_str_append(asmop_str, "; "); - } - } else { - asmop_str = rz_str_newf("%s; ", rz_asm_op_get_asm(asmop)); - } - char *asmop_hex_str_dup = NULL; - if (asmop_hex_str) { - asmop_hex_str_dup = rz_asm_op_get_hex(asmop); - asmop_hex_str = rz_str_append(asmop_hex_str, asmop_hex_str_dup); - } else { - asmop_hex_str_dup = rz_asm_op_get_hex(asmop); - asmop_hex_str = rz_str_newf("%s", asmop_hex_str_dup); - } - free(asmop_hex_str_dup); - free(buf); - rz_analysis_op_fini(&aop); break; default: rz_warn_if_reached(); @@ -356,6 +307,8 @@ static void print_rop(RzCore *core, RzList /**/ *hitlist, RzCmdS if (db && hit) { rz_cons_printf("Gadget size: %d\n", (int)size); // rop_classify(core, db, ropList, key, size); + ut8 *buf; + RzAnalysisOp aop; buf = malloc(size + 1); hit = rz_list_first(hitlist); if (!buf) { @@ -371,10 +324,13 @@ static void print_rop(RzCore *core, RzList /**/ *hitlist, RzCmdS RzRopGadgetInfo *rop_gadget_info = create_gadget_info(hit->addr); // TODO: Remove this RzStrBuf sb = { 0 }; + rz_strbuf_init(&sb); rz_il_op_effect_stringify(aop.il_op, &sb, false); process_gadget(core, rop_gadget_info, aop.il_op, hit->addr); + free_gadget_info(rop_gadget_info); rz_analysis_op_fini(&aop); rz_asm_op_free(asmop); + rz_strbuf_fini(&sb); free(buf); } rz_cons_newline(); diff --git a/librz/il/il_rop_gadget.c b/librz/il/il_rop_gadget.c new file mode 100644 index 00000000000..767cdcecdc6 --- /dev/null +++ b/librz/il/il_rop_gadget.c @@ -0,0 +1,342 @@ +// SPDX-FileCopyrightText: 2021 Florian Märkl +// SPDX-License-Identifier: LGPL-3.0-only + +#include +#include +#include + +RZ_API void il_op_pure_rop_gadget_resolve(RzCore *core, RzILOpPure *op, RzRopGadgetInfo *info); + +// TODO: Refactor this, added here because arch is dependent on IL and won't compile +static char *get_reg_profile(RzAnalysis *analysis) { + return analysis && analysis->cur && analysis->cur->get_reg_profile + ? analysis->cur->get_reg_profile(analysis) + : NULL; +} + +static bool is_reg_in_profile(const char *reg_profile, const char *str) { + if (strstr(reg_profile, str) != NULL) { + return true; + } + return false; +} + +RZ_API void add_reg_to_list(RzCore *core, RzList *list, const char *str) { + if (!str) { + return; + } + char *reg_prof = get_reg_profile(core->analysis); + if (!reg_prof) { + return; + } + + // Check if the register is correct for the given architecture. + if (is_reg_in_profile(reg_prof, str)) { + free(reg_prof); + char *copy = strdup(str); + rz_list_append(list, copy); + return; + } + + free(reg_prof); +} + +static void resolve_var_op(RzCore *core, RzILOpPure *op, RzRopGadgetInfo *info) { + if (op->code == RZ_IL_OP_VAR) { + add_reg_to_list(core, info->modified_registers, op->op.var.v); + } +} + +static void resolve_ite_op(RzCore *core, RzILOpPure *op, RzRopGadgetInfo *info) { + if (op->code == RZ_IL_OP_ITE) { + il_op_pure_rop_gadget_resolve(core, op->op.ite.condition, info); + il_op_pure_rop_gadget_resolve(core, op->op.ite.x, info); + il_op_pure_rop_gadget_resolve(core, op->op.ite.y, info); + } +} + +static void resolve_bool_op(RzCore *core, RzILOpPure *op, RzRopGadgetInfo *info) { + switch (op->code) { + case RZ_IL_OP_AND: + il_op_pure_rop_gadget_resolve(core, op->op.booland.x, info); + il_op_pure_rop_gadget_resolve(core, op->op.booland.y, info); + break; + case RZ_IL_OP_OR: + il_op_pure_rop_gadget_resolve(core, op->op.boolor.x, info); + il_op_pure_rop_gadget_resolve(core, op->op.boolor.y, info); + break; + case RZ_IL_OP_XOR: + il_op_pure_rop_gadget_resolve(core, op->op.boolxor.x, info); + il_op_pure_rop_gadget_resolve(core, op->op.boolxor.y, info); + break; + case RZ_IL_OP_INV: + il_op_pure_rop_gadget_resolve(core, op->op.boolinv.x, info); + break; + default: + break; + } +} + +static void resolve_bitvector_op(RzCore *core, RzILOpPure *op, RzRopGadgetInfo *info) { + switch (op->code) { + case RZ_IL_OP_BITV: + + break; + case RZ_IL_OP_MSB: + il_op_pure_rop_gadget_resolve(core, op->op.msb.bv, info); + break; + case RZ_IL_OP_LSB: + il_op_pure_rop_gadget_resolve(core, op->op.lsb.bv, info); + break; + case RZ_IL_OP_IS_ZERO: + il_op_pure_rop_gadget_resolve(core, op->op.is_zero.bv, info); + break; + case RZ_IL_OP_NEG: + il_op_pure_rop_gadget_resolve(core, op->op.neg.bv, info); + break; + case RZ_IL_OP_LOGNOT: + il_op_pure_rop_gadget_resolve(core, op->op.lognot.bv, info); + break; + case RZ_IL_OP_ADD: + il_op_pure_rop_gadget_resolve(core, op->op.add.x, info); + il_op_pure_rop_gadget_resolve(core, op->op.add.y, info); + break; + case RZ_IL_OP_SUB: + il_op_pure_rop_gadget_resolve(core, op->op.sub.x, info); + il_op_pure_rop_gadget_resolve(core, op->op.sub.y, info); + break; + case RZ_IL_OP_MUL: + il_op_pure_rop_gadget_resolve(core, op->op.mul.x, info); + il_op_pure_rop_gadget_resolve(core, op->op.mul.y, info); + break; + case RZ_IL_OP_DIV: + il_op_pure_rop_gadget_resolve(core, op->op.div.x, info); + il_op_pure_rop_gadget_resolve(core, op->op.div.y, info); + break; + case RZ_IL_OP_SDIV: + il_op_pure_rop_gadget_resolve(core, op->op.sdiv.x, info); + il_op_pure_rop_gadget_resolve(core, op->op.sdiv.y, info); + break; + case RZ_IL_OP_MOD: + il_op_pure_rop_gadget_resolve(core, op->op.mod.x, info); + il_op_pure_rop_gadget_resolve(core, op->op.mod.y, info); + break; + case RZ_IL_OP_SMOD: + il_op_pure_rop_gadget_resolve(core, op->op.smod.x, info); + il_op_pure_rop_gadget_resolve(core, op->op.smod.y, info); + break; + case RZ_IL_OP_LOGAND: + il_op_pure_rop_gadget_resolve(core, op->op.logand.x, info); + il_op_pure_rop_gadget_resolve(core, op->op.logand.y, info); + break; + case RZ_IL_OP_LOGOR: + il_op_pure_rop_gadget_resolve(core, op->op.logor.x, info); + il_op_pure_rop_gadget_resolve(core, op->op.logor.y, info); + break; + case RZ_IL_OP_LOGXOR: + il_op_pure_rop_gadget_resolve(core, op->op.logxor.x, info); + il_op_pure_rop_gadget_resolve(core, op->op.logxor.y, info); + break; + case RZ_IL_OP_SHIFTR: + il_op_pure_rop_gadget_resolve(core, op->op.shiftr.x, info); + il_op_pure_rop_gadget_resolve(core, op->op.shiftr.y, info); + il_op_pure_rop_gadget_resolve(core, op->op.shiftr.fill_bit, info); + break; + case RZ_IL_OP_SHIFTL: + il_op_pure_rop_gadget_resolve(core, op->op.shiftl.x, info); + il_op_pure_rop_gadget_resolve(core, op->op.shiftl.y, info); + il_op_pure_rop_gadget_resolve(core, op->op.shiftl.fill_bit, info); + break; + case RZ_IL_OP_APPEND: + il_op_pure_rop_gadget_resolve(core, op->op.append.high, info); + il_op_pure_rop_gadget_resolve(core, op->op.append.low, info); + break; + default: + break; + } +} + +static void update_gadget_info_stack_change(RzRopGadgetInfo *info, ut64 change) { + info->stack_change += change; +} + +static void set_memory_read_register(RzCore *core, RzRopGadgetInfo *info, const char *register_name) { + add_reg_to_list(core, info->memory_read.stored_in_regs, register_name); +} + +static void add_memory_dependency(RzCore *core, RzRopGadgetInfo *info, const char *register_name) { + add_reg_to_list(core, info->memory_write.dependencies, register_name); + add_reg_to_list(core, info->memory_read.dependencies, register_name); +} + +static void resolve_load_op(RzCore *core, RzILOpPure *op, RzRopGadgetInfo *info) { + if (op->code == RZ_IL_OP_LOAD) { + add_memory_dependency(core, info, (const char *)op->op.load.key); + } else if (op->code == RZ_IL_OP_LOADW) { + add_memory_dependency(core, info, (const char *)op->op.loadw.key); + } +} + +static void resolve_cast_op(RzCore *core, RzILOpPure *op, RzRopGadgetInfo *info) { + if (op->code == RZ_IL_OP_CAST) { + il_op_pure_rop_gadget_resolve(core, op->op.cast.val, info); + } +} + +static void resolve_float_op(RzCore *core, RzILOpPure *op, RzRopGadgetInfo *info) { + switch (op->code) { + case RZ_IL_OP_FLOAT: + il_op_pure_rop_gadget_resolve(core, op->op.float_.bv, info); + break; + case RZ_IL_OP_FNEG: + il_op_pure_rop_gadget_resolve(core, op->op.fneg.f, info); + break; + case RZ_IL_OP_FABS: + il_op_pure_rop_gadget_resolve(core, op->op.fabs.f, info); + break; + case RZ_IL_OP_FADD: + il_op_pure_rop_gadget_resolve(core, op->op.fadd.x, info); + il_op_pure_rop_gadget_resolve(core, op->op.fadd.y, info); + break; + case RZ_IL_OP_FSUB: + il_op_pure_rop_gadget_resolve(core, op->op.fsub.x, info); + il_op_pure_rop_gadget_resolve(core, op->op.fsub.y, info); + break; + case RZ_IL_OP_FMUL: + il_op_pure_rop_gadget_resolve(core, op->op.fmul.x, info); + il_op_pure_rop_gadget_resolve(core, op->op.fmul.y, info); + break; + case RZ_IL_OP_FDIV: + il_op_pure_rop_gadget_resolve(core, op->op.fdiv.x, info); + il_op_pure_rop_gadget_resolve(core, op->op.fdiv.y, info); + break; + case RZ_IL_OP_FMOD: + il_op_pure_rop_gadget_resolve(core, op->op.fmod.x, info); + il_op_pure_rop_gadget_resolve(core, op->op.fmod.y, info); + break; + case RZ_IL_OP_FMAD: + il_op_pure_rop_gadget_resolve(core, op->op.fmad.x, info); + il_op_pure_rop_gadget_resolve(core, op->op.fmad.y, info); + il_op_pure_rop_gadget_resolve(core, op->op.fmad.z, info); + break; + default: + break; + } +} + +RZ_API void il_op_pure_rop_gadget_resolve(RzCore *core, RzILOpPure *op, RzRopGadgetInfo *info) { + if (!op) { + return; + } + switch (op->code) { + case RZ_IL_OP_VAR: + resolve_var_op(core, op, info); + break; + case RZ_IL_OP_ITE: + resolve_ite_op(core, op, info); + break; + case RZ_IL_OP_AND: + case RZ_IL_OP_OR: + case RZ_IL_OP_XOR: + case RZ_IL_OP_INV: + resolve_bool_op(core, op, info); + break; + case RZ_IL_OP_BITV: + case RZ_IL_OP_MSB: + case RZ_IL_OP_LSB: + case RZ_IL_OP_IS_ZERO: + case RZ_IL_OP_NEG: + case RZ_IL_OP_LOGNOT: + case RZ_IL_OP_ADD: + case RZ_IL_OP_SUB: + case RZ_IL_OP_MUL: + case RZ_IL_OP_DIV: + case RZ_IL_OP_SDIV: + case RZ_IL_OP_MOD: + case RZ_IL_OP_SMOD: + case RZ_IL_OP_LOGAND: + case RZ_IL_OP_LOGOR: + case RZ_IL_OP_LOGXOR: + case RZ_IL_OP_SHIFTR: + case RZ_IL_OP_SHIFTL: + case RZ_IL_OP_APPEND: + resolve_bitvector_op(core, op, info); + break; + case RZ_IL_OP_LOAD: + case RZ_IL_OP_LOADW: + resolve_load_op(core, op, info); + break; + case RZ_IL_OP_CAST: + resolve_cast_op(core, op, info); + break; + case RZ_IL_OP_FLOAT: + case RZ_IL_OP_FNEG: + case RZ_IL_OP_FABS: + case RZ_IL_OP_FADD: + case RZ_IL_OP_FSUB: + case RZ_IL_OP_FMUL: + case RZ_IL_OP_FDIV: + case RZ_IL_OP_FMOD: + case RZ_IL_OP_FMAD: + resolve_float_op(core, op, info); + break; + default: + break; + } +} + +static void il_rop_gadget_resolve_set(RzCore *core, RzRopGadgetInfo *info, RzILOpEffect *effect) { + add_reg_to_list(core, info->modified_registers, effect->op.set.v); + il_op_pure_rop_gadget_resolve(core, effect->op.set.x, info); +} + +static void il_rop_gadget_resolve_store(RzCore *core, RzRopGadgetInfo *info, RzILOpEffect *effect) { + add_reg_to_list(core, info->memory_write.dependencies, (const char *)effect->op.store.key); + add_reg_to_list(core, info->memory_write.stored_in_regs, (const char *)effect->op.store.value); +} + +static void il_rop_gadget_resolve_seq(RzCore *core, RzRopGadgetInfo *info, RzILOpEffect *effect) { + populate_gadget_info(core, info, effect->op.seq.x); + populate_gadget_info(core, info, effect->op.seq.y); +} + +static void il_rop_gadget_resolve_branch(RzCore *core, RzRopGadgetInfo *info, RzILOpEffect *effect) { + populate_gadget_info(core, info, effect->op.branch.true_eff); + populate_gadget_info(core, info, effect->op.branch.false_eff); +} + +static void il_rop_gadget_resolve_jmp(RzCore *core, RzRopGadgetInfo *info) { + add_reg_to_list(core, info->modified_registers, "rip"); +} + +static void il_rop_gadget_resolve_nop(RzCore *core, RzRopGadgetInfo *info) { + // NOP does not change any state or register +} + +RZ_API void populate_gadget_info(RzCore *core, RzRopGadgetInfo *info, RzILOpEffect *effect) { + if (!effect) { + return; + } + switch (effect->code) { + case RZ_IL_OP_SET: + il_rop_gadget_resolve_set(core, info, effect); + break; + case RZ_IL_OP_STORE: + il_rop_gadget_resolve_store(core, info, effect); + break; + case RZ_IL_OP_SEQ: + il_rop_gadget_resolve_seq(core, info, effect); + break; + case RZ_IL_OP_BRANCH: + il_rop_gadget_resolve_branch(core, info, effect); + break; + case RZ_IL_OP_JMP: + il_rop_gadget_resolve_jmp(core, info); + break; + case RZ_IL_OP_NOP: + il_rop_gadget_resolve_nop(core, info); + break; + default: + break; + } +} diff --git a/librz/il/meson.build b/librz/il/meson.build index 3db7fceaabd..f0d3035687e 100644 --- a/librz/il/meson.build +++ b/librz/il/meson.build @@ -21,6 +21,7 @@ rz_il_sources = [ 'il_validate.c', 'il_vm.c', 'il_vm_eval.c', + 'il_rop_gadget.c', ] rz_il_inc = [ diff --git a/librz/include/rz_analysis.h b/librz/include/rz_analysis.h index 006dc555e99..5604624e78a 100644 --- a/librz/include/rz_analysis.h +++ b/librz/include/rz_analysis.h @@ -1573,6 +1573,7 @@ RZ_API int rz_analysis_archinfo(RzAnalysis *analysis, RzAnalysisInfoType query); RZ_API bool rz_analysis_use(RzAnalysis *analysis, const char *name); RZ_API bool rz_analysis_set_reg_profile(RzAnalysis *analysis); RZ_API char *rz_analysis_get_reg_profile(RzAnalysis *analysis); +RZ_API bool rz_analysis_is_reg_in_profile(RzAnalysis *analysis, const char *str); RZ_API bool rz_analysis_set_bits(RzAnalysis *analysis, int bits); RZ_API bool rz_analysis_set_os(RzAnalysis *analysis, const char *os); RZ_API void rz_analysis_set_cpu(RzAnalysis *analysis, const char *cpu); diff --git a/librz/include/rz_rop.h b/librz/include/rz_rop.h index 6f7a0e34e7c..bfb249d02ec 100644 --- a/librz/include/rz_rop.h +++ b/librz/include/rz_rop.h @@ -6,12 +6,18 @@ #endif // RZ_ROP_H -typedef struct { +#include + +typedef struct rz_rop_op_t { + RzILOpPure *op; +} RzRopOp; + +typedef struct rz_rop_memory_t { RzList *dependencies; RzList *stored_in_regs; } RzRopMemoryOp; -typedef struct { +typedef struct rz_rop_gadget_info_t { ut64 address; ut64 stack_change; RzList *modified_registers; @@ -56,6 +62,8 @@ typedef struct rz_rop_gadget_analysis_t { RZ_API int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzCmdStateOutput *state); RZ_API RzCmdStatus rz_core_rop_gadget_info(RzCore *core, const char *input, RzCmdStateOutput *state); RZ_API bool analyze_constraint(RzCore *core, char *str, RzRopConstraint *rop_constraint); +RZ_API void populate_gadget_info(RzCore *core, RzRopGadgetInfo *info, RzILOpEffect *effect); +RZ_API void add_reg_to_list(RzCore *core, RzList *list, const char *str); // ROP Constraint APIs RZ_API void rz_rop_constraint_free(RZ_NULLABLE void *data); diff --git a/test/db/cmd/cmd_rop b/test/db/cmd/cmd_rop index 13d355d6ec7..0b21abc4fa4 100644 --- a/test/db/cmd/cmd_rop +++ b/test/db/cmd/cmd_rop @@ -357,6 +357,13 @@ Gadget size: 12 0x000001be 0e949816 call 0x2d30 Gadget size: 12 + 0x000001e4 0f01 movw r0, r30 + 0x000001e6 63e9 ldi r22, 0x93 + 0x000001e8 71e0 ldi r23, 0x01 + 0x000001ea c801 movw r24, r16 + 0x000001ec 0e949816 call 0x2d30 +Gadget size: 12 + EOF EXPECT_ERR=< Date: Tue, 18 Jun 2024 05:04:05 -0400 Subject: [PATCH 05/30] tiny rop.c cleanup --- librz/core/rop.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/librz/core/rop.c b/librz/core/rop.c index 7aa1425ff7a..c73c7e14f6b 100644 --- a/librz/core/rop.c +++ b/librz/core/rop.c @@ -617,13 +617,6 @@ RZ_API int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzC continue; } if (is_end_gadget(&end_gadget, crop)) { -#if 0 - if (search->maxhits && rz_list_length (end_list) >= search->maxhits) { - // limit number of high level rop gadget results - rz_analysis_op_fini (&end_gadget); - break; - } -#endif RzRopEndListPair *epair = RZ_NEW0(RzRopEndListPair); if (epair) { // If this arch has branch delay slots, add the next instr as well From ac8749361369f2b83f81fa3dbe256b12a74be42d Mon Sep 17 00:00:00 2001 From: Giridhar Prasath R Date: Mon, 24 Jun 2024 07:10:56 -0400 Subject: [PATCH 06/30] WIP: Add rop gadget semantics - RzIL events parsing - Store register info --- librz/core/rop.c | 352 ++++++++++++++++++++++++++++++--------- librz/il/il_rop_gadget.c | 342 ------------------------------------- librz/il/meson.build | 1 - librz/include/rz_rop.h | 32 ++-- 4 files changed, 284 insertions(+), 443 deletions(-) delete mode 100644 librz/il/il_rop_gadget.c diff --git a/librz/core/rop.c b/librz/core/rop.c index c73c7e14f6b..be1fe06eff5 100644 --- a/librz/core/rop.c +++ b/librz/core/rop.c @@ -7,64 +7,6 @@ #include #include -RzRopGadgetInfo *create_gadget_info(ut64 address); - -RzRopGadgetInfo *create_gadget_info(ut64 address) { - RzRopGadgetInfo *info = RZ_NEW0(RzRopGadgetInfo); - if (!info) { - return NULL; - } - info->address = address; - info->stack_change = 0x8; - info->modified_registers = rz_list_newf(free); - info->memory_write.dependencies = rz_list_newf(free); - info->memory_write.stored_in_regs = rz_list_newf(free); - info->memory_read.dependencies = rz_list_newf(free); - info->memory_read.stored_in_regs = rz_list_newf(free); - return info; -} - -void free_gadget_info(RzRopGadgetInfo *info) { - if (!info) { - return; - } - rz_list_free(info->modified_registers); - rz_list_free(info->memory_write.dependencies); - rz_list_free(info->memory_write.stored_in_regs); - rz_list_free(info->memory_read.dependencies); - rz_list_free(info->memory_read.stored_in_regs); - - free(info); -} - -void merge_gadget_info(RzCore *core, RzRopGadgetInfo *dest, RzRopGadgetInfo *src) { - RzListIter *iter; - char *data; - rz_list_foreach (src->modified_registers, iter, data) { - add_reg_to_list(core, dest->modified_registers, data); - } - rz_list_foreach (src->memory_write.dependencies, iter, data) { - add_reg_to_list(core, dest->memory_write.dependencies, data); - } - rz_list_foreach (src->memory_write.stored_in_regs, iter, data) { - add_reg_to_list(core, dest->memory_write.stored_in_regs, data); - } - rz_list_foreach (src->memory_read.dependencies, iter, data) { - add_reg_to_list(core, dest->memory_read.dependencies, data); - } - rz_list_foreach (src->memory_read.stored_in_regs, iter, data) { - add_reg_to_list(core, dest->memory_read.stored_in_regs, data); - } - dest->stack_change += src->stack_change; -} - -RZ_API void process_gadget(RzCore *core, RzRopGadgetInfo *gadget_info, RzILOpEffect *effects, ut64 addr) { - RzRopGadgetInfo *temp_info = create_gadget_info(addr); - populate_gadget_info(core, temp_info, effects); - merge_gadget_info(core, gadget_info, temp_info); - free_gadget_info(temp_info); -} - static bool is_end_gadget(const RzAnalysisOp *aop, const ut8 crop) { if (aop->family == RZ_ANALYSIS_OP_FAMILY_SECURITY) { return false; @@ -227,6 +169,267 @@ static int rz_rop_print_json_mode(RzCore *core, RzCoreAsmHit *hit, RzList *ropLi return 0; } +void rz_reg_info_free(RzRegInfo *reg_info) { + if (!reg_info) { + return; + } + free(reg_info->name); + free(reg_info); +} + +RzRegInfo *rz_reg_info_new(RzCore *core, const char *name, ut64 init_val, ut64 new_val) { + RzRegInfo *reg_info = RZ_NEW0(RzRegInfo); + if (!reg_info) { + return NULL; + } + const RzList *head = rz_reg_get_list(core->analysis->reg, RZ_REG_TYPE_GPR); + if (!head) { + free(reg_info); + return NULL; + } + RzListIter *iter_dst; + RzRegItem *item_dst; + rz_list_foreach (head, iter_dst, item_dst) { + if (!strcmp(name, item_dst->name) && item_dst->type == RZ_REG_TYPE_GPR) { + reg_info->name = strdup(name); + break; + } + } + + if (!reg_info->name) { + free(reg_info); + return NULL; + } + reg_info->init_val = init_val; + reg_info->new_val = new_val; + return reg_info; +} + +RzRopGadgetInfo *rz_rop_gadget_info_new(ut64 address, ut64 stack_change) { + RzRopGadgetInfo *gadget_info = RZ_NEW0(RzRopGadgetInfo); + if (!gadget_info) { + return NULL; + } + gadget_info->address = address; + gadget_info->stack_change = stack_change; + 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_reg_info_free); + gadget_info->dependencies = rz_list_newf((RzListFree)rz_reg_info_free); + return gadget_info; +} + +void rz_rop_gadget_info_free(RzRopGadgetInfo *gadget_info) { + if (!gadget_info) { + return; + } + rz_pvector_free(gadget_info->modified_registers); + rz_list_free(gadget_info->dependencies); + free(gadget_info); +} + +void rz_rop_gadget_info_add_register(RzRopGadgetInfo *gadget_info, RzRegInfo *reg_info, bool is_dependency) { + if (!gadget_info || !reg_info) { + return; + } + if (!is_dependency) { + rz_pvector_push(gadget_info->modified_registers, reg_info); + } +} + +RzRegInfo *rz_rop_gadget_info_get_modified_register(RzRopGadgetInfo *gadget_info, const char *name) { + if (!gadget_info) { + return NULL; + } + RzRegInfo *reg_info; + void **it; + rz_pvector_foreach (gadget_info->modified_registers, it) { + reg_info = *it; + if (strcmp(reg_info->name, name) == 0) { + return reg_info; + } + } + return NULL; +} + +void rz_rop_gadget_info_update_register(RzRopGadgetInfo *gadget_info, RzRegInfo *new_reg_info) { + if (!gadget_info || !new_reg_info) { + return; + } + + RzRegInfo *existing_reg_info = rz_rop_gadget_info_get_modified_register(gadget_info, new_reg_info->name); + if (existing_reg_info) { + // Update the existing RzRegInfo object + existing_reg_info->init_val = new_reg_info->init_val; + existing_reg_info->new_val = new_reg_info->new_val; + } else { + // Add the new RzRegInfo object to the modified_registers vector + rz_pvector_push(gadget_info->modified_registers, new_reg_info); + } +} + +RzRegInfo *rz_reg_info_dup(RzRegInfo *src) { + if (!src) { + return NULL; + } + + RzRegInfo *dup = RZ_NEW0(RzRegInfo); + if (!dup) { + return NULL; + } + + dup->name = strdup(src->name); + dup->is_mem_read = src->is_mem_read; + dup->is_pc_write = src->is_pc_write; + dup->is_mem_write = src->is_mem_write; + dup->init_val = src->init_val; + dup->new_val = src->new_val; + + return dup; +} +void rz_rop_gadget_info_add_dependency(RzRopGadgetInfo *gadget_info, RzILEventId type, RzRegInfo *reg_info) { + if (!gadget_info || !reg_info) { + return; + } + RzRegInfo *reg_info_dup = rz_reg_info_dup(reg_info); + if (!reg_info_dup) { + return; + } + rz_list_append(gadget_info->dependencies, reg_info_dup); +} + +static void fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadget_info, const RzILEvent *curr_event, RzILEvent *event, RzPVector *vec, bool is_dependency) { + if (!gadget_info) { + return; + } + switch (event->type) { + case RZ_IL_EVENT_VAR_READ: { + RzILEventVarRead *var_read = &event->data.var_read; + RzRegInfo *reg_info = rz_rop_gadget_info_get_modified_register(gadget_info, var_read->variable); + if (reg_info && !is_dependency) { + RzRegInfo *new_reg_info = rz_reg_info_dup(reg_info); + if (!new_reg_info) { + break; + } + RzBitVector *val = rz_il_value_to_bv(var_read->value); + if (!val) { + break; + } + new_reg_info->new_val = rz_bv_to_ut64(val); + rz_rop_gadget_info_update_register(gadget_info, new_reg_info); + rz_reg_info_free(new_reg_info); + rz_pvector_push(vec, event); + break; + } + if (is_dependency && curr_event) { + // shouldn't take this path if it is a dependency + if (curr_event->type == RZ_IL_EVENT_VAR_READ) { + break; + } + rz_rop_gadget_info_add_dependency(gadget_info, curr_event->type, reg_info); + break; + } + RzBitVector *val = rz_il_value_to_bv(var_read->value); + if (!val) { + break; + } + reg_info = rz_reg_info_new(core, var_read->variable, rz_bv_to_ut64(val), rz_bv_to_ut64(val)); + rz_rop_gadget_info_add_register(gadget_info, reg_info, is_dependency); + if (reg_info && !is_dependency) { + rz_pvector_push(vec, event); + } + } break; + case RZ_IL_EVENT_VAR_WRITE: { + if (is_dependency) { + break; + } + RzILEventVarWrite *var_write = &event->data.var_write; + RzRegInfo *reg_info = rz_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); + if (!old_val || !new_val) { + break; + } + reg_info = rz_reg_info_new(core, var_write->variable, rz_bv_to_ut64(old_val), + rz_bv_to_ut64(new_val)); + rz_rop_gadget_info_add_register(gadget_info, reg_info, is_dependency); + } + } break; + case RZ_IL_EVENT_MEM_READ: { + // RzILEventMemRead *mem_read = &event->data.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); + } + } 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); + } + } break; + case RZ_IL_EVENT_PC_WRITE: { + RzILEventPCWrite *pc_write = &event->data.pc_write; + if (!gadget_info->is_pc_write) { + gadget_info->is_pc_write = true; + } + } break; + default: + break; + } +} + +static void analyze_gadget(RzCore *core, RzCoreAsmHit /**/ *hit, RzRopGadgetInfo *rop_gadget_info) { + if (!core->analysis) { + return; + } + ut64 old_addr = core->offset; + rz_core_seek(core, hit->addr, true); + rz_core_analysis_il_reinit(core); + rz_config_set(core->config, "io.cache", "true"); + rz_core_il_step(core, 1); + if (!core->analysis || !core->analysis->il_vm) { + goto cleanup; + } + RzILVM *vm = core->analysis->il_vm->vm; + if (!vm) { + goto cleanup; + } + void **it; + RzILEvent *evt; + + RzPVector vec; + rz_pvector_init(&vec, (RzPVectorFree)rz_il_event_free); + rz_pvector_foreach (vm->events, it) { + evt = *it; + fill_rop_gadget_info_from_events(core, rop_gadget_info, NULL, evt, &vec, false); + } + +cleanup: + rz_core_seek(core, old_addr, true); +} + +void print_rop_gadget_info(RzRopGadgetInfo *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: "); + RzRegInfo *reg_info; + void **it; + 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) { + rz_cons_printf("%s ", reg_info->name); + } +} static void print_rop(RzCore *core, RzList /**/ *hitlist, RzCmdStateOutput *state) { RzCoreAsmHit *hit = NULL; RzListIter *iter; @@ -307,31 +510,16 @@ static void print_rop(RzCore *core, RzList /**/ *hitlist, RzCmdS if (db && hit) { rz_cons_printf("Gadget size: %d\n", (int)size); // rop_classify(core, db, ropList, key, size); - ut8 *buf; - RzAnalysisOp aop; - buf = malloc(size + 1); - hit = rz_list_first(hitlist); - if (!buf) { - goto cleanup; + if (rz_list_empty(hitlist)) { + return; + } + const ut64 addr_start = ((RzCoreAsmHit *)rz_list_first(hitlist))->addr; + RzRopGadgetInfo *rop_gadget_info = rz_rop_gadget_info_new(addr_start, core->analysis->bits / 8); + rz_list_foreach (hitlist, iter, hit) { + analyze_gadget(core, hit, rop_gadget_info); } - RzAsmOp *asmop = rz_asm_op_new(); - buf[size] = 0; - rz_io_read_at(core->io, hit->addr, buf, size); - rz_asm_set_pc(core->rasm, hit->addr); - rz_asm_disassemble(core->rasm, asmop, buf, size); - rz_analysis_op_init(&aop); - rz_analysis_op(core->analysis, &aop, hit->addr, buf, size, RZ_ANALYSIS_OP_MASK_IL); - RzRopGadgetInfo *rop_gadget_info = create_gadget_info(hit->addr); - // TODO: Remove this - RzStrBuf sb = { 0 }; - rz_strbuf_init(&sb); - rz_il_op_effect_stringify(aop.il_op, &sb, false); - process_gadget(core, rop_gadget_info, aop.il_op, hit->addr); - free_gadget_info(rop_gadget_info); - rz_analysis_op_fini(&aop); - rz_asm_op_free(asmop); - rz_strbuf_fini(&sb); - free(buf); + print_rop_gadget_info(rop_gadget_info); + rz_rop_gadget_info_free(rop_gadget_info); } rz_cons_newline(); break; diff --git a/librz/il/il_rop_gadget.c b/librz/il/il_rop_gadget.c deleted file mode 100644 index 767cdcecdc6..00000000000 --- a/librz/il/il_rop_gadget.c +++ /dev/null @@ -1,342 +0,0 @@ -// SPDX-FileCopyrightText: 2021 Florian Märkl -// SPDX-License-Identifier: LGPL-3.0-only - -#include -#include -#include - -RZ_API void il_op_pure_rop_gadget_resolve(RzCore *core, RzILOpPure *op, RzRopGadgetInfo *info); - -// TODO: Refactor this, added here because arch is dependent on IL and won't compile -static char *get_reg_profile(RzAnalysis *analysis) { - return analysis && analysis->cur && analysis->cur->get_reg_profile - ? analysis->cur->get_reg_profile(analysis) - : NULL; -} - -static bool is_reg_in_profile(const char *reg_profile, const char *str) { - if (strstr(reg_profile, str) != NULL) { - return true; - } - return false; -} - -RZ_API void add_reg_to_list(RzCore *core, RzList *list, const char *str) { - if (!str) { - return; - } - char *reg_prof = get_reg_profile(core->analysis); - if (!reg_prof) { - return; - } - - // Check if the register is correct for the given architecture. - if (is_reg_in_profile(reg_prof, str)) { - free(reg_prof); - char *copy = strdup(str); - rz_list_append(list, copy); - return; - } - - free(reg_prof); -} - -static void resolve_var_op(RzCore *core, RzILOpPure *op, RzRopGadgetInfo *info) { - if (op->code == RZ_IL_OP_VAR) { - add_reg_to_list(core, info->modified_registers, op->op.var.v); - } -} - -static void resolve_ite_op(RzCore *core, RzILOpPure *op, RzRopGadgetInfo *info) { - if (op->code == RZ_IL_OP_ITE) { - il_op_pure_rop_gadget_resolve(core, op->op.ite.condition, info); - il_op_pure_rop_gadget_resolve(core, op->op.ite.x, info); - il_op_pure_rop_gadget_resolve(core, op->op.ite.y, info); - } -} - -static void resolve_bool_op(RzCore *core, RzILOpPure *op, RzRopGadgetInfo *info) { - switch (op->code) { - case RZ_IL_OP_AND: - il_op_pure_rop_gadget_resolve(core, op->op.booland.x, info); - il_op_pure_rop_gadget_resolve(core, op->op.booland.y, info); - break; - case RZ_IL_OP_OR: - il_op_pure_rop_gadget_resolve(core, op->op.boolor.x, info); - il_op_pure_rop_gadget_resolve(core, op->op.boolor.y, info); - break; - case RZ_IL_OP_XOR: - il_op_pure_rop_gadget_resolve(core, op->op.boolxor.x, info); - il_op_pure_rop_gadget_resolve(core, op->op.boolxor.y, info); - break; - case RZ_IL_OP_INV: - il_op_pure_rop_gadget_resolve(core, op->op.boolinv.x, info); - break; - default: - break; - } -} - -static void resolve_bitvector_op(RzCore *core, RzILOpPure *op, RzRopGadgetInfo *info) { - switch (op->code) { - case RZ_IL_OP_BITV: - - break; - case RZ_IL_OP_MSB: - il_op_pure_rop_gadget_resolve(core, op->op.msb.bv, info); - break; - case RZ_IL_OP_LSB: - il_op_pure_rop_gadget_resolve(core, op->op.lsb.bv, info); - break; - case RZ_IL_OP_IS_ZERO: - il_op_pure_rop_gadget_resolve(core, op->op.is_zero.bv, info); - break; - case RZ_IL_OP_NEG: - il_op_pure_rop_gadget_resolve(core, op->op.neg.bv, info); - break; - case RZ_IL_OP_LOGNOT: - il_op_pure_rop_gadget_resolve(core, op->op.lognot.bv, info); - break; - case RZ_IL_OP_ADD: - il_op_pure_rop_gadget_resolve(core, op->op.add.x, info); - il_op_pure_rop_gadget_resolve(core, op->op.add.y, info); - break; - case RZ_IL_OP_SUB: - il_op_pure_rop_gadget_resolve(core, op->op.sub.x, info); - il_op_pure_rop_gadget_resolve(core, op->op.sub.y, info); - break; - case RZ_IL_OP_MUL: - il_op_pure_rop_gadget_resolve(core, op->op.mul.x, info); - il_op_pure_rop_gadget_resolve(core, op->op.mul.y, info); - break; - case RZ_IL_OP_DIV: - il_op_pure_rop_gadget_resolve(core, op->op.div.x, info); - il_op_pure_rop_gadget_resolve(core, op->op.div.y, info); - break; - case RZ_IL_OP_SDIV: - il_op_pure_rop_gadget_resolve(core, op->op.sdiv.x, info); - il_op_pure_rop_gadget_resolve(core, op->op.sdiv.y, info); - break; - case RZ_IL_OP_MOD: - il_op_pure_rop_gadget_resolve(core, op->op.mod.x, info); - il_op_pure_rop_gadget_resolve(core, op->op.mod.y, info); - break; - case RZ_IL_OP_SMOD: - il_op_pure_rop_gadget_resolve(core, op->op.smod.x, info); - il_op_pure_rop_gadget_resolve(core, op->op.smod.y, info); - break; - case RZ_IL_OP_LOGAND: - il_op_pure_rop_gadget_resolve(core, op->op.logand.x, info); - il_op_pure_rop_gadget_resolve(core, op->op.logand.y, info); - break; - case RZ_IL_OP_LOGOR: - il_op_pure_rop_gadget_resolve(core, op->op.logor.x, info); - il_op_pure_rop_gadget_resolve(core, op->op.logor.y, info); - break; - case RZ_IL_OP_LOGXOR: - il_op_pure_rop_gadget_resolve(core, op->op.logxor.x, info); - il_op_pure_rop_gadget_resolve(core, op->op.logxor.y, info); - break; - case RZ_IL_OP_SHIFTR: - il_op_pure_rop_gadget_resolve(core, op->op.shiftr.x, info); - il_op_pure_rop_gadget_resolve(core, op->op.shiftr.y, info); - il_op_pure_rop_gadget_resolve(core, op->op.shiftr.fill_bit, info); - break; - case RZ_IL_OP_SHIFTL: - il_op_pure_rop_gadget_resolve(core, op->op.shiftl.x, info); - il_op_pure_rop_gadget_resolve(core, op->op.shiftl.y, info); - il_op_pure_rop_gadget_resolve(core, op->op.shiftl.fill_bit, info); - break; - case RZ_IL_OP_APPEND: - il_op_pure_rop_gadget_resolve(core, op->op.append.high, info); - il_op_pure_rop_gadget_resolve(core, op->op.append.low, info); - break; - default: - break; - } -} - -static void update_gadget_info_stack_change(RzRopGadgetInfo *info, ut64 change) { - info->stack_change += change; -} - -static void set_memory_read_register(RzCore *core, RzRopGadgetInfo *info, const char *register_name) { - add_reg_to_list(core, info->memory_read.stored_in_regs, register_name); -} - -static void add_memory_dependency(RzCore *core, RzRopGadgetInfo *info, const char *register_name) { - add_reg_to_list(core, info->memory_write.dependencies, register_name); - add_reg_to_list(core, info->memory_read.dependencies, register_name); -} - -static void resolve_load_op(RzCore *core, RzILOpPure *op, RzRopGadgetInfo *info) { - if (op->code == RZ_IL_OP_LOAD) { - add_memory_dependency(core, info, (const char *)op->op.load.key); - } else if (op->code == RZ_IL_OP_LOADW) { - add_memory_dependency(core, info, (const char *)op->op.loadw.key); - } -} - -static void resolve_cast_op(RzCore *core, RzILOpPure *op, RzRopGadgetInfo *info) { - if (op->code == RZ_IL_OP_CAST) { - il_op_pure_rop_gadget_resolve(core, op->op.cast.val, info); - } -} - -static void resolve_float_op(RzCore *core, RzILOpPure *op, RzRopGadgetInfo *info) { - switch (op->code) { - case RZ_IL_OP_FLOAT: - il_op_pure_rop_gadget_resolve(core, op->op.float_.bv, info); - break; - case RZ_IL_OP_FNEG: - il_op_pure_rop_gadget_resolve(core, op->op.fneg.f, info); - break; - case RZ_IL_OP_FABS: - il_op_pure_rop_gadget_resolve(core, op->op.fabs.f, info); - break; - case RZ_IL_OP_FADD: - il_op_pure_rop_gadget_resolve(core, op->op.fadd.x, info); - il_op_pure_rop_gadget_resolve(core, op->op.fadd.y, info); - break; - case RZ_IL_OP_FSUB: - il_op_pure_rop_gadget_resolve(core, op->op.fsub.x, info); - il_op_pure_rop_gadget_resolve(core, op->op.fsub.y, info); - break; - case RZ_IL_OP_FMUL: - il_op_pure_rop_gadget_resolve(core, op->op.fmul.x, info); - il_op_pure_rop_gadget_resolve(core, op->op.fmul.y, info); - break; - case RZ_IL_OP_FDIV: - il_op_pure_rop_gadget_resolve(core, op->op.fdiv.x, info); - il_op_pure_rop_gadget_resolve(core, op->op.fdiv.y, info); - break; - case RZ_IL_OP_FMOD: - il_op_pure_rop_gadget_resolve(core, op->op.fmod.x, info); - il_op_pure_rop_gadget_resolve(core, op->op.fmod.y, info); - break; - case RZ_IL_OP_FMAD: - il_op_pure_rop_gadget_resolve(core, op->op.fmad.x, info); - il_op_pure_rop_gadget_resolve(core, op->op.fmad.y, info); - il_op_pure_rop_gadget_resolve(core, op->op.fmad.z, info); - break; - default: - break; - } -} - -RZ_API void il_op_pure_rop_gadget_resolve(RzCore *core, RzILOpPure *op, RzRopGadgetInfo *info) { - if (!op) { - return; - } - switch (op->code) { - case RZ_IL_OP_VAR: - resolve_var_op(core, op, info); - break; - case RZ_IL_OP_ITE: - resolve_ite_op(core, op, info); - break; - case RZ_IL_OP_AND: - case RZ_IL_OP_OR: - case RZ_IL_OP_XOR: - case RZ_IL_OP_INV: - resolve_bool_op(core, op, info); - break; - case RZ_IL_OP_BITV: - case RZ_IL_OP_MSB: - case RZ_IL_OP_LSB: - case RZ_IL_OP_IS_ZERO: - case RZ_IL_OP_NEG: - case RZ_IL_OP_LOGNOT: - case RZ_IL_OP_ADD: - case RZ_IL_OP_SUB: - case RZ_IL_OP_MUL: - case RZ_IL_OP_DIV: - case RZ_IL_OP_SDIV: - case RZ_IL_OP_MOD: - case RZ_IL_OP_SMOD: - case RZ_IL_OP_LOGAND: - case RZ_IL_OP_LOGOR: - case RZ_IL_OP_LOGXOR: - case RZ_IL_OP_SHIFTR: - case RZ_IL_OP_SHIFTL: - case RZ_IL_OP_APPEND: - resolve_bitvector_op(core, op, info); - break; - case RZ_IL_OP_LOAD: - case RZ_IL_OP_LOADW: - resolve_load_op(core, op, info); - break; - case RZ_IL_OP_CAST: - resolve_cast_op(core, op, info); - break; - case RZ_IL_OP_FLOAT: - case RZ_IL_OP_FNEG: - case RZ_IL_OP_FABS: - case RZ_IL_OP_FADD: - case RZ_IL_OP_FSUB: - case RZ_IL_OP_FMUL: - case RZ_IL_OP_FDIV: - case RZ_IL_OP_FMOD: - case RZ_IL_OP_FMAD: - resolve_float_op(core, op, info); - break; - default: - break; - } -} - -static void il_rop_gadget_resolve_set(RzCore *core, RzRopGadgetInfo *info, RzILOpEffect *effect) { - add_reg_to_list(core, info->modified_registers, effect->op.set.v); - il_op_pure_rop_gadget_resolve(core, effect->op.set.x, info); -} - -static void il_rop_gadget_resolve_store(RzCore *core, RzRopGadgetInfo *info, RzILOpEffect *effect) { - add_reg_to_list(core, info->memory_write.dependencies, (const char *)effect->op.store.key); - add_reg_to_list(core, info->memory_write.stored_in_regs, (const char *)effect->op.store.value); -} - -static void il_rop_gadget_resolve_seq(RzCore *core, RzRopGadgetInfo *info, RzILOpEffect *effect) { - populate_gadget_info(core, info, effect->op.seq.x); - populate_gadget_info(core, info, effect->op.seq.y); -} - -static void il_rop_gadget_resolve_branch(RzCore *core, RzRopGadgetInfo *info, RzILOpEffect *effect) { - populate_gadget_info(core, info, effect->op.branch.true_eff); - populate_gadget_info(core, info, effect->op.branch.false_eff); -} - -static void il_rop_gadget_resolve_jmp(RzCore *core, RzRopGadgetInfo *info) { - add_reg_to_list(core, info->modified_registers, "rip"); -} - -static void il_rop_gadget_resolve_nop(RzCore *core, RzRopGadgetInfo *info) { - // NOP does not change any state or register -} - -RZ_API void populate_gadget_info(RzCore *core, RzRopGadgetInfo *info, RzILOpEffect *effect) { - if (!effect) { - return; - } - switch (effect->code) { - case RZ_IL_OP_SET: - il_rop_gadget_resolve_set(core, info, effect); - break; - case RZ_IL_OP_STORE: - il_rop_gadget_resolve_store(core, info, effect); - break; - case RZ_IL_OP_SEQ: - il_rop_gadget_resolve_seq(core, info, effect); - break; - case RZ_IL_OP_BRANCH: - il_rop_gadget_resolve_branch(core, info, effect); - break; - case RZ_IL_OP_JMP: - il_rop_gadget_resolve_jmp(core, info); - break; - case RZ_IL_OP_NOP: - il_rop_gadget_resolve_nop(core, info); - break; - default: - break; - } -} diff --git a/librz/il/meson.build b/librz/il/meson.build index f0d3035687e..3db7fceaabd 100644 --- a/librz/il/meson.build +++ b/librz/il/meson.build @@ -21,7 +21,6 @@ rz_il_sources = [ 'il_validate.c', 'il_vm.c', 'il_vm_eval.c', - 'il_rop_gadget.c', ] rz_il_inc = [ diff --git a/librz/include/rz_rop.h b/librz/include/rz_rop.h index bfb249d02ec..dd5060f1460 100644 --- a/librz/include/rz_rop.h +++ b/librz/include/rz_rop.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020-2021 z3phyr +// SPDX-FileCopyrightText: 2024 z3phyr // SPDX-License-Identifier: LGPL-3.0-only #ifndef RZ_ROP_H @@ -8,21 +8,23 @@ #include -typedef struct rz_rop_op_t { - RzILOpPure *op; -} RzRopOp; - -typedef struct rz_rop_memory_t { - RzList *dependencies; - RzList *stored_in_regs; -} RzRopMemoryOp; +typedef struct rz_reg_info_t { + char *name; + bool is_mem_read; + bool is_pc_write; + bool is_mem_write; + ut64 init_val; + ut64 new_val; +} RzRegInfo; typedef struct rz_rop_gadget_info_t { ut64 address; ut64 stack_change; - RzList *modified_registers; - RzRopMemoryOp memory_write; - RzRopMemoryOp memory_read; + ut64 curr_pc_val; + bool is_pc_write; + bool is_syscall; + RzPVector /**/ *modified_registers; + RzList /**/ *dependencies; } RzRopGadgetInfo; typedef enum rzil_instr_type { @@ -54,16 +56,10 @@ typedef struct rz_rop_constraint_t { char *args[NUM_ARGS]; } RzRopConstraint; -typedef struct rz_rop_gadget_analysis_t { - ut64 addr; -} RzRopGadgetAnalysis; - // Command APIs RZ_API int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzCmdStateOutput *state); RZ_API RzCmdStatus rz_core_rop_gadget_info(RzCore *core, const char *input, RzCmdStateOutput *state); RZ_API bool analyze_constraint(RzCore *core, char *str, RzRopConstraint *rop_constraint); -RZ_API void populate_gadget_info(RzCore *core, RzRopGadgetInfo *info, RzILOpEffect *effect); -RZ_API void add_reg_to_list(RzCore *core, RzList *list, const char *str); // ROP Constraint APIs RZ_API void rz_rop_constraint_free(RZ_NULLABLE void *data); From 7af1118289dd359d83e77a5e3165d40fa4fd1fa0 Mon Sep 17 00:00:00 2001 From: Giridhar Prasath R Date: Mon, 24 Jun 2024 07:26:44 -0400 Subject: [PATCH 07/30] Nit change --- librz/include/rz_rop.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/librz/include/rz_rop.h b/librz/include/rz_rop.h index dd5060f1460..7b295e98c7b 100644 --- a/librz/include/rz_rop.h +++ b/librz/include/rz_rop.h @@ -29,10 +29,10 @@ typedef struct rz_rop_gadget_info_t { typedef enum rzil_instr_type { // Register to register - MOV_CONST, // reg <- const - MOV_REG, // reg <- reg - MOV_OP_CONST, // reg <- reg OP const - MOV_OP_REG, // reg <- reg OP reg + MOV_CONST, ///< reg <- const + MOV_REG, ///< reg <- reg + MOV_OP_CONST, ///< reg <- reg OP const + MOV_OP_REG, ///< reg <- reg OP reg // Call functions SYSCALL, } RzILInstructionType; From 0d0331ea14e83e5661c005007b9918c348853612 Mon Sep 17 00:00:00 2001 From: Giridhar Prasath R Date: Tue, 25 Jun 2024 06:23:39 -0400 Subject: [PATCH 08/30] Cleanup and add memory rw support - Code refactor and fixed some bugs related to IL event read - memory read and var read is fixed - Fix mem leaks --- librz/core/rop.c | 159 ++++++++++++++++++++++++++++++++++++----- librz/include/rz_rop.h | 2 + 2 files changed, 145 insertions(+), 16 deletions(-) diff --git a/librz/core/rop.c b/librz/core/rop.c index be1fe06eff5..c6c34c4c289 100644 --- a/librz/core/rop.c +++ b/librz/core/rop.c @@ -177,8 +177,16 @@ void rz_reg_info_free(RzRegInfo *reg_info) { free(reg_info); } -RzRegInfo *rz_reg_info_new(RzCore *core, const char *name, ut64 init_val, ut64 new_val) { +RzRegInfo *rz_reg_info_new(RzCore *core, RzILEvent *evt, ut64 init_val, ut64 new_val) { RzRegInfo *reg_info = RZ_NEW0(RzRegInfo); + const char *name = NULL; + if (evt->type == RZ_IL_EVENT_VAR_READ) { + reg_info->is_var_read = true; + name = evt->data.var_read.variable; + } else if (evt->type == RZ_IL_EVENT_VAR_WRITE) { + reg_info->is_var_write = true; + name = evt->data.var_write.variable; + } if (!reg_info) { return NULL; } @@ -205,13 +213,13 @@ RzRegInfo *rz_reg_info_new(RzCore *core, const char *name, ut64 init_val, ut64 n return reg_info; } -RzRopGadgetInfo *rz_rop_gadget_info_new(ut64 address, ut64 stack_change) { +RzRopGadgetInfo *rz_rop_gadget_info_new(ut64 address) { RzRopGadgetInfo *gadget_info = RZ_NEW0(RzRopGadgetInfo); if (!gadget_info) { return NULL; } gadget_info->address = address; - gadget_info->stack_change = stack_change; + gadget_info->stack_change = 0LL; gadget_info->curr_pc_val = address; gadget_info->is_pc_write = false; gadget_info->is_syscall = false; @@ -260,11 +268,13 @@ void rz_rop_gadget_info_update_register(RzRopGadgetInfo *gadget_info, RzRegInfo RzRegInfo *existing_reg_info = rz_rop_gadget_info_get_modified_register(gadget_info, new_reg_info->name); if (existing_reg_info) { - // Update the existing RzRegInfo object existing_reg_info->init_val = new_reg_info->init_val; existing_reg_info->new_val = new_reg_info->new_val; + existing_reg_info->is_mem_read = new_reg_info->is_mem_read; + existing_reg_info->is_pc_write = new_reg_info->is_pc_write; + existing_reg_info->is_mem_write = new_reg_info->is_mem_write; + existing_reg_info->is_var_read = new_reg_info->is_var_read; } else { - // Add the new RzRegInfo object to the modified_registers vector rz_pvector_push(gadget_info->modified_registers, new_reg_info); } } @@ -283,23 +293,95 @@ RzRegInfo *rz_reg_info_dup(RzRegInfo *src) { dup->is_mem_read = src->is_mem_read; dup->is_pc_write = src->is_pc_write; dup->is_mem_write = src->is_mem_write; + dup->is_var_read = src->is_var_read; + dup->is_var_write = src->is_var_write; dup->init_val = src->init_val; dup->new_val = src->new_val; return dup; } -void rz_rop_gadget_info_add_dependency(RzRopGadgetInfo *gadget_info, RzILEventId type, RzRegInfo *reg_info) { + +bool is_stack_pointer(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 && !strcmp(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; +} + +bool is_base_pointer(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 && !strcmp(core->analysis->cpu, "x86")) { + return !strcmp(reg_item->name, "ebp"); + } + if (core->analysis->bits == 64) { + return !strcmp(reg_item->name, "rbp") || !strcmp(reg_item->name, "ebp"); + } + if (core->analysis->bits == 64 && !strcmp(core->analysis->cpu, "arm")) { + return !strcmp(reg_item->name, "r11"); + } + return reg_item->name; +} + +void rz_rop_gadget_info_add_dependency(RzCore *core, RzRopGadgetInfo *gadget_info, RzILEvent *evt, RzRegInfo *reg_info) { if (!gadget_info || !reg_info) { return; } + RzRegInfo *reg_info_dup = rz_reg_info_dup(reg_info); if (!reg_info_dup) { return; } + switch (evt->type) { + case RZ_IL_EVENT_MEM_READ: + // Used for reading this address + RzILEventMemRead *mem_read = &evt->data.mem_read; + reg_info->is_mem_read = true; + 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; + 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); + break; + case RZ_IL_EVENT_VAR_WRITE: + reg_info->is_var_write = true; + RzILEventVarWrite *var_write = &evt->data.var_write; + RzBitVector *init_val = rz_il_value_to_bv(var_write->old_value); + RzBitVector *new_val = rz_il_value_to_bv(var_write->new_value); + if (!init_val || !new_val) { + rz_bv_free(init_val); + rz_bv_free(new_val); + break; + } + // reg_info_dup->init_val = rz_bv_to_ut64(init_val); + 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; + } + rz_bv_free(init_val); + rz_bv_free(new_val); + break; + default: + break; + } rz_list_append(gadget_info->dependencies, reg_info_dup); } -static void fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadget_info, const RzILEvent *curr_event, RzILEvent *event, RzPVector *vec, bool is_dependency) { +static void fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadget_info, RzILEvent *curr_event, RzILEvent *event, RzPVector *vec, bool is_dependency) { if (!gadget_info) { return; } @@ -320,6 +402,7 @@ static void fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadg rz_rop_gadget_info_update_register(gadget_info, new_reg_info); rz_reg_info_free(new_reg_info); rz_pvector_push(vec, event); + rz_bv_free(val); break; } if (is_dependency && curr_event) { @@ -327,34 +410,68 @@ static void fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadg if (curr_event->type == RZ_IL_EVENT_VAR_READ) { break; } - rz_rop_gadget_info_add_dependency(gadget_info, curr_event->type, reg_info); + rz_rop_gadget_info_add_dependency(core, gadget_info, curr_event, reg_info); + break; + } + if (reg_info) { break; } RzBitVector *val = rz_il_value_to_bv(var_read->value); if (!val) { break; } - reg_info = rz_reg_info_new(core, var_read->variable, rz_bv_to_ut64(val), rz_bv_to_ut64(val)); + reg_info = rz_reg_info_new(core, event, rz_bv_to_ut64(val), rz_bv_to_ut64(val)); rz_rop_gadget_info_add_register(gadget_info, reg_info, is_dependency); - if (reg_info && !is_dependency) { + if (!is_dependency) { rz_pvector_push(vec, event); } + rz_bv_free(val); } break; case RZ_IL_EVENT_VAR_WRITE: { 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); + } RzILEventVarWrite *var_write = &event->data.var_write; RzRegInfo *reg_info = rz_rop_gadget_info_get_modified_register(gadget_info, var_write->variable); + if (reg_info && !is_dependency) { + RzRegInfo *new_reg_info = rz_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) { + rz_bv_free(old_val); + rz_bv_free(new_val); + break; + } + // new_reg_info->init_val = rz_bv_to_ut64(old_val); + new_reg_info->new_val = rz_bv_to_ut64(new_val); + new_reg_info->is_mem_write = true; + rz_rop_gadget_info_update_register(gadget_info, new_reg_info); + rz_reg_info_free(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); if (!old_val || !new_val) { + rz_bv_free(old_val); + rz_bv_free(new_val); break; } - reg_info = rz_reg_info_new(core, var_write->variable, rz_bv_to_ut64(old_val), + reg_info = rz_reg_info_new(core, event, rz_bv_to_ut64(old_val), rz_bv_to_ut64(new_val)); rz_rop_gadget_info_add_register(gadget_info, reg_info, is_dependency); + rz_bv_free(old_val); + rz_bv_free(new_val); } } break; case RZ_IL_EVENT_MEM_READ: { @@ -408,10 +525,11 @@ static void analyze_gadget(RzCore *core, RzCoreAsmHit /**/ *hit, } cleanup: + rz_pvector_flush(&vec); rz_core_seek(core, old_addr, true); } -void print_rop_gadget_info(RzRopGadgetInfo *gadget_info) { +void print_rop_gadget_info(RzCore *core, RzRopGadgetInfo *gadget_info) { rz_cons_printf("Gadget 0x%" PFMT64x "\n", gadget_info->address); rz_cons_printf("Stack change: 0x%" PFMT64x "\n", gadget_info->stack_change); @@ -420,14 +538,23 @@ void print_rop_gadget_info(RzRopGadgetInfo *gadget_info) { void **it; rz_pvector_foreach (gadget_info->modified_registers, it) { reg_info = *it; - rz_cons_printf("%s ", reg_info->name); + if (reg_info->is_var_write) { + 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) { - rz_cons_printf("%s ", reg_info->name); + if (is_stack_pointer(core, reg_info->name) || is_base_pointer(core, reg_info->name)) { + continue; + } + if (reg_info->is_mem_read) { + rz_cons_printf("Memory Read: %s %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); + } } } static void print_rop(RzCore *core, RzList /**/ *hitlist, RzCmdStateOutput *state) { @@ -514,11 +641,11 @@ static void print_rop(RzCore *core, RzList /**/ *hitlist, RzCmdS return; } const ut64 addr_start = ((RzCoreAsmHit *)rz_list_first(hitlist))->addr; - RzRopGadgetInfo *rop_gadget_info = rz_rop_gadget_info_new(addr_start, core->analysis->bits / 8); + RzRopGadgetInfo *rop_gadget_info = rz_rop_gadget_info_new(addr_start); rz_list_foreach (hitlist, iter, hit) { analyze_gadget(core, hit, rop_gadget_info); } - print_rop_gadget_info(rop_gadget_info); + print_rop_gadget_info(core, rop_gadget_info); rz_rop_gadget_info_free(rop_gadget_info); } rz_cons_newline(); diff --git a/librz/include/rz_rop.h b/librz/include/rz_rop.h index 7b295e98c7b..6d3af7d2de0 100644 --- a/librz/include/rz_rop.h +++ b/librz/include/rz_rop.h @@ -12,6 +12,8 @@ typedef struct rz_reg_info_t { char *name; bool is_mem_read; bool is_pc_write; + bool is_var_read; + bool is_var_write; bool is_mem_write; ut64 init_val; ut64 new_val; From 8e6400ec17fd7830f742d2395d8c0421fbc861d7 Mon Sep 17 00:00:00 2001 From: Giridhar Prasath R Date: Tue, 25 Jun 2024 06:41:53 -0400 Subject: [PATCH 09/30] fix dependency function flags --- librz/core/cmd/cmd_search_rop.c | 2 +- librz/core/rop.c | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/librz/core/cmd/cmd_search_rop.c b/librz/core/cmd/cmd_search_rop.c index 7736f1cd711..6278b1da7c5 100644 --- a/librz/core/cmd/cmd_search_rop.c +++ b/librz/core/cmd/cmd_search_rop.c @@ -8,7 +8,7 @@ #include "rz_types_base.h" #include "rz_rop.h" -#include +#include static RzList /**/ *parse_list(const char *str) { char *line, *data, *str_n; diff --git a/librz/core/rop.c b/librz/core/rop.c index c6c34c4c289..1029e4e504c 100644 --- a/librz/core/rop.c +++ b/librz/core/rop.c @@ -347,18 +347,24 @@ void rz_rop_gadget_info_add_dependency(RzCore *core, RzRopGadgetInfo *gadget_inf switch (evt->type) { case RZ_IL_EVENT_MEM_READ: // Used for reading this address - RzILEventMemRead *mem_read = &evt->data.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->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; 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); break; case RZ_IL_EVENT_VAR_WRITE: reg_info->is_var_write = true; + reg_info->is_mem_read = false; + reg_info->is_mem_write = false; RzILEventVarWrite *var_write = &evt->data.var_write; RzBitVector *init_val = rz_il_value_to_bv(var_write->old_value); RzBitVector *new_val = rz_il_value_to_bv(var_write->new_value); @@ -550,7 +556,9 @@ void print_rop_gadget_info(RzCore *core, RzRopGadgetInfo *gadget_info) { if (is_stack_pointer(core, reg_info->name) || is_base_pointer(core, reg_info->name)) { continue; } - if (reg_info->is_mem_read) { + 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); + } else if (reg_info->is_mem_read) { rz_cons_printf("Memory Read: %s %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); From d3e820c1768fa3d2ce0a0fdb225b017e14295b99 Mon Sep 17 00:00:00 2001 From: Giridhar Prasath R Date: Thu, 27 Jun 2024 00:21:55 -0400 Subject: [PATCH 10/30] Generate accurate Rop gadgets --- librz/core/rop.c | 82 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 25 deletions(-) diff --git a/librz/core/rop.c b/librz/core/rop.c index 1029e4e504c..edc1fb87450 100644 --- a/librz/core/rop.c +++ b/librz/core/rop.c @@ -679,7 +679,7 @@ static bool insert_into(void *user, const ut64 k, const ut64 v) { // TODO: follow unconditional jumps static RzList /**/ *construct_rop_gadget(RzCore *core, ut64 addr, ut8 *buf, int buflen, int idx, const char *grep, int regex, RzList /**/ *rx_list, - RzRopEndListPair *end_gadget, HtUU *badstart, int delta) { + RzRopEndListPair *end_gadget, HtUU *badstart, int delta, RzStrBuf *sb) { int endaddr = end_gadget->instr_offset; int branch_delay = end_gadget->delay_size; RzAnalysisOp aop = { 0 }; @@ -719,35 +719,39 @@ static RzList /**/ *construct_rop_gadget(RzCore *core, ut64 addr valid = false; goto ret; } + ut32 end_gadget_cnt = 0; while (nb_instr < max_instr) { - ht_uu_insert(localbadstart, idx, 1); + // ht_uu_insert(localbadstart, idx, 1); rz_analysis_op_init(&aop); if (idx >= delta) { valid = false; goto ret; } int error = rz_analysis_op(core->analysis, &aop, addr, buf + idx, buflen - idx, RZ_ANALYSIS_OP_MASK_DISASM); - if (error < 0 || (nb_instr == 0 && (is_end_gadget(&aop, 0) || aop.type == RZ_ANALYSIS_OP_TYPE_NOP))) { + if (error < 0 || (nb_instr == 0 && aop.type == RZ_ANALYSIS_OP_TYPE_NOP)) { valid = false; goto ret; } + if (is_end_gadget(&aop, 0)) { + end_gadget_cnt++; + } const int opsz = aop.size; // opsz = rz_strbuf_length (asmop.buf); char *opst = aop.mnemonic; + RzAsmOp asmop; + int asm_ret = rz_asm_disassemble(core->rasm, &asmop, buf + idx, buflen - idx); if (!opst) { RZ_LOG_WARN("Analysis plugin %s did not return disassembly\n", core->analysis->cur->name); - RzAsmOp asmop; rz_asm_set_pc(core->rasm, addr); - if (rz_asm_disassemble(core->rasm, &asmop, buf + idx, buflen - idx) < 0) { + if (asm_ret < 0) { valid = false; goto ret; } opst = strdup(rz_asm_op_get_asm(&asmop)); - rz_asm_op_fini(&asmop); } if (!rz_str_ncasecmp(opst, "invalid", strlen("invalid")) || - !rz_str_ncasecmp(opst, ".byte", strlen(".byte"))) { + !rz_str_ncasecmp(opst, ".byte", strlen(".byte")) || end_gadget_cnt > 1) { valid = false; goto ret; } @@ -756,8 +760,14 @@ static RzList /**/ *construct_rop_gadget(RzCore *core, ut64 addr if (hit) { hit->addr = addr; hit->len = opsz; + 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); } + if (asm_ret >= 0) { + rz_asm_op_fini(&asmop); + } // Move on to the next instruction idx += opsz; @@ -836,6 +846,7 @@ RZ_API int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzC int delta = 0; ut8 *buf; RzIOMap *map; + HtSU *unique_hitlists = ht_su_new(HT_STR_DUP); const ut64 search_from = rz_config_get_i(core->config, "search.from"), search_to = rz_config_get_i(core->config, "search.to"); @@ -993,23 +1004,6 @@ RZ_API int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzC if (rz_cons_is_breaked()) { break; } - if (i >= next) { - // We've exhausted the first end-gadget section, - // move to the next one. - free(end_gadget); - if (rz_list_get_n(end_list, 0)) { - prev = i; - end_gadget = (RzRopEndListPair *)rz_list_pop(end_list); - next = end_gadget->instr_offset; - i = next - ropdepth; - if (i < 0) { - i = 0; - } - } else { - end_gadget = NULL; - break; - } - } if (i >= end) { // read by chunk of 4k rz_io_read_at(core->io, from + i, buf + i, RZ_MIN((delta - i), 4096)); @@ -1019,19 +1013,39 @@ RZ_API int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzC ret = rz_asm_disassemble(core->rasm, asmop, buf + i, delta - i); if (ret) { rz_asm_set_pc(core->rasm, from + i); + RzStrBuf *sb = rz_strbuf_new(""); RzList *hitlist = construct_rop_gadget(core, from + i, buf, delta, i, greparg, regexp, - rx_list, end_gadget, badstart, delta); + rx_list, end_gadget, badstart, delta, sb); + if (!hitlist) { rz_asm_op_free(asmop); asmop = NULL; + rz_strbuf_free(sb); continue; } if (align && 0 != (from + i) % align) { rz_asm_op_free(asmop); asmop = NULL; + rz_strbuf_free(sb); continue; } + bool is_found = true; + char *asm_op_hex = NULL; + if (sb->len) { + asm_op_hex = rz_strbuf_get(sb); + ht_su_find(unique_hitlists, asm_op_hex, &is_found); + } + if (!is_found && asm_op_hex) { + ht_su_insert(unique_hitlists, asm_op_hex, 1); + } else { + rz_list_free(hitlist); + rz_asm_op_free(asmop); + asmop = NULL; + rz_strbuf_free(sb); + continue; + } + rz_strbuf_free(sb); if (gadgetSdb) { RzListIter *iter; @@ -1080,6 +1094,23 @@ RZ_API int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzC } rz_asm_op_free(asmop); asmop = NULL; + if (i >= next) { + // We've exhausted the first end-gadget section, + // move to the next one. + free(end_gadget); + if (rz_list_get_n(end_list, 0)) { + prev = i; + end_gadget = (RzRopEndListPair *)rz_list_pop(end_list); + next = end_gadget->instr_offset; + i = next - ropdepth; + if (i < 0) { + i = 0; + } + } else { + end_gadget = NULL; + break; + } + } } free(end_gadget); } @@ -1094,6 +1125,7 @@ RZ_API int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzC rz_cmd_state_output_array_end(state); rz_cons_break_pop(); rz_asm_op_free(asmop); + ht_su_free(unique_hitlists); rz_list_free(rx_list); rz_list_free(end_list); rz_list_free(boundaries); From d8f548916cce149502ec18c0a5af517255ddab05 Mon Sep 17 00:00:00 2001 From: Giridhar Prasath R Date: Thu, 27 Jun 2024 07:39:32 -0400 Subject: [PATCH 11/30] Regression tc fix --- librz/core/cmd/cmd_search.c | 110 +--- librz/core/cmd/cmd_search_rop.c | 722 --------------------------- librz/core/cmd_descs/cmd_descs.c | 2 +- librz/core/cmd_descs/cmd_search.yaml | 2 +- librz/core/rop.c | 51 +- librz/include/rz_rop.h | 8 +- test/db/cmd/cmd_rop | 284 ++++++++--- 7 files changed, 259 insertions(+), 920 deletions(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index 370475a16fd..3ab1daf9c40 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -237,6 +237,8 @@ RZ_IPI RzCmdStatus rz_cmd_query_gadget_handler(RzCore *core, int argc, const cha rz_list_free(constraints); return RZ_CMD_STATUS_INVALID; } + + rz_core_search_rop(core, argv[1], 0, RZ_ROP_GADGET_DETAIL, state); rz_list_free(constraints); return RZ_CMD_STATUS_OK; } @@ -246,16 +248,14 @@ RZ_IPI RzCmdStatus rz_cmd_search_gadget_handler(RzCore *core, int argc, const ch if (!input) { return RZ_CMD_STATUS_ERROR; } - rz_core_search_rop(core, argv[1], 1, state); + rz_core_search_rop(core, argv[1], 1, RZ_ROP_GADGET_PRINT, state); return RZ_CMD_STATUS_OK; } RZ_IPI RzCmdStatus rz_cmd_detail_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; - } - // Add logic + rz_core_search_rop(core, input, 1, RZ_ROP_GADGET_DETAIL, state); + return RZ_CMD_STATUS_OK; } @@ -1849,106 +1849,6 @@ static void do_string_search(RzCore *core, RzInterval search_itv, struct search_ } } -static void rop_kuery(void *data, const char *input, RzCmdStateOutput *state) { - RzCore *core = data; - Sdb *db_rop = sdb_ns(core->sdb, "rop", false); - RzListIter *it; - void **items_iter; - SdbNs *ns; - char *out; - - if (!db_rop) { - RZ_LOG_ERROR("core: could not find SDB 'rop' namespace\n"); - return; - } - - switch (state->mode) { - case RZ_OUTPUT_MODE_QUIET: - rz_list_foreach (db_rop->ns, it, ns) { - RzPVector *items = sdb_get_items(ns->sdb, false); - rz_pvector_foreach (items, items_iter) { - SdbKv *kv = *items_iter; - rz_cons_printf("%s ", sdbkv_key(kv)); - } - rz_pvector_free(items); - } - break; - case RZ_OUTPUT_MODE_JSON: - pj_o(state->d.pj); - pj_ka(state->d.pj, "gadgets"); - rz_list_foreach (db_rop->ns, it, ns) { - RzPVector *items = sdb_get_items(ns->sdb, false); - rz_pvector_foreach (items, items_iter) { - SdbKv *kv = *items_iter; - char *dup = sdbkv_dup_value(kv); - bool flag = false; // to free tok when doing strdup - char *size = strtok(dup, " "); - char *tok = strtok(NULL, "{}"); - if (!tok) { - tok = strdup("NOP"); - flag = true; - } - pj_o(state->d.pj); - pj_ks(state->d.pj, "address", sdbkv_key(kv)); - pj_ks(state->d.pj, "size", size); - pj_ks(state->d.pj, "type", ns->name); - pj_ks(state->d.pj, "effect", tok); - pj_end(state->d.pj); - free(dup); - if (flag) { - free(tok); - } - } - rz_pvector_free(items); - } - pj_end(state->d.pj); - pj_end(state->d.pj); - break; - case ' ': - if (!strcmp(input + 1, "nop")) { - out = sdb_querys(core->sdb, NULL, 0, "rop/nop/*"); - if (out) { - rz_cons_println(out); - free(out); - } - } else if (!strcmp(input + 1, "mov")) { - out = sdb_querys(core->sdb, NULL, 0, "rop/mov/*"); - if (out) { - rz_cons_println(out); - free(out); - } - } else if (!strcmp(input + 1, "const")) { - out = sdb_querys(core->sdb, NULL, 0, "rop/const/*"); - if (out) { - rz_cons_println(out); - free(out); - } - } else if (!strcmp(input + 1, "arithm")) { - out = sdb_querys(core->sdb, NULL, 0, "rop/arithm/*"); - if (out) { - rz_cons_println(out); - free(out); - } - } else if (!strcmp(input + 1, "arithm_ct")) { - out = sdb_querys(core->sdb, NULL, 0, "rop/arithm_ct/*"); - if (out) { - rz_cons_println(out); - free(out); - } - } else { - RZ_LOG_ERROR("core: Invalid ROP class\n"); - } - break; - default: - out = sdb_querys(core->sdb, NULL, 0, "rop/***"); - if (out) { - rz_cons_println(out); - free(out); - } - break; - } -} - static int memcmpdiff(const ut8 *a, const ut8 *b, int len) { int i, diff = 0; for (i = 0; i < len; i++) { diff --git a/librz/core/cmd/cmd_search_rop.c b/librz/core/cmd/cmd_search_rop.c index 6278b1da7c5..09d8d1a18c8 100644 --- a/librz/core/cmd/cmd_search_rop.c +++ b/librz/core/cmd/cmd_search_rop.c @@ -8,728 +8,6 @@ #include "rz_types_base.h" #include "rz_rop.h" -#include - -static RzList /**/ *parse_list(const char *str) { - char *line, *data, *str_n; - - if (!str) { - return NULL; - } - str_n = strdup(str); - line = strtok(str_n, "\n"); - data = strchr(line, '='); - - RzList *list = rz_str_split_duplist(data + 1, ",", false); - - free(str_n); - return list; -} - -static RzList /**/ *get_constants(const char *str) { - RzList *list; - char *p, *data; - if (!str) { - return NULL; - } - - data = strdup(str); - list = rz_list_newf(free); - p = strtok(data, ","); - while (p) { - if (strtol(p, NULL, 0)) { - rz_list_append(list, (void *)strdup(p)); - } - p = strtok(NULL, ","); - } - free(data); - return list; -} - -static bool isFlag(RzRegItem *reg) { - const char *type = rz_reg_get_type(reg->type); - - if (!strcmp(type, "flg")) - return true; - return false; -} - -// binary op -static bool simulate_op(const char *op, ut64 src1, ut64 src2, ut64 old_src1, ut64 old_src2, ut64 *result, int size) { - ut64 limit; - if (size == 64) { - limit = UT64_MAX; - } else { - limit = 1ULL << size; - } - - if (!strcmp(op, "^")) { - *result = src1 ^ src2; - return true; - } - if (!strcmp(op, "+")) { - *result = src1 + src2; - return true; - } - if (!strcmp(op, "-")) { - if (src2 > src1) { - *result = limit + (src1 - src2); - } else { - *result = src1 - src2; - } - return true; - } - if (!strcmp(op, "*")) { - *result = src1 * src2; - return true; - } - if (!strcmp(op, "|")) { - *result = src1 | src2; - return true; - } - if (!strcmp(op, "/")) { - *result = src1 / src2; - return true; - } - if (!strcmp(op, "%")) { - *result = src1 % src2; - return true; - } - if (!strcmp(op, "<<")) { - *result = src1 << src2; - return true; - } - if (!strcmp(op, ">>")) { - *result = src1 >> src2; - return true; - } - if (!strcmp(op, "&")) { - *result = src1 & src2; - return true; - } - if (!strcmp(op, "+=")) { - *result = old_src1 + src2; - return true; - } - if (!strcmp(op, "-=")) { - if (src2 > old_src1) { - *result = limit + (old_src1 - src2); - } else { - *result = old_src1 - src2; - } - return true; - } - if (!strcmp(op, "*=")) { - *result = old_src1 * src2; - return true; - } - if (!strcmp(op, "/=")) { - *result = old_src1 / src2; - return true; - } - if (!strcmp(op, "%=")) { - *result = old_src1 % src2; - return true; - } - if (!strcmp(op, "<<")) { - *result = src1 << src2; - return true; - } - if (!strcmp(op, ">>")) { - *result = src1 >> src2; - return true; - } - if (!strcmp(op, "&=")) { - *result = src1 & src2; - return true; - } - if (!strcmp(op, "^=")) { - *result = src1 ^ src2; - return true; - } - if (!strcmp(op, "|=")) { - *result = src1 | src2; - return true; - } - return false; -} - -// fill REGs with known values -static void fillRegisterValues(RzCore *core) { - RzListIter *iter_reg; - RzRegItem *reg_item; - int nr = 10; - - const RzList *regs = rz_reg_get_list(core->analysis->reg, RZ_REG_TYPE_GPR); - if (!regs) { - return; - } - rz_list_foreach (regs, iter_reg, reg_item) { - rz_reg_arena_pop(core->analysis->reg); - rz_reg_set_value(core->analysis->reg, reg_item, nr); - rz_reg_arena_push(core->analysis->reg); - nr += 3; - } -} - -// split esil string in flags part and main instruction -// hacky, only tested for x86, TODO: portable version -// NOTE: esil_main and esil_flg are heap allocated and must be freed by the caller -static void esil_split_flg(char *esil_str, char **esil_main, char **esil_flg) { - char *split = strstr(esil_str, "f,="); - const int kCommaHits = 2; - int hits = 0; - - if (split) { - while (hits != kCommaHits) { - --split; - if (*split == ',') { - hits++; - } - } - *esil_flg = strdup(++split); - *esil_main = rz_str_ndup(esil_str, strlen(esil_str) - strlen(*esil_flg) - 1); - } -} - -#define FREE_ROP \ - { \ - RZ_FREE(out); \ - RZ_FREE(esil_flg); \ - RZ_FREE(esil_main); \ - rz_list_free(ops_list); \ - ops_list = NULL; \ - rz_list_free(flg_read); \ - flg_read = NULL; \ - rz_list_free(flg_write); \ - flg_write = NULL; \ - rz_list_free(reg_read); \ - reg_read = NULL; \ - rz_list_free(reg_write); \ - reg_write = NULL; \ - rz_list_free(mem_read); \ - mem_read = NULL; \ - rz_list_free(mem_write); \ - mem_write = NULL; \ - } - -static char *rop_classify_constant(RzCore *core, RzList /**/ *ropList) { - char *esil_str, *constant; - char *ct = NULL, *esil_main = NULL, *esil_flg = NULL, *out = NULL; - RzListIter *iter_r, *iter_dst, *iter_const; - RzRegItem *item_dst; - const RzList *head; - RzList *constants; - RzList *ops_list = NULL, *flg_read = NULL, *flg_write = NULL, - *reg_read = NULL, *reg_write = NULL, *mem_read = NULL, - *mem_write = NULL; - const bool romem = rz_config_get_i(core->config, "esil.romem"); - const bool stats = rz_config_get_i(core->config, "esil.stats"); - - if (!romem || !stats) { - // eprintf ("Error: esil.romem and esil.stats must be set TRUE"); - return NULL; - } - - rz_list_foreach (ropList, iter_r, esil_str) { - constants = get_constants(esil_str); - // if there are no constants in the instruction continue - if (rz_list_empty(constants)) { - continue; - } - // init regs with known values - fillRegisterValues(core); - head = rz_reg_get_list(core->analysis->reg, RZ_REG_TYPE_GPR); - if (!head) { - ct = NULL; - goto continue_error; - } - esil_split_flg(esil_str, &esil_main, &esil_flg); - cmd_analysis_esil(core, esil_main ? esil_main : esil_str); - out = sdb_querys(core->analysis->esil->stats, NULL, 0, "*"); - if (!out) { - goto continue_error; - } - ops_list = parse_list(strstr(out, "ops.list")); - flg_read = parse_list(strstr(out, "flg.read")); - flg_write = parse_list(strstr(out, "flg.write")); - reg_read = parse_list(strstr(out, "reg.read")); - reg_write = parse_list(strstr(out, "reg.write")); - mem_read = parse_list(strstr(out, "mem.read")); - mem_write = parse_list(strstr(out, "mem.write")); - if (!rz_list_find(ops_list, "=", (RzListComparator)strcmp, NULL)) { - goto continue_error; - } - head = rz_reg_get_list(core->analysis->reg, RZ_REG_TYPE_GPR); - if (!head) { - goto out_error; - } - rz_list_foreach (head, iter_dst, item_dst) { - ut64 diff_dst, value_dst; - if (!rz_list_find(reg_write, item_dst->name, - (RzListComparator)strcmp, NULL)) { - continue; - } - - value_dst = rz_reg_get_value(core->analysis->reg, item_dst); - rz_reg_arena_swap(core->analysis->reg, false); - diff_dst = rz_reg_get_value(core->analysis->reg, item_dst); - rz_reg_arena_swap(core->analysis->reg, false); - // restore initial value - rz_reg_set_value(core->analysis->reg, item_dst, diff_dst); - - if (value_dst != diff_dst) { - rz_list_foreach (constants, iter_const, constant) { - if (value_dst == rz_num_get(NULL, constant)) { - ct = rz_str_appendf(ct, "%s <-- 0x%" PFMT64x ";", item_dst->name, value_dst); - } - } - } - } - continue_error: - // coverity may complain here but as long as the pointer is set back to - // NULL is safe that is why is used RZ_FREE - FREE_ROP; - rz_list_free(constants); - } - return ct; -out_error: - FREE_ROP; - rz_list_free(constants); - return NULL; -} - -static char *rop_classify_mov(RzCore *core, RzList /**/ *ropList) { - char *esil_str; - char *mov = NULL, *esil_main = NULL, *esil_flg = NULL, *out = NULL; - RzListIter *iter_src, *iter_r, *iter_dst; - RzRegItem *item_src, *item_dst; - const RzList *head; - RzList *ops_list = NULL, *flg_read = NULL, *flg_write = NULL, - *reg_read = NULL, *reg_write = NULL, *mem_read = NULL, - *mem_write = NULL; - const bool romem = rz_config_get_i(core->config, "esil.romem"); - const bool stats = rz_config_get_i(core->config, "esil.stats"); - - if (!romem || !stats) { - // eprintf ("Error: esil.romem and esil.stats must be set TRUE"); - return NULL; - } - - rz_list_foreach (ropList, iter_r, esil_str) { - // init regs with known values - fillRegisterValues(core); - head = rz_reg_get_list(core->analysis->reg, RZ_REG_TYPE_GPR); - if (!head) { - goto out_error; - } - esil_split_flg(esil_str, &esil_main, &esil_flg); - cmd_analysis_esil(core, esil_main ? esil_main : esil_str); - out = sdb_querys(core->analysis->esil->stats, NULL, 0, "*"); - if (out) { - ops_list = parse_list(strstr(out, "ops.list")); - flg_read = parse_list(strstr(out, "flg.read")); - flg_write = parse_list(strstr(out, "flg.write")); - reg_read = parse_list(strstr(out, "reg.read")); - reg_write = parse_list(strstr(out, "reg.write")); - mem_read = parse_list(strstr(out, "mem.read")); - mem_write = parse_list(strstr(out, "mem.write")); - } else { - goto continue_error; - } - - if (!rz_list_find(ops_list, "=", (RzListComparator)strcmp, NULL)) { - goto continue_error; - } - - head = rz_reg_get_list(core->analysis->reg, RZ_REG_TYPE_GPR); - if (!head) { - goto out_error; - } - rz_list_foreach (head, iter_dst, item_dst) { - ut64 diff_dst, value_dst; - if (!rz_list_find(reg_write, item_dst->name, - (RzListComparator)strcmp, NULL)) { - continue; - } - - // you never mov into flags - if (isFlag(item_dst)) { - continue; - } - - value_dst = rz_reg_get_value(core->analysis->reg, item_dst); - rz_reg_arena_swap(core->analysis->reg, false); - diff_dst = rz_reg_get_value(core->analysis->reg, item_dst); - rz_reg_arena_swap(core->analysis->reg, false); - rz_list_foreach (head, iter_src, item_src) { - ut64 diff_src, value_src; - if (!rz_list_find(reg_read, item_src->name, - (RzListComparator)strcmp, NULL)) { - continue; - } - // you never mov from flags - if (item_src == item_dst || isFlag(item_src)) { - continue; - } - value_src = rz_reg_get_value(core->analysis->reg, item_src); - rz_reg_arena_swap(core->analysis->reg, false); - diff_src = rz_reg_get_value(core->analysis->reg, item_src); - rz_reg_arena_swap(core->analysis->reg, false); - // restore initial value - rz_reg_set_value(core->analysis->reg, item_src, diff_src); - if (value_dst == value_src && value_dst != diff_dst) { - mov = rz_str_appendf(mov, "%s <-- %s;", - item_dst->name, item_src->name); - } - } - } - continue_error: - FREE_ROP; - } - return mov; -out_error: - FREE_ROP; - return NULL; -} - -static char *rop_classify_arithmetic(RzCore *core, RzList /**/ *ropList) { - char *esil_str, *op; - char *arithmetic = NULL, *esil_flg = NULL, *esil_main = NULL, - *out = NULL; - RzListIter *iter_src1, *iter_src2, *iter_r, *iter_dst, *iter_ops; - RzRegItem *item_src1, *item_src2, *item_dst; - const RzList *head; - RzList *ops_list = NULL, *flg_read = NULL, *flg_write = NULL, - *reg_read = NULL, *reg_write = NULL, *mem_read = NULL, - *mem_write = NULL; - const bool romem = rz_config_get_i(core->config, "esil.romem"); - const bool stats = rz_config_get_i(core->config, "esil.stats"); - ut64 *op_result = RZ_NEW0(ut64); - ut64 *op_result_r = RZ_NEW0(ut64); - - if (!romem || !stats) { - // eprintf ("Error: esil.romem and esil.stats must be set TRUE"); - free(op_result); - free(op_result_r); - return NULL; - } - - rz_list_foreach (ropList, iter_r, esil_str) { - // init regs with known values - fillRegisterValues(core); - head = rz_reg_get_list(core->analysis->reg, RZ_REG_TYPE_GPR); - if (!head) { - goto out_error; - } - esil_split_flg(esil_str, &esil_main, &esil_flg); - if (esil_main) { - cmd_analysis_esil(core, esil_main); - } else { - cmd_analysis_esil(core, esil_str); - } - out = sdb_querys(core->analysis->esil->stats, NULL, 0, "*"); - // rz_cons_println (out); - if (!out) { - goto continue_error; - } - ops_list = parse_list(strstr(out, "ops.list")); - flg_read = parse_list(strstr(out, "flg.read")); - flg_write = parse_list(strstr(out, "flg.write")); - reg_read = parse_list(strstr(out, "reg.read")); - reg_write = parse_list(strstr(out, "reg.write")); - mem_read = parse_list(strstr(out, "mem.read")); - mem_write = parse_list(strstr(out, "mem.write")); - - rz_list_foreach (ops_list, iter_ops, op) { - rz_list_foreach (head, iter_src1, item_src1) { - ut64 value_src1, diff_src1; - - value_src1 = rz_reg_get_value(core->analysis->reg, item_src1); - rz_reg_arena_swap(core->analysis->reg, false); - diff_src1 = rz_reg_get_value(core->analysis->reg, item_src1); - rz_reg_arena_swap(core->analysis->reg, false); - if (!rz_list_find(reg_read, item_src1->name, - (RzListComparator)strcmp, NULL)) { - continue; - } - - rz_list_foreach (head, iter_src2, item_src2) { - ut64 value_src2, diff_src2; - value_src2 = rz_reg_get_value(core->analysis->reg, item_src2); - rz_reg_arena_swap(core->analysis->reg, false); - diff_src2 = rz_reg_get_value(core->analysis->reg, item_src2); - - if (!rz_list_find(reg_read, item_src2->name, - (RzListComparator)strcmp, NULL)) { - continue; - } - // TODO check condition - if (iter_src1 == iter_src2) { - continue; - } - - rz_list_foreach (head, iter_dst, item_dst) { - ut64 value_dst; - bool redundant = false, simulate, simulate_r; - - value_dst = rz_reg_get_value(core->analysis->reg, item_dst); - rz_reg_arena_swap(core->analysis->reg, false); - if (!rz_list_find(reg_write, item_dst->name, - (RzListComparator)strcmp, NULL)) { - continue; - } - // don't check flags for arithmetic - if (isFlag(item_dst)) { - continue; - } - simulate = simulate_op(op, value_src1, value_src2, diff_src1, diff_src2, op_result, item_dst->size); - simulate_r = simulate_op(op, value_src2, value_src1, diff_src2, diff_src1, op_result_r, item_dst->size); - if (/*value_src1 != 0 && value_src2 != 0 && */ simulate && value_dst == *op_result) { - // rz_cons_println ("Debug: FOUND ONE !"); - char *tmp = rz_str_newf("%s <-- %s %s %s;", item_dst->name, item_src1->name, op, item_src2->name); - if (arithmetic && !strstr(arithmetic, tmp)) { - arithmetic = rz_str_append(arithmetic, tmp); - } else if (!arithmetic) { - arithmetic = rz_str_append(arithmetic, tmp); - } - free(tmp); - } else if (!redundant /*&& value_src1 != 0 && value_src2 != 0*/ && simulate_r && value_dst == *op_result_r) { - // rz_cons_println ("Debug: FOUND ONE reversed!"); - char *tmp = rz_str_newf("%s <-- %s %s %s;", item_dst->name, item_src2->name, op, item_src1->name); - if (arithmetic && !strstr(arithmetic, tmp)) { - arithmetic = rz_str_append(arithmetic, tmp); - } else if (!arithmetic) { - arithmetic = rz_str_append(arithmetic, tmp); - } - free(tmp); - } - } - } - } - } - continue_error: - FREE_ROP; - } - free(op_result); - free(op_result_r); - return arithmetic; -out_error: - FREE_ROP; - free(op_result); - free(op_result_r); - return NULL; -} - -static char *rop_classify_arithmetic_const(RzCore *core, RzList /**/ *ropList) { - char *esil_str, *op, *constant; - char *arithmetic = NULL, *esil_flg = NULL, *esil_main = NULL; - RzListIter *iter_src1, *iter_r, *iter_dst, *iter_ops, *iter_const; - RzRegItem *item_src1, *item_dst; - const RzList *head; - RzList *constants; - RzList *ops_list = NULL, *flg_read = NULL, *flg_write = NULL, *reg_read = NULL, - *reg_write = NULL, *mem_read = NULL, *mem_write = NULL; - const bool romem = rz_config_get_i(core->config, "esil.romem"); - const bool stats = rz_config_get_i(core->config, "esil.stats"); - ut64 *op_result = RZ_NEW0(ut64); - ut64 *op_result_r = RZ_NEW0(ut64); - - if (!romem || !stats) { - // eprintf ("Error: esil.romem and esil.stats must be set TRUE"); - RZ_FREE(op_result); - RZ_FREE(op_result_r); - return NULL; - } - - rz_list_foreach (ropList, iter_r, esil_str) { - constants = get_constants(esil_str); - // if there are no constants in the instruction continue - if (rz_list_empty(constants)) { - continue; - } - // init regs with known values - fillRegisterValues(core); - head = rz_reg_get_list(core->analysis->reg, RZ_REG_TYPE_GPR); - if (!head) { - arithmetic = NULL; - continue; - } - esil_split_flg(esil_str, &esil_main, &esil_flg); - if (esil_main) { - cmd_analysis_esil(core, esil_main); - } else { - cmd_analysis_esil(core, esil_str); - } - char *out = sdb_querys(core->analysis->esil->stats, NULL, 0, "*"); - // rz_cons_println (out); - if (out) { - ops_list = parse_list(strstr(out, "ops.list")); - flg_read = parse_list(strstr(out, "flg.read")); - flg_write = parse_list(strstr(out, "flg.write")); - reg_read = parse_list(strstr(out, "reg.read")); - reg_write = parse_list(strstr(out, "reg.write")); - mem_read = parse_list(strstr(out, "mem.read")); - mem_write = parse_list(strstr(out, "mem.write")); - } else { - RZ_FREE(op_result); - RZ_FREE(op_result_r); - goto continue_error; - } - - rz_list_foreach (ops_list, iter_ops, op) { - rz_list_foreach (head, iter_src1, item_src1) { - ut64 value_src1, diff_src1; - value_src1 = rz_reg_get_value(core->analysis->reg, item_src1); - rz_reg_arena_swap(core->analysis->reg, false); - diff_src1 = rz_reg_get_value(core->analysis->reg, item_src1); - rz_reg_arena_swap(core->analysis->reg, false); - - if (!rz_list_find(reg_read, item_src1->name, - (RzListComparator)strcmp, NULL)) { - continue; - } - rz_list_foreach (head, iter_dst, item_dst) { - ut64 value_dst, diff_dst; - bool redundant = false, simulate, simulate_r; - value_dst = rz_reg_get_value(core->analysis->reg, item_dst); - rz_reg_arena_swap(core->analysis->reg, false); - diff_dst = rz_reg_get_value(core->analysis->reg, item_dst); - rz_reg_arena_swap(core->analysis->reg, false); - if (!rz_list_find(reg_write, item_dst->name, - (RzListComparator)strcmp, NULL)) { - continue; - } - // don't check flags for arithmetic - if (isFlag(item_dst)) { - continue; - } - if (value_dst != diff_dst) { - rz_list_foreach (constants, iter_const, constant) { - ut64 value_ct = rz_num_get(NULL, constant); - simulate = simulate_op(op, value_src1, value_ct, - diff_src1, value_ct, op_result, - item_dst->size); - simulate_r = simulate_op(op, value_ct, value_src1, - value_ct, diff_src1, op_result_r, - item_dst->size); - if (simulate && op_result && value_dst == *op_result) { - char *tmp = rz_str_newf("%s <-- %s %s %s;", item_dst->name, item_src1->name, op, constant); - if (arithmetic && !strstr(arithmetic, tmp)) { - arithmetic = rz_str_append(arithmetic, tmp); - } else if (!arithmetic) { - arithmetic = rz_str_append(arithmetic, tmp); - } - free(tmp); - redundant = true; - } else if (!redundant && simulate_r && value_dst == *op_result_r) { - char *tmp = rz_str_newf("%s <-- %s %s %s;", item_dst->name, constant, op, item_src1->name); - if (arithmetic && !strstr(arithmetic, tmp)) { - arithmetic = rz_str_append(arithmetic, tmp); - } else if (!arithmetic) { - arithmetic = rz_str_append(arithmetic, tmp); - } - free(tmp); - } - } - } - } - } - } - continue_error: - FREE_ROP; - rz_list_free(constants); - } - free(op_result); - free(op_result_r); - return arithmetic; -} - -static int rop_classify_nops(RzCore *core, RzList /**/ *ropList) { - char *esil_str; - int changes = 1; - RzListIter *iter_r; - const bool romem = rz_config_get_i(core->config, "esil.romem"); - const bool stats = rz_config_get_i(core->config, "esil.stats"); - - if (!romem || !stats) { - // eprintf ("Error: esil.romem and esil.stats must be set TRUE\n"); - return -2; - } - - rz_list_foreach (ropList, iter_r, esil_str) { - fillRegisterValues(core); - - // rz_cons_printf ("Emulating nop:%s\n", esil_str); - cmd_analysis_esil(core, esil_str); - char *out = sdb_querys(core->analysis->esil->stats, NULL, 0, "*"); - // rz_cons_println (out); - if (out) { - free(out); - return 0; - } - // directly say NOP - continue; - } - - return changes; -} - -static void rop_classify(RzCore *core, Sdb *db, RzList /**/ *ropList, const char *key, unsigned int size) { - int nop = 0; - rop_classify_nops(core, ropList); - char *mov, *ct, *arithm, *arithm_ct, *str; - Sdb *db_nop = sdb_ns(db, "nop", true); - Sdb *db_mov = sdb_ns(db, "mov", true); - Sdb *db_ct = sdb_ns(db, "const", true); - Sdb *db_aritm = sdb_ns(db, "arithm", true); - Sdb *db_aritm_ct = sdb_ns(db, "arithm_ct", true); - - if (!db_nop || !db_mov || !db_ct || !db_aritm || !db_aritm_ct) { - RZ_LOG_ERROR("core: could not create SDB 'rop' sub-namespaces\n"); - return; - } - nop = rop_classify_nops(core, ropList); - mov = rop_classify_mov(core, ropList); - ct = rop_classify_constant(core, ropList); - arithm = rop_classify_arithmetic(core, ropList); - arithm_ct = rop_classify_arithmetic_const(core, ropList); - str = rz_str_newf("0x%u", size); - - if (nop == 1) { - char *str_nop = rz_str_newf("%s NOP", str); - sdb_set(db_nop, key, str_nop); - free(str_nop); - } else { - if (mov) { - char *str_mov = rz_str_newf("%s MOV { %s }", str, mov); - sdb_set(db_mov, key, str_mov); - free(str_mov); - free(mov); - } - if (ct) { - char *str_ct = rz_str_newf("%s LOAD_CONST { %s }", str, ct); - sdb_set(db_ct, key, str_ct); - free(str_ct); - free(ct); - } - if (arithm) { - char *str_arithm = rz_str_newf("%s ARITHMETIC { %s }", str, arithm); - sdb_set(db_aritm, key, str_arithm); - free(str_arithm); - free(arithm); - } - if (arithm_ct) { - char *str_arithm_ct = rz_str_newf("%s ARITHMETIC_CONST { %s }", str, arithm_ct); - sdb_set(db_aritm_ct, key, str_arithm_ct); - free(str_arithm_ct); - free(arithm_ct); - } - } - - free(str); -} - static void skip_whitespace(const char *str, int *idx) { while (str[*idx] == ' ' || str[*idx] == '\t' || str[*idx] == '\n' || str[*idx] == '\r') { (*idx)++; diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index 0b66e01bd26..38454b5d69a 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -1408,7 +1408,7 @@ static const RzCmdDescArg cmd_detail_gadget_args[] = { .name = "Gadget address", .type = RZ_CMD_ARG_TYPE_STRING, .flags = RZ_CMD_ARG_FLAG_LAST, - .optional = false, + .optional = true, }, { 0 }, diff --git a/librz/core/cmd_descs/cmd_search.yaml b/librz/core/cmd_descs/cmd_search.yaml index 297be4085ca..9d964e866ef 100644 --- a/librz/core/cmd_descs/cmd_search.yaml +++ b/librz/core/cmd_descs/cmd_search.yaml @@ -62,4 +62,4 @@ commands: args: - name: Gadget address type: RZ_CMD_ARG_TYPE_STRING - optional: false \ No newline at end of file + optional: true \ No newline at end of file diff --git a/librz/core/rop.c b/librz/core/rop.c index edc1fb87450..47c7787587c 100644 --- a/librz/core/rop.c +++ b/librz/core/rop.c @@ -346,7 +346,6 @@ void rz_rop_gadget_info_add_dependency(RzCore *core, RzRopGadgetInfo *gadget_inf } switch (evt->type) { case RZ_IL_EVENT_MEM_READ: - // Used for reading this address const RzILEventMemRead *mem_read = &evt->data.mem_read; reg_info->is_mem_read = true; reg_info->is_mem_write = false; @@ -494,7 +493,7 @@ static void fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadg } } break; case RZ_IL_EVENT_PC_WRITE: { - RzILEventPCWrite *pc_write = &event->data.pc_write; + // RzILEventPCWrite *pc_write = &event->data.pc_write; if (!gadget_info->is_pc_write) { gadget_info->is_pc_write = true; } @@ -645,16 +644,6 @@ static void print_rop(RzCore *core, RzList /**/ *hitlist, RzCmdS if (db && hit) { rz_cons_printf("Gadget size: %d\n", (int)size); // rop_classify(core, db, ropList, key, size); - if (rz_list_empty(hitlist)) { - return; - } - const ut64 addr_start = ((RzCoreAsmHit *)rz_list_first(hitlist))->addr; - RzRopGadgetInfo *rop_gadget_info = rz_rop_gadget_info_new(addr_start); - rz_list_foreach (hitlist, iter, hit) { - analyze_gadget(core, hit, rop_gadget_info); - } - print_rop_gadget_info(core, rop_gadget_info); - rz_rop_gadget_info_free(rop_gadget_info); } rz_cons_newline(); break; @@ -827,7 +816,32 @@ static RzList /**/ *construct_rop_gadget(RzCore *core, ut64 addr return hitlist; } -RZ_API int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzCmdStateOutput *state) { +static void handle_rop_request_type(RzCore *core, const ut8 subchain, RzRopRequestMask type, RzList *hitlist, RzCmdStateOutput *state) { + if (type & RZ_ROP_GADGET_PRINT) { + if (subchain) { + do { + print_rop(core, hitlist, state); + hitlist->head = hitlist->head->next; + } while (hitlist->head->next); + } else { + print_rop(core, hitlist, state); + } + } + if (type & RZ_ROP_GADGET_DETAIL) { + RzListIter *iter; + RzCoreAsmHit *hit; + + const ut64 addr_start = ((RzCoreAsmHit *)rz_list_first(hitlist))->addr; + RzRopGadgetInfo *rop_gadget_info = rz_rop_gadget_info_new(addr_start); + rz_list_foreach (hitlist, iter, hit) { + analyze_gadget(core, hit, rop_gadget_info); + } + print_rop_gadget_info(core, rop_gadget_info); + rz_rop_gadget_info_free(rop_gadget_info); + } +} + +RZ_API int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzRopRequestMask type, RzCmdStateOutput *state) { const ut8 crop = rz_config_get_i(core->config, "rop.conditional"); // decide if cjmp, cret, and ccall should be used too for the gadget-search const ut8 subchain = rz_config_get_i(core->config, "rop.subchains"); const ut8 max_instr = rz_config_get_i(core->config, "rop.len"); @@ -1073,14 +1087,7 @@ RZ_API int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzC free(headAddr); } - if (subchain) { - do { - print_rop(core, hitlist, state); - hitlist->head = hitlist->head->next; - } while (hitlist->head->next); - } else { - print_rop(core, hitlist, state); - } + handle_rop_request_type(core, subchain, type, hitlist, state); rz_list_free(hitlist); if (max_count > 0) { max_count--; @@ -1138,7 +1145,7 @@ RZ_API RzCmdStatus rz_core_rop_gadget_info(RzCore *core, const char *input, RzCm Sdb *gadgetSdb = sdb_ns(core->sdb, "gadget_sdb", false); if (!gadgetSdb) { - rz_core_search_rop(core, input, 0, state); + rz_core_search_rop(core, input, 0, RZ_ROP_GADGET_PRINT, state); return RZ_CMD_STATUS_OK; } void **iter; diff --git a/librz/include/rz_rop.h b/librz/include/rz_rop.h index 6d3af7d2de0..2344df22739 100644 --- a/librz/include/rz_rop.h +++ b/librz/include/rz_rop.h @@ -48,6 +48,12 @@ typedef enum { NUM_ARGS } RzRopArgType; +typedef enum { + RZ_ROP_GADGET_PRINT = 1 << 0, + RZ_ROP_GADGET_DETAIL = 1 << 1, + RZ_ROP_GADGET_ALL = RZ_ROP_GADGET_PRINT | RZ_ROP_GADGET_DETAIL +} RzRopRequestMask; + typedef struct rz_rop_endlist_pair_t { int instr_offset; int delay_size; @@ -59,7 +65,7 @@ typedef struct rz_rop_constraint_t { } RzRopConstraint; // Command APIs -RZ_API int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzCmdStateOutput *state); +RZ_API int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzRopRequestMask type, RzCmdStateOutput *state); RZ_API RzCmdStatus rz_core_rop_gadget_info(RzCore *core, const char *input, RzCmdStateOutput *state); RZ_API bool analyze_constraint(RzCore *core, char *str, RzRopConstraint *rop_constraint); diff --git a/test/db/cmd/cmd_rop b/test/db/cmd/cmd_rop index 0b21abc4fa4..cc94c3a025d 100644 --- a/test/db/cmd/cmd_rop +++ b/test/db/cmd/cmd_rop @@ -6,6 +6,12 @@ e search.maxhits=1 EOF EXPECT=< Date: Fri, 28 Jun 2024 06:23:57 -0400 Subject: [PATCH 12/30] Fix regression and add doc --- librz/arch/analysis.c | 9 + librz/core/cmd/cmd_search_rop.c | 12 ++ librz/core/rop.c | 74 ++++++-- librz/include/rz_rop.h | 76 +++++--- test/db/analysis/avr | 1 - test/db/cmd/cmd_rop | 303 ++++++++++++++++---------------- test/db/cmd/cmd_search | 16 +- 7 files changed, 288 insertions(+), 203 deletions(-) diff --git a/librz/arch/analysis.c b/librz/arch/analysis.c index 8c3d388170e..61d3b63acac 100644 --- a/librz/arch/analysis.c +++ b/librz/arch/analysis.c @@ -240,6 +240,15 @@ RZ_API char *rz_analysis_get_reg_profile(RzAnalysis *analysis) { : NULL; } +/** + * \brief Check if a register is in the analysis profile. + * \param analysis Pointer to the RzAnalysis object. + * \param str The register name to check. + * \return true if the register name is found, false otherwise. + * + * This function checks if the given register name is present + * in the register profile of the given RzAnalysis. + */ RZ_API bool rz_analysis_is_reg_in_profile(RzAnalysis *analysis, const char *str) { rz_return_val_if_fail(analysis, false); diff --git a/librz/core/cmd/cmd_search_rop.c b/librz/core/cmd/cmd_search_rop.c index 09d8d1a18c8..460bda88d48 100644 --- a/librz/core/cmd/cmd_search_rop.c +++ b/librz/core/cmd/cmd_search_rop.c @@ -335,6 +335,18 @@ static bool parse_reg_op_reg(RzCore *core, char *str, RzRopConstraint *rop_const return true; } +/** + * \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. + * \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 function returns true if any of these parsing methods succeed. + */ RZ_API bool analyze_constraint(RzCore *core, char *str, RzRopConstraint *rop_constraint) { rz_return_val_if_fail(core, NULL); return parse_reg_to_const(core, str, rop_constraint) || diff --git a/librz/core/rop.c b/librz/core/rop.c index 47c7787587c..dbd5602be48 100644 --- a/librz/core/rop.c +++ b/librz/core/rop.c @@ -841,7 +841,21 @@ static void handle_rop_request_type(RzCore *core, const ut8 subchain, RzRopReque } } -RZ_API int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzRopRequestMask type, RzCmdStateOutput *state) { +/** + * \brief Search for ROP gadgets. + * \param core Pointer to the RzCore object. + * \param greparg Grep argument string for filtering gadgets. + * \param regexp Boolean indicating if the grep argument is a regex. + * \param mask ROP request type (RzRopRequestMask). + * \param state Pointer to the command state output (RzCmdStateOutput). + * \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 + * filters results based on the grep argument and request mask. Outputs results to + * the provided state object. + */ +RZ_API int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzRopRequestMask mask, RzCmdStateOutput *state) { const ut8 crop = rz_config_get_i(core->config, "rop.conditional"); // decide if cjmp, cret, and ccall should be used too for the gadget-search const ut8 subchain = rz_config_get_i(core->config, "rop.subchains"); const ut8 max_instr = rz_config_get_i(core->config, "rop.len"); @@ -1018,6 +1032,23 @@ RZ_API int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzR if (rz_cons_is_breaked()) { break; } + if (i > next) { + // We've exhausted the first end-gadget section, + // move to the next one. + free(end_gadget); + if (rz_list_get_n(end_list, 0)) { + prev = i; + end_gadget = (RzRopEndListPair *)rz_list_pop(end_list); + next = end_gadget->instr_offset; + i = next - ropdepth; + if (i < 0) { + i = 0; + } + } else { + end_gadget = NULL; + break; + } + } if (i >= end) { // read by chunk of 4k rz_io_read_at(core->io, from + i, buf + i, RZ_MIN((delta - i), 4096)); @@ -1087,7 +1118,7 @@ RZ_API int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzR free(headAddr); } - handle_rop_request_type(core, subchain, type, hitlist, state); + handle_rop_request_type(core, subchain, mask, hitlist, state); rz_list_free(hitlist); if (max_count > 0) { max_count--; @@ -1101,23 +1132,6 @@ RZ_API int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzR } rz_asm_op_free(asmop); asmop = NULL; - if (i >= next) { - // We've exhausted the first end-gadget section, - // move to the next one. - free(end_gadget); - if (rz_list_get_n(end_list, 0)) { - prev = i; - end_gadget = (RzRopEndListPair *)rz_list_pop(end_list); - next = end_gadget->instr_offset; - i = next - ropdepth; - if (i < 0) { - i = 0; - } - } else { - end_gadget = NULL; - break; - } - } } free(end_gadget); } @@ -1141,6 +1155,16 @@ RZ_API int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzR return result; } +/** + * \brief Display ROP gadget information. + * \param core Pointer to the RzCore object. + * \param input Input string for ROP search. + * \param state Pointer to the command state output. + * \return RZ_CMD_STATUS_OK on success. + * + * 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, const char *input, RzCmdStateOutput *state) { Sdb *gadgetSdb = sdb_ns(core->sdb, "gadget_sdb", false); @@ -1182,6 +1206,12 @@ RZ_API RzCmdStatus rz_core_rop_gadget_info(RzCore *core, const char *input, RzCm return RZ_CMD_STATUS_OK; } +/** + * \brief Free an RzRopConstraint object. + * \param data Pointer to the RzRopConstraint object to free. + * + * Frees the memory allocated for an RzRopConstraint object. + */ RZ_API void rz_rop_constraint_free(RZ_NULLABLE void *data) { RzRopConstraint *constraint = data; if (!constraint) { @@ -1195,6 +1225,12 @@ RZ_API void rz_rop_constraint_free(RZ_NULLABLE void *data) { free(constraint); } +/** + * \brief Create a new list of RzRopConstraint objects. + * \return Pointer to the newly created list. + * + * Creates a new RzList for RzRopConstraint object. + */ RZ_API RzList /**/ *rz_rop_constraint_list_new(void) { RzList *list = rz_list_new(); if (list) { diff --git a/librz/include/rz_rop.h b/librz/include/rz_rop.h index 2344df22739..0861f81b73a 100644 --- a/librz/include/rz_rop.h +++ b/librz/include/rz_rop.h @@ -4,41 +4,56 @@ #ifndef RZ_ROP_H #define RZ_ROP_H -#endif // RZ_ROP_H - #include +/** + * \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. + */ + +/** + * \brief Information about a register. + */ typedef struct rz_reg_info_t { char *name; - bool is_mem_read; - bool is_pc_write; - bool is_var_read; - bool is_var_write; - bool is_mem_write; + 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; } RzRegInfo; +/** + * \brief Information about a ROP gadget. + */ typedef struct rz_rop_gadget_info_t { - ut64 address; - ut64 stack_change; - ut64 curr_pc_val; - bool is_pc_write; - bool is_syscall; - RzPVector /**/ *modified_registers; - RzList /**/ *dependencies; + ut64 address; ///< Gadget address. + ut64 stack_change; ///< Stack change. + 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. } RzRopGadgetInfo; +/** + * \brief Types of IL instructions for ROP constraints. + */ typedef enum rzil_instr_type { - // Register to register MOV_CONST, ///< reg <- const MOV_REG, ///< reg <- reg MOV_OP_CONST, ///< reg <- reg OP const MOV_OP_REG, ///< reg <- reg OP reg - // Call functions - SYSCALL, + SYSCALL, ///< syscall } RzILInstructionType; +/** + * \brief Argument types for ROP constraints. + */ typedef enum { SRC_REG, DST_REG, @@ -48,20 +63,29 @@ typedef enum { NUM_ARGS } RzRopArgType; +/** + * \brief ROP request mask for filtering gadgets. + */ typedef enum { - RZ_ROP_GADGET_PRINT = 1 << 0, - RZ_ROP_GADGET_DETAIL = 1 << 1, - RZ_ROP_GADGET_ALL = RZ_ROP_GADGET_PRINT | RZ_ROP_GADGET_DETAIL + RZ_ROP_GADGET_PRINT = 1 << 0, ///< Print ROP gadgets. + RZ_ROP_GADGET_DETAIL = 1 << 1, ///< Detailed ROP gadgets. + RZ_ROP_GADGET_ALL = RZ_ROP_GADGET_PRINT | RZ_ROP_GADGET_DETAIL ///< All ROP gadgets requests. } RzRopRequestMask; +/** + * \brief Pair representing an end gadget with instruction offset and delay size. + */ typedef struct rz_rop_endlist_pair_t { - int instr_offset; - int delay_size; + int instr_offset; ///< Instruction offset. + int delay_size; ///< Delay size. } RzRopEndListPair; +/** + * \brief Structure representing a ROP constraint. + */ typedef struct rz_rop_constraint_t { - RzILInstructionType type; - char *args[NUM_ARGS]; + RzILInstructionType type; ///< IL instruction type. + char *args[NUM_ARGS]; ///< Arguments. } RzRopConstraint; // Command APIs @@ -71,4 +95,6 @@ RZ_API bool analyze_constraint(RzCore *core, char *str, RzRopConstraint *rop_con // ROP Constraint APIs RZ_API void rz_rop_constraint_free(RZ_NULLABLE void *data); -RZ_API RzList /**/ *rz_rop_constraint_list_new(void); \ No newline at end of file +RZ_API RzList /**/ *rz_rop_constraint_list_new(void); + +#endif // RZ_ROP_H diff --git a/test/db/analysis/avr b/test/db/analysis/avr index c9655920498..e5948a1ece0 100644 --- a/test/db/analysis/avr +++ b/test/db/analysis/avr @@ -542,7 +542,6 @@ NAME=Search rop gadgets for in command FILE=bins/firmware/arduino_avr.bin ARGS=-a avr CMDS=< Date: Fri, 28 Jun 2024 06:28:44 -0400 Subject: [PATCH 13/30] fix sanity --- librz/core/rop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/librz/core/rop.c b/librz/core/rop.c index dbd5602be48..7478262c9b4 100644 --- a/librz/core/rop.c +++ b/librz/core/rop.c @@ -346,7 +346,7 @@ void rz_rop_gadget_info_add_dependency(RzCore *core, RzRopGadgetInfo *gadget_inf } switch (evt->type) { case RZ_IL_EVENT_MEM_READ: - const RzILEventMemRead *mem_read = &evt->data.mem_read; + 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; From d315965c87369a7f7b596563208826254cc8907e Mon Sep 17 00:00:00 2001 From: Giridhar Prasath R Date: Fri, 28 Jun 2024 06:44:21 -0400 Subject: [PATCH 14/30] Fix sanity switch/case --- librz/core/rop.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/librz/core/rop.c b/librz/core/rop.c index 7478262c9b4..36ab0f71bd7 100644 --- a/librz/core/rop.c +++ b/librz/core/rop.c @@ -345,26 +345,28 @@ void rz_rop_gadget_info_add_dependency(RzCore *core, RzRopGadgetInfo *gadget_inf return; } switch (evt->type) { - case RZ_IL_EVENT_MEM_READ: - RzILEventMemRead *mem_read = &evt->data.mem_read; + 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->new_val = rz_bv_to_ut64(mem_read->address); break; - case RZ_IL_EVENT_MEM_WRITE: + } + case RZ_IL_EVENT_MEM_WRITE: { reg_info->is_mem_write = true; reg_info->is_mem_read = false; reg_info->is_var_write = false; - RzILEventMemWrite *mem_write = &evt->data.mem_write; + 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); break; - case RZ_IL_EVENT_VAR_WRITE: + } + case RZ_IL_EVENT_VAR_WRITE: { reg_info->is_var_write = true; reg_info->is_mem_read = false; reg_info->is_mem_write = false; - RzILEventVarWrite *var_write = &evt->data.var_write; + const RzILEventVarWrite *var_write = &evt->data.var_write; RzBitVector *init_val = rz_il_value_to_bv(var_write->old_value); RzBitVector *new_val = rz_il_value_to_bv(var_write->new_value); if (!init_val || !new_val) { @@ -380,6 +382,7 @@ void rz_rop_gadget_info_add_dependency(RzCore *core, RzRopGadgetInfo *gadget_inf rz_bv_free(init_val); rz_bv_free(new_val); break; + } default: break; } From c2b19f02f5ada4990e4bc09e3a7287a7e77bed10 Mon Sep 17 00:00:00 2001 From: Giridhar Prasath R Date: Fri, 28 Jun 2024 07:04:54 -0400 Subject: [PATCH 15/30] Tiny rop gadget print fix --- librz/core/rop.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/librz/core/rop.c b/librz/core/rop.c index 36ab0f71bd7..b62d8315d58 100644 --- a/librz/core/rop.c +++ b/librz/core/rop.c @@ -538,7 +538,7 @@ static void analyze_gadget(RzCore *core, RzCoreAsmHit /**/ *hit, } void print_rop_gadget_info(RzCore *core, RzRopGadgetInfo *gadget_info) { - rz_cons_printf("Gadget 0x%" PFMT64x "\n", gadget_info->address); + rz_cons_printf("\nGadget 0x%" PFMT64x "\n", gadget_info->address); rz_cons_printf("Stack change: 0x%" PFMT64x "\n", gadget_info->stack_change); rz_cons_printf("Changed registers: "); @@ -550,9 +550,8 @@ void print_rop_gadget_info(RzCore *core, RzRopGadgetInfo *gadget_info) { rz_cons_printf("%s ", reg_info->name); } } - rz_cons_printf("\n"); - rz_cons_printf("Register dependencies:\n"); + rz_cons_printf("\nRegister 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)) { From 4b267430ef7dd42fa60eb9ee449c3793c6dce174 Mon Sep 17 00:00:00 2001 From: Giridhar Prasath R Date: Fri, 28 Jun 2024 20:27:55 -0400 Subject: [PATCH 16/30] fix Linter comments --- librz/core/cmd/cmd_search.c | 2 +- librz/core/cmd/cmd_search_rop.c | 4 ++-- librz/core/rop.c | 40 +++++++++++++++++++-------------- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index 3ab1daf9c40..dc73f683516 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -229,7 +229,7 @@ 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); + RzList /**/ *constraints = rop_constraint_list_parse(core, argc, argv); if (!constraints) { return RZ_CMD_STATUS_ERROR; } diff --git a/librz/core/cmd/cmd_search_rop.c b/librz/core/cmd/cmd_search_rop.c index 460bda88d48..b1eb8602fa1 100644 --- a/librz/core/cmd/cmd_search_rop.c +++ b/librz/core/cmd/cmd_search_rop.c @@ -152,7 +152,7 @@ static bool parse_reg_to_reg(RzCore *core, char *str, RzRopConstraint *rop_const return true; } -static bool parse_il_op(RzList *args, const char *str, int *idx) { +static bool parse_il_op(RzList /**/ *args, const char *str, int *idx) { RzILOpPureCode res = RZ_IL_OP_VAR; skip_whitespace(str, idx); @@ -379,7 +379,7 @@ static RzRopConstraint *rop_constraint_parse_args(RzCore *core, char *token) { return rop_constraint; } -static RzList *rop_constraint_list_parse(RzCore *core, int argc, const char **argv) { +static RzList /**/ *rop_constraint_list_parse(RzCore *core, int argc, const char **argv) { RzList *constr_list = rz_rop_constraint_list_new(); for (int i = 1; i < argc; i++) { RzList *l = rz_str_split_duplist_n(argv[i], ",", 1, false); diff --git a/librz/core/rop.c b/librz/core/rop.c index b62d8315d58..8742d41ca76 100644 --- a/librz/core/rop.c +++ b/librz/core/rop.c @@ -39,7 +39,7 @@ static bool is_end_gadget(const RzAnalysisOp *aop, const ut8 crop) { return false; } -static int rz_rop_process_asm_op(RzCore *core, RzCoreAsmHit *hit, RzAsmOp *asmop, RzAnalysisOp *aop, unsigned int *size, char **asmop_str, char **asmop_hex_str) { +static int 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) { ut8 *buf = malloc(hit->len); if (!buf) { return -1; @@ -68,7 +68,8 @@ static int rz_rop_process_asm_op(RzCore *core, RzCoreAsmHit *hit, RzAsmOp *asmop return 0; } -static int rz_rop_print_table_mode(RzCore *core, RzCoreAsmHit *hit, RzList *hitlist, RzAsmOp *asmop, unsigned int *size, char **asmop_str, char **asmop_hex_str) { +static int rz_rop_print_table_mode(const RzCore *core, const RzCoreAsmHit *hit, const RzList /**/ *hitlist, + RzAsmOp *asmop, unsigned int *size, char **asmop_str, char **asmop_hex_str) { RzAnalysisOp aop = RZ_EMPTY; if (rz_rop_process_asm_op(core, hit, asmop, &aop, size, asmop_str, asmop_hex_str) != 0) { return -1; @@ -81,7 +82,8 @@ static int rz_rop_print_table_mode(RzCore *core, RzCoreAsmHit *hit, RzList *hitl return 0; } -static int rz_rop_print_quiet_mode(RzCore *core, RzCoreAsmHit *hit, RzList *ropList, RzAsmOp *asmop, unsigned int *size, bool esil, bool colorize) { +static int rz_rop_print_quiet_mode(const RzCore *core, const RzCoreAsmHit *hit, RzList /**/ *ropList, + RzAsmOp *asmop, unsigned int *size, bool esil, bool colorize) { RzAnalysisOp aop = RZ_EMPTY; if (rz_rop_process_asm_op(core, hit, asmop, &aop, size, NULL, NULL) != 0) { return -1; @@ -107,7 +109,8 @@ static int rz_rop_print_quiet_mode(RzCore *core, RzCoreAsmHit *hit, RzList *ropL return 0; } -static int rz_rop_print_standard_mode(RzCore *core, RzCoreAsmHit *hit, RzList *ropList, RzAsmOp *asmop, unsigned int *size, bool rop_comments, bool colorize) { +static int rz_rop_print_standard_mode(const RzCore *core, const RzCoreAsmHit *hit, RzList /**/ *ropList, RzAsmOp *asmop, + unsigned int *size, const bool rop_comments, const bool colorize) { RzAnalysisOp aop = RZ_EMPTY; if (rz_rop_process_asm_op(core, hit, asmop, &aop, size, NULL, NULL) != 0) { return -1; @@ -146,7 +149,8 @@ static int rz_rop_print_standard_mode(RzCore *core, RzCoreAsmHit *hit, RzList *r return 0; } -static int rz_rop_print_json_mode(RzCore *core, RzCoreAsmHit *hit, RzList *ropList, RzCmdStateOutput *state, RzAsmOp *asmop, unsigned int *size) { +static int rz_rop_print_json_mode(const RzCore *core, const RzCoreAsmHit *hit, RzList /**/ *ropList, + const RzCmdStateOutput *state, RzAsmOp *asmop, unsigned int *size) { RzAnalysisOp aop = RZ_EMPTY; if (rz_rop_process_asm_op(core, hit, asmop, &aop, size, NULL, NULL) != 0) { @@ -177,7 +181,7 @@ void rz_reg_info_free(RzRegInfo *reg_info) { free(reg_info); } -RzRegInfo *rz_reg_info_new(RzCore *core, RzILEvent *evt, ut64 init_val, ut64 new_val) { +RzRegInfo *rz_reg_info_new(const RzCore *core, const RzILEvent *evt, const ut64 init_val, const ut64 new_val) { RzRegInfo *reg_info = RZ_NEW0(RzRegInfo); const char *name = NULL; if (evt->type == RZ_IL_EVENT_VAR_READ) { @@ -213,7 +217,7 @@ RzRegInfo *rz_reg_info_new(RzCore *core, RzILEvent *evt, ut64 init_val, ut64 new return reg_info; } -RzRopGadgetInfo *rz_rop_gadget_info_new(ut64 address) { +RzRopGadgetInfo *rz_rop_gadget_info_new(const ut64 address) { RzRopGadgetInfo *gadget_info = RZ_NEW0(RzRopGadgetInfo); if (!gadget_info) { return NULL; @@ -237,7 +241,7 @@ void rz_rop_gadget_info_free(RzRopGadgetInfo *gadget_info) { free(gadget_info); } -void rz_rop_gadget_info_add_register(RzRopGadgetInfo *gadget_info, RzRegInfo *reg_info, bool is_dependency) { +void rz_rop_gadget_info_add_register(RzRopGadgetInfo *gadget_info, RzRegInfo *reg_info, const bool is_dependency) { if (!gadget_info || !reg_info) { return; } @@ -301,7 +305,7 @@ RzRegInfo *rz_reg_info_dup(RzRegInfo *src) { return dup; } -bool is_stack_pointer(RzCore *core, const char *name) { +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; @@ -318,7 +322,7 @@ bool is_stack_pointer(RzCore *core, const char *name) { return reg_item->name; } -bool is_base_pointer(RzCore *core, const char *name) { +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; @@ -335,7 +339,7 @@ bool is_base_pointer(RzCore *core, const char *name) { return reg_item->name; } -void rz_rop_gadget_info_add_dependency(RzCore *core, RzRopGadgetInfo *gadget_info, RzILEvent *evt, RzRegInfo *reg_info) { +void rz_rop_gadget_info_add_dependency(const RzCore *core, RzRopGadgetInfo *gadget_info, const RzILEvent *evt, RzRegInfo *reg_info) { if (!gadget_info || !reg_info) { return; } @@ -389,7 +393,8 @@ void rz_rop_gadget_info_add_dependency(RzCore *core, RzRopGadgetInfo *gadget_inf rz_list_append(gadget_info->dependencies, reg_info_dup); } -static void fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadget_info, RzILEvent *curr_event, RzILEvent *event, RzPVector *vec, bool is_dependency) { +static void fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadget_info, const RzILEvent *curr_event, + RzILEvent *event, RzPVector /**/ *vec, const bool is_dependency) { if (!gadget_info) { return; } @@ -506,7 +511,7 @@ static void fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadg } } -static void analyze_gadget(RzCore *core, RzCoreAsmHit /**/ *hit, RzRopGadgetInfo *rop_gadget_info) { +static void analyze_gadget(RzCore *core, const RzCoreAsmHit *hit, RzRopGadgetInfo *rop_gadget_info) { if (!core->analysis) { return; } @@ -537,7 +542,7 @@ static void analyze_gadget(RzCore *core, RzCoreAsmHit /**/ *hit, rz_core_seek(core, old_addr, true); } -void print_rop_gadget_info(RzCore *core, RzRopGadgetInfo *gadget_info) { +static void print_rop_gadget_info(const RzCore *core, const RzRopGadgetInfo *gadget_info) { rz_cons_printf("\nGadget 0x%" PFMT64x "\n", gadget_info->address); rz_cons_printf("Stack change: 0x%" PFMT64x "\n", gadget_info->stack_change); @@ -566,7 +571,7 @@ void print_rop_gadget_info(RzCore *core, RzRopGadgetInfo *gadget_info) { } } } -static void print_rop(RzCore *core, RzList /**/ *hitlist, RzCmdStateOutput *state) { +static void print_rop(const RzCore *core, const RzList /**/ *hitlist, RzCmdStateOutput *state) { RzCoreAsmHit *hit = NULL; RzListIter *iter; unsigned int size = 0; @@ -818,7 +823,8 @@ static RzList /**/ *construct_rop_gadget(RzCore *core, ut64 addr return hitlist; } -static void handle_rop_request_type(RzCore *core, const ut8 subchain, RzRopRequestMask type, RzList *hitlist, RzCmdStateOutput *state) { +static void handle_rop_request_type(RzCore *core, const ut8 subchain, const RzRopRequestMask type, + RzList /**/ *hitlist, RzCmdStateOutput *state) { if (type & RZ_ROP_GADGET_PRINT) { if (subchain) { do { @@ -857,7 +863,7 @@ static void handle_rop_request_type(RzCore *core, const ut8 subchain, RzRopReque * filters results based on the grep argument and request mask. Outputs results to * the provided state object. */ -RZ_API int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzRopRequestMask mask, RzCmdStateOutput *state) { +RZ_API int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, const RzRopRequestMask mask, RzCmdStateOutput *state) { const ut8 crop = rz_config_get_i(core->config, "rop.conditional"); // decide if cjmp, cret, and ccall should be used too for the gadget-search const ut8 subchain = rz_config_get_i(core->config, "rop.subchains"); const ut8 max_instr = rz_config_get_i(core->config, "rop.len"); From 74a8ccbf4c3c1cfd75869a0544bc4a8807197ee2 Mon Sep 17 00:00:00 2001 From: Giridhar Prasath R Date: Wed, 3 Jul 2024 21:57:02 -0400 Subject: [PATCH 17/30] Initial refactoring --- librz/arch/analysis.c | 5 +- librz/core/cconfig.c | 3 +- librz/core/cmd/cmd_search.c | 17 +- librz/core/cmd/cmd_search_rop.c | 95 ++-- librz/core/rop.c | 919 +++++++++++++++----------------- librz/include/rz_analysis.h | 2 + librz/include/rz_rop.h | 56 +- test/unit/test_rop_constraint.c | 18 +- 8 files changed, 575 insertions(+), 540 deletions(-) diff --git a/librz/arch/analysis.c b/librz/arch/analysis.c index 61d3b63acac..990497c256c 100644 --- a/librz/arch/analysis.c +++ b/librz/arch/analysis.c @@ -8,6 +8,7 @@ #include #include #include +#include /** * \brief Returns the default size byte width of memory access operations. @@ -129,6 +130,7 @@ 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 = NULL; analysis->global_var_tree = NULL; analysis->il_vm = NULL; analysis->hash = rz_hash_new(); @@ -185,6 +187,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); rz_list_free(a->plugins); rz_analysis_debug_info_free(a->debug_info); free(a); @@ -257,7 +260,7 @@ RZ_API bool rz_analysis_is_reg_in_profile(RzAnalysis *analysis, const char *str) return false; } - if (strstr(reg_prof, str) != NULL) { + if (strstr(reg_prof, str)) { free(reg_prof); return true; } diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index 772c8a60d3b..cdb7d893fe4 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -3735,8 +3735,7 @@ RZ_API int rz_core_config_init(RzCore *core) { /* rop */ SETI("rop.len", 5, "Maximum ROP gadget length"); - SETBPREF("rop.sdb", "false", "Cache results in sdb (experimental)"); - SETBPREF("rop.db", "true", "Categorize rop gadgets in sdb"); + 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"); diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index dc73f683516..f17b6005e2a 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -225,7 +225,8 @@ RZ_IPI RzCmdStatus rz_cmd_info_gadget_handler(RzCore *core, int argc, const char return RZ_CMD_STATUS_ERROR; } - return rz_core_rop_gadget_info(core, input, state); + RzRopSearchContext *context = rz_core_rop_search_context_new(core, argv[1], 0, RZ_ROP_GADGET_PRINT, state); + return rz_core_rop_gadget_info(core, context); } RZ_IPI RzCmdStatus rz_cmd_query_gadget_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { @@ -238,9 +239,10 @@ RZ_IPI RzCmdStatus rz_cmd_query_gadget_handler(RzCore *core, int argc, const cha return RZ_CMD_STATUS_INVALID; } - rz_core_search_rop(core, argv[1], 0, RZ_ROP_GADGET_DETAIL, state); + RzRopSearchContext *context = rz_core_rop_search_context_new(core, argv[1], 1, RZ_ROP_GADGET_PRINT, state); + const RzCmdStatus cmd_status = rz_core_rop_search(core, context); rz_list_free(constraints); - return RZ_CMD_STATUS_OK; + return cmd_status; } RZ_IPI RzCmdStatus rz_cmd_search_gadget_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { @@ -248,15 +250,16 @@ RZ_IPI RzCmdStatus rz_cmd_search_gadget_handler(RzCore *core, int argc, const ch if (!input) { return RZ_CMD_STATUS_ERROR; } - rz_core_search_rop(core, argv[1], 1, RZ_ROP_GADGET_PRINT, state); - return RZ_CMD_STATUS_OK; + RzRopSearchContext *context = rz_core_rop_search_context_new(core, input, 1, RZ_ROP_GADGET_PRINT, state); + return rz_core_rop_search(core, context); } RZ_IPI RzCmdStatus rz_cmd_detail_gadget_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { const char *input = argc > 1 ? argv[1] : ""; - rz_core_search_rop(core, input, 1, RZ_ROP_GADGET_DETAIL, state); - return RZ_CMD_STATUS_OK; + RzRopSearchContext *context = rz_core_rop_search_context_new(core, input, 1, 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 b1eb8602fa1..2aacd8a0a92 100644 --- a/librz/core/cmd/cmd_search_rop.c +++ b/librz/core/cmd/cmd_search_rop.c @@ -8,18 +8,18 @@ #include "rz_types_base.h" #include "rz_rop.h" -static void skip_whitespace(const char *str, int *idx) { - while (str[*idx] == ' ' || str[*idx] == '\t' || str[*idx] == '\n' || str[*idx] == '\r') { - (*idx)++; +static void skip_whitespace(const char *str, ut64 *idx) { + while (IS_WHITECHAR(str[*idx])) { + (*idx)++; } } -static bool parse_eof(const char *str, int idx) { +static bool parse_eof(const char *str, ut64 idx) { skip_whitespace(str, &idx); return str[idx] == '\0'; } -static bool parse_il_equal(char *str, int *idx) { +static bool parse_il_equal(const char *str, ut64 *idx) { skip_whitespace(str, idx); if (*idx >= strlen(str)) { return false; @@ -31,9 +31,9 @@ static bool parse_il_equal(char *str, int *idx) { return false; } -static char *parse_register(RzCore *core, char *str, int *idx) { +static char *parse_register(const RzCore *core, const char *str, ut64 *idx) { char reg[256] = { 0 }; - int reg_idx = 0; + ut64 reg_idx = 0; skip_whitespace(str, idx); @@ -54,7 +54,8 @@ static char *parse_register(RzCore *core, char *str, int *idx) { return NULL; } -static bool parse_constant(const char *str, int *idx, unsigned long long *value) { +static bool parse_constant(const char *str, RZ_NONNULL ut64 *idx, unsigned long long *value) { + rz_return_val_if_fail(idx, false); int base = 10; int neg = 0; char num_str[256] = { 0 }; @@ -91,8 +92,8 @@ static bool parse_constant(const char *str, int *idx, unsigned long long *value) return true; } -static bool parse_reg_to_const(RzCore *core, char *str, RzRopConstraint *rop_constraint) { - int idx = 0; +static bool parse_reg_to_const(const RzCore *core, const char *str, RzRopConstraint *rop_constraint) { + ut64 idx = 0; char *dst_reg = parse_register(core, str, &idx); if (!dst_reg) { return false; @@ -118,13 +119,13 @@ static bool parse_reg_to_const(RzCore *core, char *str, RzRopConstraint *rop_con rop_constraint->args[DST_REG] = dst_reg; rop_constraint->args[SRC_REG] = NULL; char value_str[256]; - snprintf(value_str, sizeof(value_str), "%llu", const_value); + rz_strf(value_str, "%" PFMT64u, const_value); rop_constraint->args[SRC_CONST] = strdup(value_str); return true; } -static bool parse_reg_to_reg(RzCore *core, char *str, RzRopConstraint *rop_constraint) { - int idx = 0; +static bool parse_reg_to_reg(const RzCore *core, const char *str, RzRopConstraint *rop_constraint) { + ut64 idx = 0; char *dst_reg = parse_register(core, str, &idx); if (!dst_reg) { return false; @@ -152,7 +153,7 @@ static bool parse_reg_to_reg(RzCore *core, char *str, RzRopConstraint *rop_const return true; } -static bool parse_il_op(RzList /**/ *args, const char *str, int *idx) { +static bool parse_il_op(RzList /**/ *args, const char *str, ut64 *idx) { RzILOpPureCode res = RZ_IL_OP_VAR; skip_whitespace(str, idx); @@ -206,7 +207,7 @@ static bool parse_il_op(RzList /**/ *args, const char *str, in } } - RzILOpPureCode *op_ptr = malloc(sizeof(RzILOpPureCode)); + RzILOpPureCode *op_ptr = RZ_NEW0(RzILOpPureCode); if (!op_ptr) { return false; } @@ -216,8 +217,8 @@ static bool parse_il_op(RzList /**/ *args, const char *str, in return true; } -static bool parse_reg_op_const(RzCore *core, char *str, RzRopConstraint *rop_constraint) { - int idx = 0; +static bool parse_reg_op_const(const RzCore *core, const char *str, RzRopConstraint *rop_constraint) { + ut64 idx = 0; char *dst_reg = parse_register(core, str, &idx); if (!dst_reg) { return false; @@ -267,16 +268,49 @@ static bool parse_reg_op_const(RzCore *core, char *str, RzRopConstraint *rop_con } char op_str[16]; - snprintf(op_str, sizeof(op_str), "%s", rz_il_op_pure_code_stringify(*op)); + rz_strf(op_str, "%" PFMT64u, const_value); rop_constraint->args[OP] = strdup(op_str); - char value_str[256]; - snprintf(value_str, sizeof(value_str), "%llu", const_value); - rop_constraint->args[SRC_CONST] = strdup(value_str); + const char *value_str = rz_il_op_pure_code_stringify(*op); + rop_constraint->args[OP] = rz_str_dup(value_str); return true; } -static bool parse_reg_op_reg(RzCore *core, char *str, RzRopConstraint *rop_constraint) { - int idx = 0; +RZ_API RzRopSearchContext *rz_core_rop_search_context_new(const RzCore *core, const char *greparg, const int regexp, + const RzRopRequestMask mask, RzCmdStateOutput *state) { + RzRopSearchContext *context = RZ_NEW0(RzRopSearchContext); + if (!context) { + return NULL; + } + + context->greparg = greparg ? strdup(greparg) : NULL; + context->regexp = regexp; + context->mask = mask; + context->state = state; + context->max_instr = rz_config_get_i(core->config, "rop.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"); + + return context; +} + +RZ_API void rz_core_rop_search_context_free(RZ_NULLABLE RzRopSearchContext *context) { + if (!context) { + return; + } + + // Other elements have to be freed by the caller/callee. + free(context->greparg); + free(context); +} + +static bool parse_reg_op_reg(const RzCore *core, const char *str, RzRopConstraint *rop_constraint) { + ut64 idx = 0; char *dst_reg = parse_register(core, str, &idx); if (!dst_reg) { return false; @@ -294,7 +328,7 @@ static bool parse_reg_op_reg(RzCore *core, char *str, RzRopConstraint *rop_const } RzList *args = rz_list_new(); - if (!parse_il_op(args, str, &idx)) { + if (!args || !parse_il_op(args, str, &idx)) { free(dst_reg); free(src_reg1); rz_list_free(args); @@ -328,9 +362,8 @@ static bool parse_reg_op_reg(RzCore *core, char *str, RzRopConstraint *rop_const return false; } - char op_str[16]; - snprintf(op_str, sizeof(op_str), "%s", rz_il_op_pure_code_stringify(*op)); - rop_constraint->args[OP] = strdup(op_str); + const char *op_str = rz_il_op_pure_code_stringify(*op); + rop_constraint->args[OP] = rz_str_dup(op_str); rop_constraint->args[SRC_CONST] = dst_reg2; return true; } @@ -347,8 +380,8 @@ static bool parse_reg_op_reg(RzCore *core, char *str, RzRopConstraint *rop_const * * The function returns true if any of these parsing methods succeed. */ -RZ_API bool analyze_constraint(RzCore *core, char *str, RzRopConstraint *rop_constraint) { - rz_return_val_if_fail(core, NULL); +RZ_API bool rz_core_rop_analyze_constraint(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) || parse_reg_op_const(core, str, rop_constraint) || @@ -369,7 +402,7 @@ static RzRopConstraint *rop_constraint_parse_args(RzCore *core, char *token) { rz_list_free(l); return NULL; } - if (!analyze_constraint(core, token, rop_constraint)) { + if (!rz_core_rop_analyze_constraint(core, token, rop_constraint)) { free(rop_constraint); rz_list_free(l); return NULL; @@ -379,7 +412,7 @@ static RzRopConstraint *rop_constraint_parse_args(RzCore *core, char *token) { return rop_constraint; } -static RzList /**/ *rop_constraint_list_parse(RzCore *core, int argc, const char **argv) { +static RzList /**/ *rop_constraint_list_parse(RzCore *core, const int argc, const char **argv) { RzList *constr_list = rz_rop_constraint_list_new(); for (int i = 1; i < argc; i++) { RzList *l = rz_str_split_duplist_n(argv[i], ",", 1, false); diff --git a/librz/core/rop.c b/librz/core/rop.c index 8742d41ca76..1a968abfbae 100644 --- a/librz/core/rop.c +++ b/librz/core/rop.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2010-2021 z3phyr +// SPDX-FileCopyrightText: 2024 z3phyr // SPDX-License-Identifier: LGPL-3.0-only #include @@ -25,18 +25,23 @@ static bool is_end_gadget(const RzAnalysisOp *aop, const ut8 crop) { case RZ_ANALYSIS_OP_TYPE_JMP: case RZ_ANALYSIS_OP_TYPE_CALL: return true; + default: + return false; } - if (crop) { // if conditional jumps, calls and returns should be used for the gadget-search too - 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; - } + + 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: + return true; + default: + return false; } - return false; } static int 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) { @@ -48,7 +53,7 @@ static int rz_rop_process_asm_op(const RzCore *core, const RzCoreAsmHit *hit, Rz rz_asm_set_pc(core->rasm, hit->addr); rz_asm_disassemble(core->rasm, asmop, buf, hit->len); rz_analysis_op_init(aop); - rz_analysis_op(core->analysis, aop, hit->addr, buf, hit->len, RZ_ANALYSIS_OP_MASK_ESIL); + rz_analysis_op(core->analysis, aop, hit->addr, buf, hit->len, RZ_ANALYSIS_OP_MASK_DISASM); *size += hit->len; // Append assembly operation string @@ -69,32 +74,38 @@ static int rz_rop_process_asm_op(const RzCore *core, const RzCoreAsmHit *hit, Rz } static int rz_rop_print_table_mode(const RzCore *core, const RzCoreAsmHit *hit, const RzList /**/ *hitlist, - RzAsmOp *asmop, unsigned int *size, char **asmop_str, char **asmop_hex_str) { + unsigned int *size, char **asmop_str, char **asmop_hex_str) { RzAnalysisOp aop = RZ_EMPTY; + RzAsmOp *asmop = rz_asm_op_new(); + if (!asmop) { + return -1; + } + if (rz_rop_process_asm_op(core, hit, asmop, &aop, size, asmop_str, asmop_hex_str) != 0) { + rz_asm_op_free(asmop); return -1; } const ut64 addr_last = ((RzCoreAsmHit *)rz_list_last(hitlist))->addr; if (addr_last != hit->addr) { *asmop_str = rz_str_append(*asmop_str, "; "); } + rz_asm_op_free(asmop); rz_analysis_op_fini(&aop); return 0; } -static int rz_rop_print_quiet_mode(const RzCore *core, const RzCoreAsmHit *hit, RzList /**/ *ropList, - RzAsmOp *asmop, unsigned int *size, bool esil, bool colorize) { +static int rz_rop_print_quiet_mode(const RzCore *core, const RzCoreAsmHit *hit, unsigned int *size, const bool colorize) { RzAnalysisOp aop = RZ_EMPTY; - if (rz_rop_process_asm_op(core, hit, asmop, &aop, size, NULL, NULL) != 0) { + RzAsmOp *asmop = rz_asm_op_new(); + if (!asmop) { return -1; } - const char *opstr = RZ_STRBUF_SAFEGET(&aop.esil); - if (aop.type != RZ_ANALYSIS_OP_TYPE_RET) { - rz_list_append(ropList, rz_str_newf(" %s", opstr)); + + if (rz_rop_process_asm_op(core, hit, asmop, &aop, size, NULL, NULL) != 0) { + rz_asm_op_free(asmop); + return -1; } - if (esil) { - rz_cons_printf("%s\n", opstr); - } else if (colorize) { + if (colorize) { RzStrBuf *bw_str = rz_strbuf_new(rz_asm_op_get_asm(asmop)); RzAsmParseParam *param = rz_asm_get_parse_param(core->analysis->reg, aop.type); RzStrBuf *colored_asm = rz_asm_colorize_asm_str(bw_str, core->print, param, asmop->asm_toks); @@ -105,21 +116,23 @@ static int rz_rop_print_quiet_mode(const RzCore *core, const RzCoreAsmHit *hit, } else { rz_cons_printf(" %s;", rz_asm_op_get_asm(asmop)); } + rz_asm_op_free(asmop); rz_analysis_op_fini(&aop); return 0; } -static int rz_rop_print_standard_mode(const RzCore *core, const RzCoreAsmHit *hit, RzList /**/ *ropList, RzAsmOp *asmop, +static int rz_rop_print_standard_mode(const RzCore *core, const RzCoreAsmHit *hit, unsigned int *size, const bool rop_comments, const bool colorize) { RzAnalysisOp aop = RZ_EMPTY; + RzAsmOp *asmop = rz_asm_op_new(); + if (!asmop) { + return -1; + } if (rz_rop_process_asm_op(core, hit, asmop, &aop, size, NULL, NULL) != 0) { + rz_asm_op_free(asmop); return -1; } const char *comment = rop_comments ? rz_meta_get_string(core->analysis, RZ_META_TYPE_COMMENT, hit->addr) : NULL; - if (aop.type != RZ_ANALYSIS_OP_TYPE_RET) { - char *opstr_n = rz_str_newf(" %s", RZ_STRBUF_SAFEGET(&aop.esil)); - rz_list_append(ropList, opstr_n); - } char *asm_op_hex = rz_asm_op_get_hex(asmop); if (colorize) { RzStrBuf *bw_str = rz_strbuf_new(rz_asm_op_get_asm(asmop)); @@ -146,34 +159,34 @@ static int rz_rop_print_standard_mode(const RzCore *core, const RzCoreAsmHit *hi } free(asm_op_hex); rz_analysis_op_fini(&aop); + rz_asm_op_free(asmop); return 0; } -static int rz_rop_print_json_mode(const RzCore *core, const RzCoreAsmHit *hit, RzList /**/ *ropList, - const RzCmdStateOutput *state, RzAsmOp *asmop, unsigned int *size) { +static int rz_rop_print_json_mode(const RzCore *core, const RzCoreAsmHit *hit, unsigned int *size, PJ *pj) { RzAnalysisOp aop = RZ_EMPTY; - - if (rz_rop_process_asm_op(core, hit, asmop, &aop, size, NULL, NULL) != 0) { + RzAsmOp *asmop = rz_asm_op_new(); + if (!asmop) { return -1; } - - if (aop.type != RZ_ANALYSIS_OP_TYPE_RET) { - char *opstr_n = rz_str_newf(" %s", RZ_STRBUF_SAFEGET(&aop.esil)); - rz_list_append(ropList, opstr_n); + if (rz_rop_process_asm_op(core, hit, asmop, &aop, size, NULL, NULL) != 0) { + rz_asm_op_free(asmop); + return -1; } - pj_o(state->d.pj); - pj_kn(state->d.pj, "offset", hit->addr); - pj_ki(state->d.pj, "size", hit->len); - pj_ks(state->d.pj, "opcode", rz_asm_op_get_asm(asmop)); - pj_ks(state->d.pj, "type", rz_analysis_optype_to_string(aop.type)); - pj_end(state->d.pj); + pj_o(pj); + pj_kn(pj, "offset", hit->addr); + pj_ki(pj, "size", hit->len); + pj_ks(pj, "opcode", rz_asm_op_get_asm(asmop)); + pj_ks(pj, "type", rz_analysis_optype_to_string(aop.type)); + pj_end(pj); rz_analysis_op_fini(&aop); + rz_asm_op_free(asmop); return 0; } -void rz_reg_info_free(RzRegInfo *reg_info) { +RZ_IPI void rz_core_rop_reg_info_free(RzRopRegInfo *reg_info) { if (!reg_info) { return; } @@ -181,8 +194,8 @@ void rz_reg_info_free(RzRegInfo *reg_info) { free(reg_info); } -RzRegInfo *rz_reg_info_new(const RzCore *core, const RzILEvent *evt, const ut64 init_val, const ut64 new_val) { - RzRegInfo *reg_info = RZ_NEW0(RzRegInfo); +RZ_IPI RzRopRegInfo *rz_core_rop_reg_info_new(const RzCore *core, const RzILEvent *evt, const ut64 init_val, const ut64 new_val) { + RzRopRegInfo *reg_info = RZ_NEW0(RzRopRegInfo); const char *name = NULL; if (evt->type == RZ_IL_EVENT_VAR_READ) { reg_info->is_var_read = true; @@ -202,7 +215,7 @@ RzRegInfo *rz_reg_info_new(const RzCore *core, const RzILEvent *evt, const ut64 RzListIter *iter_dst; RzRegItem *item_dst; rz_list_foreach (head, iter_dst, item_dst) { - if (!strcmp(name, item_dst->name) && item_dst->type == RZ_REG_TYPE_GPR) { + if (RZ_STR_EQ(name, item_dst->name) && item_dst->type == RZ_REG_TYPE_GPR) { reg_info->name = strdup(name); break; } @@ -217,7 +230,7 @@ RzRegInfo *rz_reg_info_new(const RzCore *core, const RzILEvent *evt, const ut64 return reg_info; } -RzRopGadgetInfo *rz_rop_gadget_info_new(const ut64 address) { +RZ_API RzRopGadgetInfo *rz_core_rop_gadget_info_new(const ut64 address) { RzRopGadgetInfo *gadget_info = RZ_NEW0(RzRopGadgetInfo); if (!gadget_info) { return NULL; @@ -227,12 +240,12 @@ RzRopGadgetInfo *rz_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_reg_info_free); - gadget_info->dependencies = rz_list_newf((RzListFree)rz_reg_info_free); + 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); return gadget_info; } -void rz_rop_gadget_info_free(RzRopGadgetInfo *gadget_info) { +RZ_API void rz_core_rop_gadget_info_free(RzRopGadgetInfo *gadget_info) { if (!gadget_info) { return; } @@ -241,7 +254,7 @@ void rz_rop_gadget_info_free(RzRopGadgetInfo *gadget_info) { free(gadget_info); } -void rz_rop_gadget_info_add_register(RzRopGadgetInfo *gadget_info, RzRegInfo *reg_info, const bool is_dependency) { +RZ_API void rz_core_rop_gadget_info_add_register(RzRopGadgetInfo *gadget_info, RzRopRegInfo *reg_info, const bool is_dependency) { if (!gadget_info || !reg_info) { return; } @@ -250,27 +263,27 @@ void rz_rop_gadget_info_add_register(RzRopGadgetInfo *gadget_info, RzRegInfo *re } } -RzRegInfo *rz_rop_gadget_info_get_modified_register(RzRopGadgetInfo *gadget_info, const char *name) { +RZ_API RzRopRegInfo *rz_core_rop_gadget_info_get_modified_register(RzRopGadgetInfo *gadget_info, const char *name) { if (!gadget_info) { return NULL; } - RzRegInfo *reg_info; + RzRopRegInfo *reg_info; void **it; rz_pvector_foreach (gadget_info->modified_registers, it) { reg_info = *it; - if (strcmp(reg_info->name, name) == 0) { + if (RZ_STR_EQ(reg_info->name, name)) { return reg_info; } } return NULL; } -void rz_rop_gadget_info_update_register(RzRopGadgetInfo *gadget_info, RzRegInfo *new_reg_info) { +RZ_API void rz_core_rop_gadget_info_update_register(RzRopGadgetInfo *gadget_info, RzRopRegInfo *new_reg_info) { if (!gadget_info || !new_reg_info) { return; } - RzRegInfo *existing_reg_info = rz_rop_gadget_info_get_modified_register(gadget_info, new_reg_info->name); + RzRopRegInfo *existing_reg_info = rz_core_rop_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; @@ -283,12 +296,12 @@ void rz_rop_gadget_info_update_register(RzRopGadgetInfo *gadget_info, RzRegInfo } } -RzRegInfo *rz_reg_info_dup(RzRegInfo *src) { +RZ_IPI RzRopRegInfo *rz_core_rop_reg_info_dup(RzRopRegInfo *src) { if (!src) { return NULL; } - RzRegInfo *dup = RZ_NEW0(RzRegInfo); + RzRopRegInfo *dup = RZ_NEW0(RzRopRegInfo); if (!dup) { return NULL; } @@ -310,7 +323,7 @@ static bool is_stack_pointer(const RzCore *core, const char *name) { if (!reg_item) { return false; } - if (core->analysis->bits == 32 && !strcmp(core->analysis->cpu, "x86")) { + if (core->analysis->bits == 32 && RZ_STR_EQ(core->analysis->cpu, "x86")) { return !strcmp(reg_item->name, "esp"); } if (core->analysis->bits == 64) { @@ -322,29 +335,29 @@ static bool is_stack_pointer(const RzCore *core, const char *name) { return reg_item->name; } -bool is_base_pointer(const RzCore *core, const char *name) { +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; } - if (core->analysis->bits == 32 && !strcmp(core->analysis->cpu, "x86")) { - return !strcmp(reg_item->name, "ebp"); + if (core->analysis->bits == 32 && RZ_STR_EQ(core->analysis->cpu, "x86")) { + return RZ_STR_EQ(reg_item->name, "ebp"); } if (core->analysis->bits == 64) { - return !strcmp(reg_item->name, "rbp") || !strcmp(reg_item->name, "ebp"); + return RZ_STR_EQ(reg_item->name, "rbp") || RZ_STR_EQ(reg_item->name, "ebp"); } if (core->analysis->bits == 64 && !strcmp(core->analysis->cpu, "arm")) { - return !strcmp(reg_item->name, "r11"); + return RZ_STR_EQ(reg_item->name, "r11"); } return reg_item->name; } -void rz_rop_gadget_info_add_dependency(const RzCore *core, RzRopGadgetInfo *gadget_info, const RzILEvent *evt, RzRegInfo *reg_info) { +static void rz_rop_gadget_info_add_dependency(const RzCore *core, RzRopGadgetInfo *gadget_info, const RzILEvent *evt, RzRopRegInfo *reg_info) { if (!gadget_info || !reg_info) { return; } - RzRegInfo *reg_info_dup = rz_reg_info_dup(reg_info); + RzRopRegInfo *reg_info_dup = rz_core_rop_reg_info_dup(reg_info); if (!reg_info_dup) { return; } @@ -378,7 +391,6 @@ void rz_rop_gadget_info_add_dependency(const RzCore *core, RzRopGadgetInfo *gadg rz_bv_free(new_val); break; } - // reg_info_dup->init_val = rz_bv_to_ut64(init_val); 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; @@ -393,17 +405,17 @@ void rz_rop_gadget_info_add_dependency(const RzCore *core, RzRopGadgetInfo *gadg rz_list_append(gadget_info->dependencies, reg_info_dup); } -static void fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadget_info, const RzILEvent *curr_event, +static int fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadget_info, const RzILEvent *curr_event, RzILEvent *event, RzPVector /**/ *vec, const bool is_dependency) { if (!gadget_info) { - return; + return -1; } switch (event->type) { case RZ_IL_EVENT_VAR_READ: { RzILEventVarRead *var_read = &event->data.var_read; - RzRegInfo *reg_info = rz_rop_gadget_info_get_modified_register(gadget_info, var_read->variable); + RzRopRegInfo *reg_info = rz_core_rop_gadget_info_get_modified_register(gadget_info, var_read->variable); if (reg_info && !is_dependency) { - RzRegInfo *new_reg_info = rz_reg_info_dup(reg_info); + RzRopRegInfo *new_reg_info = rz_core_rop_reg_info_dup(reg_info); if (!new_reg_info) { break; } @@ -412,8 +424,8 @@ static void fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadg break; } new_reg_info->new_val = rz_bv_to_ut64(val); - rz_rop_gadget_info_update_register(gadget_info, new_reg_info); - rz_reg_info_free(new_reg_info); + rz_core_rop_gadget_info_update_register(gadget_info, new_reg_info); + //rz_core_rop_reg_info_free(new_reg_info); rz_pvector_push(vec, event); rz_bv_free(val); break; @@ -433,8 +445,8 @@ static void fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadg if (!val) { break; } - reg_info = rz_reg_info_new(core, event, rz_bv_to_ut64(val), rz_bv_to_ut64(val)); - rz_rop_gadget_info_add_register(gadget_info, reg_info, is_dependency); + 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); } @@ -449,9 +461,9 @@ static void fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadg fill_rop_gadget_info_from_events(core, gadget_info, event, evt, vec, true); } RzILEventVarWrite *var_write = &event->data.var_write; - RzRegInfo *reg_info = rz_rop_gadget_info_get_modified_register(gadget_info, var_write->variable); + RzRopRegInfo *reg_info = rz_core_rop_gadget_info_get_modified_register(gadget_info, var_write->variable); if (reg_info && !is_dependency) { - RzRegInfo *new_reg_info = rz_reg_info_dup(reg_info); + RzRopRegInfo *new_reg_info = rz_core_rop_reg_info_dup(reg_info); if (!new_reg_info) { break; } @@ -462,11 +474,9 @@ static void fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadg rz_bv_free(new_val); break; } - // new_reg_info->init_val = rz_bv_to_ut64(old_val); new_reg_info->new_val = rz_bv_to_ut64(new_val); new_reg_info->is_mem_write = true; - rz_rop_gadget_info_update_register(gadget_info, new_reg_info); - rz_reg_info_free(new_reg_info); + rz_core_rop_gadget_info_update_register(gadget_info, new_reg_info); rz_bv_free(old_val); rz_bv_free(new_val); break; @@ -480,15 +490,14 @@ static void fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadg rz_bv_free(new_val); break; } - reg_info = rz_reg_info_new(core, event, rz_bv_to_ut64(old_val), + reg_info = rz_core_rop_reg_info_new(core, event, rz_bv_to_ut64(old_val), rz_bv_to_ut64(new_val)); - rz_rop_gadget_info_add_register(gadget_info, reg_info, is_dependency); + rz_core_rop_gadget_info_add_register(gadget_info, reg_info, is_dependency); rz_bv_free(old_val); rz_bv_free(new_val); } } break; case RZ_IL_EVENT_MEM_READ: { - // RzILEventMemRead *mem_read = &event->data.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); @@ -501,7 +510,6 @@ static void fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadg } } break; case RZ_IL_EVENT_PC_WRITE: { - // RzILEventPCWrite *pc_write = &event->data.pc_write; if (!gadget_info->is_pc_write) { gadget_info->is_pc_write = true; } @@ -509,37 +517,44 @@ static void fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadg default: break; } + return 0; } -static void analyze_gadget(RzCore *core, const RzCoreAsmHit *hit, RzRopGadgetInfo *rop_gadget_info) { - if (!core->analysis) { - return; - } +static int analyze_gadget(RzCore *core, const RzCoreAsmHit *hit, RzRopGadgetInfo *rop_gadget_info) { + rz_return_val_if_fail(core && core->analysis, -1); + int ret = 0; + ut64 old_addr = core->offset; rz_core_seek(core, hit->addr, true); rz_core_analysis_il_reinit(core); rz_config_set(core->config, "io.cache", "true"); rz_core_il_step(core, 1); - if (!core->analysis || !core->analysis->il_vm) { + + if (!core->analysis->il_vm) { + ret = -1; goto cleanup; } RzILVM *vm = core->analysis->il_vm->vm; if (!vm) { + ret = -1; goto cleanup; } void **it; - RzILEvent *evt; RzPVector vec; rz_pvector_init(&vec, (RzPVectorFree)rz_il_event_free); rz_pvector_foreach (vm->events, it) { - evt = *it; - fill_rop_gadget_info_from_events(core, rop_gadget_info, NULL, evt, &vec, false); + RzILEvent *evt = *it; + ret = fill_rop_gadget_info_from_events(core, rop_gadget_info, NULL, evt, &vec, false); + if (ret < 0) { + break; + } } cleanup: rz_pvector_flush(&vec); rz_core_seek(core, old_addr, true); + return ret; } static void print_rop_gadget_info(const RzCore *core, const RzRopGadgetInfo *gadget_info) { @@ -547,7 +562,7 @@ static void print_rop_gadget_info(const RzCore *core, const RzRopGadgetInfo *gad rz_cons_printf("Stack change: 0x%" PFMT64x "\n", gadget_info->stack_change); rz_cons_printf("Changed registers: "); - RzRegInfo *reg_info; + RzRopRegInfo *reg_info; void **it; rz_pvector_foreach (gadget_info->modified_registers, it) { reg_info = *it; @@ -571,26 +586,14 @@ static void print_rop_gadget_info(const RzCore *core, const RzRopGadgetInfo *gad } } } -static void print_rop(const RzCore *core, const RzList /**/ *hitlist, RzCmdStateOutput *state) { - RzCoreAsmHit *hit = NULL; + +static int print_rop(const RzCore *core, const RzList /**/ *hitlist, RzCmdStateOutput *state) { + const RzCoreAsmHit *hit = NULL; RzListIter *iter; unsigned int size = 0; - RzList *ropList = NULL; char *asmop_str = NULL, *asmop_hex_str = NULL; - Sdb *db = NULL; const bool colorize = rz_config_get_i(core->config, "scr.color"); const bool rop_comments = rz_config_get_i(core->config, "rop.comments"); - const bool esil = rz_config_get_i(core->config, "asm.esil"); - const bool rop_db = rz_config_get_i(core->config, "rop.db"); - if (rop_db) { - db = sdb_ns(core->sdb, "rop", true); - ropList = rz_list_newf(free); - if (!db) { - RZ_LOG_ERROR("core: Could not create SDB 'rop' namespace\n"); - rz_list_free(ropList); - return; - } - } rz_cmd_state_output_set_columnsf(state, "XXs", "addr", "bytes", "disasm"); if (state->mode == RZ_OUTPUT_MODE_JSON) { @@ -601,42 +604,32 @@ static void print_rop(const RzCore *core, const RzList /**/ *hit } const ut64 addr = ((RzCoreAsmHit *)rz_list_first(hitlist))->addr; + int result = 0; rz_list_foreach (hitlist, iter, hit) { - RzAsmOp *asmop = rz_asm_op_new(); switch (state->mode) { case RZ_OUTPUT_MODE_JSON: - if (rz_rop_print_json_mode(core, hit, ropList, state, asmop, &size) != 0) { - goto cleanup; - } + result = rz_rop_print_json_mode(core, hit, &size, state->d.pj) != 0; break; case RZ_OUTPUT_MODE_QUIET: - if (rz_rop_print_quiet_mode(core, hit, ropList, asmop, &size, esil, colorize) != 0) { - goto cleanup; - } + result = rz_rop_print_quiet_mode(core, hit, &size, colorize) != 0; break; case RZ_OUTPUT_MODE_STANDARD: - if (rz_rop_print_standard_mode(core, hit, ropList, asmop, &size, rop_comments, colorize) != 0) { - goto cleanup; - } + result = rz_rop_print_standard_mode(core, hit, &size, rop_comments, colorize) != 0; break; case RZ_OUTPUT_MODE_TABLE: - if (rz_rop_print_table_mode(core, hit, hitlist, asmop, &size, &asmop_str, &asmop_hex_str) != 0) { - goto cleanup; - } + result = rz_rop_print_table_mode(core, hit, hitlist, &size, &asmop_str, &asmop_hex_str) != 0; break; default: rz_warn_if_reached(); break; } - rz_asm_op_free(asmop); + if (result != 0) { + return result; + } } switch (state->mode) { case RZ_OUTPUT_MODE_JSON: pj_end(state->d.pj); - if (db && hit) { - // const char *key = rz_strf(tmpbuf, "0x%08" PFMT64x, addr); - // rop_classify(core, db, ropList, key, size); - } if (hit) { pj_kn(state->d.pj, "retaddr", hit->addr); pj_ki(state->d.pj, "size", size); @@ -648,9 +641,8 @@ static void print_rop(const RzCore *core, const RzList /**/ *hit break; // fallthrough case RZ_OUTPUT_MODE_STANDARD: - if (db && hit) { + if (hit) { rz_cons_printf("Gadget size: %d\n", (int)size); - // rop_classify(core, db, ropList, key, size); } rz_cons_newline(); break; @@ -662,46 +654,73 @@ static void print_rop(const RzCore *core, const RzList /**/ *hit default: rz_warn_if_reached(); } -cleanup: - rz_list_free(ropList); + return 0; } -static bool insert_into(void *user, const ut64 k, const ut64 v) { - HtUU *ht = (HtUU *)user; - ht_uu_insert(ht, k, v); - return true; +static int handle_rop_list(RzStrBuf *sb, const RzRopSearchContext *context, + const RzRopEndListPair *end_gadget, RZ_OWN RzList *hitlist) { + rz_return_val_if_fail(sb && context && context->unique_hitlists, -1); + if (end_gadget->delay_size && rz_list_length(hitlist) < 1 + end_gadget->delay_size) { + rz_list_free(hitlist); + return -1; + } + + bool is_found = true; + const char *asm_op_hex = NULL; + if (sb->len) { + asm_op_hex = rz_strbuf_get(sb); + ht_su_find(context->unique_hitlists, asm_op_hex, &is_found); + } + if (!is_found && asm_op_hex) { + ht_su_insert(context->unique_hitlists, asm_op_hex, 1); + } else { + rz_list_free(hitlist); + return -1; + } + return 0; } +void handle_greparg(const RzRopSearchContext *context, char **grep_str, int *count, const RzList *rx_list) { + char *start = context->greparg; + char *end = strchr(context->greparg, ';'); + if (!end) { // We filter on a single opcode, so no ";" + end = start + strlen(context->greparg); + } + *grep_str = calloc(1, end - start + 1); + if (*grep_str) { + strncpy(*grep_str, start, end - start); + } + if (context->regexp && rz_list_length(rx_list) > 0) { + //rx = rz_list_get_n(rx_list, (*count)++); + } +} + + // TODO: follow unconditional jumps -static RzList /**/ *construct_rop_gadget(RzCore *core, ut64 addr, ut8 *buf, int buflen, - int idx, const char *grep, int regex, RzList /**/ *rx_list, - RzRopEndListPair *end_gadget, HtUU *badstart, int delta, RzStrBuf *sb) { +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; - int branch_delay = end_gadget->delay_size; RzAnalysisOp aop = { 0 }; const char *start = NULL, *end = NULL; char *grep_str = NULL; RzCoreAsmHit *hit = NULL; - RzList *hitlist = rz_core_asm_hit_list_new(); - ut8 nb_instr = 0; - const ut8 max_instr = rz_config_get_i(core->config, "rop.len"); bool valid = false; int grep_find; int search_hit; char *rx = NULL; - HtUUOptions opt = { 0 }; - HtUU *localbadstart = ht_uu_new_opt(&opt); int count = 0; - if (grep) { - start = grep; - end = strchr(grep, ';'); + RzStrBuf *sb = rz_strbuf_new(""); + if (context->greparg) { + //handle_greparg(context, &grep_str, &count, rx_list); + start = context->greparg; + end = strchr(context->greparg, ';'); if (!end) { // We filter on a single opcode, so no ";" - end = start + strlen(grep); + end = start + strlen(context->greparg); } grep_str = calloc(1, end - start + 1); strncpy(grep_str, start, end - start); - if (regex) { + if (context->regexp) { // get the first regexp. if (rz_list_length(rx_list) > 0) { rx = rz_list_get_n(rx_list, count++); @@ -709,21 +728,21 @@ static RzList /**/ *construct_rop_gadget(RzCore *core, ut64 addr } } - bool found; - ht_uu_find(badstart, idx, &found); - if (found) { - valid = false; + ut32 end_gadget_cnt = 0; + RzList *hitlist = rz_core_asm_hit_list_new(); + if (!hitlist) { goto ret; } - ut32 end_gadget_cnt = 0; - while (nb_instr < max_instr) { - // ht_uu_insert(localbadstart, idx, 1); + ut8 nb_instr = 0; + int addr = context->from + idx; + int delta = context->to - context->from; + while (nb_instr < context->max_instr) { rz_analysis_op_init(&aop); if (idx >= delta) { valid = false; goto ret; } - int error = rz_analysis_op(core->analysis, &aop, addr, buf + idx, buflen - idx, RZ_ANALYSIS_OP_MASK_DISASM); + int error = rz_analysis_op(core->analysis, &aop, addr, buf + idx, delta - idx, RZ_ANALYSIS_OP_MASK_DISASM); if (error < 0 || (nb_instr == 0 && aop.type == RZ_ANALYSIS_OP_TYPE_NOP)) { valid = false; goto ret; @@ -733,10 +752,9 @@ static RzList /**/ *construct_rop_gadget(RzCore *core, ut64 addr end_gadget_cnt++; } const int opsz = aop.size; - // opsz = rz_strbuf_length (asmop.buf); char *opst = aop.mnemonic; - RzAsmOp asmop; - int asm_ret = rz_asm_disassemble(core->rasm, &asmop, buf + idx, buflen - idx); + RzAsmOp asmop = RZ_EMPTY; + int asm_ret = rz_asm_disassemble(core->rasm, &asmop, buf + idx, delta - idx); if (!opst) { RZ_LOG_WARN("Analysis plugin %s did not return disassembly\n", core->analysis->cur->name); rz_asm_set_pc(core->rasm, addr); @@ -770,9 +788,9 @@ static RzList /**/ *construct_rop_gadget(RzCore *core, ut64 addr addr += opsz; if (rx) { grep_find = rz_regex_contains(rx, opst, RZ_REGEX_ZERO_TERMINATED, RZ_REGEX_EXTENDED, RZ_REGEX_DEFAULT); - search_hit = (end && grep && grep_find); + search_hit = end && context->greparg && grep_find; } else { - search_hit = (end && grep && strstr(opst, grep_str)); + search_hit = end && context->greparg && strstr(opst, grep_str); } // Handle (possible) grep @@ -789,12 +807,12 @@ static RzList /**/ *construct_rop_gadget(RzCore *core, ut64 addr } else { end = NULL; } - if (regex) { + if (context->regexp) { rx = rz_list_get_n(rx_list, count++); } } - if (endaddr <= (idx - opsz)) { - valid = (endaddr == idx - opsz); + if (endaddr <= idx - opsz) { + valid = endaddr == idx - opsz; goto ret; } rz_analysis_op_fini(&aop); @@ -803,415 +821,358 @@ static RzList /**/ *construct_rop_gadget(RzCore *core, ut64 addr ret: rz_analysis_op_fini(&aop); free(grep_str); - if (regex && rx) { + if (context->regexp && rx) { rz_list_free(hitlist); - ht_uu_free(localbadstart); + rz_strbuf_free(sb); return NULL; } - if (!valid || (grep && end)) { + if (!valid || (context->greparg && end)) { rz_list_free(hitlist); - ht_uu_free(localbadstart); + rz_strbuf_free(sb); return NULL; } - ht_uu_foreach(localbadstart, insert_into, badstart); - ht_uu_free(localbadstart); - // If our arch has bds then we better be including them - if (branch_delay && rz_list_length(hitlist) < (1 + branch_delay)) { - rz_list_free(hitlist); + if (handle_rop_list(sb, context, end_gadget, hitlist) < 0) { + rz_strbuf_free(sb); return NULL; } + rz_strbuf_free(sb); return hitlist; } -static void handle_rop_request_type(RzCore *core, const ut8 subchain, const RzRopRequestMask type, - RzList /**/ *hitlist, RzCmdStateOutput *state) { - if (type & RZ_ROP_GADGET_PRINT) { - if (subchain) { +static int handle_rop_request_type(RzCore *core, RzRopSearchContext *context, RzList /**/ *hitlist) { + rz_return_val_if_fail(core && core->analysis, -1); + if (context->mask & RZ_ROP_GADGET_PRINT) { + if (context->subchain) { do { - print_rop(core, hitlist, state); + print_rop(core, hitlist, context->state); hitlist->head = hitlist->head->next; } while (hitlist->head->next); } else { - print_rop(core, hitlist, state); + print_rop(core, hitlist, context->state); } } - if (type & RZ_ROP_GADGET_DETAIL) { + 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; + + + 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; - RzRopGadgetInfo *rop_gadget_info = rz_rop_gadget_info_new(addr_start); + rop_gadget_info = rz_core_rop_gadget_info_new(addr_start); rz_list_foreach (hitlist, iter, hit) { - analyze_gadget(core, hit, rop_gadget_info); + 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); + } + if (context->mask & RZ_ROP_GADGET_PRINT_DETAIL) { print_rop_gadget_info(core, rop_gadget_info); - rz_rop_gadget_info_free(rop_gadget_info); } + return 0; } -/** - * \brief Search for ROP gadgets. - * \param core Pointer to the RzCore object. - * \param greparg Grep argument string for filtering gadgets. - * \param regexp Boolean indicating if the grep argument is a regex. - * \param mask ROP request type (RzRopRequestMask). - * \param state Pointer to the command state output (RzCmdStateOutput). - * \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 - * filters results based on the grep argument and request mask. Outputs results to - * the provided state object. - */ -RZ_API int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, const RzRopRequestMask mask, RzCmdStateOutput *state) { - const ut8 crop = rz_config_get_i(core->config, "rop.conditional"); // decide if cjmp, cret, and ccall should be used too for the gadget-search - const ut8 subchain = rz_config_get_i(core->config, "rop.subchains"); - const ut8 max_instr = rz_config_get_i(core->config, "rop.len"); - const char *arch = rz_config_get(core->config, "asm.arch"); - int max_count = rz_config_get_i(core->config, "search.maxhits"); - int i = 0, end = 0, increment = 1, ret, result = true; - RzList /**/ *end_list = rz_list_newf(free); - RzList /**/ *rx_list = NULL; - int align = core->search->align; - RzListIter *itermap = NULL; - char *grep_arg = NULL; - char *tok, *gregexp = NULL; - char *rx = NULL; - RzAsmOp *asmop = NULL; - RzList *boundaries = NULL; - int delta = 0; - ut8 *buf; - RzIOMap *map; - HtSU *unique_hitlists = ht_su_new(HT_STR_DUP); - +static int fetch_search_itv(const RzCore *core, RzInterval *search_itv) { + rz_return_val_if_fail(core && core->config, -1); const ut64 search_from = rz_config_get_i(core->config, "search.from"), search_to = rz_config_get_i(core->config, "search.to"); if (search_from > search_to && search_to) { RZ_LOG_ERROR("core: search.from > search.to is not supported\n"); - ret = false; - goto bad; + return -1; } - // {.addr = UT64_MAX, .size = 0} means search range is unspecified - RzInterval search_itv = { search_from, search_to - search_from }; - bool empty_search_itv = search_from == search_to && search_from != UT64_MAX; + search_itv->addr = search_from; + search_itv->size = search_to - search_from; + + const bool empty_search_itv = search_from == search_to && search_from != UT64_MAX; if (empty_search_itv) { RZ_LOG_ERROR("core: `from` address is equal `to`\n"); - ret = false; - goto bad; + return -1; } // TODO full address cannot be represented, shrink 1 byte to [0, UT64_MAX) if (search_from == UT64_MAX && search_to == UT64_MAX) { - search_itv.addr = 0; - search_itv.size = UT64_MAX; + search_itv->addr = 0; + search_itv->size = UT64_MAX; } + return 0; +} + +static RzList * /* */ compute_end_gadget_list(const RzCore *core, const ut8 *buf, const RzRopSearchContext *context) { + RzList /* */ *end_list = rz_list_newf(free); + const int delta = context->to - context->from; - Sdb *gadgetSdb = NULL; - if (rz_config_get_i(core->config, "rop.sdb")) { - if (!(gadgetSdb = sdb_ns(core->sdb, "gadget_sdb", false))) { - gadgetSdb = sdb_ns(core->sdb, "gadget_sdb", true); + for (int i = 0; i < delta; i += context->increment) { + RzAnalysisOp end_gadget = RZ_EMPTY; + // Disassemble one. + rz_analysis_op_init(&end_gadget); + if (rz_analysis_op(core->analysis, &end_gadget, context->from + i, buf + i, + delta - i, RZ_ANALYSIS_OP_MASK_BASIC) < 1) { + rz_analysis_op_fini(&end_gadget); + continue; + } + + if (is_end_gadget(&end_gadget, context->crop)) { + RzRopEndListPair *epair = RZ_NEW0(RzRopEndListPair); + if (epair) { + epair->instr_offset = i + (end_gadget.delay ? context->increment : 0); + epair->delay_size = end_gadget.delay; + rz_list_append(end_list, epair); + } + } + rz_analysis_op_fini(&end_gadget); + if (rz_cons_is_breaked()) { + break; } } - if (max_count == 0) { - max_count = -1; + return end_list; +} + +static void set_increment_based_on_arch(const RzCore *core, const char *arch, int *increment) { + if (RZ_STR_EQ(arch, "mips")) { // MIPS has no jump-in-the-middle + *increment = 4; + } else if (RZ_STR_EQ(arch, "arm")) { // ARM has no jump-in-the-middle + *increment = rz_config_get_i(core->config, "asm.bits") == 16 ? 2 : 4; + } else if (RZ_STR_EQ(arch, "avr")) { // AVR is halfword aligned. + *increment = 2; } - if (max_instr <= 1) { - rz_list_free(end_list); - RZ_LOG_ERROR("core: ROP length (rop.len) must be greater than 1.\n"); - if (max_instr == 1) { - RZ_LOG_ERROR("core: For rop.len = 1, use /c to search for single " - "instructions. See /c? for help.\n"); +} + +static RzList * /**/ handle_grep_args(const char *greparg, const bool regexp) { + if (!greparg || !regexp) { + return NULL; + } + + char *grep_arg = strdup(greparg); + if (!grep_arg) { + return NULL; + } + char *gregexp = rz_str_replace(grep_arg, ",,", ";", true); + if (!gregexp) { + return NULL; + } + + RzList *rx_list = rz_list_newf(free); + if (!rx_list) { + free(gregexp); + return NULL; + } + + const char *tok = strtok(gregexp, ";"); + while (tok) { + char *rx = strdup(tok); + if (!rx) { + break; } - return false; + rz_list_append(rx_list, rx); + tok = strtok(NULL, ";"); } - if (!strcmp(arch, "mips")) { // MIPS has no jump-in-the-middle - increment = 4; - } else if (!strcmp(arch, "arm")) { // ARM has no jump-in-the-middle - increment = rz_config_get_i(core->config, "asm.bits") == 16 ? 2 : 4; - } else if (!strcmp(arch, "avr")) { // AVR is halfword aligned. - increment = 2; + free(gregexp); + return rx_list; +} + +static bool process_disassembly(RzCore *core, ut8 *buf, const int idx, RzRopSearchContext *context, + RzList *rx_list, RzRopEndListPair *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); + if (!ret) { + goto fini; + } + + 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; + } + + if (core->search->align && (context->from + idx) % core->search->align != 0) { + rz_list_free(hitlist); + goto fini; } - if (greparg) { - grep_arg = strdup(greparg); - grep_arg = rz_str_replace(grep_arg, ",,", ";", true); + if (handle_rop_request_type(core, context, hitlist) < 0) { + rz_list_free(hitlist); + goto fini; } + rz_list_free(hitlist); - // Deal with the grep guy. - if (grep_arg && regexp) { - if (!rx_list) { - rx_list = rz_list_newf(free); + if (context->max_count > 0) { + context->max_count--; + if (context->max_count < 1) { + status = true; } - gregexp = strdup(grep_arg); - tok = strtok(gregexp, ";"); - while (tok) { - rx = strdup(tok); - rz_list_append(rx_list, rx); - tok = strtok(NULL, ";"); + } + +fini: + rz_asm_op_free(asmop); + return status; +} + +RZ_BORROW static int update_end_gadget(int *i, const int ropdepth, RzRopEndListPair **end_gadget, const RzRopSearchContext *context) { + if (*i > (*end_gadget)->instr_offset) { + // We've exhausted the first end-gadget section, + // move to the next one. + 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; + if (*i < 0) { + *i = 0; + } + } else { + *end_gadget = NULL; + return -1; } } - rz_cmd_state_output_array_start(state); + return 0; +} + +/** + * \brief Search for ROP gadgets. + * \param core Pointer to the RzCore object. + * \param context Pointer to the RzRopSearchContext 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 + * 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_return_val_if_fail(core && core->search, RZ_CMD_STATUS_ERROR); + int result = -1; + + RzInterval search_itv; + result = fetch_search_itv(core, &search_itv); + if (result != 0) { + return -1; + } + + if (context->max_instr <= 1) { + RZ_LOG_ERROR("core: ROP length (rop.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 " + "instructions. See /c? for help.\n"); + } + return -1; + } + const char *arch = rz_config_get(core->config, "asm.arch"); + set_increment_based_on_arch(core, 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"); - boundaries = rz_core_get_boundaries_prot(core, -1, mode_str, "search"); + RzList *boundaries = rz_core_get_boundaries_prot(core, -1, mode_str, "search"); if (!boundaries) { - rz_cmd_state_output_array_end(state); + 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) { - HtUUOptions opt = { 0 }; - HtUU *badstart = ht_uu_new_opt(&opt); if (!rz_itv_overlap(search_itv, map->itv)) { continue; } - RzInterval itv = rz_itv_intersect(search_itv, map->itv); - ut64 from = itv.addr, to = rz_itv_end(itv); + const RzInterval itv = rz_itv_intersect(search_itv, map->itv); + context->from = itv.addr; + context->to = rz_itv_end(itv); if (rz_cons_is_breaked()) { break; } - delta = to - from; - buf = calloc(1, delta); + const ut64 delta = context->to - context->from; + ut8 *buf = calloc(1, delta); if (!buf) { result = false; - goto bad; + continue; } - (void)rz_io_read_at(core->io, from, buf, delta); - - // Find the end gadgets. - for (i = 0; i < delta; i += increment) { - RzAnalysisOp end_gadget = RZ_EMPTY; - // Disassemble one. - rz_analysis_op_init(&end_gadget); - if (rz_analysis_op(core->analysis, &end_gadget, from + i, buf + i, - delta - i, RZ_ANALYSIS_OP_MASK_BASIC) < 1) { - rz_analysis_op_fini(&end_gadget); - continue; - } - if (is_end_gadget(&end_gadget, crop)) { - RzRopEndListPair *epair = RZ_NEW0(RzRopEndListPair); - if (epair) { - // If this arch has branch delay slots, add the next instr as well - if (end_gadget.delay) { - epair->instr_offset = i + increment; - epair->delay_size = end_gadget.delay; - } else { - epair->instr_offset = (intptr_t)i; - epair->delay_size = end_gadget.delay; - } - rz_list_append(end_list, (void *)(intptr_t)epair); - } + if (rz_io_nread_at(core->io, context->from, buf, delta) < 0) { + free(buf); + continue; + } + + context->end_list = compute_end_gadget_list(core, buf, context); + // If we have no end gadgets, just skip all of this search nonsense. + if (rz_list_empty(context->end_list)) { + free(buf); + rz_list_free(context->end_list); + continue; + } + rz_list_reverse(context->end_list); + const int max_inst_size_x86 = 15; + // Get the depth of rop search, 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; + if (rz_cons_is_breaked()) { + break; + } + RzRopEndListPair *end_gadget = rz_list_pop(context->end_list); + // Start at just before the first end gadget. + const int next = end_gadget->instr_offset; + const int prev = 0; + for (int i = 0; i < delta && context->max_count; i += context->increment) { + // TODO: Test this and check if this line is needed in x86 + if (context->increment == 1 && i < prev - max_inst_size_x86) { + i = prev - max_inst_size_x86; + } else if (context->increment != 1 && i < prev) { + i = prev; } - rz_analysis_op_fini(&end_gadget); if (rz_cons_is_breaked()) { break; } - // Right now we have a list of all of the end/stop gadgets. - // We can just construct gadgets from a little bit before them. - } - rz_list_reverse(end_list); - // If we have no end gadgets, just skip all of this search nonsense. - if (!rz_list_empty(end_list)) { - int prev, next, ropdepth; - const int max_inst_size_x86 = 15; - // Get the depth of rop search, should just be max_instr - // instructions, x86 and friends are weird length instructions, so - // we'll just assume 15 byte instructions. - ropdepth = increment == 1 ? max_instr * max_inst_size_x86 /* wow, x86 is long */ : max_instr * increment; - if (rz_cons_is_breaked()) { + if (i > next && update_end_gadget(&i, ropdepth, &end_gadget, context) < 0) { break; } - RzRopEndListPair *end_gadget = rz_list_pop(end_list); - next = end_gadget->instr_offset; - prev = 0; - // Start at just before the first end gadget. - for (i = 0; i < delta && max_count; i += increment) { - if (increment == 1) { - // give in-boundary instructions a shot - if (i < prev - max_inst_size_x86) { - i = prev - max_inst_size_x86; - } - } else { - if (i < prev) { - i = prev; - } - } - if (i < 0) { - i = 0; - } - if (rz_cons_is_breaked()) { - break; - } - if (i > next) { - // We've exhausted the first end-gadget section, - // move to the next one. - free(end_gadget); - if (rz_list_get_n(end_list, 0)) { - prev = i; - end_gadget = (RzRopEndListPair *)rz_list_pop(end_list); - next = end_gadget->instr_offset; - i = next - ropdepth; - if (i < 0) { - i = 0; - } - } else { - end_gadget = NULL; - break; - } - } - if (i >= end) { // read by chunk of 4k - rz_io_read_at(core->io, from + i, buf + i, - RZ_MIN((delta - i), 4096)); - end = i + 2048; - } - asmop = rz_asm_op_new(); - ret = rz_asm_disassemble(core->rasm, asmop, buf + i, delta - i); - if (ret) { - rz_asm_set_pc(core->rasm, from + i); - RzStrBuf *sb = rz_strbuf_new(""); - RzList *hitlist = construct_rop_gadget(core, - from + i, buf, delta, i, greparg, regexp, - rx_list, end_gadget, badstart, delta, sb); - - if (!hitlist) { - rz_asm_op_free(asmop); - asmop = NULL; - rz_strbuf_free(sb); - continue; - } - if (align && 0 != (from + i) % align) { - rz_asm_op_free(asmop); - asmop = NULL; - rz_strbuf_free(sb); - continue; - } - bool is_found = true; - char *asm_op_hex = NULL; - if (sb->len) { - asm_op_hex = rz_strbuf_get(sb); - ht_su_find(unique_hitlists, asm_op_hex, &is_found); - } - if (!is_found && asm_op_hex) { - ht_su_insert(unique_hitlists, asm_op_hex, 1); - } else { - rz_list_free(hitlist); - rz_asm_op_free(asmop); - asmop = NULL; - rz_strbuf_free(sb); - continue; - } - rz_strbuf_free(sb); - if (gadgetSdb) { - RzListIter *iter; - - RzCoreAsmHit *hit = rz_list_first(hitlist); - char *headAddr = rz_str_newf("%" PFMT64x, hit->addr); - if (!headAddr) { - result = false; - free(buf); - ht_uu_free(badstart); - goto bad; - } - - rz_list_foreach (hitlist, iter, hit) { - char *addr = rz_str_newf("%" PFMT64x "(%" PFMT32d ")", hit->addr, hit->len); - if (!addr) { - free(headAddr); - result = false; - free(buf); - ht_uu_free(badstart); - goto bad; - } - sdb_concat(gadgetSdb, headAddr, addr); - free(addr); - } - free(headAddr); - } - - handle_rop_request_type(core, subchain, mask, hitlist, state); - rz_list_free(hitlist); - if (max_count > 0) { - max_count--; - if (max_count < 1) { - break; - } - } - } - if (increment != 1) { - i = next; - } - rz_asm_op_free(asmop); - asmop = NULL; + if (process_disassembly(core, buf, i, context, rx_list, end_gadget)) { + break; } - free(end_gadget); } + free(end_gadget); free(buf); - ht_uu_free(badstart); + rz_list_free(context->end_list); } + ht_su_free(context->unique_hitlists); if (rz_cons_is_breaked()) { eprintf("\n"); } -bad: - rz_cmd_state_output_array_end(state); + rz_cmd_state_output_array_end(context->state); rz_cons_break_pop(); - rz_asm_op_free(asmop); - ht_su_free(unique_hitlists); rz_list_free(rx_list); - rz_list_free(end_list); + rz_core_rop_search_context_free(context); rz_list_free(boundaries); - free(grep_arg); - free(gregexp); return result; } /** * \brief Display ROP gadget information. * \param core Pointer to the RzCore object. - * \param input Input string for ROP search. - * \param state Pointer to the command state output. + * \param context Pointer to the RzRopSearchContext object. * \return RZ_CMD_STATUS_OK on success. * * 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, const char *input, RzCmdStateOutput *state) { - Sdb *gadgetSdb = sdb_ns(core->sdb, "gadget_sdb", false); - - if (!gadgetSdb) { - rz_core_search_rop(core, input, 0, RZ_ROP_GADGET_PRINT, state); - return RZ_CMD_STATUS_OK; - } - void **iter; - RzPVector *items = sdb_get_items(gadgetSdb, true); +RZ_API RzCmdStatus rz_core_rop_gadget_info(RzCore *core, RZ_OWN RzRopSearchContext *context) { + rz_return_val_if_fail(core && core->analysis, RZ_CMD_STATUS_ERROR); - rz_cmd_state_output_array_start(state); - rz_pvector_foreach (items, iter) { - SdbKv *kv = *iter; - RzList *hitlist = rz_core_asm_hit_list_new(); - if (!hitlist) { - break; - } - - const char *s = sdbkv_value(kv); - ut64 addr; - int opsz; - do { - RzCoreAsmHit *hit = rz_core_asm_hit_new(); - if (!hit) { - rz_list_free(hitlist); - break; - } - sscanf(s, "%" PFMT64x "(%" PFMT32d ")", &addr, &opsz); - hit->addr = addr; - hit->len = opsz; - rz_list_append(hitlist, hit); - } while (*(s = strchr(s, ')') + 1) != '\0'); - - print_rop(core, hitlist, state); - rz_list_free(hitlist); + if (!core->analysis->ht_rop) { + // TODO: resolve this logic later. } - rz_pvector_free(items); - rz_cmd_state_output_array_end(state); - return RZ_CMD_STATUS_OK; + return rz_core_rop_search(core, context); } /** @@ -1220,7 +1181,7 @@ RZ_API RzCmdStatus rz_core_rop_gadget_info(RzCore *core, const char *input, RzCm * * Frees the memory allocated for an RzRopConstraint object. */ -RZ_API void rz_rop_constraint_free(RZ_NULLABLE void *data) { +RZ_API void rz_core_rop_constraint_free(RZ_NULLABLE void *data) { RzRopConstraint *constraint = data; if (!constraint) { return; @@ -1242,7 +1203,7 @@ RZ_API void rz_rop_constraint_free(RZ_NULLABLE void *data) { RZ_API RzList /**/ *rz_rop_constraint_list_new(void) { RzList *list = rz_list_new(); if (list) { - list->free = &rz_rop_constraint_free; + list->free = &rz_core_rop_constraint_free; } return list; } \ No newline at end of file diff --git a/librz/include/rz_analysis.h b/librz/include/rz_analysis.h index 5604624e78a..17008e4975f 100644 --- a/librz/include/rz_analysis.h +++ b/librz/include/rz_analysis.h @@ -528,6 +528,7 @@ typedef struct rz_analysis_t { RzPlatformTarget *arch_target; RzPlatformTargetIndex *platform_target; HtSP *ht_global_var; // global variables + HtUP *ht_rop; ///< store rop gadget address. RBTree global_var_tree; // global variables by address. must not overlap RzHash *hash; RzAnalysisDebugInfo *debug_info; ///< store all debug info parsed from DWARF, etc.. @@ -1887,6 +1888,7 @@ RZ_API RZ_OWN RzAnalysisVarGlobal *rz_analysis_var_global_new(RZ_NONNULL const c RZ_API bool rz_analysis_var_global_add(RzAnalysis *analysis, RZ_NONNULL RzAnalysisVarGlobal *global_var); RZ_API bool rz_analysis_var_global_create(RzAnalysis *analysis, RZ_NONNULL const char *name, RZ_NONNULL RZ_BORROW RzType *type, ut64 addr); RZ_API void rz_analysis_var_global_free(RzAnalysisVarGlobal *glob); + RZ_API RZ_NULLABLE RzFlagItem *rz_analysis_var_global_get_flag_item(RzAnalysisVarGlobal *glob); RZ_API bool rz_analysis_var_global_delete(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisVarGlobal *glob); RZ_API bool rz_analysis_var_global_delete_byname(RzAnalysis *analysis, RZ_NONNULL const char *name); diff --git a/librz/include/rz_rop.h b/librz/include/rz_rop.h index 0861f81b73a..6e89f851704 100644 --- a/librz/include/rz_rop.h +++ b/librz/include/rz_rop.h @@ -16,7 +16,7 @@ /** * \brief Information about a register. */ -typedef struct rz_reg_info_t { +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. @@ -25,7 +25,7 @@ typedef struct rz_reg_info_t { bool is_mem_write; ///< Register involved in Memory write. ut64 init_val; ut64 new_val; -} RzRegInfo; +} RzRopRegInfo; /** * \brief Information about a ROP gadget. @@ -43,13 +43,13 @@ typedef struct rz_rop_gadget_info_t { /** * \brief Types of IL instructions for ROP constraints. */ -typedef enum rzil_instr_type { +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 -} RzILInstructionType; +} RzRopILInstructionType; /** * \brief Argument types for ROP constraints. @@ -68,8 +68,9 @@ typedef enum { */ typedef enum { RZ_ROP_GADGET_PRINT = 1 << 0, ///< Print ROP gadgets. - RZ_ROP_GADGET_DETAIL = 1 << 1, ///< Detailed ROP gadgets. - RZ_ROP_GADGET_ALL = RZ_ROP_GADGET_PRINT | RZ_ROP_GADGET_DETAIL ///< All ROP gadgets requests. + 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; /** @@ -84,17 +85,50 @@ typedef struct rz_rop_endlist_pair_t { * \brief Structure representing a ROP constraint. */ typedef struct rz_rop_constraint_t { - RzILInstructionType type; ///< IL instruction type. + 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; + ut8 subchain; + ut8 crop; + char *greparg; + int regexp; + int max_count; + int increment; + RzRopRequestMask mask; + RzCmdStateOutput *state; + ut64 from; + ut64 to; + RzList /* */ *end_list; + HtSU *unique_hitlists; +} RzRopSearchContext; + // Command APIs -RZ_API int rz_core_search_rop(RzCore *core, const char *greparg, int regexp, RzRopRequestMask type, RzCmdStateOutput *state); -RZ_API RzCmdStatus rz_core_rop_gadget_info(RzCore *core, const char *input, RzCmdStateOutput *state); -RZ_API bool analyze_constraint(RzCore *core, char *str, RzRopConstraint *rop_constraint); +RZ_API RzCmdStatus rz_core_rop_search(RzCore *core, RzRopSearchContext *context); +RZ_API RzCmdStatus rz_core_rop_gadget_info(RzCore *core, RzRopSearchContext *context); +RZ_API bool rz_core_rop_analyze_constraint(RzCore *core, const char *str, RzRopConstraint *rop_constraint); + +// ROP Search Context APIs +RZ_API RzRopSearchContext *rz_core_rop_search_context_new(const RzCore *core, const char *greparg, int regexp, RzRopRequestMask mask, RzCmdStateOutput *state); +RZ_API void rz_core_rop_search_context_free(RZ_NULLABLE RzRopSearchContext *context); // ROP Constraint APIs -RZ_API void rz_rop_constraint_free(RZ_NULLABLE void *data); +RZ_API void rz_core_rop_constraint_free(RZ_NULLABLE void *data); RZ_API RzList /**/ *rz_rop_constraint_list_new(void); +// ROP Gadget Info APIs +RZ_API void rz_core_rop_gadget_info_free(RzRopGadgetInfo *gadget_info); +RZ_API void rz_core_rop_gadget_info_add_register(RzRopGadgetInfo *gadget_info, RzRopRegInfo *reg_info, bool is_dependency); +RZ_API RzRopRegInfo *rz_core_rop_gadget_info_get_modified_register(RzRopGadgetInfo *gadget_info, const char *name); +RZ_API void rz_core_rop_gadget_info_update_register(RzRopGadgetInfo *gadget_info, RzRopRegInfo *new_reg_info); +RZ_API 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); + #endif // RZ_ROP_H diff --git a/test/unit/test_rop_constraint.c b/test/unit/test_rop_constraint.c index d274bdef730..b01462816a1 100644 --- a/test/unit/test_rop_constraint.c +++ b/test/unit/test_rop_constraint.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 z3phyr +// SPDX-FileCopyrightText: 2024 z3phyr // SPDX-License-Identifier: LGPL-3.0-only #include @@ -42,7 +42,7 @@ bool test_parse_reg_to_const(void) { // Test case 1: Valid register to constant char str1[] = " eax = 123 "; - mu_assert("parse_reg_to_const failed on valid input", analyze_constraint(core, str1, &rop_constraint)); + mu_assert("parse_reg_to_const failed on valid input", rz_core_rop_analyze_constraint(core, str1, &rop_constraint)); mu_assert_eq(strcmp(rop_constraint.args[DST_REG], "eax"), 0, "Invalid destination register"); mu_assert("Source register should be NULL", rop_constraint.args[SRC_REG] == NULL); mu_assert_eq(strcmp(rop_constraint.args[SRC_CONST], "123"), 0, "Invalid constant value"); @@ -52,7 +52,7 @@ bool test_parse_reg_to_const(void) { // Test case 2: Invalid format char str2[] = "eax ="; - mu_assert("parse_reg_to_const should fail on invalid input", !analyze_constraint(core, str2, &rop_constraint)); + mu_assert("parse_reg_to_const should fail on invalid input", !rz_core_rop_analyze_constraint(core, str2, &rop_constraint)); mu_end; } @@ -65,7 +65,7 @@ bool test_parse_reg_to_reg(void) { // Test case 1: Valid register to register char str1[] = "eax = ebx "; - mu_assert("parse_reg_to_reg failed on valid input", analyze_constraint(core, str1, &rop_constraint)); + mu_assert("parse_reg_to_reg failed on valid input", rz_core_rop_analyze_constraint(core, str1, &rop_constraint)); mu_assert_eq(strcmp(rop_constraint.args[DST_REG], "eax"), 0, "Invalid destination register"); mu_assert_eq(strcmp(rop_constraint.args[SRC_REG], "ebx"), 0, "Invalid source register"); @@ -74,7 +74,7 @@ bool test_parse_reg_to_reg(void) { // Test case 2: Invalid format char str2[] = "eax ="; - mu_assert("parse_reg_to_reg should fail on invalid input", !analyze_constraint(core, str2, &rop_constraint)); + mu_assert("parse_reg_to_reg should fail on invalid input", !rz_core_rop_analyze_constraint(core, str2, &rop_constraint)); mu_end; } @@ -87,7 +87,7 @@ bool test_parse_reg_op_const(void) { // Test case 1: Valid register operation with constant char str1[] = "eax=eax+3"; - mu_assert("parse_reg_op_const failed on valid input", analyze_constraint(core, str1, &rop_constraint)); + mu_assert("parse_reg_op_const failed on valid input", rz_core_rop_analyze_constraint(core, str1, &rop_constraint)); mu_assert_eq(strcmp(rop_constraint.args[DST_REG], "eax"), 0, "Invalid destination register"); mu_assert_eq(strcmp(rop_constraint.args[SRC_REG], "eax"), 0, "Invalid source register"); mu_assert_eq(strcmp(rop_constraint.args[OP], "add"), 0, "Invalid operator"); @@ -100,7 +100,7 @@ bool test_parse_reg_op_const(void) { // Test case 2: Invalid format char str2[] = "eax=eax+"; - mu_assert("parse_reg_op_const should fail on invalid input", !analyze_constraint(core, str2, &rop_constraint)); + mu_assert("parse_reg_op_const should fail on invalid input", !rz_core_rop_analyze_constraint(core, str2, &rop_constraint)); mu_end; } @@ -113,7 +113,7 @@ bool test_parse_reg_op_reg(void) { // Test case 1: Valid register operation with register char str1[] = "eax=eax-ebx"; - mu_assert("parse_reg_op_reg failed on valid input", analyze_constraint(core, str1, &rop_constraint)); + mu_assert("parse_reg_op_reg failed on valid input", rz_core_rop_analyze_constraint(core, str1, &rop_constraint)); mu_assert_eq(strcmp(rop_constraint.args[DST_REG], "eax"), 0, "Invalid destination register"); mu_assert_eq(strcmp(rop_constraint.args[SRC_REG], "eax"), 0, "Invalid source register"); mu_assert_eq(strcmp(rop_constraint.args[OP], "sub"), 0, "Invalid operator"); @@ -126,7 +126,7 @@ bool test_parse_reg_op_reg(void) { // Test case 2: Invalid format char str2[] = "eax = eax+ "; - mu_assert("parse_reg_op_reg should fail on invalid input", !analyze_constraint(core, str2, &rop_constraint)); + mu_assert("parse_reg_op_reg should fail on invalid input", !rz_core_rop_analyze_constraint(core, str2, &rop_constraint)); mu_end; } From 070cbab992320959f7105402a7005ccc1129d3c4 Mon Sep 17 00:00:00 2001 From: Giridhar Prasath R Date: Sat, 6 Jul 2024 19:31:10 -0400 Subject: [PATCH 18/30] Final refactoring and test case --- librz/core/cmd/cmd_search_rop.c | 15 +- librz/core/project_migrate.c | 24 ++- librz/core/rop.c | 199 ++++++++++++++++++++---- librz/include/rz_project.h | 2 +- test/db/cmd/project | 1 + test/integration/test_project_migrate.c | 9 ++ test/prj/v17-rop-config.rzdb | 81 ++++++++++ 7 files changed, 290 insertions(+), 41 deletions(-) create mode 100644 test/prj/v17-rop-config.rzdb diff --git a/librz/core/cmd/cmd_search_rop.c b/librz/core/cmd/cmd_search_rop.c index 2aacd8a0a92..995e5646f78 100644 --- a/librz/core/cmd/cmd_search_rop.c +++ b/librz/core/cmd/cmd_search_rop.c @@ -10,7 +10,7 @@ static void skip_whitespace(const char *str, ut64 *idx) { while (IS_WHITECHAR(str[*idx])) { - (*idx)++; + (*idx)++; } } @@ -56,25 +56,26 @@ static char *parse_register(const RzCore *core, const char *str, ut64 *idx) { static bool parse_constant(const char *str, RZ_NONNULL ut64 *idx, unsigned long long *value) { rz_return_val_if_fail(idx, false); - int base = 10; int neg = 0; - char num_str[256] = { 0 }; - int num_idx = 0; + int len = strlen(str); skip_whitespace(str, idx); - if (str[*idx] == '-') { + if (*idx < len && str[*idx] == '-') { neg = 1; (*idx)++; } skip_whitespace(str, idx); - if (str[*idx] == '0' && (str[*idx + 1] == 'x' || str[*idx + 1] == 'X')) { + int base = 10; + if (*idx + 1 < len && str[*idx] == '0' && (str[*idx + 1] == 'x' || str[*idx + 1] == 'X')) { base = 16; *idx += 2; } + int num_idx = 0; + char num_str[256] = { 0 }; while (isdigit(str[*idx]) || (base == 16 && isxdigit(str[*idx]))) { num_str[num_idx++] = str[*idx]; (*idx)++; @@ -104,7 +105,7 @@ static bool parse_reg_to_const(const RzCore *core, const char *str, RzRopConstra return false; } - unsigned long long const_value; + ut64 const_value; if (!parse_constant(str, &idx, &const_value)) { free(dst_reg); return false; diff --git a/librz/core/project_migrate.c b/librz/core/project_migrate.c index 4517ceb4c81..8cd8ff84f20 100644 --- a/librz/core/project_migrate.c +++ b/librz/core/project_migrate.c @@ -656,6 +656,27 @@ RZ_API bool rz_project_migrate_v16_v17(RzProject *prj, RzSerializeResultInfo *re return true; } +// -- +// Migration 17 -> 18 +// +// Changes from : +// Removed: +// - "rop.sdb" +// - "rop.db" +// Set: +// - "rop.cache" + +RZ_API bool rz_project_migrate_v17_v18(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_unset(config_db, "rop.sdb"); + sdb_unset(config_db, "rop.db"); + sdb_set(config_db, "rop.cache", false); + return true; +} + static bool (*const migrations[])(RzProject *prj, RzSerializeResultInfo *res) = { rz_project_migrate_v1_v2, rz_project_migrate_v2_v3, @@ -672,7 +693,8 @@ static bool (*const migrations[])(RzProject *prj, RzSerializeResultInfo *res) = rz_project_migrate_v13_v14, rz_project_migrate_v14_v15, rz_project_migrate_v15_v16, - rz_project_migrate_v16_v17 + rz_project_migrate_v16_v17, + rz_project_migrate_v17_v18 }; /// Migrate the given project to the current version in-place diff --git a/librz/core/rop.c b/librz/core/rop.c index 1a968abfbae..6d618fac5bf 100644 --- a/librz/core/rop.c +++ b/librz/core/rop.c @@ -49,9 +49,15 @@ static int rz_rop_process_asm_op(const RzCore *core, const RzCoreAsmHit *hit, Rz if (!buf) { return -1; } - rz_io_read_at(core->io, hit->addr, buf, hit->len); + if (rz_io_nread_at(core->io, hit->addr, buf, hit->len) < 0) { + free(buf); + return -1; + } rz_asm_set_pc(core->rasm, hit->addr); - rz_asm_disassemble(core->rasm, asmop, buf, hit->len); + if (rz_asm_disassemble(core->rasm, asmop, buf, hit->len) < 0) { + free(buf); + return -1; + } rz_analysis_op_init(aop); rz_analysis_op(core->analysis, aop, hit->addr, buf, hit->len, RZ_ANALYSIS_OP_MASK_DISASM); *size += hit->len; @@ -397,6 +403,7 @@ static void rz_rop_gadget_info_add_dependency(const RzCore *core, RzRopGadgetInf } rz_bv_free(init_val); rz_bv_free(new_val); + break; } default: @@ -412,7 +419,7 @@ static int fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadge } switch (event->type) { case RZ_IL_EVENT_VAR_READ: { - RzILEventVarRead *var_read = &event->data.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); if (reg_info && !is_dependency) { RzRopRegInfo *new_reg_info = rz_core_rop_reg_info_dup(reg_info); @@ -425,7 +432,7 @@ static int fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadge } 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_rop_reg_info_free(new_reg_info); rz_pvector_push(vec, event); rz_bv_free(val); break; @@ -460,7 +467,7 @@ static int fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadge RzILEvent *evt = rz_pvector_pop(vec); fill_rop_gadget_info_from_events(core, gadget_info, event, evt, vec, true); } - RzILEventVarWrite *var_write = &event->data.var_write; + 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); @@ -469,14 +476,11 @@ static int fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadge } 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) { - rz_bv_free(old_val); - rz_bv_free(new_val); - break; + 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); } - 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; @@ -680,22 +684,159 @@ static int handle_rop_list(RzStrBuf *sb, const RzRopSearchContext *context, return 0; } -void handle_greparg(const RzRopSearchContext *context, char **grep_str, int *count, const RzList *rx_list) { - char *start = context->greparg; - char *end = strchr(context->greparg, ';'); - if (!end) { // We filter on a single opcode, so no ";" - end = start + strlen(context->greparg); - } - *grep_str = calloc(1, end - start + 1); - if (*grep_str) { - strncpy(*grep_str, start, end - start); +static void init_grep_context(const RzRopSearchContext *context, char **grep_str, + const char **start, const char **end, const RzList /**/ *rx_list, char **rx, int *count) { + if (context->greparg) { + *start = context->greparg; + *end = strchr(context->greparg, ';'); + if (!*end) { + *end = *start + strlen(context->greparg); } + *grep_str = calloc(1, *end - *start + 1); + strncpy(*grep_str, *start, *end - *start); if (context->regexp && rz_list_length(rx_list) > 0) { - //rx = rz_list_get_n(rx_list, (*count)++); + *rx = rz_list_get_n(rx_list, (*count)++); } + } +} + +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); + if (error < 0 || (aop->type == RZ_ANALYSIS_OP_TYPE_NOP && aop->size == 0)) { + return false; + } + if (is_end_gadget(aop, 0)) { + (*end_gadget_cnt)++; + } + return true; } +static bool is_invalid_instruction(const char *opst, const int end_gadget_cnt) { + return !rz_str_ncasecmp(opst, "invalid", strlen("invalid")) || + !rz_str_ncasecmp(opst, ".byte", strlen(".byte")) || + end_gadget_cnt > 1; +} +static void update_search_context(const RzRopSearchContext *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 ; + *end = strchr(*start, ';'); + if (!*end) { + *end = *start + strlen(*start); // latest field? + } + free(*grep_str); + *grep_str = calloc(1, *end - *start + 1); + if (*grep_str) { + strncpy(*grep_str, *start, *end - *start); + } + } else { + *end = NULL; + } + + if (context->regexp) { + *rx = rz_list_get_n(rx_list, (*count)++); + } +} + +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); + + RzList *hitlist = rz_core_asm_hit_list_new(); + if (!hitlist) { + goto cleanup; + } + + ut8 nb_instr = 0; + int addr = context->from + idx; + int delta = context->to - context->from; + ut32 end_gadget_cnt = 0; + + RzAnalysisOp aop = { 0 }; + 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)) { + valid = false; + goto cleanup; + } + + char *opst = aop.mnemonic; + RzAsmOp asmop = RZ_EMPTY; + int ret = rz_asm_disassemble(core->rasm, &asmop, buf + idx, delta - idx) < 0; + if (ret < 0) { + valid = false; + goto cleanup; + } + + if (is_invalid_instruction(opst, end_gadget_cnt)) { + valid = false; + goto cleanup; + } + + hit = rz_core_asm_hit_new(); + if (!hit) { + valid = false; + goto cleanup; + } + + hit->addr = addr; + hit->len = aop.size; + 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); + if (ret >= 0) { + rz_asm_op_fini(&asmop); + } + idx += aop.size; + addr += aop.size; + + bool search_hit = false; + 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 { + 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; + goto cleanup; + } + rz_analysis_op_fini(&aop); + nb_instr++; + } + +cleanup: + rz_analysis_op_fini(&aop); + free(grep_str); + if ((context->regexp && rx) || (!valid || (context->greparg && end))) { + rz_list_free(hitlist); + rz_strbuf_free(sb); + return NULL; + } + if (handle_rop_list(sb, context, end_gadget, hitlist) < 0) { + rz_strbuf_free(sb); + return NULL; + } + rz_strbuf_free(sb); + return hitlist; +} +// #endif +#if 0 // TODO: follow unconditional jumps static RzList /**/ *construct_rop_gadget(RzCore *core, ut8 *buf, int idx, RzRopSearchContext *context, RzList /**/ *rx_list, RzRopEndListPair *end_gadget) { @@ -772,8 +913,6 @@ static RzList /**/ *construct_rop_gadget(RzCore *core, ut8 *buf, hit = rz_core_asm_hit_new(); if (hit) { - hit->addr = addr; - hit->len = opsz; char *asm_op_hex = rz_asm_op_get_hex(&asmop); rz_strbuf_append(sb, asm_op_hex); free(asm_op_hex); @@ -821,16 +960,12 @@ static RzList /**/ *construct_rop_gadget(RzCore *core, ut8 *buf, ret: rz_analysis_op_fini(&aop); free(grep_str); - if (context->regexp && rx) { - rz_list_free(hitlist); - rz_strbuf_free(sb); - return NULL; - } - if (!valid || (context->greparg && end)) { + if ((context->regexp && rx) || (!valid || (context->greparg && end))) { rz_list_free(hitlist); rz_strbuf_free(sb); return NULL; } + if (handle_rop_list(sb, context, end_gadget, hitlist) < 0) { rz_strbuf_free(sb); return NULL; @@ -838,6 +973,7 @@ static RzList /**/ *construct_rop_gadget(RzCore *core, ut8 *buf, rz_strbuf_free(sb); return hitlist; } +#endif static int handle_rop_request_type(RzCore *core, RzRopSearchContext *context, RzList /**/ *hitlist) { rz_return_val_if_fail(core && core->analysis, -1); @@ -856,7 +992,6 @@ static int handle_rop_request_type(RzCore *core, RzRopSearchContext *context, Rz } RzRopGadgetInfo *rop_gadget_info = NULL; - if (context->mask & RZ_ROP_GADGET_ANALYZE) { RzListIter *iter; RzCoreAsmHit *hit; @@ -1122,9 +1257,9 @@ RZ_API RzCmdStatus rz_core_rop_search(RzCore *core, RZ_OWN RzRopSearchContext *c RzRopEndListPair *end_gadget = rz_list_pop(context->end_list); // Start at just before the first end gadget. const int next = end_gadget->instr_offset; - const int prev = 0; for (int i = 0; i < delta && context->max_count; i += context->increment) { // TODO: Test this and check if this line is needed in x86 + const int prev = 0; if (context->increment == 1 && i < prev - max_inst_size_x86) { i = prev - max_inst_size_x86; } else if (context->increment != 1 && i < prev) { diff --git a/librz/include/rz_project.h b/librz/include/rz_project.h index b5d02cd6167..fb1fea532d5 100644 --- a/librz/include/rz_project.h +++ b/librz/include/rz_project.h @@ -12,7 +12,7 @@ extern "C" { #endif -#define RZ_PROJECT_VERSION 17 +#define RZ_PROJECT_VERSION 18 typedef Sdb RzProject; diff --git a/test/db/cmd/project b/test/db/cmd/project index 8ffef6e5ddb..354c282dbbe 100644 --- a/test/db/cmd/project +++ b/test/db/cmd/project @@ -375,6 +375,7 @@ Detailed project load info: project migrated from version 14 to 15. project migrated from version 15 to 16. project migrated from version 16 to 17. + project migrated from version 17 to 18. EOF RUN diff --git a/test/integration/test_project_migrate.c b/test/integration/test_project_migrate.c index 81923664ee6..2fa54505130 100644 --- a/test/integration/test_project_migrate.c +++ b/test/integration/test_project_migrate.c @@ -978,6 +978,14 @@ static bool test_load_v16() { mu_end; } +static bool test_load_v17() { + RzCore *core = rz_core_new(); + BEGIN_LOAD_TEST(core, 17, "prj/v17-rop-config.rzdb"); + mu_assert_eq(rz_config_get_i(core->config, "rop.cache"), false, "rop.cache"); + 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); @@ -1020,6 +1028,7 @@ int all_tests() { mu_run_test(test_load_v15_seek_history); mu_run_test(test_load_v15_str_config); mu_run_test(test_load_v16); + mu_run_test(test_load_v17); return tests_passed != tests_run; } diff --git a/test/prj/v17-rop-config.rzdb b/test/prj/v17-rop-config.rzdb new file mode 100644 index 00000000000..01d6bb7ce8f --- /dev/null +++ b/test/prj/v17-rop-config.rzdb @@ -0,0 +1,81 @@ +/ +type=rizin rz-db project +version=15 + +/core +blocksize=0x100 +offset=0x5ae0 + +/core/analysis + +/core/analysis/blocks + +/core/analysis/callables + +/core/analysis/cc + +/core/analysis/classes + +/core/analysis/classes/attrs + +/core/analysis/functions + +/core/analysis/hints + +/core/analysis/imports + +/core/analysis/meta + +/core/analysis/meta/spaces +name=CS +spacestack=["*"] + +/core/analysis/meta/spaces/spaces +bin=s + +/core/analysis/noreturn + +/core/analysis/types + +/core/analysis/vars + +/core/analysis/xrefs + +/core/config +rop.cache=false +rop.comments=false +rop.conditional=false +rop.len=5 +rop.subchains=false + +/core/debug + +/core/debug/breakpoints + +/core/file +relative=../bins/elf/ls + +/core/flags +base=0 +realnames=1 + +/core/flags/flags + +/core/flags/spaces +name=fs +spacestack=["*"] + +/core/flags/spaces/spaces +classes=s +relocs=s +sections=s +segments=s +strings=s +symbols=s + +/core/flags/tags + +/core/flags/zones + +/core/seek +0={"offset":23264,"cursor":0,"current":true} From 6cdd9bcfb4082f5c7cc3c1d97bd430317d83e672 Mon Sep 17 00:00:00 2001 From: Giridhar Prasath R Date: Sun, 7 Jul 2024 15:12:40 -0400 Subject: [PATCH 19/30] Refactoring and doxygen fixes --- librz/core/cmd/cmd_search.c | 8 +- librz/core/cmd/cmd_search_rop.c | 29 ++- librz/core/rop.c | 228 +++++++----------------- librz/include/rz_project.h | 1 + librz/include/rz_rop.h | 18 +- test/db/analysis/avr | 24 +++ test/db/cmd/cmd_rop | 118 ++++++++++-- test/db/cmd/cmd_search | 39 ++++ test/integration/test_project_migrate.c | 18 ++ test/prj/v17-rop-config.rzdb | 2 +- 10 files changed, 290 insertions(+), 195 deletions(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index f17b6005e2a..0f5a03bf8bb 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -225,7 +225,7 @@ RZ_IPI RzCmdStatus rz_cmd_info_gadget_handler(RzCore *core, int argc, const char return RZ_CMD_STATUS_ERROR; } - RzRopSearchContext *context = rz_core_rop_search_context_new(core, argv[1], 0, RZ_ROP_GADGET_PRINT, state); + RzRopSearchContext *context = rz_core_rop_search_context_new(core, argv[1], false, RZ_ROP_GADGET_PRINT, state); return rz_core_rop_gadget_info(core, context); } @@ -239,7 +239,7 @@ 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, argv[1], 1, RZ_ROP_GADGET_PRINT, state); + 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); return cmd_status; @@ -250,14 +250,14 @@ 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, 1, RZ_ROP_GADGET_PRINT, state); + RzRopSearchContext *context = rz_core_rop_search_context_new(core, input, true, RZ_ROP_GADGET_PRINT, state); return rz_core_rop_search(core, context); } 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, 1, RZ_ROP_GADGET_PRINT_DETAIL | RZ_ROP_GADGET_ANALYZE, state); + RzRopSearchContext *context = rz_core_rop_search_context_new(core, input, true, RZ_ROP_GADGET_PRINT_DETAIL | RZ_ROP_GADGET_ANALYZE, state); return rz_core_rop_search(core, context); ; } diff --git a/librz/core/cmd/cmd_search_rop.c b/librz/core/cmd/cmd_search_rop.c index 995e5646f78..d35003ba0ae 100644 --- a/librz/core/cmd/cmd_search_rop.c +++ b/librz/core/cmd/cmd_search_rop.c @@ -270,14 +270,29 @@ static bool parse_reg_op_const(const RzCore *core, const char *str, RzRopConstra char op_str[16]; rz_strf(op_str, "%" PFMT64u, const_value); - rop_constraint->args[OP] = strdup(op_str); + rop_constraint->args[SRC_CONST] = strdup(op_str); const char *value_str = rz_il_op_pure_code_stringify(*op); rop_constraint->args[OP] = rz_str_dup(value_str); return true; } -RZ_API RzRopSearchContext *rz_core_rop_search_context_new(const RzCore *core, const char *greparg, const int regexp, - const RzRopRequestMask mask, RzCmdStateOutput *state) { +/** + * \brief Create a new RzRopSearchContext 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 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. + * + * This function allocates and initializes a new RzRopSearchContext object. + */ +RZ_OWN RZ_API RzRopSearchContext *rz_core_rop_search_context_new(RZ_NONNULL const RzCore *core, RZ_NULLABLE const char *greparg, const bool regexp, + const RzRopRequestMask mask, RZ_BORROW RzCmdStateOutput *state) { + + rz_return_val_if_fail(core, NULL); + rz_return_val_if_fail(state, NULL); + RzRopSearchContext *context = RZ_NEW0(RzRopSearchContext); if (!context) { return NULL; @@ -300,12 +315,18 @@ RZ_API RzRopSearchContext *rz_core_rop_search_context_new(const RzCore *core, co return context; } +/** + * \brief Free an RzRopSearchContext object. + * \param context RZ_NULLABLE Pointer to the RzRopSearchContext object to free. + * + * Frees the memory allocated for an RzRopSearchContext object. + * Note: Other elements must be freed by the caller/callee. + */ RZ_API void rz_core_rop_search_context_free(RZ_NULLABLE RzRopSearchContext *context) { if (!context) { return; } - // Other elements have to be freed by the caller/callee. free(context->greparg); free(context); } diff --git a/librz/core/rop.c b/librz/core/rop.c index 6d618fac5bf..f6f6af37215 100644 --- a/librz/core/rop.c +++ b/librz/core/rop.c @@ -236,11 +236,19 @@ RZ_IPI RzRopRegInfo *rz_core_rop_reg_info_new(const RzCore *core, const RzILEven return reg_info; } -RZ_API RzRopGadgetInfo *rz_core_rop_gadget_info_new(const ut64 address) { +/** + * \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. + * + * This function allocates and initializes a new RzRopGadgetInfo 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); if (!gadget_info) { return NULL; } + gadget_info->address = address; gadget_info->stack_change = 0LL; gadget_info->curr_pc_val = address; @@ -248,35 +256,54 @@ RZ_API RzRopGadgetInfo *rz_core_rop_gadget_info_new(const ut64 address) { 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); + return gadget_info; } -RZ_API void rz_core_rop_gadget_info_free(RzRopGadgetInfo *gadget_info) { - if (!gadget_info) { - return; - } +/** + * \brief Free an RzRopGadgetInfo object. + * \param gadget_info RZ_NULLABLE Pointer to the RzRopGadgetInfo object to free. + * + * Frees the memory allocated for an RzRopGadgetInfo object, including its modified registers and dependencies. + */ +RZ_API void rz_core_rop_gadget_info_free(RZ_NULLABLE RzRopGadgetInfo *gadget_info) { + rz_return_if_fail(gadget_info); + rz_pvector_free(gadget_info->modified_registers); rz_list_free(gadget_info->dependencies); free(gadget_info); } -RZ_API void rz_core_rop_gadget_info_add_register(RzRopGadgetInfo *gadget_info, RzRopRegInfo *reg_info, const bool is_dependency) { - if (!gadget_info || !reg_info) { - return; - } +/** + * \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. + * \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. + */ +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); + if (!is_dependency) { rz_pvector_push(gadget_info->modified_registers, reg_info); } } -RZ_API RzRopRegInfo *rz_core_rop_gadget_info_get_modified_register(RzRopGadgetInfo *gadget_info, const char *name) { - if (!gadget_info) { - return NULL; - } - RzRopRegInfo *reg_info; +/** + * \brief Get the modified register info by name. + * \param gadget_info RZ_NONNULL Pointer to the RzRopGadgetInfo 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. + * + * Searches the modified registers in the RzRopGadgetInfo object for the register with the given name and returns its info. + */ +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_return_val_if_fail(gadget_info && name, NULL); void **it; - rz_pvector_foreach (gadget_info->modified_registers, it) { - reg_info = *it; + rz_pvector_foreach(gadget_info->modified_registers, it) { + RzRopRegInfo *reg_info = *it; if (RZ_STR_EQ(reg_info->name, name)) { return reg_info; } @@ -284,10 +311,18 @@ RZ_API RzRopRegInfo *rz_core_rop_gadget_info_get_modified_register(RzRopGadgetIn return NULL; } -RZ_API void rz_core_rop_gadget_info_update_register(RzRopGadgetInfo *gadget_info, RzRopRegInfo *new_reg_info) { - if (!gadget_info || !new_reg_info) { - return; - } +/** + * \brief Update a register info in the RzRopGadgetInfo object. + * \param gadget_info RZ_INOUT Pointer to the RzRopGadgetInfo object. + * \param new_reg_info RZ_NONNULL Pointer to the new RzRopRegInfo object. + * \return 0 on success, -1 on failure. + * + * Updates the register info in the RzRopGadgetInfo 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 int rz_core_rop_gadget_info_update_register(RZ_INOUT RzRopGadgetInfo *gadget_info, RZ_NONNULL RzRopRegInfo *new_reg_info) { + rz_return_val_if_fail(gadget_info, -1); + rz_return_val_if_fail(new_reg_info, -1); RzRopRegInfo *existing_reg_info = rz_core_rop_gadget_info_get_modified_register(gadget_info, new_reg_info->name); if (existing_reg_info) { @@ -300,12 +335,11 @@ RZ_API void rz_core_rop_gadget_info_update_register(RzRopGadgetInfo *gadget_info } else { rz_pvector_push(gadget_info->modified_registers, new_reg_info); } + return 0; } RZ_IPI RzRopRegInfo *rz_core_rop_reg_info_dup(RzRopRegInfo *src) { - if (!src) { - return NULL; - } + rz_return_val_if_fail(src, NULL); RzRopRegInfo *dup = RZ_NEW0(RzRopRegInfo); if (!dup) { @@ -359,9 +393,6 @@ static bool is_base_pointer(const RzCore *core, const char *name) { } static void rz_rop_gadget_info_add_dependency(const RzCore *core, RzRopGadgetInfo *gadget_info, const RzILEvent *evt, RzRopRegInfo *reg_info) { - if (!gadget_info || !reg_info) { - return; - } RzRopRegInfo *reg_info_dup = rz_core_rop_reg_info_dup(reg_info); if (!reg_info_dup) { @@ -431,7 +462,9 @@ static int fill_rop_gadget_info_from_events(RzCore *core, RzRopGadgetInfo *gadge break; } new_reg_info->new_val = rz_bv_to_ut64(val); - rz_core_rop_gadget_info_update_register(gadget_info, new_reg_info); + if (rz_core_rop_gadget_info_update_register(gadget_info, new_reg_info) < 0) { + break; + } rz_core_rop_reg_info_free(new_reg_info); rz_pvector_push(vec, event); rz_bv_free(val); @@ -835,145 +868,6 @@ static RzList *construct_rop_gadget(RzCore *core, ut8 *buf, int idx, RzRopSearch rz_strbuf_free(sb); return hitlist; } -// #endif -#if 0 -// TODO: follow unconditional jumps -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; - RzAnalysisOp aop = { 0 }; - const char *start = NULL, *end = NULL; - char *grep_str = NULL; - RzCoreAsmHit *hit = NULL; - bool valid = false; - int grep_find; - int search_hit; - char *rx = NULL; - int count = 0; - - RzStrBuf *sb = rz_strbuf_new(""); - if (context->greparg) { - //handle_greparg(context, &grep_str, &count, rx_list); - start = context->greparg; - end = strchr(context->greparg, ';'); - if (!end) { // We filter on a single opcode, so no ";" - end = start + strlen(context->greparg); - } - grep_str = calloc(1, end - start + 1); - strncpy(grep_str, start, end - start); - if (context->regexp) { - // get the first regexp. - if (rz_list_length(rx_list) > 0) { - rx = rz_list_get_n(rx_list, count++); - } - } - } - - ut32 end_gadget_cnt = 0; - RzList *hitlist = rz_core_asm_hit_list_new(); - if (!hitlist) { - goto ret; - } - ut8 nb_instr = 0; - int addr = context->from + idx; - int delta = context->to - context->from; - while (nb_instr < context->max_instr) { - rz_analysis_op_init(&aop); - if (idx >= delta) { - valid = false; - goto ret; - } - int error = rz_analysis_op(core->analysis, &aop, addr, buf + idx, delta - idx, RZ_ANALYSIS_OP_MASK_DISASM); - if (error < 0 || (nb_instr == 0 && aop.type == RZ_ANALYSIS_OP_TYPE_NOP)) { - valid = false; - goto ret; - } - - if (is_end_gadget(&aop, 0)) { - end_gadget_cnt++; - } - const int opsz = aop.size; - char *opst = aop.mnemonic; - RzAsmOp asmop = RZ_EMPTY; - int asm_ret = rz_asm_disassemble(core->rasm, &asmop, buf + idx, delta - idx); - if (!opst) { - RZ_LOG_WARN("Analysis plugin %s did not return disassembly\n", core->analysis->cur->name); - rz_asm_set_pc(core->rasm, addr); - if (asm_ret < 0) { - valid = false; - goto ret; - } - opst = strdup(rz_asm_op_get_asm(&asmop)); - } - if (!rz_str_ncasecmp(opst, "invalid", strlen("invalid")) || - !rz_str_ncasecmp(opst, ".byte", strlen(".byte")) || end_gadget_cnt > 1) { - valid = false; - goto ret; - } - - hit = rz_core_asm_hit_new(); - if (hit) { - 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); - } - if (asm_ret >= 0) { - rz_asm_op_fini(&asmop); - } - - // Move on to the next instruction - idx += opsz; - addr += opsz; - if (rx) { - 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 { - search_hit = end && context->greparg && strstr(opst, grep_str); - } - - // Handle (possible) grep - if (search_hit) { - if (end[0] == ';') { // fields are semicolon-separated - start = end + 1; // skip the ; - end = strchr(start, ';'); - end = end ? end : start + strlen(start); // latest field? - free(grep_str); - grep_str = calloc(1, end - start + 1); - if (grep_str) { - strncpy(grep_str, start, end - start); - } - } else { - end = NULL; - } - if (context->regexp) { - rx = rz_list_get_n(rx_list, count++); - } - } - if (endaddr <= idx - opsz) { - valid = endaddr == idx - opsz; - goto ret; - } - rz_analysis_op_fini(&aop); - nb_instr++; - } -ret: - rz_analysis_op_fini(&aop); - free(grep_str); - if ((context->regexp && rx) || (!valid || (context->greparg && end))) { - rz_list_free(hitlist); - rz_strbuf_free(sb); - return NULL; - } - - if (handle_rop_list(sb, context, end_gadget, hitlist) < 0) { - rz_strbuf_free(sb); - return NULL; - } - rz_strbuf_free(sb); - return hitlist; -} -#endif static int handle_rop_request_type(RzCore *core, RzRopSearchContext *context, RzList /**/ *hitlist) { rz_return_val_if_fail(core && core->analysis, -1); @@ -1335,7 +1229,7 @@ RZ_API void rz_core_rop_constraint_free(RZ_NULLABLE void *data) { * * Creates a new RzList for RzRopConstraint object. */ -RZ_API RzList /**/ *rz_rop_constraint_list_new(void) { +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; diff --git a/librz/include/rz_project.h b/librz/include/rz_project.h index fb1fea532d5..5b1463c8ecb 100644 --- a/librz/include/rz_project.h +++ b/librz/include/rz_project.h @@ -62,6 +62,7 @@ RZ_API bool rz_project_migrate_v13_v14(RzProject *prj, RzSerializeResultInfo *re RZ_API bool rz_project_migrate_v14_v15(RzProject *prj, RzSerializeResultInfo *res); RZ_API bool rz_project_migrate_v15_v16(RzProject *prj, RzSerializeResultInfo *res); RZ_API bool rz_project_migrate_v16_v17(RzProject *prj, RzSerializeResultInfo *res); + RZ_API bool rz_project_migrate_v17_v18(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 index 6e89f851704..be3c35f1b53 100644 --- a/librz/include/rz_rop.h +++ b/librz/include/rz_rop.h @@ -97,7 +97,7 @@ typedef struct rz_rop_search_context_t { ut8 subchain; ut8 crop; char *greparg; - int regexp; + bool regexp; int max_count; int increment; RzRopRequestMask mask; @@ -114,21 +114,23 @@ RZ_API RzCmdStatus rz_core_rop_gadget_info(RzCore *core, RzRopSearchContext *con RZ_API bool rz_core_rop_analyze_constraint(RzCore *core, const char *str, RzRopConstraint *rop_constraint); // ROP Search Context APIs -RZ_API RzRopSearchContext *rz_core_rop_search_context_new(const RzCore *core, const char *greparg, int regexp, RzRopRequestMask mask, RzCmdStateOutput *state); +RZ_OWN RZ_API RzRopSearchContext *rz_core_rop_search_context_new(RZ_NONNULL const RzCore *core, RZ_NULLABLE const char *greparg, + bool regexp, RzRopRequestMask mask, 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 RzList /**/ *rz_rop_constraint_list_new(void); +RZ_OWN RZ_API RzList /**/ *rz_rop_constraint_list_new(void); // ROP Gadget Info APIs -RZ_API void rz_core_rop_gadget_info_free(RzRopGadgetInfo *gadget_info); -RZ_API void rz_core_rop_gadget_info_add_register(RzRopGadgetInfo *gadget_info, RzRopRegInfo *reg_info, bool is_dependency); -RZ_API RzRopRegInfo *rz_core_rop_gadget_info_get_modified_register(RzRopGadgetInfo *gadget_info, const char *name); -RZ_API void rz_core_rop_gadget_info_update_register(RzRopGadgetInfo *gadget_info, RzRopRegInfo *new_reg_info); -RZ_API RzRopGadgetInfo *rz_core_rop_gadget_info_new(ut64 address); +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 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); #endif // RZ_ROP_H diff --git a/test/db/analysis/avr b/test/db/analysis/avr index e5948a1ece0..d782a3808d3 100644 --- a/test/db/analysis/avr +++ b/test/db/analysis/avr @@ -552,6 +552,12 @@ EXPECT=< Date: Sun, 7 Jul 2024 18:41:44 -0400 Subject: [PATCH 20/30] Migration test fix --- librz/core/project_migrate.c | 2 +- librz/core/rop.c | 12 ++++++------ librz/include/rz_rop.h | 4 ++-- test/prj/v17-rop-config.rzdb | 3 ++- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/librz/core/project_migrate.c b/librz/core/project_migrate.c index 8cd8ff84f20..7547725d386 100644 --- a/librz/core/project_migrate.c +++ b/librz/core/project_migrate.c @@ -694,7 +694,7 @@ static bool (*const migrations[])(RzProject *prj, RzSerializeResultInfo *res) = rz_project_migrate_v14_v15, rz_project_migrate_v15_v16, rz_project_migrate_v16_v17, - rz_project_migrate_v17_v18 + rz_project_migrate_v17_v18, }; /// Migrate the given project to the current version in-place diff --git a/librz/core/rop.c b/librz/core/rop.c index f6f6af37215..ac9071d75f7 100644 --- a/librz/core/rop.c +++ b/librz/core/rop.c @@ -695,7 +695,7 @@ static int print_rop(const RzCore *core, const RzList /**/ *hitl } static int handle_rop_list(RzStrBuf *sb, const RzRopSearchContext *context, - const RzRopEndListPair *end_gadget, RZ_OWN RzList *hitlist) { + const RzRopEndListPair *end_gadget, RZ_OWN RzList /**/ *hitlist) { rz_return_val_if_fail(sb && context && context->unique_hitlists, -1); if (end_gadget->delay_size && rz_list_length(hitlist) < 1 + end_gadget->delay_size) { rz_list_free(hitlist); @@ -931,8 +931,8 @@ static int fetch_search_itv(const RzCore *core, RzInterval *search_itv) { return 0; } -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 RzRopSearchContext *context) { + RzList /**/ *end_list = rz_list_newf(free); const int delta = context->to - context->from; for (int i = 0; i < delta; i += context->increment) { @@ -971,8 +971,8 @@ 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) { +static RzList /**/ *handle_grep_args(const char *greparg, const bool regexp) { + if (!greparg && !regexp) { return NULL; } @@ -1006,7 +1006,7 @@ static RzList * /**/ handle_grep_args(const char *greparg, const bool re } static bool process_disassembly(RzCore *core, ut8 *buf, const int idx, RzRopSearchContext *context, - RzList *rx_list, RzRopEndListPair *end_gadget) { + RzList /**/ *rx_list, RzRopEndListPair *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); diff --git a/librz/include/rz_rop.h b/librz/include/rz_rop.h index be3c35f1b53..f0ac171943f 100644 --- a/librz/include/rz_rop.h +++ b/librz/include/rz_rop.h @@ -104,12 +104,12 @@ typedef struct rz_rop_search_context_t { RzCmdStateOutput *state; ut64 from; ut64 to; - RzList /* */ *end_list; + RzList /**/ *end_list; HtSU *unique_hitlists; } RzRopSearchContext; // Command APIs -RZ_API RzCmdStatus rz_core_rop_search(RzCore *core, RzRopSearchContext *context); +RZ_API RzCmdStatus rz_core_rop_search(RzCore *core, RZ_OWN RzRopSearchContext *context); RZ_API RzCmdStatus rz_core_rop_gadget_info(RzCore *core, RzRopSearchContext *context); RZ_API bool rz_core_rop_analyze_constraint(RzCore *core, const char *str, RzRopConstraint *rop_constraint); diff --git a/test/prj/v17-rop-config.rzdb b/test/prj/v17-rop-config.rzdb index b3f00a383c9..41c4e0a26f7 100644 --- a/test/prj/v17-rop-config.rzdb +++ b/test/prj/v17-rop-config.rzdb @@ -42,7 +42,8 @@ bin=s /core/analysis/xrefs /core/config -rop.cache=false +rop.sdb=false +rop.db=false rop.comments=false rop.conditional=false rop.len=5 From 5993781e22a936356dffde68f48d10a3d029a6bc Mon Sep 17 00:00:00 2001 From: Giridhar Prasath R Date: Sun, 7 Jul 2024 19:51:04 -0400 Subject: [PATCH 21/30] Fix migration intergration issues --- librz/core/cmd/cmd_search.c | 2 +- librz/core/project_migrate.c | 2 +- librz/core/rop.c | 4 ++-- test/integration/test_project_migrate.c | 2 +- test/prj/v15-seek-history.rzdb | 2 +- test/prj/v15-str-config.rzdb | 2 +- test/prj/v16-flags-base.rzdb | 2 +- test/prj/v17-rop-config.rzdb | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index 0f5a03bf8bb..e0c0ab9f0de 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -259,7 +259,7 @@ RZ_IPI RzCmdStatus rz_cmd_detail_gadget_handler(RzCore *core, int argc, const ch RzRopSearchContext *context = rz_core_rop_search_context_new(core, input, true, 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/project_migrate.c b/librz/core/project_migrate.c index 7547725d386..9cbf4fe3ccc 100644 --- a/librz/core/project_migrate.c +++ b/librz/core/project_migrate.c @@ -673,7 +673,7 @@ RZ_API bool rz_project_migrate_v17_v18(RzProject *prj, RzSerializeResultInfo *re RZ_SERIALIZE_SUB(core_db, config_db, res, "config", return false;); sdb_unset(config_db, "rop.sdb"); sdb_unset(config_db, "rop.db"); - sdb_set(config_db, "rop.cache", false); + sdb_set(config_db, "rop.cache", "false"); return true; } diff --git a/librz/core/rop.c b/librz/core/rop.c index ac9071d75f7..2cfb758ebf9 100644 --- a/librz/core/rop.c +++ b/librz/core/rop.c @@ -283,7 +283,7 @@ RZ_API void rz_core_rop_gadget_info_free(RZ_NULLABLE RzRopGadgetInfo *gadget_inf * Adds the given register info to the modified registers of the RzRopGadgetInfo 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_NONNULL RzRopRegInfo *reg_info, const bool is_dependency) { rz_return_if_fail(gadget_info && reg_info); if (!is_dependency) { @@ -302,7 +302,7 @@ RZ_API void rz_core_rop_gadget_info_add_register(const RZ_NONNULL RZ_OUT RzRopGa 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_return_val_if_fail(gadget_info && name, NULL); void **it; - rz_pvector_foreach(gadget_info->modified_registers, it) { + rz_pvector_foreach (gadget_info->modified_registers, it) { RzRopRegInfo *reg_info = *it; if (RZ_STR_EQ(reg_info->name, name)) { return reg_info; diff --git a/test/integration/test_project_migrate.c b/test/integration/test_project_migrate.c index 640e5c7b4b4..5d93019483b 100644 --- a/test/integration/test_project_migrate.c +++ b/test/integration/test_project_migrate.c @@ -998,7 +998,7 @@ static bool test_load_v16() { static bool test_load_v17() { RzCore *core = rz_core_new(); BEGIN_LOAD_TEST(core, 17, "prj/v17-rop-config.rzdb"); - mu_assert_eq(rz_config_get_i(core->config, "rop.cache"), false, "rop.cache"); + mu_assert_eq(rz_config_get_b(core->config, "rop.cache"), false, "rop.cache"); rz_core_free(core); mu_end; } diff --git a/test/prj/v15-seek-history.rzdb b/test/prj/v15-seek-history.rzdb index 71fbd8c21f7..00feabc506b 100644 --- a/test/prj/v15-seek-history.rzdb +++ b/test/prj/v15-seek-history.rzdb @@ -55,7 +55,7 @@ prj.file=./test/prj/v15-seek-history.rzdb /core/debug/breakpoints /core/file -relative=../bins/elf/ls +relative=../bins/elf/crackme0x05 /core/flags base=0 diff --git a/test/prj/v15-str-config.rzdb b/test/prj/v15-str-config.rzdb index 00cecdd003f..b911293f4d6 100644 --- a/test/prj/v15-str-config.rzdb +++ b/test/prj/v15-str-config.rzdb @@ -74,7 +74,7 @@ bin.verbose=false /core/debug/breakpoints /core/file -relative=../bins/elf/ls +relative=../bins/elf/crackme0x05 /core/flags base=0 diff --git a/test/prj/v16-flags-base.rzdb b/test/prj/v16-flags-base.rzdb index 250a9a3de9b..5f5d3451508 100644 --- a/test/prj/v16-flags-base.rzdb +++ b/test/prj/v16-flags-base.rzdb @@ -48,7 +48,7 @@ bin=s /core/debug/breakpoints /core/file -relative=../bins/elf/ls +relative=../bins/elf/crackme0x05 /core/flags base=100 diff --git a/test/prj/v17-rop-config.rzdb b/test/prj/v17-rop-config.rzdb index 41c4e0a26f7..d855d3bca08 100644 --- a/test/prj/v17-rop-config.rzdb +++ b/test/prj/v17-rop-config.rzdb @@ -54,7 +54,7 @@ rop.subchains=false /core/debug/breakpoints /core/file -relative=../bins/elf/ls +relative=../bins/elf/crackme0x05 /core/flags base=0 From 51de827f1bf0bb3ef4b2f452910d03a954eaa06a Mon Sep 17 00:00:00 2001 From: Giridhar Prasath R Date: Sun, 7 Jul 2024 19:58:09 -0400 Subject: [PATCH 22/30] Linter fixes --- librz/core/rop.c | 4 ++-- librz/include/rz_rop.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/librz/core/rop.c b/librz/core/rop.c index 2cfb758ebf9..b1b426c9455 100644 --- a/librz/core/rop.c +++ b/librz/core/rop.c @@ -772,7 +772,7 @@ static void update_search_context(const RzRopSearchContext *context, const char } } -static RzList *construct_rop_gadget(RzCore *core, ut8 *buf, int idx, RzRopSearchContext *context, +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; @@ -931,7 +931,7 @@ static int fetch_search_itv(const RzCore *core, RzInterval *search_itv) { return 0; } -static RzList * /**/ compute_end_gadget_list(const RzCore *core, const ut8 *buf, const RzRopSearchContext *context) { +static RzList /**/ *compute_end_gadget_list(const RzCore *core, const ut8 *buf, const RzRopSearchContext *context) { RzList /**/ *end_list = rz_list_newf(free); const int delta = context->to - context->from; diff --git a/librz/include/rz_rop.h b/librz/include/rz_rop.h index f0ac171943f..c7787b32c91 100644 --- a/librz/include/rz_rop.h +++ b/librz/include/rz_rop.h @@ -110,12 +110,12 @@ typedef struct rz_rop_search_context_t { // 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, 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); // 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, - bool regexp, RzRopRequestMask mask, RZ_BORROW RzCmdStateOutput *state); + bool regexp, RzRopRequestMask mask, RZ_BORROW RzCmdStateOutput *state); RZ_API void rz_core_rop_search_context_free(RZ_NULLABLE RzRopSearchContext *context); // ROP Constraint APIs @@ -125,7 +125,7 @@ RZ_OWN RZ_API RzList /**/ *rz_rop_constraint_list_new(void); // 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_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); From bbfaaa380d5773729a7ca112d2227b99f7fd1ec6 Mon Sep 17 00:00:00 2001 From: Giridhar Prasath R Date: Sun, 7 Jul 2024 23:13:49 -0400 Subject: [PATCH 23/30] Linter fixes --- librz/include/rz_project.h | 2 +- test/.sync_disk_db | Bin 0 -> 1118 bytes test/prj/v15-seek-history.rzdb | 2 +- test/prj/v15-str-config.rzdb | 2 +- test/prj/v16-flags-base.rzdb | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 test/.sync_disk_db diff --git a/librz/include/rz_project.h b/librz/include/rz_project.h index 5b1463c8ecb..5fc61ae7b95 100644 --- a/librz/include/rz_project.h +++ b/librz/include/rz_project.h @@ -62,7 +62,7 @@ RZ_API bool rz_project_migrate_v13_v14(RzProject *prj, RzSerializeResultInfo *re RZ_API bool rz_project_migrate_v14_v15(RzProject *prj, RzSerializeResultInfo *res); RZ_API bool rz_project_migrate_v15_v16(RzProject *prj, RzSerializeResultInfo *res); RZ_API bool rz_project_migrate_v16_v17(RzProject *prj, RzSerializeResultInfo *res); - RZ_API bool rz_project_migrate_v17_v18(RzProject *prj, RzSerializeResultInfo *res); +RZ_API bool rz_project_migrate_v17_v18(RzProject *prj, RzSerializeResultInfo *res); RZ_API bool rz_project_migrate(RzProject *prj, unsigned long version, RzSerializeResultInfo *res); #ifdef __cplusplus diff --git a/test/.sync_disk_db b/test/.sync_disk_db new file mode 100644 index 0000000000000000000000000000000000000000..5b29d84cd1b5d6d0756117181848da6f6e4c2815 GIT binary patch literal 1118 zcmdO6VPMe1f$f0eqj)q7hI1P51Ez6eaU4+XaKkLD3=CEI`3y;^sc8(XKo1rdB<3=t zrl&KoaWOFDR%WMGGUTO}r{(7-B^EKj0God{mlRMj4D4Us&dmVipK`0L;YAV$0H9x4 A!2kdN literal 0 HcmV?d00001 diff --git a/test/prj/v15-seek-history.rzdb b/test/prj/v15-seek-history.rzdb index 00feabc506b..71fbd8c21f7 100644 --- a/test/prj/v15-seek-history.rzdb +++ b/test/prj/v15-seek-history.rzdb @@ -55,7 +55,7 @@ prj.file=./test/prj/v15-seek-history.rzdb /core/debug/breakpoints /core/file -relative=../bins/elf/crackme0x05 +relative=../bins/elf/ls /core/flags base=0 diff --git a/test/prj/v15-str-config.rzdb b/test/prj/v15-str-config.rzdb index b911293f4d6..00cecdd003f 100644 --- a/test/prj/v15-str-config.rzdb +++ b/test/prj/v15-str-config.rzdb @@ -74,7 +74,7 @@ bin.verbose=false /core/debug/breakpoints /core/file -relative=../bins/elf/crackme0x05 +relative=../bins/elf/ls /core/flags base=0 diff --git a/test/prj/v16-flags-base.rzdb b/test/prj/v16-flags-base.rzdb index 5f5d3451508..250a9a3de9b 100644 --- a/test/prj/v16-flags-base.rzdb +++ b/test/prj/v16-flags-base.rzdb @@ -48,7 +48,7 @@ bin=s /core/debug/breakpoints /core/file -relative=../bins/elf/crackme0x05 +relative=../bins/elf/ls /core/flags base=100 From 15cb8ed7a2eb2814e4eb23119ae6f8366b26fc32 Mon Sep 17 00:00:00 2001 From: Giridhar Prasath R Date: Sun, 7 Jul 2024 23:53:03 -0400 Subject: [PATCH 24/30] Ignore test sync db --- .gitignore | 1 + test/.sync_disk_db | Bin 1118 -> 0 bytes 2 files changed, 1 insertion(+) delete mode 100644 test/.sync_disk_db diff --git a/.gitignore b/.gitignore index 2447d8df650..1f44b3410a4 100644 --- a/.gitignore +++ b/.gitignore @@ -116,6 +116,7 @@ peda-session-* /.vs .cache/ test/.tmp/* +test/.sync_disk_db subprojects/capstone-*/ subprojects/pcre2*/ subprojects/libzip-*/ diff --git a/test/.sync_disk_db b/test/.sync_disk_db deleted file mode 100644 index 5b29d84cd1b5d6d0756117181848da6f6e4c2815..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1118 zcmdO6VPMe1f$f0eqj)q7hI1P51Ez6eaU4+XaKkLD3=CEI`3y;^sc8(XKo1rdB<3=t zrl&KoaWOFDR%WMGGUTO}r{(7-B^EKj0God{mlRMj4D4Us&dmVipK`0L;YAV$0H9x4 A!2kdN From 583406e9f372b90b89090380b361f2f5853d66e3 Mon Sep 17 00:00:00 2001 From: Giridhar Prasath R Date: Mon, 8 Jul 2024 21:02:59 -0400 Subject: [PATCH 25/30] Review fixes --- librz/core/rop.c | 54 ++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/librz/core/rop.c b/librz/core/rop.c index b1b426c9455..78bb850e4a2 100644 --- a/librz/core/rop.c +++ b/librz/core/rop.c @@ -44,19 +44,19 @@ static bool is_end_gadget(const RzAnalysisOp *aop, const ut8 crop) { } } -static int 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 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) { ut8 *buf = malloc(hit->len); if (!buf) { - return -1; + return false; } if (rz_io_nread_at(core->io, hit->addr, buf, hit->len) < 0) { free(buf); - return -1; + return false; } rz_asm_set_pc(core->rasm, hit->addr); if (rz_asm_disassemble(core->rasm, asmop, buf, hit->len) < 0) { free(buf); - return -1; + return false; } rz_analysis_op_init(aop); rz_analysis_op(core->analysis, aop, hit->addr, buf, hit->len, RZ_ANALYSIS_OP_MASK_DISASM); @@ -76,20 +76,20 @@ static int rz_rop_process_asm_op(const RzCore *core, const RzCoreAsmHit *hit, Rz } free(buf); - return 0; + return true; } -static int rz_rop_print_table_mode(const RzCore *core, const RzCoreAsmHit *hit, const RzList /**/ *hitlist, +static bool rz_rop_print_table_mode(const RzCore *core, const RzCoreAsmHit *hit, const RzList /**/ *hitlist, unsigned int *size, char **asmop_str, char **asmop_hex_str) { RzAnalysisOp aop = RZ_EMPTY; RzAsmOp *asmop = rz_asm_op_new(); if (!asmop) { - return -1; + return false; } - if (rz_rop_process_asm_op(core, hit, asmop, &aop, size, asmop_str, asmop_hex_str) != 0) { + if (!rz_rop_process_asm_op(core, hit, asmop, &aop, size, asmop_str, asmop_hex_str)) { rz_asm_op_free(asmop); - return -1; + return false; } const ut64 addr_last = ((RzCoreAsmHit *)rz_list_last(hitlist))->addr; if (addr_last != hit->addr) { @@ -97,19 +97,19 @@ static int rz_rop_print_table_mode(const RzCore *core, const RzCoreAsmHit *hit, } rz_asm_op_free(asmop); rz_analysis_op_fini(&aop); - return 0; + return true; } -static int rz_rop_print_quiet_mode(const RzCore *core, const RzCoreAsmHit *hit, unsigned int *size, const bool colorize) { +static bool rz_rop_print_quiet_mode(const RzCore *core, const RzCoreAsmHit *hit, unsigned int *size, const bool colorize) { RzAnalysisOp aop = RZ_EMPTY; RzAsmOp *asmop = rz_asm_op_new(); if (!asmop) { - return -1; + return false; } - if (rz_rop_process_asm_op(core, hit, asmop, &aop, size, NULL, NULL) != 0) { + if (!rz_rop_process_asm_op(core, hit, asmop, &aop, size, NULL, NULL)) { rz_asm_op_free(asmop); - return -1; + return false; } if (colorize) { RzStrBuf *bw_str = rz_strbuf_new(rz_asm_op_get_asm(asmop)); @@ -124,19 +124,19 @@ static int rz_rop_print_quiet_mode(const RzCore *core, const RzCoreAsmHit *hit, } rz_asm_op_free(asmop); rz_analysis_op_fini(&aop); - return 0; + return true; } -static int rz_rop_print_standard_mode(const RzCore *core, const RzCoreAsmHit *hit, +static bool rz_rop_print_standard_mode(const RzCore *core, const RzCoreAsmHit *hit, unsigned int *size, const bool rop_comments, const bool colorize) { RzAnalysisOp aop = RZ_EMPTY; RzAsmOp *asmop = rz_asm_op_new(); if (!asmop) { - return -1; + return false; } - if (rz_rop_process_asm_op(core, hit, asmop, &aop, size, NULL, NULL) != 0) { + if (!rz_rop_process_asm_op(core, hit, asmop, &aop, size, NULL, NULL)) { rz_asm_op_free(asmop); - return -1; + return false; } const char *comment = rop_comments ? rz_meta_get_string(core->analysis, RZ_META_TYPE_COMMENT, hit->addr) : NULL; char *asm_op_hex = rz_asm_op_get_hex(asmop); @@ -166,18 +166,18 @@ static int rz_rop_print_standard_mode(const RzCore *core, const RzCoreAsmHit *hi free(asm_op_hex); rz_analysis_op_fini(&aop); rz_asm_op_free(asmop); - return 0; + return true; } -static int rz_rop_print_json_mode(const RzCore *core, const RzCoreAsmHit *hit, unsigned int *size, PJ *pj) { +static bool rz_rop_print_json_mode(const RzCore *core, const RzCoreAsmHit *hit, unsigned int *size, PJ *pj) { RzAnalysisOp aop = RZ_EMPTY; RzAsmOp *asmop = rz_asm_op_new(); if (!asmop) { - return -1; + return false; } - if (rz_rop_process_asm_op(core, hit, asmop, &aop, size, NULL, NULL) != 0) { + if (!rz_rop_process_asm_op(core, hit, asmop, &aop, size, NULL, NULL)) { rz_asm_op_free(asmop); - return -1; + return false; } pj_o(pj); @@ -189,7 +189,7 @@ static int rz_rop_print_json_mode(const RzCore *core, const RzCoreAsmHit *hit, u rz_analysis_op_fini(&aop); rz_asm_op_free(asmop); - return 0; + return true; } RZ_IPI void rz_core_rop_reg_info_free(RzRopRegInfo *reg_info) { @@ -641,7 +641,7 @@ static int print_rop(const RzCore *core, const RzList /**/ *hitl } const ut64 addr = ((RzCoreAsmHit *)rz_list_first(hitlist))->addr; - int result = 0; + bool result = 0; rz_list_foreach (hitlist, iter, hit) { switch (state->mode) { case RZ_OUTPUT_MODE_JSON: @@ -660,7 +660,7 @@ static int print_rop(const RzCore *core, const RzList /**/ *hitl rz_warn_if_reached(); break; } - if (result != 0) { + if (!result) { return result; } } From 5314e3fc061040d21343036dcecbda701beb4874 Mon Sep 17 00:00:00 2001 From: Giridhar Prasath R Date: Tue, 9 Jul 2024 11:56:29 -0400 Subject: [PATCH 26/30] Review comment fixes --- librz/arch/analysis.c | 2 +- librz/core/cmd/cmd_search_rop.c | 6 ++---- librz/include/rz_rop.h | 7 ++++++- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/librz/arch/analysis.c b/librz/arch/analysis.c index 990497c256c..cc5814a4488 100644 --- a/librz/arch/analysis.c +++ b/librz/arch/analysis.c @@ -253,7 +253,7 @@ RZ_API char *rz_analysis_get_reg_profile(RzAnalysis *analysis) { * in the register profile of the given RzAnalysis. */ RZ_API bool rz_analysis_is_reg_in_profile(RzAnalysis *analysis, const char *str) { - rz_return_val_if_fail(analysis, false); + rz_return_val_if_fail(analysis && str, false); char *reg_prof = rz_analysis_get_reg_profile(analysis); if (!reg_prof) { diff --git a/librz/core/cmd/cmd_search_rop.c b/librz/core/cmd/cmd_search_rop.c index d35003ba0ae..3b1a7f13c43 100644 --- a/librz/core/cmd/cmd_search_rop.c +++ b/librz/core/cmd/cmd_search_rop.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2009-2016 Alexandru Caciulescu +// SPDX-FileCopyrightText: 2024 z3phyr // SPDX-License-Identifier: LGPL-3.0-only #include @@ -119,9 +119,7 @@ static bool parse_reg_to_const(const RzCore *core, const char *str, RzRopConstra rop_constraint->type = MOV_CONST; rop_constraint->args[DST_REG] = dst_reg; rop_constraint->args[SRC_REG] = NULL; - char value_str[256]; - rz_strf(value_str, "%" PFMT64u, const_value); - rop_constraint->args[SRC_CONST] = strdup(value_str); + rop_constraint->args[SRC_CONST] = rz_str_newf("%" PFMT64u, const_value); return true; } diff --git a/librz/include/rz_rop.h b/librz/include/rz_rop.h index c7787b32c91..a136c2e7a4c 100644 --- a/librz/include/rz_rop.h +++ b/librz/include/rz_rop.h @@ -5,7 +5,9 @@ #define RZ_ROP_H #include - +#ifdef __cplusplus +extern "C" { +#endif /** * \file rz_rop.h * \brief Return-Oriented Programming (ROP) related APIs and structures.. @@ -133,4 +135,7 @@ 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); +#ifdef __cplusplus +} +#endif #endif // RZ_ROP_H From e9d3fc772bf8bedb62f1ba61f8b08ba1134be6a4 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Wed, 10 Jul 2024 11:16:42 +0800 Subject: [PATCH 27/30] Moved around lines for readability --- librz/include/rz_rop.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/librz/include/rz_rop.h b/librz/include/rz_rop.h index a136c2e7a4c..4d1f7c61ee5 100644 --- a/librz/include/rz_rop.h +++ b/librz/include/rz_rop.h @@ -4,10 +4,6 @@ #ifndef RZ_ROP_H #define RZ_ROP_H -#include -#ifdef __cplusplus -extern "C" { -#endif /** * \file rz_rop.h * \brief Return-Oriented Programming (ROP) related APIs and structures.. @@ -15,6 +11,12 @@ extern "C" { * This file contains definitions, structures, and function prototypes for handling ROP gadgets and constraints. */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + /** * \brief Information about a register. */ From 69f5a30a3498669b05d91ca50816f4d1d0fe62fa Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Wed, 10 Jul 2024 11:17:46 +0800 Subject: [PATCH 28/30] Fixed copyright in librz/core/cmd/cmd_search_rop.c --- librz/core/cmd/cmd_search_rop.c | 1 + 1 file changed, 1 insertion(+) diff --git a/librz/core/cmd/cmd_search_rop.c b/librz/core/cmd/cmd_search_rop.c index 3b1a7f13c43..7b88c5f114b 100644 --- a/librz/core/cmd/cmd_search_rop.c +++ b/librz/core/cmd/cmd_search_rop.c @@ -1,4 +1,5 @@ // SPDX-FileCopyrightText: 2024 z3phyr +// SPDX-FileCopyrightText: 2009-2016 Alexandru Caciulescu // SPDX-License-Identifier: LGPL-3.0-only #include From bdb8efe27bb6728b212c2603adc9dbb36355fcc2 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Wed, 10 Jul 2024 11:20:06 +0800 Subject: [PATCH 29/30] Rename var in function librz/arch/analysis.c --- librz/arch/analysis.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/librz/arch/analysis.c b/librz/arch/analysis.c index cc5814a4488..8414332e76a 100644 --- a/librz/arch/analysis.c +++ b/librz/arch/analysis.c @@ -246,21 +246,21 @@ RZ_API char *rz_analysis_get_reg_profile(RzAnalysis *analysis) { /** * \brief Check if a register is in the analysis profile. * \param analysis Pointer to the RzAnalysis object. - * \param str The register name to check. + * \param name The register name to check. * \return true if the register name is found, false otherwise. * * This function checks if the given register name is present * in the register profile of the given RzAnalysis. */ -RZ_API bool rz_analysis_is_reg_in_profile(RzAnalysis *analysis, const char *str) { - rz_return_val_if_fail(analysis && str, false); +RZ_API bool rz_analysis_is_reg_in_profile(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL const char *name) { + rz_return_val_if_fail(analysis && name, false); char *reg_prof = rz_analysis_get_reg_profile(analysis); if (!reg_prof) { return false; } - if (strstr(reg_prof, str)) { + if (strstr(reg_prof, name)) { free(reg_prof); return true; } From 267adbeb1729b2aa9b2cf9f09a7d383fc698cb7d Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Wed, 10 Jul 2024 11:20:40 +0800 Subject: [PATCH 30/30] Fix definition in librz/include/rz_analysis.h --- librz/include/rz_analysis.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/librz/include/rz_analysis.h b/librz/include/rz_analysis.h index 17008e4975f..ffa34e46eb5 100644 --- a/librz/include/rz_analysis.h +++ b/librz/include/rz_analysis.h @@ -1574,7 +1574,7 @@ RZ_API int rz_analysis_archinfo(RzAnalysis *analysis, RzAnalysisInfoType query); RZ_API bool rz_analysis_use(RzAnalysis *analysis, const char *name); RZ_API bool rz_analysis_set_reg_profile(RzAnalysis *analysis); RZ_API char *rz_analysis_get_reg_profile(RzAnalysis *analysis); -RZ_API bool rz_analysis_is_reg_in_profile(RzAnalysis *analysis, const char *str); +RZ_API bool rz_analysis_is_reg_in_profile(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL const char *name); RZ_API bool rz_analysis_set_bits(RzAnalysis *analysis, int bits); RZ_API bool rz_analysis_set_os(RzAnalysis *analysis, const char *os); RZ_API void rz_analysis_set_cpu(RzAnalysis *analysis, const char *cpu);