core/cmd: port /R commands to the rzshell (#4504)

* Port /R to new handler code
* Use the same stack buf for diff modes
* Add table mode print
* Add gadget size
This commit is contained in:
z3phyr 2024-06-01 08:26:25 -05:00 committed by GitHub
parent aca16bebbd
commit 6e4ea01a97
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 433 additions and 208 deletions

View file

@ -17,6 +17,10 @@
#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",
@ -125,26 +129,6 @@ static const char *help_msg_slash_r[] = {
NULL
};
static const char *help_msg_slash_R[] = {
"Usage: /R", "", "Search for ROP gadgets",
"/R", " [filter-by-string]", "Show gadgets",
"/R/", " [filter-by-regexp]", "Show gadgets [regular expression]",
"/R/j", " [filter-by-regexp]", "JSON output [regular expression]",
"/R/q", " [filter-by-regexp]", "Show gadgets in a quiet manner [regular expression]",
"/Rj", " [filter-by-string]", "JSON output",
"/Rk", " [select-by-class]", "Query stored ROP gadgets",
"/Rq", " [filter-by-string]", "Show gadgets in a quiet manner",
NULL
};
static const char *help_msg_slash_Rk[] = {
"Usage: /Rk", "", "Query stored ROP gadgets",
"/Rk", " [nop|mov|const|arithm|arithm_ct]", "Show gadgets",
"/Rkj", "", "JSON output",
"/Rkq", "", "List Gadgets offsets",
NULL
};
static const char *help_msg_slash_x[] = {
"Usage:", "/x [hexpairs]:[binmask]", "Search in memory",
"/x ", "9090cd80", "search for those bytes",
@ -246,6 +230,68 @@ fail:
return -1;
}
RZ_IPI RzCmdStatus rz_cmd_info_gadget_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
const char *input = argc > 1 ? argv[1] : "";
if (!input) {
return RZ_CMD_STATUS_ERROR;
}
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;
}
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;
}
RZ_IPI RzCmdStatus rz_cmd_search_gadget_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
const char *input = argc > 1 ? argv[1] : "";
if (!input) {
return RZ_CMD_STATUS_ERROR;
}
rz_core_search_rop(core, argv[1], 1, state);
return RZ_CMD_STATUS_OK;
}
static void cmd_search_bin(RzCore *core, RzInterval itv) {
ut64 from = itv.addr, to = rz_itv_end(itv);
int size; // , sz = sizeof (buf);
@ -1138,20 +1184,22 @@ ret:
return hitlist;
}
static void print_rop(RzCore *core, RzList /*<RzCoreAsmHit *>*/ *hitlist, PJ *pj, int mode) {
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;
RzAsmOp asmop;
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);
@ -1162,57 +1210,51 @@ static void print_rop(RzCore *core, RzList /*<RzCoreAsmHit *>*/ *hitlist, PJ *pj
}
}
switch (mode) {
case 'j':
pj_o(pj);
pj_ka(pj, "opcodes");
rz_list_foreach (hitlist, iter, hit) {
ut8 *buf = malloc(hit->len);
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) {
return;
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_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, (void *)opstr_n);
rz_list_append(ropList, opstr_n);
}
pj_o(pj);
pj_kn(pj, "offset", hit->addr);
pj_ki(pj, "size", hit->len);
pj_ks(pj, "opcode", rz_asm_op_get_asm(&asmop));
pj_ks(pj, "type", rz_analysis_optype_to_string(aop.type));
pj_end(pj);
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);
}
pj_end(pj);
if (db && hit) {
const ut64 addr = ((RzCoreAsmHit *)rz_list_first(hitlist))->addr;
// 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);
}
if (hit) {
pj_kn(pj, "retaddr", hit->addr);
pj_ki(pj, "size", size);
}
pj_end(pj);
break;
case 'q':
// Print gadgets in a 'linear manner', each sequence
// on one line.
rz_cons_printf("0x%08" PFMT64x ":",
((RzCoreAsmHit *)rz_list_first(hitlist))->addr);
rz_list_foreach (hitlist, iter, hit) {
ut8 *buf = malloc(hit->len);
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_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;
@ -1223,53 +1265,46 @@ static void print_rop(RzCore *core, RzList /*<RzCoreAsmHit *>*/ *hitlist, PJ *pj
if (esil) {
rz_cons_printf("%s\n", opstr);
} else if (colorize) {
RzStrBuf *colored_asm, *bw_str = rz_strbuf_new(rz_asm_op_get_asm(&asmop));
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);
colored_asm = rz_asm_colorize_asm_str(bw_str, core->print, param, asmop->asm_toks);
rz_asm_parse_param_free(param);
rz_cons_printf(" %s%s;", colored_asm ? rz_strbuf_get(colored_asm) : "", Color_RESET);
rz_strbuf_free(colored_asm);
rz_strbuf_free(bw_str);
} else {
rz_cons_printf(" %s;", rz_asm_op_get_asm(&asmop));
rz_cons_printf(" %s;", rz_asm_op_get_asm(asmop));
}
free(buf);
rz_analysis_op_fini(&aop);
}
if (db && hit) {
const ut64 addr = ((RzCoreAsmHit *)rz_list_first(hitlist))->addr;
// 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);
}
break;
default:
// Print gadgets with new instruction on a new line.
rz_list_foreach (hitlist, iter, hit) {
const char *comment = rop_comments ? rz_meta_get_string(core->analysis, RZ_META_TYPE_COMMENT, hit->addr) : NULL;
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;
}
ut8 *buf = malloc(1 + hit->len);
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_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, (void *)opstr_n);
rz_list_append(ropList, opstr_n);
}
char *asm_op_hex = rz_asm_op_get_hex(&asmop);
char *asm_op_hex = rz_asm_op_get_hex(asmop);
if (colorize) {
RzStrBuf *colored_asm, *bw_str = rz_strbuf_new(rz_asm_op_get_asm(&asmop));
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);
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",
@ -1279,50 +1314,136 @@ static void print_rop(RzCore *core, RzList /*<RzCoreAsmHit *>*/ *hitlist, PJ *pj
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);
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));
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 ut64 addr = ((RzCoreAsmHit *)rz_list_first(hitlist))->addr;
// 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);
}
}
if (mode != 'j') {
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, RzInterval search_itv, int opt, const char *grep, int regexp, struct search_parameters *param) {
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, mode = 0, increment = 1, ret, result = true;
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 *tok, *gregexp = 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;
RzAsmOp asmop;
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")) {
@ -1351,36 +1472,17 @@ static int rz_core_search_rop(RzCore *core, RzInterval search_itv, int opt, cons
increment = 2;
}
// Options, like JSON, linear, ...
grep_arg = strchr(grep, ' ');
if (*grep) {
if (grep_arg) {
mode = *(grep_arg - 1);
} else {
mode = *grep;
++grep;
}
}
if (grep_arg) {
grep_arg = strdup(grep_arg);
if (greparg) {
grep_arg = strdup(greparg);
grep_arg = rz_str_replace(grep_arg, ",,", ";", true);
grep = grep_arg;
}
if (*grep == ' ') { // grep mode
for (++grep; *grep == ' '; grep++) {
;
}
} else {
grep = NULL;
}
// Deal with the grep guy.
if (grep && regexp) {
if (grep_arg && regexp) {
if (!rx_list) {
rx_list = rz_list_newf(free);
}
gregexp = strdup(grep);
gregexp = strdup(grep_arg);
tok = strtok(gregexp, ";");
while (tok) {
rx = strdup(tok);
@ -1388,12 +1490,14 @@ static int rz_core_search_rop(RzCore *core, RzInterval search_itv, int opt, cons
tok = strtok(NULL, ";");
}
}
if (param->outmode == RZ_MODE_JSON) {
pj_a(param->pj);
}
rz_cmd_state_output_array_start(state);
rz_cons_break_push(NULL, NULL);
rz_list_foreach (param->boundaries, itermap, map) {
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)) {
@ -1504,25 +1608,32 @@ static int rz_core_search_rop(RzCore *core, RzInterval search_itv, int opt, cons
RZ_MIN((delta - i), 4096));
end = i + 2048;
}
ret = rz_asm_disassemble(core->rasm, &asmop, buf + i, delta - i);
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, grep, regexp,
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))) {
if (align && 0 != (from + i) % align) {
rz_asm_op_free(asmop);
asmop = NULL;
continue;
}
if (gadgetSdb) {
RzListIter *iter;
RzCoreAsmHit *hit = (RzCoreAsmHit *)rz_list_first(hitlist);
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;
}
@ -1531,6 +1642,8 @@ static int rz_core_search_rop(RzCore *core, RzInterval search_itv, int opt, cons
if (!addr) {
free(headAddr);
result = false;
free(buf);
ht_uu_free(badstart);
goto bad;
}
sdb_concat(gadgetSdb, headAddr, addr);
@ -1539,16 +1652,13 @@ static int rz_core_search_rop(RzCore *core, RzInterval search_itv, int opt, cons
free(headAddr);
}
if (param->outmode == RZ_MODE_JSON) {
mode = 'j';
}
if ((mode == 'q') && subchain) {
if (subchain) {
do {
print_rop(core, hitlist, NULL, mode);
print_rop(core, hitlist, state);
hitlist->head = hitlist->head->next;
} while (hitlist->head->next);
} else {
print_rop(core, hitlist, param->pj, mode);
print_rop(core, hitlist, state);
}
rz_list_free(hitlist);
if (max_count > 0) {
@ -1561,21 +1671,24 @@ static int rz_core_search_rop(RzCore *core, RzInterval search_itv, int opt, cons
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");
}
if (param->outmode == RZ_MODE_JSON) {
pj_end(param->pj);
}
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;
@ -2452,8 +2565,8 @@ static void do_string_search(RzCore *core, RzInterval search_itv, struct search_
}
}
static void rop_kuery(void *data, const char *input, PJ *pj) {
RzCore *core = (RzCore *)data;
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;
@ -2465,8 +2578,8 @@ static void rop_kuery(void *data, const char *input, PJ *pj) {
return;
}
switch (*input) {
case 'q':
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) {
@ -2476,9 +2589,9 @@ static void rop_kuery(void *data, const char *input, PJ *pj) {
rz_pvector_free(items);
}
break;
case 'j':
pj_o(pj);
pj_ka(pj, "gadgets");
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) {
@ -2491,12 +2604,12 @@ static void rop_kuery(void *data, const char *input, PJ *pj) {
tok = strdup("NOP");
flag = true;
}
pj_o(pj);
pj_ks(pj, "address", sdbkv_key(kv));
pj_ks(pj, "size", size);
pj_ks(pj, "type", ns->name);
pj_ks(pj, "effect", tok);
pj_end(pj);
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);
@ -2504,8 +2617,8 @@ static void rop_kuery(void *data, const char *input, PJ *pj) {
}
rz_pvector_free(items);
}
pj_end(pj);
pj_end(pj);
pj_end(state->d.pj);
pj_end(state->d.pj);
break;
case ' ':
if (!strcmp(input + 1, "nop")) {
@ -3073,62 +3186,6 @@ reread:
}
break;
}
case 'R': // "/R"
if (input[1] == '?') {
rz_core_cmd_help(core, help_msg_slash_R);
} else if (input[1] == '/') {
rz_core_search_rop(core, search_itv, 0, input + 1, 1, &param);
} else if (input[1] == 'k') {
if (input[2] == '?') {
rz_core_cmd_help(core, help_msg_slash_Rk);
} else {
rop_kuery(core, input + 2, param.pj);
}
} else {
Sdb *gadgetSdb = sdb_ns(core->sdb, "gadget_sdb", false);
if (!gadgetSdb) {
rz_core_search_rop(core, search_itv, 0, input + 1, 0, &param);
} else {
void **iter;
RzPVector *items = sdb_get_items(gadgetSdb, true);
rz_pvector_foreach (items, iter) {
SdbKv *kv = *iter;
RzList *hitlist = rz_core_asm_hit_list_new();
if (!hitlist) {
goto beach;
}
const char *s = sdbkv_value(kv);
ut64 addr;
int opsz;
int mode = 0;
// Options, like JSON, linear, ...
if (*(input + 1)) {
mode = *(input + 1);
}
do {
RzCoreAsmHit *hit = rz_core_asm_hit_new();
if (!hit) {
rz_list_free(hitlist);
goto beach;
}
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, param.pj, mode);
rz_list_free(hitlist);
}
rz_pvector_free(items);
}
}
goto beach;
case 'r': // "/r"
{
ut64 n = (input[1] == ' ' || (input[1] && input[2] == ' '))
@ -3758,6 +3815,10 @@ reread:
}
break;
case 'x': // "/x" search hex
if (!input[1]) {
RZ_LOG_ERROR("core: missing hexpairs:binmask\n");
break;
}
if (input[1] == '?') {
rz_core_cmd_help(core, help_msg_slash_x);
} else {

View file

@ -101,6 +101,9 @@ static const RzCmdDescArg interpret_output_args[2];
static const RzCmdDescArg interpret_pipe_args[2];
static const RzCmdDescArg interpret_macro_args[4];
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 remote_args[3];
static const RzCmdDescArg remote_send_args[3];
static const RzCmdDescArg remote_add_args[2];
@ -1350,6 +1353,53 @@ static const RzCmdDescHelp interpret_macro_multiple_help = {
static const RzCmdDescHelp cmd_search_help = {
.summary = "Search for bytes, regexps, patterns, ..",
};
static const RzCmdDescHelp slash_R_help = {
.summary = "List ROP Gadgets",
};
static const RzCmdDescArg cmd_info_gadget_args[] = {
{
.name = "filter-by-string",
.type = RZ_CMD_ARG_TYPE_STRING,
.flags = RZ_CMD_ARG_FLAG_LAST,
.optional = true,
},
{ 0 },
};
static const RzCmdDescHelp cmd_info_gadget_help = {
.summary = "List ROP Gadgets",
.args = cmd_info_gadget_args,
};
static const RzCmdDescArg cmd_search_gadget_args[] = {
{
.name = "filter-by-regex",
.type = RZ_CMD_ARG_TYPE_STRING,
.flags = RZ_CMD_ARG_FLAG_LAST,
.optional = true,
},
{ 0 },
};
static const RzCmdDescHelp cmd_search_gadget_help = {
.summary = "List ROP Gadgets [regular expression]",
.args = cmd_search_gadget_args,
};
static const RzCmdDescArg cmd_query_gadget_args[] = {
{
.name = "nop|mov|arithm",
.type = RZ_CMD_ARG_TYPE_STRING,
.flags = RZ_CMD_ARG_FLAG_LAST,
.optional = false,
},
{ 0 },
};
static const RzCmdDescHelp cmd_query_gadget_help = {
.summary = "Query ROP Gadgets",
.args = cmd_query_gadget_args,
};
static const RzCmdDescHelp R_help = {
.summary = "Connect with other instances of rizin",
@ -19169,6 +19219,16 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) {
RzCmdDesc *cmd_search_cd = rz_cmd_desc_oldinput_new(core->rcmd, root_cd, "/", rz_cmd_search, &cmd_search_help);
rz_warn_if_fail(cmd_search_cd);
RzCmdDesc *slash_R_cd = rz_cmd_desc_group_state_new(core->rcmd, cmd_search_cd, "/R", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_info_gadget_handler, &cmd_info_gadget_help, &slash_R_help);
rz_warn_if_fail(slash_R_cd);
rz_cmd_desc_set_default_mode(slash_R_cd, RZ_OUTPUT_MODE_STANDARD);
RzCmdDesc *cmd_search_gadget_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_R_cd, "/R/", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_gadget_handler, &cmd_search_gadget_help);
rz_warn_if_fail(cmd_search_gadget_cd);
rz_cmd_desc_set_default_mode(cmd_search_gadget_cd, RZ_OUTPUT_MODE_STANDARD);
RzCmdDesc *cmd_query_gadget_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_R_cd, "/Rk", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_query_gadget_handler, &cmd_query_gadget_help);
rz_warn_if_fail(cmd_query_gadget_cd);
rz_cmd_desc_set_default_mode(cmd_query_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);

View file

@ -61,6 +61,12 @@ RZ_IPI RzCmdStatus rz_interpret_pipe_handler(RzCore *core, int argc, const char
RZ_IPI RzCmdStatus rz_interpret_macro_handler(RzCore *core, int argc, const char **argv);
// "..("
RZ_IPI RzCmdStatus rz_interpret_macro_multiple_handler(RzCore *core, int argc, const char **argv);
// "/R"
RZ_IPI RzCmdStatus rz_cmd_info_gadget_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state);
// "/R/"
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);
// "/"
RZ_IPI int rz_cmd_search(void *data, const char *input);
// "R"

View file

@ -153,8 +153,9 @@ commands:
subcommands: cmd_interpret
- name: /
cname: cmd_search
summary: Search for bytes, regexps, patterns, ..
type: RZ_CMD_DESC_TYPE_OLDINPUT
summary: Search for bytes, regexps, patterns, ..
subcommands: cmd_search
- name: "R"
summary: Connect with other instances of rizin
subcommands: cmd_remote

View file

@ -0,0 +1,50 @@
# SPDX-FileCopyrightText: 2024 RizinOrg <info@rizin.re>
# SPDX-License-Identifier: LGPL-3.0-only
---
name: cmd_search
commands:
- name: "/R"
summary: List ROP Gadgets
subcommands:
- name: "/R"
cname: cmd_info_gadget
summary: List ROP Gadgets
type: RZ_CMD_DESC_TYPE_ARGV_STATE
default_mode: RZ_OUTPUT_MODE_STANDARD
modes:
- RZ_OUTPUT_MODE_STANDARD
- RZ_OUTPUT_MODE_JSON
- RZ_OUTPUT_MODE_QUIET
- RZ_OUTPUT_MODE_TABLE
args:
- name: filter-by-string
type: RZ_CMD_ARG_TYPE_STRING
optional: true
- name: "/R/"
cname: cmd_search_gadget
summary: List ROP Gadgets [regular expression]
type: RZ_CMD_DESC_TYPE_ARGV_STATE
default_mode: RZ_OUTPUT_MODE_STANDARD
modes:
- RZ_OUTPUT_MODE_STANDARD
- RZ_OUTPUT_MODE_JSON
- RZ_OUTPUT_MODE_QUIET
- RZ_OUTPUT_MODE_TABLE
args:
- name: filter-by-regex
type: RZ_CMD_ARG_TYPE_STRING
optional: true
- name: "/Rk"
cname: cmd_query_gadget
summary: Query ROP Gadgets
type: RZ_CMD_DESC_TYPE_ARGV_STATE
default_mode: RZ_OUTPUT_MODE_STANDARD
modes:
- RZ_OUTPUT_MODE_STANDARD
- RZ_OUTPUT_MODE_JSON
- RZ_OUTPUT_MODE_QUIET
- RZ_OUTPUT_MODE_TABLE
args:
- name: nop|mov|arithm
type: RZ_CMD_ARG_TYPE_STRING
optional: false

View file

@ -25,6 +25,7 @@ cmd_descs_yaml = files(
'cmd_remote.yaml',
'cmd_resize.yaml',
'cmd_seek.yaml',
'cmd_search.yaml',
'cmd_shell.yaml',
'cmd_system.yaml',
'cmd_tasks.yaml',

View file

@ -551,26 +551,31 @@ EXPECT=<<EOF
0x00000284 8058 subi r24, 0x80
0x00000286 82bb out 0x12, r24
0x00000288 0895 ret
Gadget size: 10
0x00000294 7304 cpc r7, r3
0x00000296 88b3 in r24, 0x18
0x00000298 8058 subi r24, 0x80
0x0000029a 88bb out 0x18, r24
0x0000029c 0895 ret
Gadget size: 10
0x000005c6 8fb5 in r24, 0x2f
0x000005c8 8f77 andi r24, 0x7f
0x000005ca 02c0 rjmp 0x5d0
Gadget size: 6
0x000005cc 8fb5 in r24, 0x2f
0x000005ce 8f7d andi r24, 0xdf
0x000005d0 8fbd out 0x2f, r24
0x000005d2 0895 ret
Gadget size: 8
0x000005d4 85b5 in r24, 0x25
0x000005d6 8f7d andi r24, 0xdf
0x000005d8 85bd out 0x25, r24
0x000005da 0895 ret
Gadget size: 8
EOF
RUN
@ -588,26 +593,31 @@ EXPECT=<<EOF
0x00000284 8058 subi r24, 0x80
0x00000286 82bb out 0x12, r24
0x00000288 0895 ret
Gadget size: 10
0x00000294 7304 cpc r7, r3
0x00000296 88b3 in r24, 0x18
0x00000298 8058 subi r24, 0x80
0x0000029a 88bb out 0x18, r24
0x0000029c 0895 ret
Gadget size: 10
0x000005c6 8fb5 in r24, 0x2f
0x000005c8 8f77 andi r24, 0x7f
0x000005ca 02c0 rjmp 0x5d0
Gadget size: 6
0x000005cc 8fb5 in r24, 0x2f
0x000005ce 8f7d andi r24, 0xdf
0x000005d0 8fbd out 0x2f, r24
0x000005d2 0895 ret
Gadget size: 8
0x000005d4 85b5 in r24, 0x25
0x000005d6 8f7d andi r24, 0xdf
0x000005d8 85bd out 0x25, r24
0x000005da 0895 ret
Gadget size: 8
EOF
RUN

View file

@ -43,23 +43,27 @@ EXPECT=<<EOF
0x000000bb b900000000 mov ecx, 0
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 15
0x000000b5 80b801000000b9 cmp byte [eax + 1], 0xb9
0x000000bc 0000 add byte [eax], al
0x000000be 0000 add byte [eax], al
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 14
0x000000b7 0100 add dword [eax], eax
0x000000b9 0000 add byte [eax], al
0x000000bb b900000000 mov ecx, 0
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 12
0x000000b8 0000 add byte [eax], al
0x000000ba 00b900000000 add byte [ecx], bh
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 11
EOF
RUN
@ -78,12 +82,14 @@ EXPECT=<<EOF
0x000000bb b900000000 mov ecx, 0
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 15
0x000000b7 0100 add dword [eax], eax
0x000000b9 0000 add byte [eax], al
0x000000bb b900000000 mov ecx, 0
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 12
EOF
RUN
@ -118,17 +124,20 @@ EXPECT=<<EOF
0x000000bb b900000000 mov ecx, 0
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 15
0x000000b7 0100 add dword [eax], eax
0x000000b9 0000 add byte [eax], al
0x000000bb b900000000 mov ecx, 0
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 12
0x000000b8 0000 add byte [eax], al
0x000000ba 00b900000000 add byte [ecx], bh
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 11
EOF
RUN
@ -152,7 +161,7 @@ ARGS=-n
CMDS=<<EOF
e asm.arch=x86
e asm.bits=32
"/R/ (ecx|eax)"
/R/ "(ecx|eax)"
EOF
EXPECT=<<EOF
0x000000b4 cd80 int 0x80
@ -160,23 +169,27 @@ EXPECT=<<EOF
0x000000bb b900000000 mov ecx, 0
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 15
0x000000b5 80b801000000b9 cmp byte [eax + 1], 0xb9
0x000000bc 0000 add byte [eax], al
0x000000be 0000 add byte [eax], al
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 14
0x000000b7 0100 add dword [eax], eax
0x000000b9 0000 add byte [eax], al
0x000000bb b900000000 mov ecx, 0
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 12
0x000000b8 0000 add byte [eax], al
0x000000ba 00b900000000 add byte [ecx], bh
0x000000c0 cd80 int 0x80
0x000000c2 c3 ret
Gadget size: 11
EOF
RUN
@ -188,7 +201,7 @@ e asm.bits=32
e rop.len=15
e search.from=0x08048340
e search.to=0x08048400
"/R push esp"
/R push esp
EOF
EXPECT=<<EOF
0x08048350 fff4 push esp
@ -201,19 +214,21 @@ EXPECT=<<EOF
0x0804835e 6690 nop
0x08048360 8b1c24 mov ebx, dword [esp]
0x08048363 c3 ret
Gadget size: 20
EOF
RUN
NAME=search rop with sequence.
FILE=bins/elf/analysis/x86-helloworld-gcc
CMDS="/R push esi;push ebx"
CMDS=/R "push esi;push ebx"
EXPECT=<<EOF
0x08048421 57 push edi
0x08048422 31ff xor edi, edi
0x08048424 56 push esi
0x08048425 53 push ebx
0x08048426 e805ffffff call 0x8048330
Gadget size: 10
EOF
RUN
@ -222,7 +237,7 @@ NAME=search rop with regex sequence.
FILE=bins/elf/analysis/x86-helloworld-gcc
CMDS=<<EOF
e asm.bits=32
"/R/ push esi;push ebx"
/R/ "push esi;push ebx"
EOF
EXPECT=<<EOF
0x08048421 57 push edi
@ -230,6 +245,7 @@ EXPECT=<<EOF
0x08048424 56 push esi
0x08048425 53 push ebx
0x08048426 e805ffffff call 0x8048330
Gadget size: 10
EOF
RUN
@ -249,83 +265,97 @@ EXPECT=<<EOF
0x00000012 e6e3 ldi r30, 0x36
0x00000014 f4e3 ldi r31, 0x34
0x00000016 02c0 rjmp 0x1c
Gadget size: 10
0x00000020 d9f7 brne 0x18
0x00000022 22e0 ldi r18, 0x02
0x00000024 a4e1 ldi r26, 0x14
0x00000026 b2e0 ldi r27, 0x02
0x00000028 01c0 rjmp 0x2c
Gadget size: 10
0x00000030 e1f7 brne 0x2a
0x00000032 10e0 ldi r17, 0x00
0x00000034 c2e6 ldi r28, 0x62
0x00000036 d0e0 ldi r29, 0x00
0x00000038 04c0 rjmp 0x42
Gadget size: 10
0x00000072 6ce0 ldi r22, 0x0c
0x00000074 71e0 ldi r23, 0x01
0x00000076 8fe1 ldi r24, 0x1f
0x00000078 92e0 ldi r25, 0x02
0x0000007a 0e946b04 call 0x8d6
Gadget size: 12
0x00000098 a701 movw r20, r14
0x0000009a 6ae0 ldi r22, 0x0a
0x0000009c 8fe1 ldi r24, 0x1f
0x0000009e 92e0 ldi r25, 0x02
0x000000a0 0e94d808 call 0x11b0
Gadget size: 12
0x000000c4 1082 st Z, r1
0x000000c6 60e0 ldi r22, 0x00
0x000000c8 71e0 ldi r23, 0x01
0x000000ca c801 movw r24, r16
0x000000cc 0e949816 call 0x2d30
Gadget size: 12
0x000000d4 6de1 ldi r22, 0x1d
0x000000d6 71e0 ldi r23, 0x01
0x000000d8 8fe1 ldi r24, 0x1f
0x000000da 92e0 ldi r25, 0x02
0x000000dc 0e946b04 call 0x8d6
Gadget size: 12
0x000000de 6b04 cpc r6, r11
0x000000e0 81e0 ldi r24, 0x01
0x000000e2 90e0 ldi r25, 0x00
0x000000e4 08c0 rjmp 0xf6
Gadget size: 8
0x000000e6 66e4 ldi r22, 0x46
0x000000e8 71e0 ldi r23, 0x01
0x000000ea 8fe1 ldi r24, 0x1f
0x000000ec 92e0 ldi r25, 0x02
0x000000ee 0e946b04 call 0x8d6
Gadget size: 12
0x00000112 6de6 ldi r22, 0x6d
0x00000114 71e0 ldi r23, 0x01
0x00000116 8fe1 ldi r24, 0x1f
0x00000118 92e0 ldi r25, 0x02
0x0000011a 0e946b04 call 0x8d6
Gadget size: 12
0x00000126 6fe7 ldi r22, 0x7f
0x00000128 71e0 ldi r23, 0x01
0x0000012a 8fe1 ldi r24, 0x1f
0x0000012c 92e0 ldi r25, 0x02
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
0x000001bc c801 movw r24, r16
0x000001be 0e949816 call 0x2d30
Gadget size: 12
EOF
EXPECT_ERR=<<EOF

View file

@ -428,14 +428,17 @@ EXPECT=<<EOF
0x00000003 5b pop ebx
0x00000004 5d pop ebp
0x00000005 c3 ret
Gadget size: 6
0x00000001 c408 les ecx, [eax]
0x00000003 5b pop ebx
0x00000004 5d pop ebp
0x00000005 c3 ret
Gadget size: 5
0x00000002 085b5d or byte [ebx + 0x5d], bl
0x00000005 c3 ret
Gadget size: 4
EOF
RUN
@ -454,6 +457,7 @@ EOF
EXPECT=<<EOF
0x00000002 085b5d or byte [ebx + 0x5d], bl
0x00000005 c3 ret
Gadget size: 4
EOF
RUN
@ -479,6 +483,8 @@ EXPECT=<<EOF
0x00000014 04000000 sllv zero, zero, zero
0x00000018 08000000 jr zero
0x0000001c 00000070 madd zero, zero
Gadget size: 20
EOF
RUN