static void parse_localvar (RParse *p, char *newstr, size_t newstr_len, const char *var, const char *reg, char sign, char *ireg, bool att) { RStrBuf *sb = r_strbuf_new (""); if (att) { if (p->localvar_only) { if (ireg) { r_strbuf_setf (sb, "(%%%s)", ireg); } snprintf (newstr, newstr_len - 1, "%s%s", var, r_strbuf_get (sb)); } else { if (ireg) { r_strbuf_setf (sb, ", %%%s", ireg); } snprintf (newstr, newstr_len - 1, "%s(%%%s%s)", var, reg, r_strbuf_get (sb)); } } else { if (ireg) { r_strbuf_setf (sb, " + %s", ireg); } if (p->localvar_only) { snprintf (newstr, newstr_len - 1, "[%s%s]", var, r_strbuf_get (sb)); } else { snprintf (newstr, newstr_len - 1, "[%s%s %c %s]", reg, r_strbuf_get (sb), sign, var); } } r_strbuf_free (sb); }
static int disassemble(RAsm *a, RAsmOp *op, const ut8 *buf, int len) { static struct disassemble_info disasm_obj; if (len < 2) { return -1; } buf_global = r_strbuf_get (&op->buf_asm); Offset = a->pc; if (len > sizeof (bytes)) { len = sizeof (bytes); } memcpy (bytes, buf, len); // TODO handle compact buf_len = len; /* prepare disassembler */ memset (&disasm_obj,'\0', sizeof (struct disassemble_info)); disasm_obj.buffer = bytes; disasm_obj.buffer_length = len; disasm_obj.read_memory_func = &arc_buffer_read_memory; disasm_obj.symbol_at_address_func = &symbol_at_address; disasm_obj.memory_error_func = &memory_error_func; disasm_obj.print_address_func = &print_address; disasm_obj.endian = !a->big_endian; disasm_obj.fprintf_func = &buf_fprintf; disasm_obj.stream = stdout; disasm_obj.mach = 0; r_strbuf_set (&op->buf_asm, ""); if (a->bits == 16) { op->size = ARCompact_decodeInstr ((bfd_vma)Offset, &disasm_obj); } else { op->size = ARCTangent_decodeInstr ((bfd_vma)Offset, &disasm_obj); } if (op->size == -1) { r_strbuf_set (&op->buf_asm, "(data)"); } return op->size; }
static int stack_clean (RCore *core, ut64 addr, RAnalFunction *fcn) { int offset, ret; char *tmp, *str, *sig; RAnalOp *op = r_core_anal_op (core, addr); if (!op) { return 0; } str = strdup (r_strbuf_get (&op->esil)); if (!str) { return 0; } tmp = strchr (str, ','); if (!tmp) { free (str); return 0; } *tmp++ = 0; offset = r_num_math (core->num, str); const char *sp = r_reg_get_name (core->anal->reg, R_REG_NAME_SP); sig = sdb_fmt (-1, "%s,+=", sp); ret = 0; if (!strncmp (tmp, sig, strlen (sig))) { const char *esil = sdb_fmt (-1, "%d,%s,-=", offset, sp); r_anal_esil_parse (core->anal->esil, esil); r_anal_esil_dumpstack (core->anal->esil); r_anal_esil_stack_free (core->anal->esil); r_core_esil_step (core, UT64_MAX, NULL); ret = op->size; } r_anal_op_free (op); free (str); return ret; }
R_API void r_anal_esil_trace (RAnalEsil *esil, RAnalOp *op) { const char *expr = r_strbuf_get (&op->esil); int esil_debug = esil->debug; if (ocbs_set) { eprintf ("cannot call recursively\n"); } ocbs = esil->cb; ocbs_set = R_TRUE; if (!DB) DB = sdb_new0 (); sdb_num_set (DB, "idx", esil->trace_idx, 0); sdb_num_set (DB, KEY ("addr"), op->addr, 0); // sdb_set (DB, KEY ("opcode"), op->mnemonic, 0); // sdb_set (DB, KEY ("addr"), expr, 0); eprintf ("[ESIL] ADDR 0x%08"PFMT64x"\n", op->addr); //eprintf ("[ESIL] OPCODE %s\n", op->mnemonic); eprintf ("[ESIL] EXPR = %s\n", expr); /* set hooks */ esil->debug = 0; esil->cb.hook_reg_read = trace_hook_reg_read; esil->cb.hook_reg_write = trace_hook_reg_write; esil->cb.hook_mem_read = trace_hook_mem_read; esil->cb.hook_mem_write = trace_hook_mem_write; /* evaluate esil expression */ r_anal_esil_parse (esil, expr); /* restore hooks */ esil->cb = ocbs; ocbs_set = R_FALSE; esil->debug = esil_debug; esil->trace_idx ++; }
static int disassemble(struct r_asm_t *a, struct r_asm_op_t *op, const ut8 *buf, int len) { static struct disassemble_info disasm_obj; if (len < 4) { return -1; } buf_global = r_strbuf_get (&op->buf_asm); Offset = a->pc; memcpy (bytes, buf, 4); // TODO handle thumb /* prepare disassembler */ memset (&disasm_obj,'\0', sizeof (struct disassemble_info)); mips_mode = a->bits; disasm_obj.arch = CPU_LOONGSON_2F; disasm_obj.buffer = bytes; disasm_obj.read_memory_func = &mips_buffer_read_memory; disasm_obj.symbol_at_address_func = &symbol_at_address; disasm_obj.memory_error_func = &memory_error_func; disasm_obj.print_address_func = &print_address; disasm_obj.buffer_vma = Offset; disasm_obj.buffer_length = 4; disasm_obj.endian = !a->big_endian; disasm_obj.fprintf_func = &buf_fprintf; disasm_obj.stream = stdout; op->size = (disasm_obj.endian == BFD_ENDIAN_LITTLE) ? print_insn_little_mips ((bfd_vma)Offset, &disasm_obj) : print_insn_big_mips ((bfd_vma)Offset, &disasm_obj); if (op->size == -1) { r_strbuf_set (&op->buf_asm, "(data)"); } return op->size; }
static int analyze(RAnal *anal, RAnalOp *op, ut64 offset, ut8* buf, int len) { char *bytes, *optype = NULL, *stackop = NULL; int ret; ret = r_anal_op (anal, op, offset, buf, len); if (ret) { stackop = stackop2str (op->stackop); optype = optype2str (op->type); bytes = r_hex_bin2strdup (buf, ret); printf ("bytes: %s\n", bytes); printf ("type: %s\n", optype); if (op->jump != -1LL) printf ("jump: 0x%08"PFMT64x"\n", op->jump); if (op->fail != -1LL) printf ("fail: 0x%08"PFMT64x"\n", op->fail); //if (op->ref != -1LL) // printf ("ref: 0x%08"PFMT64x"\n", op->ref); if (op->val != -1LL) printf ("value: 0x%08"PFMT64x"\n", op->val); printf ("stackop: %s\n", stackop); printf ("esil: %s\n", r_strbuf_get (&op->esil)); printf ("stackptr: %"PFMT64d"\n", op->stackptr); printf ("decode str: %s\n", r_anal_op_to_string (anal, op)); printf ("--\n"); free (optype); free (stackop); free (bytes); } return ret; }
R_API RAnalOp *r_anal_op_copy (RAnalOp *op) { RAnalOp *nop = R_NEW (RAnalOp); *nop = *op; nop->mnemonic = strdup (op->mnemonic); nop->src[0] = r_anal_value_copy (op->src[0]); nop->src[1] = r_anal_value_copy (op->src[1]); nop->src[2] = r_anal_value_copy (op->src[2]); nop->dst = r_anal_value_copy (op->dst); r_strbuf_init (&nop->esil); r_strbuf_set (&nop->esil, r_strbuf_get (&op->esil)); return nop; }
static int assemble(RAsm *a, RAsmOp *op, const char *str) { ut8 *opbuf = (ut8*)r_strbuf_get (&op->buf); int ret = mips_assemble (str, a->pc, opbuf); if (a->big_endian) { ut8 tmp = opbuf[0]; opbuf[0] = opbuf[3]; opbuf[3] = tmp; tmp = opbuf[1]; opbuf[1] = opbuf[2]; opbuf[2] = tmp; } return ret; }
static inline void mk_reg_str(const char *regname, int delta, bool sign, bool att, char *ireg, char *dest, int len) { RStrBuf *sb = r_strbuf_new (""); if (att) { if (ireg) { r_strbuf_setf (sb, ", %%%s", ireg); } if (delta < 10) { snprintf (dest, len - 1, "%s%d(%%%s%s)", sign ? "" : "-", delta, regname, r_strbuf_get (sb)); } else { snprintf (dest, len - 1, "%s0x%x(%%%s%s)", sign ? "" : "-", delta, regname, r_strbuf_get (sb)); } } else { if (ireg) { r_strbuf_setf (sb, " + %s", ireg); } if (delta < 10) { snprintf (dest, len - 1, "[%s%s %c %d]", regname, r_strbuf_get (sb), sign ? '+':'-', delta); } else { snprintf (dest, len - 1, "[%s%s %c 0x%x]", regname, r_strbuf_get (sb), sign ? '+':'-', delta); } } r_strbuf_free (sb); }
static ut64 ws_find_label(int l, RIOBind iob) { RIO *io = iob.io; ut64 cur = 0, size = iob.desc_size (io->desc); ut8 buf[128]; RAsmOp aop; iob.read_at (iob.io, cur, buf, 128); while (cur <= size && wsdis (&aop, buf, 128)) { const char *buf_asm = r_strbuf_get (&aop.buf_asm); // r_asm_op_get_asm (&aop); if (buf_asm && (strlen (buf_asm) > 4) && buf_asm[0] == 'm' && buf_asm[1] == 'a' && l == atoi (buf_asm + 5)) { return cur; } cur = cur + aop.size; iob.read_at (iob.io, cur, buf, 128); } return 0; }
static int disassemble(RAsm *a, RAsmOp *op, const ut8 *buf, int len) { RAsmLm32Instruction instr = {0}; instr.value = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; instr.addr = a->pc; if (r_asm_lm32_decode (&instr)) { r_strbuf_set (&op->buf_asm, "invalid"); a->invhex = 1; return -1; } //op->buf_asm is 256 chars long, which is more than sufficient if (r_asm_lm32_stringify (&instr, r_strbuf_get (&op->buf_asm))) { r_strbuf_set (&op->buf_asm, "invalid"); a->invhex = 1; return -1; } return 4; }
R_API RAnalOp *r_anal_op_copy (RAnalOp *op) { RAnalOp *nop = R_NEW0 (RAnalOp); if (!nop) return NULL; *nop = *op; if (op->mnemonic) { nop->mnemonic = strdup (op->mnemonic); if (!nop->mnemonic) { free (nop); return NULL; } } else { nop->mnemonic = NULL; } nop->src[0] = r_anal_value_copy (op->src[0]); nop->src[1] = r_anal_value_copy (op->src[1]); nop->src[2] = r_anal_value_copy (op->src[2]); nop->dst = r_anal_value_copy (op->dst); r_strbuf_init (&nop->esil); r_strbuf_set (&nop->esil, r_strbuf_get (&op->esil)); return nop; }
R_API const char *r_anal_op_to_esil_string(RAnal *anal, RAnalOp *op) { return r_strbuf_get (&op->esil); }
static int do_disassemble(RAsm *a, RAsmOp *op, const ut8 *buf, int len) { int dlen = i8080_disasm (buf, r_strbuf_get (&op->buf_asm), len); return op->size = R_MAX (0, dlen); }
static int assemble(RAsm *a, RAsmOp *op, const char *buf) { int len = dcpu16_assemble ((ut8*)r_strbuf_get (&op->buf), buf); op->buf.len = len; return len; }
// 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; }
static int disassemble(RAsm *a, struct r_asm_op_t *op, const ut8 *buf, int len) { char *buf_asm = r_strbuf_get (&op->buf_asm); arch_xap_disasm (buf_asm, buf, a->pc); return (op->size = 2); }
static RList *r_core_asm_back_disassemble (RCore *core, ut64 addr, int len, ut64 max_hit_count, ut8 disassmble_each_addr, ut32 extra_padding) { RList *hits;; RAsmOp op; ut8 *buf = NULL; ut8 max_invalid_b4_exit = 4, last_num_invalid = 0; int current_instr_len = 0; ut64 current_instr_addr = addr, current_buf_pos = 0, next_buf_pos = len; RCoreAsmHit dummy_value; ut32 hit_count = 0; if (disassmble_each_addr) { return r_core_asm_back_disassemble_all(core, addr, len, max_hit_count, extra_padding+1); } hits = r_core_asm_hit_list_new (); buf = malloc (len + extra_padding); if (!hits || !buf) { if (hits) { r_list_purge (hits); free (hits); } free (buf); return NULL; } if (!r_io_read_at (core->io, (addr + extra_padding) - len, buf, len + extra_padding)) { r_list_purge (hits); free (hits); free (buf); return NULL; } // // XXX - This is a heavy handed approach without a // an appropriate btree or hash table for storing // hits, because are using: // 1) Sorted RList with many inserts and searches // 2) Pruning hits to find the most optimal disassembly // greedy approach // 1) Consume previous bytes // 1a) Instruction is invalid (incr current_instr_addr) // 1b) Disasm is perfect // 1c) Disasm is underlap (disasm(current_instr_addr, next_instr_addr - current_instr_addr) short some bytes) // 1d) Disasm is overlap (disasm(current_instr_addr, next_instr_addr - current_instr_addr) over some bytes) memset (&dummy_value, 0, sizeof (RCoreAsmHit)); // disassemble instructions previous to current address, extra_padding can move the location of addr // so we need to account for that with current_buf_pos current_buf_pos = len - extra_padding - 1; next_buf_pos = len + extra_padding - 1; current_instr_addr = addr - 1; do { if (r_cons_is_breaked ()) { break; } // reset assembler r_asm_set_pc (core->assembler, current_instr_addr); current_instr_len = next_buf_pos - current_buf_pos; current_instr_len = r_asm_disassemble (core->assembler, &op, buf+current_buf_pos, current_instr_len); IFDBG { ut32 byte_cnt = current_instr_len ? current_instr_len : 1; eprintf("current_instr_addr: 0x%"PFMT64x", current_buf_pos: 0x%"PFMT64x", current_instr_len: %d \n", current_instr_addr, current_buf_pos, current_instr_len); ut8 *hex_str = (ut8*)r_hex_bin2strdup(buf+current_buf_pos, byte_cnt); eprintf ("==== current_instr_bytes: %s ",hex_str); if (current_instr_len > 0) { eprintf("op.buf_asm: %s\n", r_strbuf_get (&op.buf_asm)); } else { eprintf("op.buf_asm: <invalid>\n"); } free (hex_str); } // disassembly invalid if (current_instr_len == 0 || strstr (r_strbuf_get (&op.buf_asm), "invalid")) { if (current_instr_len == 0) { current_instr_len = 1; } add_hit_to_sorted_hits(hits, current_instr_addr, current_instr_len, /* is_valid */ false); hit_count ++; last_num_invalid ++; // disassembly perfect } else if (current_buf_pos + current_instr_len == next_buf_pos) { // i think this may be the only case where an invalid instruction will be // added because handle_forward_disassemble and handle_disassembly_overlap // are only called in cases where a valid instruction has been found. // and they are lazy, since they purge the hit list ut32 purge_results = 0; ut8 is_valid = true; IFDBG eprintf(" handling underlap case: current_instr_addr: 0x%"PFMT64x".\n", current_instr_addr); purge_results = prune_hits_in_addr_range(hits, current_instr_addr, current_instr_len, /* is_valid */ true); if (purge_results) { handle_forward_disassemble(core, hits, buf, len, current_buf_pos+current_instr_len, current_instr_addr+current_instr_len, addr); hit_count = r_list_length(hits); } add_hit_to_sorted_hits(hits, current_instr_addr, current_instr_len, is_valid); //handle_forward_disassemble(core, hits, buf, len, current_buf_pos+current_instr_len, current_instr_addr+current_instr_len, addr/*end_addr*/); hit_count ++; next_buf_pos = current_buf_pos; last_num_invalid = 0; // disassembly underlap } else if (current_buf_pos + current_instr_len < next_buf_pos) { ut32 purge_results = 0; ut8 is_valid = true; purge_results = prune_hits_in_addr_range(hits, current_instr_addr, current_instr_len, /* is_valid */ true); add_hit_to_sorted_hits(hits, current_instr_addr, current_instr_len, is_valid); if (hit_count < purge_results) { hit_count = 0; // WTF?? } else { hit_count -= purge_results; } next_buf_pos = current_buf_pos; handle_forward_disassemble(core, hits, buf, len - extra_padding, current_buf_pos+current_instr_len, current_instr_addr+current_instr_len, addr); hit_count = r_list_length(hits); last_num_invalid = 0; // disassembly overlap } else if (current_buf_pos + current_instr_len > next_buf_pos) { //ut64 value = handle_disassembly_overlap(core, hits, buf, len, current_buf_pos, current_instr_addr); next_buf_pos = current_buf_pos; hit_count = r_list_length (hits); last_num_invalid = 0; } // walk backwards by one instruction IFDBG eprintf(" current_instr_addr: 0x%"PFMT64x" current_instr_len: %d next_instr_addr: 0x%04"PFMT64x"\n", current_instr_addr, current_instr_len, next_buf_pos); IFDBG eprintf(" hit count: %d \n", hit_count ); current_instr_addr -= 1; current_buf_pos -= 1; if (hit_count >= max_hit_count && (last_num_invalid >= max_invalid_b4_exit || last_num_invalid == 0)) { break; } } while (((int) current_buf_pos >= 0) && (int)(len - current_buf_pos) >= 0); r_asm_set_pc (core->assembler, addr); free (buf); return hits; }
R_API char *r_asm_op_get_asm(RAsmOp *op) { return r_strbuf_get (&op->buf_asm); }
R_API ut8 *r_asm_op_get_buf(RAsmOp *op) { r_return_val_if_fail (op, NULL); return (ut8*)r_strbuf_get (&op->buf); }
R_API char *pj_fmt(PrintfCallback p, const char *fmt, ...) { va_list ap; va_start (ap, fmt); char ch[2] = { 0 }; PJ *j = pj_new (); while (*fmt) { j->is_first = true; ch[0] = *fmt; switch (*fmt) { case '\\': fmt++; switch (*fmt) { // TODO: add \x, and \e case 'e': pj_raw (j, "\x1b"); break; case 'r': pj_raw (j, "\r"); break; case 'n': pj_raw (j, "\n"); break; case 'b': pj_raw (j, "\b"); break; } break; case '\'': pj_raw (j, "\""); break; case '%': fmt++; switch (*fmt) { case 'b': pj_b (j, va_arg (ap, int)); break; case 's': pj_s (j, va_arg (ap, const char *)); break; case 'S': { const char *s = va_arg (ap, const char *); char *es = r_base64_encode_dyn (s, -1); pj_s (j, es); free (es); } break; case 'n': pj_n (j, va_arg (ap, ut64)); break; case 'd': pj_d (j, va_arg (ap, double)); break; case 'i': pj_i (j, va_arg (ap, int)); break; default: eprintf ("Invalid format\n"); break; } break; default: ch[0] = *fmt; pj_raw (j, ch); break; } fmt++; } char *ret = NULL; if (p) { p ("%s", r_strbuf_get (j->sb)); pj_free (j); } else { ret = pj_drain (j); } va_end (ap); return ret; }
static int disassemble(RAsm *a, RAsmOp *op, const ut8 *buf, int len) { static int omode = 0; int mode, ret; ut64 off = a->pc; mode = (a->bits == 64)? CS_MODE_64: (a->bits == 32)? CS_MODE_32: (a->bits == 16)? CS_MODE_16: 0; if (cd && mode != omode) { cs_close (&cd); cd = 0; } if (op) { op->size = 0; } omode = mode; if (cd == 0) { ret = cs_open (CS_ARCH_X86, mode, &cd); if (ret) { return 0; } } if (a->features && *a->features) { cs_option (cd, CS_OPT_DETAIL, CS_OPT_ON); } else { cs_option (cd, CS_OPT_DETAIL, CS_OPT_OFF); } // always unsigned immediates (kernel addresses) // maybe r2 should have an option for this too? #if CS_API_MAJOR >= 4 cs_option (cd, CS_OPT_UNSIGNED, CS_OPT_ON); #endif if (a->syntax == R_ASM_SYNTAX_MASM) { #if CS_API_MAJOR >= 4 cs_option (cd, CS_OPT_SYNTAX, CS_OPT_SYNTAX_MASM); #endif } else if (a->syntax == R_ASM_SYNTAX_ATT) { cs_option (cd, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); } else { cs_option (cd, CS_OPT_SYNTAX, CS_OPT_SYNTAX_INTEL); } if (!op) { return true; } op->size = 1; cs_insn *insn = NULL; #if USE_ITER_API { size_t size = len; if (!insn || cd < 1) { insn = cs_malloc (cd); } if (!insn) { cs_free (insn, n); return 0; } memset (insn, 0, insn->size); insn->size = 1; n = cs_disasm_iter (cd, (const uint8_t**)&buf, &size, (uint64_t*)&off, insn); } #else n = cs_disasm (cd, (const ut8*)buf, len, off, 1, &insn); #endif if (op) { op->size = 0; } if (a->features && *a->features) { if (!check_features (a, insn)) { op->size = insn->size; r_asm_op_set_asm (op, "illegal"); } } if (op->size == 0 && n > 0 && insn->size > 0) { char *ptrstr; op->size = insn->size; char *buf_asm = sdb_fmt ("%s%s%s", insn->mnemonic, insn->op_str[0]?" ":"", insn->op_str); ptrstr = strstr (buf_asm, "ptr "); if (ptrstr) { memmove (ptrstr, ptrstr + 4, strlen (ptrstr + 4) + 1); } r_asm_op_set_asm (op, buf_asm); } else { decompile_vm (a, op, buf, len); } if (a->syntax == R_ASM_SYNTAX_JZ) { char *buf_asm = r_strbuf_get (&op->buf_asm); if (!strncmp (buf_asm, "je ", 3)) { memcpy (buf_asm, "jz", 2); } else if (!strncmp (buf_asm, "jne ", 4)) { memcpy (buf_asm, "jnz", 3); } } #if 0 // [eax + ebx*4] => [eax + ebx * 4] char *ast = strchr (op->buf_asm, '*'); if (ast && ast > op->buf_asm) { ast--; if (ast[0] != ' ') { char *tmp = strdup (ast + 1); if (tmp) { ast[0] = ' '; if (tmp[0] && tmp[1] && tmp[1] != ' ') { strcpy (ast, " * "); strcpy (ast + 3, tmp + 1); } else { strcpy (ast + 1, tmp); } free (tmp); } } } #endif #if USE_ITER_API /* do nothing because it should be allocated once and freed in the_end */ #else if (insn) { cs_free (insn, n); } #endif return op->size; }
R_API const char *pj_string(PJ *j) { return r_strbuf_get (j->sb); }
static int ws_anal(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len, RAnalOpMask mask) { memset (op, '\0', sizeof (RAnalOp)); op->addr = addr; op->type = R_ANAL_OP_TYPE_UNK; RAsmOp *aop = R_NEW0 (RAsmOp); op->size = wsdis (aop, data, len); if (op->size) { const char *buf_asm = r_strbuf_get (&aop->buf_asm); // r_asm_op_get_asm (aop); switch (*buf_asm) { case 'n': op->type = R_ANAL_OP_TYPE_NOP; break; case 'e': op->type = R_ANAL_OP_TYPE_TRAP; break; case 'd': op->type = (buf_asm[1] == 'u')? R_ANAL_OP_TYPE_UPUSH: R_ANAL_OP_TYPE_DIV; break; case 'i': op->type = R_ANAL_OP_TYPE_ILL; break; case 'a': op->type = R_ANAL_OP_TYPE_ADD; break; case 'm': op->type = (buf_asm[1] == 'o') ? R_ANAL_OP_TYPE_MOD : R_ANAL_OP_TYPE_MUL; break; case 'r': op->type = R_ANAL_OP_TYPE_RET; break; case 'l': op->type = R_ANAL_OP_TYPE_LOAD; break; case 'c': if (buf_asm[1] == 'a') { op->type = R_ANAL_OP_TYPE_CALL; op->fail = addr + aop->size; op->jump = ws_find_label (atoi (buf_asm + 5), anal->iob); } else { op->type = R_ANAL_OP_TYPE_UPUSH; } break; case 'j': if (buf_asm[1] == 'm') { op->type = R_ANAL_OP_TYPE_JMP; op->jump = ws_find_label(atoi (buf_asm + 4), anal->iob); } else { op->type = R_ANAL_OP_TYPE_CJMP; op->jump = ws_find_label(atoi(buf_asm + 3), anal->iob); } op->fail = addr + aop->size; break; case 'g': op->type = R_ANAL_OP_TYPE_IO; break; case 'p': if (buf_asm[1] == 'o') { op->type = R_ANAL_OP_TYPE_POP; } else { if (buf_asm[2] == 's') { op->type = R_ANAL_OP_TYPE_PUSH; if (127 > atoi (buf_asm + 5) && atoi (buf_asm + 5) >= 33) { char c[4]; c[3] = '\0'; c[0] = c[2] = '\''; c[1] = (char) atoi (buf_asm + 5); r_meta_set_string (anal, R_META_TYPE_COMMENT, addr, c); } } else { op->type = R_ANAL_OP_TYPE_IO; } } break; case 's': switch (buf_asm[1]) { case 'u': op->type = R_ANAL_OP_TYPE_SUB; break; case 't': op->type = R_ANAL_OP_TYPE_STORE; break; case 'l': op->type = R_ANAL_OP_TYPE_LOAD; // XXX break; case 'w': op->type = R_ANAL_OP_TYPE_ROR; } break; } } free (aop); return op->size; }