R_API struct r_anal_refline_t *r_anal_reflines_get(struct r_anal_t *anal, ut64 addr, ut8 *buf, ut64 len, int nlines, int linesout, int linescall) { RAnalRefline *list2, *list = R_NEW (RAnalRefline); RAnalOp op = {0}; ut8 *ptr = buf; ut8 *end = buf + len; ut64 opc = addr; int sz = 0, index = 0; INIT_LIST_HEAD (&(list->list)); end -= 8; // XXX Fix some segfaults when r_anal backends are buggy /* analyze code block */ while (ptr<end) { if (nlines != -1 && --nlines == 0) break; #if 0 if (config.interrupted) break; int dt = data_type(config.seek+bsz); if (dt != DATA_FUN && dt != DATA_CODE) { ut64 sz = data_size (config.seek+bsz); if (sz > 0) { ptr += sz; bsz += sz; continue; } } #endif addr += sz; // This can segflauta if opcode length and buffer check fails r_anal_op_fini (&op); sz = r_anal_op (anal, &op, addr, ptr, (int)(end-ptr)); if (sz > 0) { /* store data */ switch (op.type) { case R_ANAL_OP_TYPE_CALL: if (!linescall) break; case R_ANAL_OP_TYPE_CJMP: case R_ANAL_OP_TYPE_JMP: if (!linesout && (op.jump > opc+len || op.jump < opc)) goto __next; if (op.jump == 0LL) goto __next; list2 = R_NEW (RAnalRefline); list2->from = addr; list2->to = op.jump; list2->index = index++; list_add_tail (&(list2->list), &(list->list)); break; } } else sz = 1; __next: ptr += sz; } r_anal_op_fini (&op); return list; }
int emu_step (emu *e, ut8 *buf) { int ret; ut64 addr = r_reg_getv (e->reg, r_reg_get_name (e->reg, R_REG_NAME_PC)); //Check Breakboints here: new return stat for that if (e->plugin->read) { if (e->plugin->min_read_sz) e->plugin->read (e, addr, buf, e->plugin->min_read_sz); else e->plugin->read (e, addr, buf, sizeof(int)); } else { if (e->plugin->min_read_sz) emu_read (e, addr, buf, e->plugin->min_read_sz); else emu_read (e, addr, buf, sizeof(int)); } if (e->plugin->deps & EMU_PLUGIN_DEP_ASM) { //only disassemble if it is necessary r_asm_set_pc (e->a, addr); if (e->plugin->min_read_sz) r_asm_disassemble (e->a, e->op, buf, e->plugin->min_read_sz); else r_asm_disassemble (e->a, e->op, buf, sizeof(int)); } if (e->plugin->deps & EMU_PLUGIN_DEP_ANAL) { //only analize if it is necessary if (e->plugin->min_read_sz) r_anal_op (e->anal, e->anop, addr, buf, e->plugin->min_read_sz); else r_anal_op (e->anal, e->anop, addr, buf, sizeof(int)); } ret = e->plugin->step (e, buf); if (e->plugin->deps & EMU_PLUGIN_DEP_ANAL) r_anal_op_fini (e->anop); return ret; }
R_API void r_anal_op_free(void *_op) { if (!_op) { return; } r_anal_op_fini (_op); memset (_op, 0, sizeof (RAnalOp)); free (_op); }
static int prevopsz (RCore *core, ut64 addr) { ut64 target = addr; ut64 base = target-OPDELTA; int len, ret, i; ut8 buf[OPDELTA*2]; RAnalOp op; r_core_read_at (core, base, buf, sizeof (buf)); for (i=0; i<sizeof (buf); i++) { ret = r_anal_op (core->anal, &op, base+i, buf+i, sizeof (buf)-i); if (!ret) continue; len = op.size; r_anal_op_fini (&op); // XXX if (len<1) continue; i += len-1; if (target == base+i+1) return len; } return 4; }
static int prevopsz (RCore *core, ut64 addr) { const int delta = 32; ut64 target = addr; ut64 base = target-delta; int len, ret, i; ut8 buf[delta*2]; RAnalOp op; r_core_read_at (core, base, buf, sizeof (buf)); for (i=0; i<sizeof (buf); i++) { ret = r_anal_op (core->anal, &op, addr+i, buf+i, sizeof (buf)-i); if (!ret) continue; len = op.length; r_anal_op_fini (&op); if (len<1) continue; i += len-1; if (target == base+i+1) return len; } return 4; }
R_API void r_anal_op_free(void *_op) { if (!_op) return; r_anal_op_fini (_op); free (_op); }
// TODO: add support for byte-per-byte opcode search R_API RList *r_core_asm_strsearch(RCore *core, const char *input, ut64 from, ut64 to, int maxhits, int regexp, int everyByte, int mode) { RCoreAsmHit *hit; RAsmOp op; RList *hits; ut64 at, toff = core->offset; ut8 *buf; int align = core->search->align; RRegex* rx = NULL; char *tok, *tokens[1024], *code = NULL, *ptr; int idx, tidx = 0, len = 0; int tokcount, matchcount, count = 0; int matches = 0; const int addrbytes = core->io->addrbytes; if (!input || !*input) { return NULL; } ut64 usrimm = r_num_math (core->num, input + 1); if (core->blocksize < 8) { eprintf ("error: block size too small\n"); return NULL; } if (!(buf = (ut8 *)calloc (core->blocksize, 1))) { return NULL; } if (!(ptr = strdup (input))) { free (buf); return NULL; } if (!(hits = r_core_asm_hit_list_new ())) { free (buf); free (ptr); return NULL; } tokens[0] = NULL; for (tokcount = 0; tokcount < R_ARRAY_SIZE (tokens) - 1; tokcount++) { tok = strtok (tokcount? NULL: ptr, ";"); if (!tok) { break; } tokens[tokcount] = r_str_trim_head_tail (tok); } tokens[tokcount] = NULL; r_cons_break_push (NULL, NULL); char *opst = NULL; for (at = from, matchcount = 0; at < to; at += core->blocksize) { if (r_cons_is_breaked ()) { break; } if (!r_io_is_valid_offset (core->io, at, 0)) { break; } (void)r_io_read_at (core->io, at, buf, core->blocksize); idx = 0, matchcount = 0; while (addrbytes * (idx + 1) <= core->blocksize) { ut64 addr = at + idx; if (addr >= to) { break; } r_asm_set_pc (core->assembler, addr); if (mode == 'i') { RAnalOp analop = {0}; if (r_anal_op (core->anal, &analop, addr, buf + idx, 15, 0) < 1) { idx ++; // TODO: honor mininstrsz continue; } if (analop.val == usrimm) { if (!(hit = r_core_asm_hit_new ())) { r_list_purge (hits); R_FREE (hits); goto beach; } hit->addr = addr; hit->len = analop.size; // idx + len - tidx; if (hit->len == -1) { r_core_asm_hit_free (hit); goto beach; } r_asm_disassemble (core->assembler, &op, buf + addrbytes * idx, core->blocksize - addrbytes * idx); hit->code = r_str_newf (r_strbuf_get (&op.buf_asm)); idx = (matchcount)? tidx + 1: idx + 1; matchcount = 0; r_list_append (hits, hit); continue; } r_anal_op_fini (&analop); idx ++; // TODO: honor mininstrsz continue; } else if (mode == 'e') { RAnalOp analop = {0}; if (r_anal_op (core->anal, &analop, addr, buf + idx, 15, R_ANAL_OP_MASK_ESIL) < 1) { idx ++; // TODO: honor mininstrsz continue; } //opsz = analop.size; opst = strdup (r_strbuf_get (&analop.esil)); r_anal_op_fini (&analop); } else { if (!(len = r_asm_disassemble ( core->assembler, &op, buf + addrbytes * idx, core->blocksize - addrbytes * idx))) { idx = (matchcount)? tidx + 1: idx + 1; matchcount = 0; continue; } //opsz = op.size; opst = strdup (r_strbuf_get (&op.buf_asm)); } if (opst) { matches = strcmp (opst, "invalid") && strcmp (opst, "unaligned"); } if (matches && tokens[matchcount]) { if (!regexp) { matches = strstr (opst, tokens[matchcount]) != NULL; } else { rx = r_regex_new (tokens[matchcount], ""); if (r_regex_comp (rx, tokens[matchcount], R_REGEX_EXTENDED|R_REGEX_NOSUB) == 0) { matches = r_regex_exec (rx, opst, 0, 0, 0) == 0; } r_regex_free (rx); } } if (align && align > 1) { if (addr % align) { matches = false; } } if (matches) { code = r_str_appendf (code, "%s; ", opst); if (matchcount == tokcount - 1) { if (tokcount == 1) { tidx = idx; } if (!(hit = r_core_asm_hit_new ())) { r_list_purge (hits); R_FREE (hits); goto beach; } hit->addr = addr; hit->len = idx + len - tidx; if (hit->len == -1) { r_core_asm_hit_free (hit); goto beach; } code[strlen (code) - 2] = 0; hit->code = strdup (code); r_list_append (hits, hit); R_FREE (code); matchcount = 0; idx = tidx + 1; if (maxhits) { count++; if (count >= maxhits) { //eprintf ("Error: search.maxhits reached\n"); goto beach; } } } else if (!matchcount) { tidx = idx; matchcount++; idx += len; } else { matchcount++; idx += len; } } else { if (everyByte) { idx = matchcount? tidx + 1: idx + 1; } else { idx += R_MAX (1, len); } R_FREE (code); matchcount = 0; } R_FREE (opst); } } r_cons_break_pop (); r_asm_set_pc (core->assembler, toff); beach: free (buf); free (ptr); free (code); R_FREE (opst); r_cons_break_pop (); return hits; }