Ropchain constraint syntax parser (#4552)

Co-authored-by: Giridhar Prasath R <giridh1337@gmail.com>
This commit is contained in:
z3phyr 2024-07-09 23:41:47 -05:00 committed by GitHub
parent e3d27c9316
commit c8d05054c1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 2516 additions and 1555 deletions

1
.gitignore vendored
View file

@ -116,6 +116,7 @@ peda-session-*
/.vs
.cache/
test/.tmp/*
test/.sync_disk_db
subprojects/capstone-*/
subprojects/pcre2*/
subprojects/libzip-*/

View file

@ -8,6 +8,7 @@
#include <rz_util/rz_path.h>
#include <rz_arch.h>
#include <rz_lib.h>
#include <rz_rop.h>
/**
* \brief Returns the default size byte width of memory access operations.
@ -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);
@ -240,6 +243,31 @@ 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 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(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, name)) {
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);

View file

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

View file

@ -1,12 +1,10 @@
// SPDX-FileCopyrightText: 2010-2021 pancake <pancake@nopcode.org>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_util/ht_uu.h>
#include <rz_asm.h>
#include <rz_core.h>
#include <rz_io.h>
#include <rz_list.h>
#include <rz_util/rz_regex.h>
#include <rz_types_base.h>
#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 /*<RzCoreAsmHit *>*/ *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,51 +225,24 @@ 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;
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);
}
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);
return RZ_CMD_STATUS_OK;
RzList /*<RzILOpPureCode *>*/ *constraints = rop_constraint_list_parse(core, argc, argv);
if (!constraints) {
return RZ_CMD_STATUS_ERROR;
}
if (rz_list_empty(constraints)) {
rz_list_free(constraints);
return RZ_CMD_STATUS_INVALID;
}
RzRopSearchContext *context = rz_core_rop_search_context_new(core, argv[1], false, RZ_ROP_GADGET_PRINT, state);
const RzCmdStatus cmd_status = rz_core_rop_search(core, context);
rz_list_free(constraints);
return cmd_status;
}
RZ_IPI RzCmdStatus rz_cmd_search_gadget_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
@ -288,8 +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, state);
return RZ_CMD_STATUS_OK;
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, 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) {
@ -1011,689 +981,6 @@ RZ_API RZ_OWN RzList /*<RzIOMap *>*/ *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 /*<RzCoreAsmHit *>*/ *construct_rop_gadget(RzCore *core, ut64 addr, ut8 *buf, int buflen, int idx, const char *grep, int regex, RzList /*<char *>*/ *rx_list, struct endlist_pair *end_gadget, HtUU *badstart) {
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);
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 /*<RzCoreAsmHit *>*/ *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);
}
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 /*<endlist_pair>*/ *end_list = rz_list_newf(free);
RzList /*<char *>*/ *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 + 32 < 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 = next - ropdepth; i < (delta - max_inst_size_x86) && 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);
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;
@ -2565,106 +1852,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++) {

File diff suppressed because it is too large Load diff

View file

@ -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 = " <key>[=<val>] [<key>[=<val>] ...]]",
.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 = true,
},
{ 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);

View file

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

View file

@ -36,7 +36,22 @@ 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:
- RZ_OUTPUT_MODE_STANDARD
- RZ_OUTPUT_MODE_JSON
- RZ_OUTPUT_MODE_QUIET
- RZ_OUTPUT_MODE_TABLE
args_str: " <key>[=<val>] [<key>[=<val>] ...]]"
args:
- 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:
@ -45,6 +60,6 @@ commands:
- RZ_OUTPUT_MODE_QUIET
- RZ_OUTPUT_MODE_TABLE
args:
- name: nop|mov|arithm
- name: Gadget address
type: RZ_CMD_ARG_TYPE_STRING
optional: false
optional: true

View file

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

View file

@ -656,6 +656,27 @@ RZ_API bool rz_project_migrate_v16_v17(RzProject *prj, RzSerializeResultInfo *re
return true;
}
// --
// Migration 17 -> 18
//
// Changes from <commit hash not yet known>:
// 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

1238
librz/core/rop.c Normal file

File diff suppressed because it is too large Load diff

View file

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

View file

@ -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..
@ -1573,6 +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(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);
@ -1886,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);

View file

@ -12,7 +12,7 @@
extern "C" {
#endif
#define RZ_PROJECT_VERSION 17
#define RZ_PROJECT_VERSION 18
typedef Sdb RzProject;
@ -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

143
librz/include/rz_rop.h Normal file
View file

@ -0,0 +1,143 @@
// SPDX-FileCopyrightText: 2024 z3phyr <giridh1337@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#ifndef RZ_ROP_H
#define RZ_ROP_H
/**
* \file rz_rop.h
* \brief Return-Oriented Programming (ROP) related APIs and structures..
*
* This file contains definitions, structures, and function prototypes for handling ROP gadgets and constraints.
*/
#include <rz_cmd.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Information about a register.
*/
typedef struct rz_rop_reg_info_t {
char *name;
bool is_mem_read; ///< Register involved in Memory read.
bool is_pc_write; ///< PC write flag.
bool is_var_read; ///< Register involved in Variable read.
bool is_var_write; ///< Register involved in Variable write.
bool is_mem_write; ///< Register involved in Memory write.
ut64 init_val;
ut64 new_val;
} RzRopRegInfo;
/**
* \brief Information about a ROP gadget.
*/
typedef struct rz_rop_gadget_info_t {
ut64 address; ///< Gadget address.
ut64 stack_change; ///< Stack change.
ut64 curr_pc_val; ///< Current PC value.
bool is_pc_write; ///< PC write flag.
bool is_syscall; ///< Syscall flag.
RzPVector /*<RzRegInfo *>*/ *modified_registers; ///< Modified registers.
RzList /*<RzRegInfo *>*/ *dependencies; ///< Dependencies.
} RzRopGadgetInfo;
/**
* \brief Types of IL instructions for ROP constraints.
*/
typedef enum rz_rop_il_instr_type {
MOV_CONST, ///< reg <- const
MOV_REG, ///< reg <- reg
MOV_OP_CONST, ///< reg <- reg OP const
MOV_OP_REG, ///< reg <- reg OP reg
SYSCALL, ///< syscall
} RzRopILInstructionType;
/**
* \brief Argument types for ROP constraints.
*/
typedef enum {
SRC_REG,
DST_REG,
SRC_CONST,
DST_REG_SECOND,
OP,
NUM_ARGS
} RzRopArgType;
/**
* \brief ROP request mask for filtering gadgets.
*/
typedef enum {
RZ_ROP_GADGET_PRINT = 1 << 0, ///< Print ROP gadgets.
RZ_ROP_GADGET_PRINT_DETAIL = 1 << 1, ///< Detailed ROP gadgets.
RZ_ROP_GADGET_ANALYZE = 1 << 2, ///< Detailed ROP gadgets.
RZ_ROP_GADGET_ALL = RZ_ROP_GADGET_PRINT | RZ_ROP_GADGET_PRINT_DETAIL | RZ_ROP_GADGET_ANALYZE ///< All ROP gadgets requests.
} RzRopRequestMask;
/**
* \brief Pair representing an end gadget with instruction offset and delay size.
*/
typedef struct rz_rop_endlist_pair_t {
int instr_offset; ///< Instruction offset.
int delay_size; ///< Delay size.
} RzRopEndListPair;
/**
* \brief Structure representing a ROP constraint.
*/
typedef struct rz_rop_constraint_t {
RzRopILInstructionType type; ///< IL instruction type.
char *args[NUM_ARGS]; ///< Arguments.
} RzRopConstraint;
/**
* \brief Structure representing a ROP search context.
*/
typedef struct rz_rop_search_context_t {
ut8 max_instr;
ut8 subchain;
ut8 crop;
char *greparg;
bool regexp;
int max_count;
int increment;
RzRopRequestMask mask;
RzCmdStateOutput *state;
ut64 from;
ut64 to;
RzList /*<RzRopEndListPair *>*/ *end_list;
HtSU *unique_hitlists;
} RzRopSearchContext;
// Command APIs
RZ_API RzCmdStatus rz_core_rop_search(RzCore *core, RZ_OWN RzRopSearchContext *context);
RZ_API RzCmdStatus rz_core_rop_gadget_info(RzCore *core, RZ_OWN RzRopSearchContext *context);
RZ_API bool rz_core_rop_analyze_constraint(RzCore *core, const char *str, RzRopConstraint *rop_constraint);
// 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);
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_OWN RZ_API RzList /*<RzRopConstraint *>*/ *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_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);
#ifdef __cplusplus
}
#endif
#endif // RZ_ROP_H

View file

@ -542,7 +542,6 @@ NAME=Search rop gadgets for in command
FILE=bins/firmware/arduino_avr.bin
ARGS=-a avr
CMDS=<<EOF
e search.align=2
/R in r24
EOF
EXPECT=<<EOF
@ -553,6 +552,12 @@ EXPECT=<<EOF
0x00000288 0895 ret
Gadget size: 10
0x00000282 82b3 in r24, 0x12
0x00000284 8058 subi r24, 0x80
0x00000286 82bb out 0x12, r24
0x00000288 0895 ret
Gadget size: 8
0x00000294 7304 cpc r7, r3
0x00000296 88b3 in r24, 0x18
0x00000298 8058 subi r24, 0x80
@ -560,6 +565,12 @@ Gadget size: 10
0x0000029c 0895 ret
Gadget size: 10
0x00000296 88b3 in r24, 0x18
0x00000298 8058 subi r24, 0x80
0x0000029a 88bb out 0x18, r24
0x0000029c 0895 ret
Gadget size: 8
0x000005c6 8fb5 in r24, 0x2f
0x000005c8 8f77 andi r24, 0x7f
0x000005ca 02c0 rjmp 0x5d0
@ -595,6 +606,12 @@ EXPECT=<<EOF
0x00000288 0895 ret
Gadget size: 10
0x00000282 82b3 in r24, 0x12
0x00000284 8058 subi r24, 0x80
0x00000286 82bb out 0x12, r24
0x00000288 0895 ret
Gadget size: 8
0x00000294 7304 cpc r7, r3
0x00000296 88b3 in r24, 0x18
0x00000298 8058 subi r24, 0x80
@ -602,6 +619,12 @@ Gadget size: 10
0x0000029c 0895 ret
Gadget size: 10
0x00000296 88b3 in r24, 0x18
0x00000298 8058 subi r24, 0x80
0x0000029a 88bb out 0x18, r24
0x0000029c 0895 ret
Gadget size: 8
0x000005c6 8fb5 in r24, 0x2f
0x000005c8 8f77 andi r24, 0x7f
0x000005ca 02c0 rjmp 0x5d0

View file

@ -13,7 +13,7 @@ NAME=rop search without maxhits
FILE=bins/elf/varsub
CMDS=/Rq pop r15~?
EXPECT=<<EOF
4
7
EOF
RUN
@ -52,6 +52,12 @@ Gadget size: 15
0x000000c2 c3 ret
Gadget size: 14
0x000000b6 b801000000 mov eax, 1
0x000000bb b900000000 mov ecx, 0
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 13
0x000000b7 0100 add dword [eax], eax
0x000000b9 0000 add byte [eax], al
0x000000bb b900000000 mov ecx, 0
@ -65,6 +71,40 @@ Gadget size: 12
0x000000c2 c3 ret
Gadget size: 11
0x000000b9 0000 add byte [eax], al
0x000000bb b900000000 mov ecx, 0
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 10
0x000000ba 00b900000000 add byte [ecx], bh
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 9
0x000000bb b900000000 mov ecx, 0
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 8
0x000000bc 0000 add byte [eax], al
0x000000be 0000 add byte [eax], al
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 7
0x000000be 0000 add byte [eax], al
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 5
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 3
0x000000c2 c3 ret
Gadget size: 1
EOF
RUN
@ -84,6 +124,12 @@ EXPECT=<<EOF
0x000000c2 c3 ret
Gadget size: 15
0x000000b6 b801000000 mov eax, 1
0x000000bb b900000000 mov ecx, 0
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 13
0x000000b7 0100 add dword [eax], eax
0x000000b9 0000 add byte [eax], al
0x000000bb b900000000 mov ecx, 0
@ -91,6 +137,17 @@ Gadget size: 15
0x000000c2 c3 ret
Gadget size: 12
0x000000b9 0000 add byte [eax], al
0x000000bb b900000000 mov ecx, 0
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 10
0x000000bb b900000000 mov ecx, 0
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 8
EOF
RUN
@ -105,8 +162,16 @@ EOF
EXPECT=<<EOF
0x000000b4: int 0x80; mov eax, 1; mov ecx, 0; int 0x80; ret;
0x000000b5: cmp byte [eax + 1], 0xb9; add byte [eax], al; add byte [eax], al; int 0x80; ret;
0x000000b6: mov eax, 1; mov ecx, 0; int 0x80; ret;
0x000000b7: add dword [eax], eax; add byte [eax], al; mov ecx, 0; int 0x80; ret;
0x000000b8: add byte [eax], al; add byte [ecx], bh; int 0x80; ret;
0x000000b9: add byte [eax], al; mov ecx, 0; int 0x80; ret;
0x000000ba: add byte [ecx], bh; int 0x80; ret;
0x000000bb: mov ecx, 0; int 0x80; ret;
0x000000bc: add byte [eax], al; add byte [eax], al; int 0x80; ret;
0x000000be: add byte [eax], al; int 0x80; ret;
0x000000c0: int 0x80; ret;
0x000000c2: ret;
EOF
RUN
@ -126,6 +191,12 @@ EXPECT=<<EOF
0x000000c2 c3 ret
Gadget size: 15
0x000000b6 b801000000 mov eax, 1
0x000000bb b900000000 mov ecx, 0
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 13
0x000000b7 0100 add dword [eax], eax
0x000000b9 0000 add byte [eax], al
0x000000bb b900000000 mov ecx, 0
@ -139,6 +210,22 @@ Gadget size: 12
0x000000c2 c3 ret
Gadget size: 11
0x000000b9 0000 add byte [eax], al
0x000000bb b900000000 mov ecx, 0
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 10
0x000000ba 00b900000000 add byte [ecx], bh
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 9
0x000000bb b900000000 mov ecx, 0
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 8
EOF
RUN
@ -151,7 +238,7 @@ e asm.bits=32
/Rj ecx
EOF
EXPECT=<<EOF
[{"opcodes":[{"offset":180,"size":2,"opcode":"int 0x80","type":"swi"},{"offset":182,"size":5,"opcode":"mov eax, 1","type":"mov"},{"offset":187,"size":5,"opcode":"mov ecx, 0","type":"mov"},{"offset":192,"size":2,"opcode":"int 0x80","type":"swi"},{"offset":194,"size":1,"opcode":"ret","type":"ret"}],"retaddr":194,"size":15},{"opcodes":[{"offset":183,"size":2,"opcode":"add dword [eax], eax","type":"add"},{"offset":185,"size":2,"opcode":"add byte [eax], al","type":"add"},{"offset":187,"size":5,"opcode":"mov ecx, 0","type":"mov"},{"offset":192,"size":2,"opcode":"int 0x80","type":"swi"},{"offset":194,"size":1,"opcode":"ret","type":"ret"}],"retaddr":194,"size":12},{"opcodes":[{"offset":184,"size":2,"opcode":"add byte [eax], al","type":"add"},{"offset":186,"size":6,"opcode":"add byte [ecx], bh","type":"add"},{"offset":192,"size":2,"opcode":"int 0x80","type":"swi"},{"offset":194,"size":1,"opcode":"ret","type":"ret"}],"retaddr":194,"size":11}]
[{"opcodes":[{"offset":180,"size":2,"opcode":"int 0x80","type":"swi"},{"offset":182,"size":5,"opcode":"mov eax, 1","type":"mov"},{"offset":187,"size":5,"opcode":"mov ecx, 0","type":"mov"},{"offset":192,"size":2,"opcode":"int 0x80","type":"swi"},{"offset":194,"size":1,"opcode":"ret","type":"ret"}],"retaddr":194,"size":15},{"opcodes":[{"offset":182,"size":5,"opcode":"mov eax, 1","type":"mov"},{"offset":187,"size":5,"opcode":"mov ecx, 0","type":"mov"},{"offset":192,"size":2,"opcode":"int 0x80","type":"swi"},{"offset":194,"size":1,"opcode":"ret","type":"ret"}],"retaddr":194,"size":13},{"opcodes":[{"offset":183,"size":2,"opcode":"add dword [eax], eax","type":"add"},{"offset":185,"size":2,"opcode":"add byte [eax], al","type":"add"},{"offset":187,"size":5,"opcode":"mov ecx, 0","type":"mov"},{"offset":192,"size":2,"opcode":"int 0x80","type":"swi"},{"offset":194,"size":1,"opcode":"ret","type":"ret"}],"retaddr":194,"size":12},{"opcodes":[{"offset":184,"size":2,"opcode":"add byte [eax], al","type":"add"},{"offset":186,"size":6,"opcode":"add byte [ecx], bh","type":"add"},{"offset":192,"size":2,"opcode":"int 0x80","type":"swi"},{"offset":194,"size":1,"opcode":"ret","type":"ret"}],"retaddr":194,"size":11},{"opcodes":[{"offset":185,"size":2,"opcode":"add byte [eax], al","type":"add"},{"offset":187,"size":5,"opcode":"mov ecx, 0","type":"mov"},{"offset":192,"size":2,"opcode":"int 0x80","type":"swi"},{"offset":194,"size":1,"opcode":"ret","type":"ret"}],"retaddr":194,"size":10},{"opcodes":[{"offset":186,"size":6,"opcode":"add byte [ecx], bh","type":"add"},{"offset":192,"size":2,"opcode":"int 0x80","type":"swi"},{"offset":194,"size":1,"opcode":"ret","type":"ret"}],"retaddr":194,"size":9},{"opcodes":[{"offset":187,"size":5,"opcode":"mov ecx, 0","type":"mov"},{"offset":192,"size":2,"opcode":"int 0x80","type":"swi"},{"offset":194,"size":1,"opcode":"ret","type":"ret"}],"retaddr":194,"size":8}]
EOF
RUN
@ -178,6 +265,12 @@ Gadget size: 15
0x000000c2 c3 ret
Gadget size: 14
0x000000b6 b801000000 mov eax, 1
0x000000bb b900000000 mov ecx, 0
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 13
0x000000b7 0100 add dword [eax], eax
0x000000b9 0000 add byte [eax], al
0x000000bb b900000000 mov ecx, 0
@ -191,6 +284,33 @@ Gadget size: 12
0x000000c2 c3 ret
Gadget size: 11
0x000000b9 0000 add byte [eax], al
0x000000bb b900000000 mov ecx, 0
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 10
0x000000ba 00b900000000 add byte [ecx], bh
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 9
0x000000bb b900000000 mov ecx, 0
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 8
0x000000bc 0000 add byte [eax], al
0x000000be 0000 add byte [eax], al
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 7
0x000000be 0000 add byte [eax], al
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 5
EOF
RUN
@ -230,6 +350,17 @@ EXPECT=<<EOF
0x08048426 e805ffffff call 0x8048330
Gadget size: 10
0x08048422 31ff xor edi, edi
0x08048424 56 push esi
0x08048425 53 push ebx
0x08048426 e805ffffff call 0x8048330
Gadget size: 9
0x08048424 56 push esi
0x08048425 53 push ebx
0x08048426 e805ffffff call 0x8048330
Gadget size: 7
EOF
RUN
@ -247,6 +378,17 @@ EXPECT=<<EOF
0x08048426 e805ffffff call 0x8048330
Gadget size: 10
0x08048422 31ff xor edi, edi
0x08048424 56 push esi
0x08048425 53 push ebx
0x08048426 e805ffffff call 0x8048330
Gadget size: 9
0x08048424 56 push esi
0x08048425 53 push ebx
0x08048426 e805ffffff call 0x8048330
Gadget size: 7
EOF
RUN
@ -267,6 +409,21 @@ EXPECT=<<EOF
0x00000016 02c0 rjmp 0x1c
Gadget size: 10
0x00000010 b1e0 ldi r27, 0x01
0x00000012 e6e3 ldi r30, 0x36
0x00000014 f4e3 ldi r31, 0x34
0x00000016 02c0 rjmp 0x1c
Gadget size: 8
0x00000012 e6e3 ldi r30, 0x36
0x00000014 f4e3 ldi r31, 0x34
0x00000016 02c0 rjmp 0x1c
Gadget size: 6
0x00000014 f4e3 ldi r31, 0x34
0x00000016 02c0 rjmp 0x1c
Gadget size: 4
0x00000020 d9f7 brne 0x18
0x00000022 22e0 ldi r18, 0x02
0x00000024 a4e1 ldi r26, 0x14
@ -274,6 +431,21 @@ Gadget size: 10
0x00000028 01c0 rjmp 0x2c
Gadget size: 10
0x00000022 22e0 ldi r18, 0x02
0x00000024 a4e1 ldi r26, 0x14
0x00000026 b2e0 ldi r27, 0x02
0x00000028 01c0 rjmp 0x2c
Gadget size: 8
0x00000024 a4e1 ldi r26, 0x14
0x00000026 b2e0 ldi r27, 0x02
0x00000028 01c0 rjmp 0x2c
Gadget size: 6
0x00000026 b2e0 ldi r27, 0x02
0x00000028 01c0 rjmp 0x2c
Gadget size: 4
0x00000030 e1f7 brne 0x2a
0x00000032 10e0 ldi r17, 0x00
0x00000034 c2e6 ldi r28, 0x62
@ -281,6 +453,21 @@ Gadget size: 10
0x00000038 04c0 rjmp 0x42
Gadget size: 10
0x00000032 10e0 ldi r17, 0x00
0x00000034 c2e6 ldi r28, 0x62
0x00000036 d0e0 ldi r29, 0x00
0x00000038 04c0 rjmp 0x42
Gadget size: 8
0x00000034 c2e6 ldi r28, 0x62
0x00000036 d0e0 ldi r29, 0x00
0x00000038 04c0 rjmp 0x42
Gadget size: 6
0x00000036 d0e0 ldi r29, 0x00
0x00000038 04c0 rjmp 0x42
Gadget size: 4
0x00000072 6ce0 ldi r22, 0x0c
0x00000074 71e0 ldi r23, 0x01
0x00000076 8fe1 ldi r24, 0x1f
@ -288,6 +475,21 @@ Gadget size: 10
0x0000007a 0e946b04 call 0x8d6
Gadget size: 12
0x00000074 71e0 ldi r23, 0x01
0x00000076 8fe1 ldi r24, 0x1f
0x00000078 92e0 ldi r25, 0x02
0x0000007a 0e946b04 call 0x8d6
Gadget size: 10
0x00000076 8fe1 ldi r24, 0x1f
0x00000078 92e0 ldi r25, 0x02
0x0000007a 0e946b04 call 0x8d6
Gadget size: 8
0x00000078 92e0 ldi r25, 0x02
0x0000007a 0e946b04 call 0x8d6
Gadget size: 6
0x00000098 a701 movw r20, r14
0x0000009a 6ae0 ldi r22, 0x0a
0x0000009c 8fe1 ldi r24, 0x1f
@ -295,6 +497,21 @@ Gadget size: 12
0x000000a0 0e94d808 call 0x11b0
Gadget size: 12
0x0000009a 6ae0 ldi r22, 0x0a
0x0000009c 8fe1 ldi r24, 0x1f
0x0000009e 92e0 ldi r25, 0x02
0x000000a0 0e94d808 call 0x11b0
Gadget size: 10
0x0000009c 8fe1 ldi r24, 0x1f
0x0000009e 92e0 ldi r25, 0x02
0x000000a0 0e94d808 call 0x11b0
Gadget size: 8
0x0000009e 92e0 ldi r25, 0x02
0x000000a0 0e94d808 call 0x11b0
Gadget size: 6
0x000000c4 1082 st Z, r1
0x000000c6 60e0 ldi r22, 0x00
0x000000c8 71e0 ldi r23, 0x01
@ -302,6 +519,17 @@ Gadget size: 12
0x000000cc 0e949816 call 0x2d30
Gadget size: 12
0x000000c6 60e0 ldi r22, 0x00
0x000000c8 71e0 ldi r23, 0x01
0x000000ca c801 movw r24, r16
0x000000cc 0e949816 call 0x2d30
Gadget size: 10
0x000000c8 71e0 ldi r23, 0x01
0x000000ca c801 movw r24, r16
0x000000cc 0e949816 call 0x2d30
Gadget size: 8
0x000000d4 6de1 ldi r22, 0x1d
0x000000d6 71e0 ldi r23, 0x01
0x000000d8 8fe1 ldi r24, 0x1f
@ -315,6 +543,15 @@ Gadget size: 12
0x000000e4 08c0 rjmp 0xf6
Gadget size: 8
0x000000e0 81e0 ldi r24, 0x01
0x000000e2 90e0 ldi r25, 0x00
0x000000e4 08c0 rjmp 0xf6
Gadget size: 6
0x000000e2 90e0 ldi r25, 0x00
0x000000e4 08c0 rjmp 0xf6
Gadget size: 4
0x000000e6 66e4 ldi r22, 0x46
0x000000e8 71e0 ldi r23, 0x01
0x000000ea 8fe1 ldi r24, 0x1f
@ -336,20 +573,6 @@ Gadget size: 12
0x0000012e 0e946b04 call 0x8d6
Gadget size: 12
0x0000013a 6de6 ldi r22, 0x6d
0x0000013c 71e0 ldi r23, 0x01
0x0000013e 8fe1 ldi r24, 0x1f
0x00000140 92e0 ldi r25, 0x02
0x00000142 0e946b04 call 0x8d6
Gadget size: 12
0x0000015a 6fe7 ldi r22, 0x7f
0x0000015c 71e0 ldi r23, 0x01
0x0000015e 8fe1 ldi r24, 0x1f
0x00000160 92e0 ldi r25, 0x02
0x00000162 0e946b04 call 0x8d6
Gadget size: 12
0x000001b6 1082 st Z, r1
0x000001b8 6fe8 ldi r22, 0x8f
0x000001ba 71e0 ldi r23, 0x01
@ -357,6 +580,25 @@ Gadget size: 12
0x000001be 0e949816 call 0x2d30
Gadget size: 12
0x000001b8 6fe8 ldi r22, 0x8f
0x000001ba 71e0 ldi r23, 0x01
0x000001bc c801 movw r24, r16
0x000001be 0e949816 call 0x2d30
Gadget size: 10
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
0x000001e6 63e9 ldi r22, 0x93
0x000001e8 71e0 ldi r23, 0x01
0x000001ea c801 movw r24, r16
0x000001ec 0e949816 call 0x2d30
Gadget size: 10
EOF
EXPECT_ERR=<<EOF
EOF

View file

@ -440,6 +440,18 @@ Gadget size: 5
0x00000005 c3 ret
Gadget size: 4
0x00000003 5b pop ebx
0x00000004 5d pop ebp
0x00000005 c3 ret
Gadget size: 3
0x00000004 5d pop ebp
0x00000005 c3 ret
Gadget size: 2
0x00000005 c3 ret
Gadget size: 1
EOF
RUN
@ -469,6 +481,7 @@ CMDS=<<EOF
e asm.bits=32
e asm.arch=mips
e scr.color=false
e rop.len=8
wx 1b000000040000001a0000004c08410018000000040000000800000000000070
/R
q
@ -478,13 +491,51 @@ EXPECT=<<EOF
0x00000004 04000000 sllv zero, zero, zero
0x00000008 1a000000 div zero, zero, zero
0x0000000c 4c084100 syscall 0x10421
0x00000010 18000000 mult zero, zero
0x00000014 04000000 sllv zero, zero, zero
0x00000018 08000000 jr zero
0x0000001c 00000070 madd zero, zero
Gadget size: 32
0x00000004 04000000 sllv zero, zero, zero
0x00000008 1a000000 div zero, zero, zero
0x0000000c 4c084100 syscall 0x10421
0x00000010 18000000 mult zero, zero
0x00000014 04000000 sllv zero, zero, zero
0x00000018 08000000 jr zero
0x0000001c 00000070 madd zero, zero
Gadget size: 28
0x00000008 1a000000 div zero, zero, zero
0x0000000c 4c084100 syscall 0x10421
0x00000010 18000000 mult zero, zero
0x00000014 04000000 sllv zero, zero, zero
0x00000018 08000000 jr zero
0x0000001c 00000070 madd zero, zero
Gadget size: 24
0x0000000c 4c084100 syscall 0x10421
0x00000010 18000000 mult zero, zero
0x00000014 04000000 sllv zero, zero, zero
0x00000018 08000000 jr zero
0x0000001c 00000070 madd zero, zero
Gadget size: 20
0x00000010 18000000 mult zero, zero
0x00000014 04000000 sllv zero, zero, zero
0x00000018 08000000 jr zero
0x0000001c 00000070 madd zero, zero
Gadget size: 16
0x00000014 04000000 sllv zero, zero, zero
0x00000018 08000000 jr zero
0x0000001c 00000070 madd zero, zero
Gadget size: 12
0x00000018 08000000 jr zero
0x0000001c 00000070 madd zero, zero
Gadget size: 8
EOF
RUN

View file

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

View file

@ -590,6 +590,23 @@ static bool test_migrate_v16_v17_flags_base() {
mu_end;
}
static bool test_migrate_v17_v18_rop_config() {
RzProject *prj = rz_project_load_file_raw("prj/v17-rop-config.rzdb");
mu_assert_notnull(prj, "load raw project");
RzSerializeResultInfo *res = rz_serialize_result_info_new();
bool s = rz_project_migrate_v17_v18(prj, res);
mu_assert_true(s, "migrate success");
Sdb *core_db = sdb_ns(prj, "core", false);
mu_assert_notnull(core_db, "core ns");
Sdb *config_db = sdb_ns(core_db, "config", false);
mu_assert_null(sdb_get(config_db, "rop.sdb"), "config");
mu_assert_null(sdb_get(config_db, "rop.db"), "config");
mu_assert_streq_free(sdb_get(config_db, "rop.cache"), "false", "config");
rz_serialize_result_info_free(res);
rz_project_free(prj);
mu_end;
}
/// Load project of given version from file into core and check the log for migration success messages
#define BEGIN_LOAD_TEST(core, version, file) \
@ -978,6 +995,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_b(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);
@ -998,6 +1023,7 @@ int all_tests() {
mu_run_test(test_migrate_v14_v15);
mu_run_test(test_migrate_v15_v16_str_config);
mu_run_test(test_migrate_v16_v17_flags_base);
mu_run_test(test_migrate_v17_v18_rop_config);
mu_run_test(test_load_v1_noreturn);
mu_run_test(test_load_v1_noreturn_empty);
mu_run_test(test_load_v1_unknown_type);
@ -1020,6 +1046,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;
}

View file

@ -0,0 +1,82 @@
/
type=rizin rz-db project
version=17
/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.sdb=false
rop.db=false
rop.comments=false
rop.conditional=false
rop.len=5
rop.subchains=false
/core/debug
/core/debug/breakpoints
/core/file
relative=../bins/elf/crackme0x05
/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}

View file

@ -76,6 +76,7 @@ if get_option('enable_tests')
'rbtree',
'reg',
'regex',
'rop_constraint',
'run',
'rz_test',
'sdb_array',

View file

@ -0,0 +1,142 @@
// SPDX-FileCopyrightText: 2024 z3phyr <giridh1337@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_core.h>
#include "minunit.h"
#include <rz_rop.h>
// 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", 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");
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", !rz_core_rop_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", 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");
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", !rz_core_rop_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", 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");
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", !rz_core_rop_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", 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");
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", !rz_core_rop_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)