Ropchain constraint syntax parser (#4552)
Co-authored-by: Giridhar Prasath R <giridh1337@gmail.com>
This commit is contained in:
parent
e3d27c9316
commit
c8d05054c1
23 changed files with 2516 additions and 1555 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -116,6 +116,7 @@ peda-session-*
|
|||
/.vs
|
||||
.cache/
|
||||
test/.tmp/*
|
||||
test/.sync_disk_db
|
||||
subprojects/capstone-*/
|
||||
subprojects/pcre2*/
|
||||
subprojects/libzip-*/
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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
1238
librz/core/rop.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
143
librz/include/rz_rop.h
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
82
test/prj/v17-rop-config.rzdb
Normal file
82
test/prj/v17-rop-config.rzdb
Normal 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}
|
||||
|
|
@ -76,6 +76,7 @@ if get_option('enable_tests')
|
|||
'rbtree',
|
||||
'reg',
|
||||
'regex',
|
||||
'rop_constraint',
|
||||
'run',
|
||||
'rz_test',
|
||||
'sdb_array',
|
||||
|
|
|
|||
142
test/unit/test_rop_constraint.c
Normal file
142
test/unit/test_rop_constraint.c
Normal 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)
|
||||
Loading…
Reference in a new issue