static RList * r_core_asm_back_disassemble_all(RCore *core, ut64 addr, ut64 len, ut64 max_hit_count, ut32 extra_padding){ RList *hits = r_core_asm_hit_list_new (); RCoreAsmHit dummy_value; RCoreAsmHit *hit = NULL; RAsmOp op; ut8 *buf = (ut8 *)malloc (len + extra_padding); int current_instr_len = 0; ut64 current_instr_addr = addr, current_buf_pos = len - 1, hit_count = 0; memset (&dummy_value, 0, sizeof (RCoreAsmHit)); if (hits == NULL || buf == NULL ){ if (hits) { r_list_purge (hits); free (hits); } free (buf); return NULL; } if (r_io_read_at (core->io, addr-(len+extra_padding), buf, len+extra_padding) != len+extra_padding) { r_list_purge (hits); free (hits); free (buf); return NULL; } if (len == 0){ return hits; } current_buf_pos = len - 1; do { if (r_cons_singleton ()->breaked) break; // reset assembler r_asm_set_pc (core->assembler, current_instr_addr); current_instr_len = len - current_buf_pos + extra_padding; IFDBG eprintf("current_buf_pos: 0x%"PFMT64x", current_instr_len: %d\n", current_buf_pos, current_instr_len); current_instr_len = r_asm_disassemble (core->assembler, &op, buf+current_buf_pos, current_instr_len); hit = r_core_asm_hit_new (); hit->addr = current_instr_addr; hit->len = current_instr_len; hit->code = NULL; r_list_add_sorted (hits, hit, ((RListComparator)rcoreasm_address_comparator)); current_buf_pos--; current_instr_addr--; hit_count++; } while ( ((int) current_buf_pos >= 0) && (int)(len - current_buf_pos) >= 0 && hit_count <= max_hit_count); free(buf); return hits; }
R_API ut64 r_io_read_i(RIO *io, ut64 addr, int sz, int endian) { ut64 ret = 0LL; int err; ut8 buf[8]; if (sz > 8) sz = 8; if (sz < 0) sz = 1; err = r_io_read_at (io, addr, buf, sz); if (err == sz) r_mem_copyendian ((ut8*)&ret, buf, sz, endian); else return -1; //else perror("Cannot read"); return ret; }
R_API RBuffer *r_io_read_buf(RIO *io, ut64 addr, int len) { RBuffer *b = R_NEW0 (RBuffer); if (!b) return NULL; b->buf = malloc (len); if (!b->buf) { free (b); return NULL; } len = r_io_read_at (io, addr, b->buf, len); b->length = (len < 0)? 0: len; return b; }
static void cmd_write_bits(RCore *core, int set, ut64 val) { ut64 ret, orig; // used to set/unset bit in current address r_io_read_at (core->io, core->offset, (ut8*)&orig, sizeof (orig)); if (set) { ret = orig | val; } else { ret = orig & (~(val)); } if (!r_core_write_at (core, core->offset, (const ut8*)&ret, sizeof (ret))) { cmd_write_fail (); } }
R_API RList *r_core_asm_bwdisassemble (RCore *core, ut64 addr, int n, int len) { RCoreAsmHit *hit; RAsmOp op; RList *hits = NULL; ut8 *buf; ut64 at; int instrlen, ni, idx; if (!(hits = r_core_asm_hit_list_new ())) return NULL; buf = (ut8 *)malloc (len); if (!buf) { r_list_destroy (hits); return NULL; } if (r_io_read_at (core->io, addr-len, buf, len) != len) { r_list_destroy (hits); free (buf); return NULL; } for (idx = 1; idx < len; idx++) { if (r_cons_singleton ()->breaked) break; at = addr - idx; ni = 1; while (at < addr) { r_asm_set_pc (core->assembler, at); //XXX HACK We need another way to detect invalid disasm!! if (!(instrlen = r_asm_disassemble (core->assembler, &op, buf+(len-(addr-at)), addr-at)) || strstr (op.buf_asm, "invalid")) { break; } else { at += instrlen; if (at == addr) { if (ni == n) { if (!(hit = r_core_asm_hit_new ())) { r_list_destroy (hits); free (buf); return NULL; } hit->addr = addr-idx; hit->len = idx; hit->code = NULL; r_list_append (hits, hit); } } else ni++; } } } r_asm_set_pc (core->assembler, addr); free (buf); return hits; }
R_API void r_core_visual_asm(RCore *core) { RCoreVisualAsm cva = {0}; cva.core = core; r_io_read_at (core->io, core->offset, cva.buf, sizeof (cva.buf)); cva.blocklen = r_hex_bin2str (cva.buf, sizeof (cva.buf), cva.blockbuf); r_line_readline_cb (readline_callback, &cva); if (cva.acode && cva.acode->len>0) if (r_cons_yesno ('y', "Save changes? (Y/n)")) r_core_cmdf (core, "wx %s", cva.acode->buf_hex); r_asm_code_free (cva.acode); }
R_API int r_core_read_at(RCore *core, ut64 addr, ut8 *buf, int size) { int ret; if (!core->io || !core->file || size<1) return R_FALSE; r_io_set_fd (core->io, core->file->fd); // XXX ignore ret? -- ultra slow method.. inverse resolution of io plugin brbrb ret = r_io_read_at (core->io, addr, buf, size); if (ret != size) { if (ret<size && ret>0) memset (buf+ret, 0xff, size-ret); else memset (buf, 0xff, size); } if (addr>=core->offset && addr<=core->offset+core->blocksize) r_core_block_read (core, 0); return (ret!=UT64_MAX); }
R_API bool r_core_dump(RCore *core, const char *file, ut64 addr, ut64 size, int append) { ut64 i; ut8 *buf; int bs = core->blocksize; FILE *fd; if (append) { fd = r_sandbox_fopen (file, "ab"); } else { r_sys_truncate (file, 0); fd = r_sandbox_fopen (file, "wb"); } if (!fd) { eprintf ("Cannot open '%s' for writing\n", file); return false; } /* some io backends seems to be buggy in those cases */ if (bs > 4096) { bs = 4096; } buf = malloc (bs); if (!buf) { eprintf ("Cannot alloc %d byte(s)\n", bs); fclose (fd); return false; } r_cons_break_push (NULL, NULL); for (i = 0; i < size; i += bs) { if (r_cons_is_breaked ()) { break; } if ((i + bs) > size) { bs = size - i; } r_io_read_at (core->io, addr + i, buf, bs); if (fwrite (buf, bs, 1, fd) < 1) { eprintf ("write error\n"); break; } } r_cons_break_pop (); fclose (fd); free (buf); return true; }
static bool ioMemcpy (RCore *core, ut64 dst, ut64 src, int len) { bool ret = false; if (len > 0) { ut8 * buf = calloc (1, len); if (buf) { if (r_io_read_at (core->io, src, buf, len)) { if (r_io_write_at (core->io, dst, buf, len)) { r_core_block_read (core); ret = true; } else { eprintf ("r_io_write_at failed at 0x%08"PFMT64x"\n", dst); } } else { eprintf ("r_io_read_at failed at 0x%08"PFMT64x"\n", src); } free (buf); } } return ret; }
R_API int r_core_read_at(RCore *core, ut64 addr, ut8 *buf, int size) { int ret; if (!core->io || !core->file || size<1) return R_FALSE; #if 0 r_io_set_fd (core->io, core->file->fd); // XXX ignore ret? -- ultra slow method.. inverse resolution of io plugin brbrb ret = r_io_read_at (core->io, addr, buf, size); if (addr>=core->offset && addr<=core->offset+core->blocksize) r_core_block_read (core, 0); #else r_io_set_fd (core->io, core->file->fd); // XXX ignore ret? -- ultra slow method.. inverse resolution of io plugin brbrb //ret = r_io_read_at (core->io, addr, buf, size); r_io_seek (core->io, addr, R_IO_SEEK_SET); ret = r_io_read (core->io, buf, size); if (ret != size) { if (ret>=size || ret<0) ret = 0; memset (buf+ret, 0xff, size-ret); } if (addr>=core->offset && addr<=core->offset+core->blocksize) r_core_block_read (core, 0); #endif return (ret==size); //UT64_MAX); }
bool test_r_io_priority(void) { RIO *io = r_io_new(); ut32 map0, map1; ut64 buf; bool ret; io->va = true; r_io_open_at (io, "malloc://8", R_PERM_RW, 0644, 0x0); map0 = r_io_map_get (io, 0)->id; ret = r_io_read_at (io, 0, (ut8 *)&buf, 8); mu_assert ("should be able to read", ret); mu_assert_memeq ((ut8 *)&buf, (ut8 *)"\x00\x00\x00\x00\x00\x00\x00\x00", 8, "0 should be there initially"); buf = 0x9090909090909090; r_io_write_at (io, 0, (ut8 *)&buf, 8); mu_assert_memeq ((ut8 *)&buf, (ut8 *)"\x90\x90\x90\x90\x90\x90\x90\x90", 8, "0x90 should have been written"); r_io_open_at (io, "malloc://2", R_PERM_RW, 0644, 0x4); map1 = r_io_map_get (io, 4)->id; r_io_read_at (io, 0, (ut8 *)&buf, 8); mu_assert_memeq ((ut8 *)&buf, (ut8 *)"\x90\x90\x90\x90\x00\x00\x90\x90", 8, "0x00 from map1 should overlap"); buf ^= UT64_MAX; r_io_write_at (io, 0, (ut8 *)&buf, 8); r_io_read_at (io, 0, (ut8 *)&buf, 8); mu_assert_memeq ((ut8 *)&buf, (ut8 *)"\x6f\x6f\x6f\x6f\xff\xff\x6f\x6f", 8, "memory has been xored"); r_io_map_priorize (io, map0); r_io_read_at (io, 0, (ut8 *)&buf, 8); mu_assert_memeq ((ut8 *)&buf, (ut8 *)"\x6f\x6f\x6f\x6f\x90\x90\x6f\x6f", 8, "map0 should have been prioritized"); r_io_map_remap (io, map1, 0x2); r_io_read_at (io, 0, (ut8 *)&buf, 8); mu_assert_memeq ((ut8 *)&buf, (ut8 *)"\x6f\x6f\x6f\x6f\x90\x90\x6f\x6f", 8, "map1 should have been remapped"); r_io_map_priorize (io, map1); r_io_read_at (io, 0, (ut8 *)&buf, 8); mu_assert_memeq ((ut8 *)&buf, (ut8 *)"\x6f\x6f\xff\xff\x90\x90\x6f\x6f", 8, "map1 should have been prioritized"); r_io_free (io); mu_end; }
// 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) { RCoreAsmHit *hit; RAsmOp op; RList *hits; ut64 at, toff = core->offset; ut8 *buf; char *tok, *tokens[1024], *code = NULL, *ptr; int idx, tidx = 0, ret, len; int tokcount, matchcount; if (!*input) return NULL; if (core->blocksize<=OPSZ) { eprintf ("error: block size too small\n"); return NULL; } if (!(buf = (ut8 *)malloc (core->blocksize))) 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<(sizeof (tokens) / sizeof (char*)) - 1; tokcount++) { tok = strtok (tokcount? NULL: ptr, ","); if (tok == NULL) break; tokens[tokcount] = r_str_trim_head_tail (tok); } tokens[tokcount] = NULL; r_cons_break (NULL, NULL); for (at = from, matchcount = 0; at < to; at += core->blocksize-OPSZ) { if (r_cons_singleton ()->breaked) break; ret = r_io_read_at (core->io, at, buf, core->blocksize); if (ret != core->blocksize) break; idx = 0, matchcount = 0; while (idx<core->blocksize) { r_asm_set_pc (core->assembler, at+idx); op.buf_asm[0] = 0; op.buf_hex[0] = 0; if (!(len = r_asm_disassemble (core->assembler, &op, buf+idx, core->blocksize-idx))) { idx = (matchcount)? tidx+1: idx+1; matchcount = 0; continue; } if (tokens[matchcount] && strstr (op.buf_asm, tokens[matchcount])) { code = r_str_concatf (code, "%s", op.buf_asm); if (matchcount == tokcount-1) { if (tokcount == 1) tidx = idx; if (!(hit = r_core_asm_hit_new ())) { r_list_purge (hits); free (hits); hits = NULL; goto beach; } hit->addr = at+tidx; hit->len = idx+len-tidx; if (hit->len == -1) { r_core_asm_hit_free (hit); goto beach; } hit->code = strdup (code); r_list_append (hits, hit); R_FREE (code); matchcount = 0; idx = tidx+1; } else if (matchcount == 0) { tidx = idx; matchcount++; idx += len; } else { matchcount++; idx += len; } } else { idx = matchcount? tidx+1: idx+1; R_FREE (code); matchcount = 0; } } } r_asm_set_pc (core->assembler, toff); beach: free (buf); free (ptr); free (code); return hits; }
R_API RList *r_core_asm_bwdisassemble (RCore *core, ut64 addr, int n, int len) { RList *hits = r_core_asm_hit_list_new(); RCoreAsmHit dummy_value; RAsmOp op; ut8 *buf = (ut8 *)malloc (len); ut64 instrlen = 0, at = 0; ut32 idx = 0, hit_count = 0; memset (&dummy_value, 0, sizeof (RCoreAsmHit)); if (hits == NULL || buf == NULL ){ if (hits) { r_list_purge (hits); free (hits); } free (buf); return NULL; } if (r_io_read_at (core->io, addr-len, buf, len) != len) { if (hits) { r_list_purge (hits); free (hits); } free (buf); return NULL; } for (idx = 1; idx < len; idx++) { ut32 current_buf_pos; if (r_cons_singleton ()->breaked) break; at = addr - idx; hit_count = 0; // XXX - buf here. at may be greater than addr if near boundary. for (current_buf_pos = len - idx, hit_count = 0; current_buf_pos < len && hit_count <= n; current_buf_pos += instrlen, at += instrlen, hit_count++) { r_asm_set_pc (core->assembler, at); //XXX HACK We need another way to detect invalid disasm!! if (!(instrlen = r_asm_disassemble (core->assembler, &op, buf+(len-(addr-at)), addr-at)) || strstr (op.buf_asm, "invalid")) { break; } } if (hit_count >= n) break; } if (hit_count == n) { at = addr - idx; hit_count = 0; r_asm_set_pc (core->assembler, at); for ( hit_count = 0; hit_count < n; hit_count++) { instrlen = r_asm_disassemble (core->assembler, &op, buf+(len-(addr-at)), addr-at); add_hit_to_hits(hits, at, instrlen, R_TRUE); at += instrlen; } } r_asm_set_pc (core->assembler, addr); free (buf); return hits; }
static void print_format_values(RCore *core, const char *fmt, bool onstack, ut64 src, bool color) { char opt; ut64 bval = src; int i; int endian = core->print->big_endian; int width = (core->anal->bits == 64)? 8: 4; int bsize = R_MIN (64, core->blocksize); ut8 *buf = malloc (bsize); if (!buf) { eprintf ("Cannot allocate %d byte(s)\n", bsize); free (buf); return; } if (fmt) { opt = *fmt; } else { opt = 'p'; // void *ptr } if (onstack || ((opt != 'd' && opt != 'x') && !onstack)) { if (color) { r_cons_printf (Color_BGREEN"0x%08"PFMT64x Color_RESET" --> ", bval); } else { r_cons_printf ("0x%08"PFMT64x" --> ", bval); } r_io_read_at (core->io, bval, buf, bsize); } if (onstack) { // Fetch value from stack bval = get_buf_val (buf, endian, width); if (opt != 'd' && opt != 'x') { r_io_read_at (core->io, bval, buf, bsize); // update buf with val from stack } } r_cons_print (color? Color_BGREEN: ""); switch (opt) { case 'z' : // Null terminated string r_cons_print (color ?Color_RESET Color_BWHITE:""); r_cons_print ("\""); for (i = 0; i < MAXSTRLEN; i++) { if (buf[i] == '\0') { break; } ut8 b = buf[i]; if (IS_PRINTABLE (b)) { r_cons_printf ("%c", b); } else { r_cons_printf ("\\x%02x", b); } if (i == MAXSTRLEN - 1) { r_cons_print ("..."); // To show string is truncated } } r_cons_print ("\""); r_cons_newline (); break; case 'd' : // integer case 'x' : r_cons_printf ("0x%08" PFMT64x, bval); r_cons_newline (); break; case 'c' : // char r_cons_print ("\'"); ut8 ch = buf[0]; if (IS_PRINTABLE (ch)) { r_cons_printf ("%c", ch); } else { r_cons_printf ("\\x%02x", ch); } r_cons_print ("\'"); r_cons_newline (); break; case 'p' : // pointer { // Try to deref the pointer once again r_cons_printf ("0x%08"PFMT64x, get_buf_val (buf, endian, width)); r_cons_newline (); break; } default: //TODO: support types like structs and unions r_cons_println ("unk_format"); } r_cons_print (Color_RESET); free (buf); }
static ut64 num_callback(RNum *userptr, const char *str, int *ok) { RCore *core = (RCore *)userptr; // XXX ? RAnalFunction *fcn; char *ptr, *bptr; RFlagItem *flag; RIOSection *s; RAnalOp op; ut64 ret = 0; if (ok) *ok = R_FALSE; if (*str=='[') { int refsz = (core->assembler->bits & R_SYS_BITS_64)? 8: 4; const char *p = strchr (str+5, ':'); ut64 n; // TODO: honor endian if (p) { refsz = atoi (str+1); str = p; } // push state { char *o = strdup (str+1); const char *q = r_num_calc_index (core->num, NULL); r_str_replace_char (o, ']', 0); n = r_num_math (core->num, o); r_num_calc_index (core->num, q); free (o); } // pop state switch (refsz) { case 8: { ut64 num = 0; r_io_read_at (core->io, n, (ut8*)&num, sizeof (num)); return num; } case 4: { ut32 num = 0; r_io_read_at (core->io, n, (ut8*)&num, sizeof (num)); return num; } case 2: { ut16 num = 0; r_io_read_at (core->io, n, (ut8*)&num, sizeof (num)); return num; } case 1: { ut8 num = 0; r_io_read_at (core->io, n, (ut8*)&num, sizeof (num)); return num; } default: eprintf ("Invalid reference size: %d (%s)\n", refsz, str); break; } } else if (str[0]=='$') { if (ok) *ok = 1; // TODO: group analop-dependant vars after a char, so i can filter r_anal_op (core->anal, &op, core->offset, core->block, core->blocksize); switch (str[1]) { case '.': // can use pc, sp, a0, a1, ... return r_debug_reg_get (core->dbg, str+2); case '{': bptr = strdup (str+2); ptr = strchr (bptr, '}'); if (ptr != NULL) { ut64 ret; ptr[0] = '\0'; ret = r_config_get_i (core->config, bptr); free (bptr); return ret; } break; case 'h': { int rows; r_cons_get_size (&rows); return rows; } case 'e': return op.eob; case 'j': return op.jump; case 'f': return op.fail; case 'r': return op.ref; case 'l': return op.length; case 'b': return core->blocksize; case 's': return core->file->size; case 'w': return r_config_get_i (core->config, "asm.bits") / 8; case 'S': s = r_io_section_get (core->io, r_io_section_vaddr_to_offset (core->io, core->offset)); return s? (str[2]=='S'? s->size: s->offset): 0; case '?': return core->num->value; case '$': return core->offset; case 'o': return core->io->off; case 'C': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_CALL); case 'J': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_CODE); case 'D': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_DATA); case 'X': return getref (core, atoi (str+2), 'x', R_ANAL_REF_TYPE_CALL); case 'I': fcn = r_anal_fcn_find (core->anal, core->offset, 0); return fcn? fcn->ninstr: 0; case 'F': fcn = r_anal_fcn_find (core->anal, core->offset, 0); return fcn? fcn->size: 0; } } else if (*str>'A') { if ((flag = r_flag_get (core->flags, str))) { ret = flag->offset; if (ok) *ok = R_TRUE; } } return ret; }
// 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; }
R_API RList *r_core_asm_bwdisassemble (RCore *core, ut64 addr, int n, int len) { RList *hits = r_core_asm_hit_list_new(); RAsmOp op; ut8 *buf; ut64 buf_addr, instrlen = 0, at = 0; ut32 idx = 0, hit_count = 0, buf_len = 0; int numinstr, ii; RAsmCode *c; if (!hits) return NULL; buf_addr = addr - len; buf_len = len; buf = (ut8 *)malloc (buf_len); if (!buf) { r_list_free (hits); return NULL; } if (r_io_read_at (core->io, buf_addr, buf, buf_len) != buf_len) { r_list_free (hits); free (buf); return NULL; } if (!memcmp (buf, "\xff\xff\xff\xff", R_MIN (4, buf_len))) { eprintf ("error reading at 0x%08"PFMT64x"\n", buf_addr); r_list_free (hits); free (buf); return NULL; } if (n<0) n = -n; for (idx = 1; idx < len; idx++) { if (r_cons_singleton ()->breaked) break; at = addr - idx; hit_count = 0; r_asm_set_pc (core->assembler, at); // XXX: the disassemble errors are because of this line. mdisasm must not be used here //c = r_asm_mdisassemble (core->assembler, buf+idx, buf_len-idx); //+buf_len-idx, idx); c = r_asm_mdisassemble (core->assembler, buf+buf_len-idx, idx); // XXX: relaying on string contents in the buf_asm is a bad idea if (strstr (c->buf_asm, "invalid") || strstr (c->buf_asm, ".byte")) { r_asm_code_free (c); continue; } //eprintf ("-->(%x)(%s)\n", at, c->buf_asm); for (numinstr = ii = 0; c->buf_asm[ii] ; ii++) { if (c->buf_asm[ii] == '\n') numinstr++; } //eprintf ("mdisasm worked! for 0x%llx with %d\n", addr-len+idx, numinstr); r_asm_code_free (c); if (numinstr >= n || idx > 32 * n) { //eprintf ("idx = %d len = %d ninst = %d n = %d\n", idx, len, numinstr, n); break; } //eprintf ("idx = %d len = %d\n", idx, len); } at = addr - idx; hit_count = 0; for (hit_count = 0; hit_count < n; hit_count++) { if (r_cons_singleton ()->breaked) break; r_asm_set_pc (core->assembler, at); instrlen = r_asm_disassemble (core->assembler, &op, buf+buf_len-(addr-at), addr-at); //addr-at); // eprintf ("INST LEN = %d\n", instrlen); if (instrlen<1) { eprintf ("dissasm failed at %llx\n", at); instrlen = 1; // break; } add_hit_to_hits (hits, at, instrlen, R_TRUE); at += instrlen; } free (buf); return hits; }
R_API RList *r_core_asm_bwdisassemble (RCore *core, ut64 addr, int n, int len) { RList *hits = r_core_asm_hit_list_new(); RAsmOp op; // len = n * 32; // if (n > core->blocksize) n = core->blocksize; ut8 *buf; ut64 instrlen = 0, at = 0; ut32 idx = 0, hit_count = 0; int numinstr, asmlen, ii; RAsmCode *c; if (len < 1) { r_list_free (hits); return NULL; } buf = (ut8 *)malloc (len); if (!hits || !buf) { if (hits) { r_list_free (hits); } free (buf); return NULL; } if (r_io_read_at (core->io, addr-len, buf, len) != len) { if (hits) { r_list_free (hits); } free (buf); return NULL; } for (idx = 1; idx < len; ++idx) { if (r_cons_singleton ()->breaked) break; at = addr - idx; hit_count = 0; c = r_asm_mdisassemble (core->assembler, buf+(len-idx), idx); if (strstr(c->buf_asm, "invalid") || strstr(c->buf_asm, ".byte")) { r_asm_code_free(c); continue; } numinstr = 0; asmlen = strlen(c->buf_asm); for(ii = 0; ii < asmlen; ++ii) { if (c->buf_asm[ii] == '\n') ++numinstr; } r_asm_code_free(c); if (numinstr >= n || idx > 32 * n) { break; } } at = addr - idx; hit_count = 0; r_asm_set_pc (core->assembler, at); at = addr-idx; for ( hit_count = 0; hit_count < n; hit_count++) { instrlen = r_asm_disassemble (core->assembler, &op, buf+(len-(addr-at)), addr-at); add_hit_to_hits(hits, at, instrlen, true); at += instrlen; } free (buf); return hits; }
// 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) { 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, ret, len; int tokcount, matchcount, count = 0; int matches = 0; if (!*input) return NULL; if (core->blocksize <= OPSZ) { 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<(sizeof (tokens) / sizeof (char*)) - 1; tokcount++) { tok = strtok (tokcount? NULL: ptr, ";"); if (!tok) break; tokens[tokcount] = r_str_trim_head_tail (tok); } tokens[tokcount] = NULL; r_cons_break (NULL, NULL); for (at = from, matchcount = 0; at < to; at += core->blocksize-OPSZ) { matches = 0; if (r_cons_singleton ()->breaked) break; ret = r_io_read_at (core->io, at, buf, core->blocksize); if (ret != core->blocksize) break; idx = 0, matchcount = 0; while (idx < core->blocksize) { ut64 addr = at + idx; r_asm_set_pc (core->assembler, addr); op.buf_asm[0] = 0; op.buf_hex[0] = 0; if (!(len = r_asm_disassemble (core->assembler, &op, buf+idx, core->blocksize-idx))) { idx = (matchcount)? tidx+1: idx+1; matchcount = 0; continue; } matches = true; if (!strcmp (op.buf_asm, "unaligned")) matches = false; if (!strcmp (op.buf_asm, "invalid")) matches = false; if (matches && tokens[matchcount]) { if (!regexp) matches = strstr(op.buf_asm, tokens[matchcount]) != NULL; else { rx = r_regex_new (tokens[matchcount], ""); matches = r_regex_exec (rx, op.buf_asm, 0, 0, 0) == 0; r_regex_free (rx); } } if (align && align>1) { if (addr % align) { matches = false; } } if (matches) { code = r_str_concatf (code, "%s; ", op.buf_asm); if (matchcount == tokcount-1) { if (tokcount == 1) tidx = idx; if (!(hit = r_core_asm_hit_new ())) { r_list_purge (hits); free (hits); hits = NULL; 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 == 0) { tidx = idx; matchcount++; idx += len; } else { matchcount++; idx += len; } } else { idx = matchcount? tidx+1: idx+1; R_FREE (code); matchcount = 0; } } at += OPSZ; } r_asm_set_pc (core->assembler, toff); beach: free (buf); free (ptr); free (code); return hits; }
static int perform_mapped_file_yank (RCore *core, ut64 offset, ut64 len, const char *filename) { // grab the current file descriptor, so we can reset core and io state // after our io op is done RIODesc *yankfd = NULL; ut64 fd = core->file ? core->file->desc->fd : -1, yank_file_sz = 0, loadaddr = 0, addr = offset; int res = R_FALSE; if (filename && *filename) { ut64 load_align = r_config_get_i (core->config, "file.loadalign"); RIOMap * map = NULL; yankfd = r_io_open (core->io, filename, R_IO_READ, 0644); // map the file in for IO operations. if (yankfd && load_align) { yank_file_sz = r_io_size (core->io); map = r_io_map_add_next_available (core->io, yankfd->fd, R_IO_READ, 0, 0, yank_file_sz, load_align); loadaddr = map ? map->from : -1; if (yankfd && map && loadaddr != -1) { // ***NOTE*** this is important, we need to // address the file at its physical address! addr += loadaddr; } else if (yankfd) { eprintf ("Unable to map the opened file: %s", filename); r_io_close (core->io, yankfd); yankfd = NULL; } else { eprintf ("Unable to open the file: %s", filename); } } } // if len is -1 then we yank in everything if (len == -1) len = yank_file_sz; IFDBG eprintf ("yankfd: %p, yank->fd = %d, fd=%d\n", yankfd, (int)(yankfd ? yankfd->fd : -1), (int)fd); // this wont happen if the file failed to open or the file failed to // map into the IO layer if (yankfd) { ut64 res = r_io_seek (core->io, addr, R_IO_SEEK_SET), actual_len = len <= yank_file_sz ? len : 0; ut8 *buf = NULL; IFDBG eprintf ( "Addr (%"PFMT64d ") file_sz (%"PFMT64d ") actual_len (%"PFMT64d ") len (%"PFMT64d ") bytes from file: %s\n", addr, yank_file_sz, actual_len, len, filename); if (actual_len > 0 && res == addr) { IFDBG eprintf ( "Creating buffer and reading %"PFMT64d " bytes from file: %s\n", actual_len, filename); buf = malloc (actual_len); actual_len = r_io_read_at (core->io, addr, buf, actual_len); IFDBG eprintf ( "Reading %"PFMT64d " bytes from file: %s\n", actual_len, filename); /*IFDBG { int i = 0; eprintf ("Read these bytes from file: \n"); for (i = 0; i < actual_len; i++) eprintf ("%02x", buf[i]); eprintf ("\n"); }*/ r_core_yank_set (core, R_CORE_FOREIGN_ADDR, buf, len); res = R_TRUE; } else if (res != addr) { eprintf ( "ERROR: Unable to yank data from file: (loadaddr (0x%" PFMT64x ") (addr (0x%" PFMT64x ") > file_sz (0x%"PFMT64x ")\n", res, addr, yank_file_sz ); } else if (actual_len == 0) { eprintf ( "ERROR: Unable to yank from file: addr+len (0x%" PFMT64x ") > file_sz (0x%"PFMT64x ")\n", addr+len, yank_file_sz ); } r_io_close (core->io, yankfd); free (buf); } if (fd != -1) { r_io_raise (core->io, fd); core->switch_file_view = 1; r_core_block_read (core, 0); } return res; }
R_API RList *r_core_asm_bwdisassemble(RCore *core, ut64 addr, int n, int len) { RAsmOp op; // len = n * 32; // if (n > core->blocksize) n = core->blocksize; ut8 *buf; ut64 at; ut32 idx = 0, hit_count; int numinstr, asmlen, ii; int addrbytes = core->assembler->addrbytes; RAsmCode *c; RList *hits = r_core_asm_hit_list_new(); if (!hits) return NULL; len = R_MIN (len - len % addrbytes, addrbytes * addr); if (len < 1) { r_list_free (hits); return NULL; } buf = (ut8 *)malloc (len); if (!buf) { if (hits) { r_list_free (hits); } return NULL; } else if (!hits) { free (buf); return NULL; } len = len > addr ? addr : len; if (!r_io_read_at (core->io, addr - len, buf, len)) { r_list_free (hits); free (buf); return NULL; } for (idx = addrbytes; idx < len; idx += addrbytes) { if (r_cons_singleton ()->breaked) break; c = r_asm_mdisassemble (core->assembler, buf+(len-idx), idx); if (strstr (c->buf_asm, "invalid") || strstr (c->buf_asm, ".byte")) { r_asm_code_free(c); continue; } numinstr = 0; asmlen = strlen (c->buf_asm); for(ii = 0; ii < asmlen; ++ii) { if (c->buf_asm[ii] == '\n') ++numinstr; } r_asm_code_free(c); if (numinstr >= n || idx > 16 * n) { // assume average instruction length <= 16 break; } } at = addr - idx / addrbytes; r_asm_set_pc (core->assembler, at); for (hit_count = 0; hit_count < n; hit_count++) { int instrlen = r_asm_disassemble (core->assembler, &op, buf + len - addrbytes*(addr-at), addrbytes * (addr-at)); add_hit_to_hits (hits, at, instrlen, true); at += instrlen; } free (buf); return hits; }
static int perform_mapped_file_yank(RCore *core, ut64 offset, ut64 len, const char *filename) { // grab the current file descriptor, so we can reset core and io state // after our io op is done RIODesc *yankdesc = NULL; ut64 fd = core->file? core->file->fd: -1, yank_file_sz = 0, loadaddr = 0, addr = offset; int res = false; if (filename && *filename) { ut64 load_align = r_config_get_i (core->config, "file.loadalign"); RIOMap *map = NULL; yankdesc = r_io_open_nomap (core->io, filename, R_PERM_R, 0644); // map the file in for IO operations. if (yankdesc && load_align) { yank_file_sz = r_io_size (core->io); map = r_io_map_add_next_available (core->io, yankdesc->fd, R_PERM_R, 0, 0, yank_file_sz, load_align); loadaddr = map? map->itv.addr: -1; if (yankdesc && map && loadaddr != -1) { // ***NOTE*** this is important, we need to // address the file at its physical address! addr += loadaddr; } else if (yankdesc) { eprintf ("Unable to map the opened file: %s", filename); r_io_desc_close (yankdesc); yankdesc = NULL; } else { eprintf ("Unable to open the file: %s", filename); } } } // if len is -1 then we yank in everything if (len == -1) { len = yank_file_sz; } // this wont happen if the file failed to open or the file failed to // map into the IO layer if (yankdesc) { ut64 res = r_io_seek (core->io, addr, R_IO_SEEK_SET); ut64 actual_len = len <= yank_file_sz? len: 0; ut8 *buf = NULL; if (actual_len > 0 && res == addr) { buf = malloc (actual_len); if (!r_io_read_at (core->io, addr, buf, actual_len)) { actual_len = 0; } r_core_yank_set (core, R_CORE_FOREIGN_ADDR, buf, len); res = true; } else if (res != addr) { eprintf ( "ERROR: Unable to yank data from file: (loadaddr (0x%" PFMT64x ") (addr (0x%" PFMT64x ") > file_sz (0x%"PFMT64x ")\n", res, addr, yank_file_sz ); } else if (actual_len == 0) { eprintf ( "ERROR: Unable to yank from file: addr+len (0x%" PFMT64x ") > file_sz (0x%"PFMT64x ")\n", addr + len, yank_file_sz ); } r_io_desc_close (yankdesc); free (buf); } if (fd != -1) { r_io_use_fd (core->io, fd); core->switch_file_view = 1; r_core_block_read (core); } return res; }
/* TODO: simplify using r_write */ static int cmd_write(void *data, const char *input) { int wseek, i, size, len = strlen (input); RCore *core = (RCore *)data; char *tmp, *str, *ostr; const char *arg, *filename; char _fn[32]; ut64 off; ut8 *buf; st64 num = 0; const char* help_msg[] = { "Usage:","w[x] [str] [<file] [<<EOF] [@addr]","", "w","[1248][+-][n]","increment/decrement byte,word..", "w"," foobar","write string 'foobar'", "w0"," [len]","write 'len' bytes with value 0x00", "w6","[de] base64/hex","write base64 [d]ecoded or [e]ncoded string", "wa"," push ebp","write opcode, separated by ';' (use '\"' around the command)", "waf"," file","assemble file and write bytes", "wA"," r 0","alter/modify opcode at current seek (see wA?)", "wb"," 010203","fill current block with cyclic hexpairs", "wB","[-]0xVALUE","set or unset bits with given value", "wc","","list all write changes", "wc","[ir*?]","write cache undo/commit/reset/list (io.cache)", "wd"," [off] [n]","duplicate N bytes from offset at current seek (memcpy) (see y?)", "we","[nNsxX] [arg]","extend write operations (insert instead of replace)", "wf"," -|file","write contents of file at current offset", "wF"," -|file","write contents of hexpairs file here", "wh"," r2","whereis/which shell command", "wm"," f0ff","set binary mask hexpair to be used as cyclic write mask", "wo?"," hex","write in block with operation. 'wo?' fmi", "wp"," -|file","apply radare patch file. See wp? fmi", "wr"," 10","write 10 random bytes", "ws"," pstring","write 1 byte for length and then the string", "wt"," file [sz]","write to file (from current seek, blocksize or sz bytes)", "ww"," foobar","write wide string 'f\\x00o\\x00o\\x00b\\x00a\\x00r\\x00'", "wx"," 9090","write two intel nops", "wv"," eip+34","write 32-64 bit value", NULL }; if (!input) return 0; #define WSEEK(x,y) if (wseek)r_core_seek_delta (x,y) wseek = r_config_get_i (core->config, "cfg.wseek"); str = ostr = strdup ((input&&*input)?input+1:""); _fn[0] = 0; switch (*input) { case 'B': switch (input[1]) { case ' ': cmd_write_bits (core, 1, r_num_math (core->num, input+2)); break; case '-': cmd_write_bits (core, 0, r_num_math (core->num, input+2)); break; default: eprintf ("Usage: wB 0x2000 # or wB-0x2000\n"); break; } break; case '0': { ut64 len = r_num_math (core->num, input+1); if (len>0) { ut8 *buf = calloc (1, len); if (buf) { r_io_write (core->io, buf, len); free (buf); } else eprintf ("Cannot allocate %d bytes\n", (int)len); } } break; case '1': case '2': case '4': case '8': if (input[1] && input[2]) { if (input[1]==input[2]) { num = 1; } else num = r_num_math (core->num, input+2); } switch (input[2] ? input[1] : 0) { case '+': cmd_write_inc (core, *input-'0', num); break; case '-': cmd_write_inc (core, *input-'0', -num); break; default: eprintf ("Usage: w[1248][+-][num] # inc/dec byte/word/..\n"); } break; case '6': { int fail = 0; if(input[1] && input[2] != ' ') { fail = 1; } ut8 *buf; int len, str_len; const char *str; if (input[1] && input[2] && input[3]) str = input + 3; else str = ""; str_len = strlen (str) + 1; if (!fail) { switch (input[1]) { case 'd': buf = malloc (str_len); len = r_base64_decode (buf, str, 0); if(len == 0) { free(buf); fail = 1; } break; case 'e': { ut8 *bin_buf = malloc(str_len); int bin_len = r_hex_str2bin(str, bin_buf); if(bin_len == 0) { fail = 1; } else { buf = malloc(str_len * 4 + 1); len = r_base64_encode((char *)buf, bin_buf, bin_len); if(len == 0) { free(buf); fail = 1; } } free (bin_buf); break; } default: fail = 1; break; } } if(!fail) { r_core_write_at (core, core->offset, buf, len); WSEEK (core, len); r_core_block_read (core, 0); free(buf); } else { eprintf ("Usage: w6[de] base64/hex\n"); } break; } case 'h': { char *p = strchr (input, ' '); if (p) { while (*p==' ') p++; p = r_file_path (p); if (p) { r_cons_printf ("%s\n", p); free (p); } } } break; case 'e': { ut64 addr = 0, len = 0, b_size = 0; st64 dist = 0; ut8* bytes = NULL; int cmd_suc = R_FALSE; char *input_shadow = NULL, *p = NULL; switch (input[1]) { case 'n': if (input[2] == ' ') { len = *input ? r_num_math ( core->num, input+3) : 0; if (len > 0){ ut64 cur_off = core->offset; cmd_suc = r_core_extend_at (core, core->offset, len); core->offset = cur_off; r_core_block_read (core, 0); } } break; case 'N': if (input[2] == ' ') { input += 3; while (*input && *input == ' ') input++; addr = r_num_math (core->num, input); while (*input && *input != ' ') input++; input++; len = *input ? r_num_math (core->num, input) : 0; if (len > 0){ ut64 cur_off = core->offset; cmd_suc = r_core_extend_at (core, addr, len); cmd_suc = r_core_seek (core, cur_off, 1); core->offset = addr; r_core_block_read (core, 0); } } break; case 'x': if (input[2] == ' ') { input+=2; len = *input ? strlen (input) : 0; bytes = len > 1? malloc (len+1) : NULL; len = bytes ? r_hex_str2bin (input, bytes) : 0; if (len > 0) { ut64 cur_off = core->offset; cmd_suc = r_core_extend_at (core, cur_off, len); if (cmd_suc) { r_core_write_at (core, cur_off, bytes, len); } core->offset = cur_off; r_core_block_read (core, 0); } free (bytes); } break; case 'X': if (input[2] == ' ') { addr = r_num_math (core->num, input+3); input += 3; while (*input && *input != ' ') input++; input++; len = *input ? strlen (input) : 0; bytes = len > 1? malloc (len+1) : NULL; len = bytes ? r_hex_str2bin (input, bytes) : 0; if (len > 0) { //ut64 cur_off = core->offset; cmd_suc = r_core_extend_at (core, addr, len); if (cmd_suc) { r_core_write_at (core, addr, bytes, len); } core->offset = addr; r_core_block_read (core, 0); } free (bytes); } break; case 's': input += 3; while (*input && *input == ' ') input++; len = strlen (input); input_shadow = len > 0? malloc (len+1): 0; // since the distance can be negative, // the r_num_math will perform an unwanted operation // the solution is to tokenize the string :/ if (input_shadow) { strncpy (input_shadow, input, len+1); p = strtok (input_shadow, " "); addr = p && *p ? r_num_math (core->num, p) : 0; p = strtok (NULL, " "); dist = p && *p ? r_num_math (core->num, p) : 0; p = strtok (NULL, " "); b_size = p && *p ? r_num_math (core->num, p) : 0; if (dist != 0){ r_core_shift_block (core, addr, b_size, dist); r_core_seek (core, addr, 1); cmd_suc = R_TRUE; } } free (input_shadow); break; case '?': default: cmd_suc = R_FALSE; } if (cmd_suc == R_FALSE) { r_cons_printf ("|Usage: write extend\n" "wen <num> insert num null bytes at current offset\n" "wex <hex_bytes> insert bytes at current offset\n" "weN <addr> <len> insert bytes at address\n" "weX <addr> <hex_bytes> insert bytes at address\n" "wes <addr> <dist> <block_size> shift a blocksize left or write in the editor\n" ); } } break; case 'p': if (input[1]=='-' || (input[1]==' ' && input[2]=='-')) { char *out = r_core_editor (core, NULL, NULL); if (out) { r_core_patch (core, out); free (out); } } else { if (input[1]==' ' && input[2]) { char *data = r_file_slurp (input+2, NULL); if (data) { r_core_patch (core, data); free (data); } } else { eprintf ("Usage: wp [-|r2patch-file]\n" "TODO: rapatch format documentation here\n"); } } break; case 'u': // TODO: implement it in an API RCore.write_unified_hexpatch() is ETOOLONG if (input[1]==' ') { char *data = r_file_slurp (input+2, NULL); if (data) { char sign = ' '; int line = 0, offs = 0, hexa = 0; int newline = 1; for (i=0; data[i]; i++) { switch (data[i]) { case '+': if (newline) sign = 1; break; case '-': if (newline) { sign = 0; offs = i + ((data[i+1]==' ')?2:1); } break; case ' ': data[i] = 0; if (sign) { if (!line) line = i+1; else if (!hexa) hexa = i+1; } break; case '\r': break; case '\n': newline = 1; if (sign == -1) { offs = 0; line = 0; hexa = 0; } else if (sign) { if (offs && hexa) { r_cons_printf ("wx %s @ %s\n", data+hexa, data+offs); } else eprintf ("food\n"); offs = 0; line = 0; } else hexa = 0; sign = -1; continue; } newline = 0; } free (data); } } else { eprintf ("|Usage: wu [unified-diff-patch] # see 'cu'\n"); } break; case 'r': off = r_num_math (core->num, input+1); len = (int)off; if (len>0) { buf = malloc (len); if (buf != NULL) { r_num_irand (); for (i=0; i<len; i++) buf[i] = r_num_rand (256); r_core_write_at (core, core->offset, buf, len); WSEEK (core, len); free (buf); } else eprintf ("Cannot allocate %d bytes\n", len); } break; case 'A': switch (input[1]) { case ' ': if (input[2] && input[3]==' ') { r_asm_set_pc (core->assembler, core->offset); eprintf ("modify (%c)=%s\n", input[2], input+4); len = r_asm_modify (core->assembler, core->block, input[2], r_num_math (core->num, input+4)); eprintf ("len=%d\n", len); if (len>0) { r_core_write_at (core, core->offset, core->block, len); WSEEK (core, len); } else eprintf ("r_asm_modify = %d\n", len); } else eprintf ("Usage: wA [type] [value]\n"); break; case '?': default: r_cons_printf ("|Usage: wA [type] [value]\n" "|Types:\n" "| r raw write value\n" "| v set value (taking care of current address)\n" "| d destination register\n" "| 0 1st src register\n" "| 1 2nd src register\n" "|Example: wA r 0 # e800000000\n"); break; } break; case 'c': switch (input[1]) { case 'i': r_io_cache_commit (core->io, 0, UT64_MAX); r_core_block_read (core, 0); break; case 'r': r_io_cache_reset (core->io, R_TRUE); /* Before loading the core block we have to make sure that if * the cache wrote past the original EOF these changes are no * longer displayed. */ memset (core->block, 0xff, core->blocksize); r_core_block_read (core, 0); break; case '+': if (input[2]=='*') { //r_io_cache_reset (core->io, R_TRUE); eprintf ("TODO\n"); } else if (input[2]==' ') { char *p = strchr (input+3, ' '); ut64 to, from = core->offset; if (p) { *p = 0; from = r_num_math (core->num, input+3); to = r_num_math (core->num, input+3); if (to<from) { eprintf ("Invalid range (from>to)\n"); return 0; } } else { from = r_num_math (core->num, input+3); to = from + core->blocksize; } r_io_cache_commit (core->io, from, to); } else { eprintf ("Invalidate write cache at 0x%08"PFMT64x"\n", core->offset); r_io_cache_commit (core->io, core->offset, core->offset+1); } break; case '-': if (input[2]=='*') { r_io_cache_reset (core->io, R_TRUE); } else if (input[2]==' ') { char *p = strchr (input+3, ' '); ut64 to, from = core->offset; if (p) { *p = 0; from = r_num_math (core->num, input+3); to = r_num_math (core->num, input+3); if (to<from) { eprintf ("Invalid range (from>to)\n"); return 0; } } else { from = r_num_math (core->num, input+3); to = from + core->blocksize; } r_io_cache_invalidate (core->io, from, to); } else { eprintf ("Invalidate write cache at 0x%08"PFMT64x"\n", core->offset); r_io_cache_invalidate (core->io, core->offset, core->offset+core->blocksize); } /* See 'r' above. */ memset (core->block, 0xff, core->blocksize); r_core_block_read (core, 0); break; case '?': { const char* help_msg[] = { "Usage:", "wc[ir+-*?]"," # NOTE: Uses io.cache=true", "wc","","list all write changes", "wc-"," [from] [to]","remove write op at curseek or given addr", "wc+"," [addr]","commit change from cache to io", "wc*","","\"\" in radare commands", "wcr","","reset all write changes in cache", "wci","","commit write cache", NULL }; r_core_cmd_help(core, help_msg); } break; case '*': r_io_cache_list (core->io, R_TRUE); break; case '\0': //if (!r_config_get_i (core->config, "io.cache")) // eprintf ("[warning] e io.cache must be true\n"); r_io_cache_list (core->io, R_FALSE); break; } break; case ' ': /* write string */ len = r_str_unescape (str); r_core_write_at (core, core->offset, (const ut8*)str, len); #if 0 r_io_use_desc (core->io, core->file->desc); r_io_write_at (core->io, core->offset, (const ut8*)str, len); #endif WSEEK (core, len); r_core_block_read (core, 0); break; case 't': // "wt" if (*str == '?' || *str == '\0') { eprintf ("Usage: wt[a] file [size] write 'size' bytes in current block to file\n"); free (ostr); return 0; } else { int append = 0; st64 sz = core->blocksize; if (*str=='a') { // "wta" append = 1; str++; if (str[0]==' ') { filename = str+1; } else { const char* prefix = r_config_get (core->config, "cfg.prefixdump"); snprintf (_fn, sizeof (_fn), "%s.0x%08"PFMT64x, prefix, core->offset); filename = _fn; } } else if (*str != ' ') { const char* prefix = r_config_get (core->config, "cfg.prefixdump"); snprintf(_fn, sizeof(_fn), "%s.0x%08"PFMT64x, prefix, core->offset); filename = _fn; } else filename = str+1; tmp = strchr (str+1, ' '); if (tmp) { sz = (st64) r_num_math (core->num, tmp+1); if (!sz) { sz = core->blocksize; } *tmp = 0; if (sz<1) eprintf ("Invalid length\n"); else r_core_dump (core, filename, core->offset, (ut64)sz, append); } else { if (!r_file_dump (filename, core->block, core->blocksize, append)) { sz = 0; } else sz = core->blocksize; } eprintf ("Dumped %"PFMT64d" bytes from 0x%08"PFMT64x" into %s\n", sz, core->offset, filename); } break; case 'f': arg = (const char *)(input+((input[1]==' ')?2:1)); if (!strcmp (arg, "-")) { char *out = r_core_editor (core, NULL, NULL); if (out) { r_io_write_at (core->io, core->offset, (ut8*)out, strlen (out)); free (out); } } else if ((buf = (ut8*) r_file_slurp (arg, &size))) { r_io_use_desc (core->io, core->file->desc); r_io_write_at (core->io, core->offset, buf, size); WSEEK (core, size); free (buf); r_core_block_read (core, 0); } else eprintf ("Cannot open file '%s'\n", arg); break; case 'F': arg = (const char *)(input+((input[1]==' ')?2:1)); if (!strcmp (arg, "-")) { int len; ut8 *out; char *in = r_core_editor (core, NULL, NULL); if (in) { out = (ut8 *)strdup (in); if (out) { len = r_hex_str2bin (in, out); if (len>0) r_io_write_at (core->io, core->offset, out, len); free (out); } free (in); } } else if ((buf = r_file_slurp_hexpairs (arg, &size))) { r_io_use_desc (core->io, core->file->desc); r_io_write_at (core->io, core->offset, buf, size); WSEEK (core, size); free (buf); r_core_block_read (core, 0); } else eprintf ("Cannot open file '%s'\n", arg); break; case 'w': str++; len = (len-1)<<1; if (len>0) tmp = malloc (len+1); else tmp = NULL; if (tmp) { for (i=0; i<len; i++) { if (i%2) tmp[i] = 0; else tmp[i] = str[i>>1]; } str = tmp; r_io_use_desc (core->io, core->file->desc); r_io_write_at (core->io, core->offset, (const ut8*)str, len); WSEEK (core, len); r_core_block_read (core, 0); free (tmp); } else eprintf ("Cannot malloc %d\n", len); break; case 'x': { int b, len = strlen (input); ut8 *buf = malloc (len+1); len = r_hex_str2bin (input+1, buf); if (len != 0) { if (len<0) len = -len+1; if (len<core->blocksize) { b = core->block[len]&0xf; b |= (buf[len]&0xf0); } else b = buf[len]; buf[len] = b; r_core_write_at (core, core->offset, buf, len); WSEEK (core, len); r_core_block_read (core, 0); } else eprintf ("Error: invalid hexpair string\n"); free (buf); } break; case 'a': switch (input[1]) { case 'o': if (input[2] == ' ') r_core_hack (core, input+3); else r_core_hack_help (core); break; case ' ': case '*': { const char *file = input[1]=='*'? input+2: input+1; RAsmCode *acode; r_asm_set_pc (core->assembler, core->offset); acode = r_asm_massemble (core->assembler, file); if (acode) { if (input[1]=='*') { r_cons_printf ("wx %s\n", acode->buf_hex); } else { if (r_config_get_i (core->config, "scr.prompt")) eprintf ("Written %d bytes (%s) = wx %s\n", acode->len, input+2, acode->buf_hex); r_core_write_at (core, core->offset, acode->buf, acode->len); WSEEK (core, acode->len); r_core_block_read (core, 0); } r_asm_code_free (acode); } } break; case 'f': if ((input[2]==' '||input[2]=='*')) { const char *file = input[2]=='*'? input+4: input+3; RAsmCode *acode; r_asm_set_pc (core->assembler, core->offset); acode = r_asm_assemble_file (core->assembler, file); if (acode) { if (input[2]=='*') { r_cons_printf ("wx %s\n", acode->buf_hex); } else { if (r_config_get_i (core->config, "scr.prompt")) eprintf ("Written %d bytes (%s)=wx %s\n", acode->len, input+1, acode->buf_hex); r_core_write_at (core, core->offset, acode->buf, acode->len); WSEEK (core, acode->len); r_core_block_read (core, 0); } r_asm_code_free (acode); } else eprintf ("Cannot assemble file\n"); } else eprintf ("Wrong argument\n"); break; default: r_cons_printf ("|Usage: wa[of*] [arg]\n" "| wa nop : write nopcode using asm.arch and asm.bits\n" "| wa* mov eax, 33 : show 'wx' op with hexpair bytes of assembled opcode\n" "| \"wa nop;nop\" : assemble more than one instruction (note the quotes)\n" "| waf foo.asm : assemble file and write bytes\n" "| wao nop : convert current opcode into nops\n" "| wao? : show help for assembler operation on current opcode (hack)\n"); break; } break; case 'b': { int len = strlen (input); ut8 *buf = malloc (len+1); if (buf) { len = r_hex_str2bin (input+1, buf); if (len > 0) { r_mem_copyloop (core->block, buf, core->blocksize, len); r_core_write_at (core, core->offset, core->block, core->blocksize); WSEEK (core, core->blocksize); r_core_block_read (core, 0); } else eprintf ("Wrong argument\n"); free (buf); } else eprintf ("Cannot malloc %d\n", len+1); } break; case 'm': size = r_hex_str2bin (input+1, (ut8*)str); switch (input[1]) { case '\0': eprintf ("Current write mask: TODO\n"); // TODO break; case '?': break; case '-': r_io_set_write_mask (core->io, 0, 0); eprintf ("Write mask disabled\n"); break; case ' ': if (size>0) { r_io_use_desc (core->io, core->file->desc); r_io_set_write_mask (core->io, (const ut8*)str, size); WSEEK (core, size); eprintf ("Write mask set to '"); for (i=0; i<size; i++) eprintf ("%02x", str[i]); eprintf ("'\n"); } else eprintf ("Invalid string\n"); break; } break; case 'v': cmd_write_value (core, input); break; case 'o': cmd_write_op (core, input); break; case 'd': if (input[1] && input[1]==' ') { char *arg, *inp = strdup (input+2); arg = strchr (inp, ' '); if (arg) { *arg = 0; ut64 addr = r_num_math (core->num, input+2); ut64 len = r_num_math (core->num, arg+1); ut8 *data = malloc (len); r_io_read_at (core->io, addr, data, len); r_io_write_at (core->io, core->offset, data, len); free (data); } else eprintf ("See wd?\n"); free (inp); } else eprintf ("Usage: wd [source-offset] [length] @ [dest-offset]\n"); break; case 's': if (str && *str && str[1]) { len = r_str_unescape (str+1); if (len>255) { eprintf ("Too large\n"); } else { ut8 ulen = (ut8)len; r_core_write_at (core, core->offset, &ulen, 1); r_core_write_at (core, core->offset+1, (const ut8*)str+1, len); WSEEK (core, len); r_core_block_read (core, 0); } } else eprintf ("Too short.\n"); break; default: case '?': if (core->oobi) { eprintf ("Writing oobi buffer!\n"); r_io_use_desc (core->io, core->file->desc); r_io_write (core->io, core->oobi, core->oobi_len); WSEEK (core, core->oobi_len); r_core_block_read (core, 0); } else { r_core_cmd_help (core, help_msg); } break; }
static int cmd_cmp(void *data, const char *input) { RCore *core = data; FILE *fd; ut8 *buf; int ret; ut32 v32; ut64 v64; switch (*input) { case ' ': radare_compare (core, core->block, (ut8*)input+1, strlen (input+1)+1); break; case 'x': if (input[1]!=' ') { eprintf ("Usage: cx 001122'\n"); return 0; } buf = (ut8*)malloc (strlen (input+2)); ret = r_hex_str2bin (input+2, buf); if (ret<1) eprintf ("Cannot parse hexpair\n"); else radare_compare (core, core->block, buf, ret); free (buf); break; case 'X': buf = malloc (core->blocksize); ret = r_io_read_at (core->io, r_num_math (core->num, input+1), buf, core->blocksize); radare_compare (core, core->block, buf, ret); free (buf); break; case 'f': if (input[1]!=' ') { eprintf ("Please. use 'cf [file]'\n"); return 0; } fd = fopen (input+2, "rb"); if (fd == NULL) { eprintf ("Cannot open file '%s'\n", input+2); return 0; } buf = (ut8 *)malloc (core->blocksize); fread (buf, 1, core->blocksize, fd); fclose (fd); radare_compare (core, core->block, buf, core->blocksize); free (buf); break; case 'q': v64 = (ut64) r_num_math (core->num, input+1); radare_compare (core, core->block, (ut8*)&v64, sizeof (v64)); break; case 'd': v32 = (ut32) r_num_math (core->num, input+1); radare_compare (core, core->block, (ut8*)&v32, sizeof (v32)); break; #if 0 case 'c': radare_compare_code ( r_num_math (core->num, input+1), core->block, core->blocksize); break; case 'D': { // XXX ugly hack char cmd[1024]; sprintf (cmd, "radiff -b %s %s", ".curblock", input+2); r_file_dump (".curblock", config.block, config.block_size); radare_system(cmd); unlink(".curblock"); } break; #endif case 'g': { // XXX: this is broken int diffops = 0; RCore *core2; char *file2 = NULL; if (input[1]=='o') { file2 = (char*)r_str_chop_ro (input+2); r_anal_diff_setup (core->anal, R_TRUE, -1, -1); } else if (input[1]==' ') { file2 = (char*)r_str_chop_ro (input+2); r_anal_diff_setup (core->anal, R_FALSE, -1, -1); } else { eprintf ("Usage: cg[o] [file]\n"); eprintf (" cg - byte-per-byte code graph diff\n"); eprintf (" cgo - opcode-bytes code graph diff\n"); return R_FALSE; } if (!(core2 = r_core_new ())) { eprintf ("Cannot init diff core\n"); return R_FALSE; } core2->io->va = core->io->va; core2->anal->split = core->anal->split; if (!r_core_file_open (core2, file2, 0, 0LL)) { eprintf ("Cannot open diff file '%s'\n", file2); r_core_free (core2); return R_FALSE; } // TODO: must replicate on core1 too r_config_set_i (core2->config, "io.va", R_TRUE); r_config_set_i (core2->config, "anal.split", R_TRUE); r_anal_diff_setup (core->anal, diffops, -1, -1); r_anal_diff_setup (core2->anal, diffops, -1, -1); r_core_bin_load (core2, file2); r_core_gdiff (core, core2); r_core_diff_show (core, core2); r_core_free (core2); } break; case '?': r_cons_strcat ( "Usage: c[?cdfx] [argument]\n" " c [string] Compares a plain with escaped chars string\n" //" cc [offset] Code bindiff current block against offset\n" " cd [value] Compare a doubleword from a math expression\n" //" cD [file] Like above, but using radiff -b\n"); " cq [value] Compare a quadword from a math expression\n" " cx [hexpair] Compare hexpair string\n" " cX [addr] Like 'cc' but using hexdiff output\n" " cf [file] Compare contents of file at current seek\n" " cg[o] [file] Graphdiff current file and [file]\n"); break; default: eprintf ("Usage: c[?Ddxf] [argument]\n"); } return 0; }
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) != 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_singleton ()->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", op.buf_asm); else eprintf("op.buf_asm: <invalid>\n"); free(hex_str); } // disassembly invalid if (current_instr_len == 0 || strstr (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; }
static ut64 readQword (RCoreObjc *objc, ut64 addr) { ut8 buf[8]; (void)r_io_read_at (objc->core->io, addr, buf, sizeof (buf)); return r_read_le64 (buf); }
static int do_hash(const char *algo, RIO *io, int bsize, int rad) { ut8 *buf; RHash *ctx; ut64 j, fsize; int i; ut64 algobit = r_hash_name_to_bits (algo); if (algobit == R_HASH_NONE) { eprintf ("Invalid hashing algorithm specified\n"); return 1; } fsize = r_io_size (io); if (bsize == 0 || bsize > fsize) bsize = fsize; if (to == 0LL) to = fsize; if (from>to) { eprintf ("Invalid -f -t range\n"); return 1; } if (fsize == -1LL) { eprintf ("Unknown file size\n"); return 1; } buf = malloc (bsize+1); ctx = r_hash_new (R_TRUE, algobit); if (incremental) { for (i=1; i<0x800000; i<<=1) { if (algobit & i) { int hashbit = i & algobit; int dlen = r_hash_size (hashbit); r_hash_do_begin (ctx, i); for (j=from; j<to; j+=bsize) { r_io_read_at (io, j, buf, bsize); do_hash_internal (ctx, hashbit, buf, ((j+bsize)<fsize)? bsize: (fsize-j), rad, 0); } r_hash_do_end (ctx, i); do_hash_print (ctx, i, dlen, rad); } } } else { /* iterate over all algorithm bits */ for (i=1; i<0x800000; i<<=1) { ut64 f, t, ofrom, oto; if (algobit & i) { int hashbit = i & algobit; ofrom = from; oto = to; f = from; t = to; for (j=f; j<t; j+=bsize) { int nsize = (j+bsize<fsize)? bsize: (fsize-j); r_io_read_at (io, j, buf, bsize); from = j; to = j+bsize; do_hash_internal (ctx, hashbit, buf, nsize, rad, 1); } from = ofrom; to = oto; } } } r_hash_free (ctx); free (buf); return 0; }
/* TODO: simplify using r_write */ static int cmd_write(void *data, const char *input) { ut64 off; ut8 *buf; const char *arg; int wseek, i, size, len = strlen (input); char *tmp, *str, *ostr; RCore *core = (RCore *)data; #define WSEEK(x,y) if (wseek)r_core_seek_delta (x,y) wseek = r_config_get_i (core->config, "cfg.wseek"); str = ostr = strdup (input+1); switch (*input) { case 'h': { char *p = strchr (input, ' '); if (p) { while (*p==' ') p++; p = r_file_path (p); if (p) { r_cons_printf ("%s\n", p); free (p); } } } break; case 'e': { ut64 addr = 0, len = 0, b_size = 0; st64 dist = 0; ut8* bytes = NULL; int cmd_suc = R_FALSE; char *input_shadow = NULL, *p = NULL; switch (input[1]) { case 'n': if (input[2] == ' ') { len = *input ? r_num_math (core->num, input+3) : 0; if (len > 0){ ut64 cur_off = core->offset; cmd_suc = r_core_extend_at (core, core->offset, len); core->offset = cur_off; r_core_block_read (core, 0); } } break; case 'N': if (input[2] == ' ') { input += 3; while (*input && *input == ' ') input++; addr = r_num_math (core->num, input); while (*input && *input != ' ') input++; input++; len = *input ? r_num_math (core->num, input) : 0; if (len > 0){ ut64 cur_off = core->offset; cmd_suc = r_core_extend_at (core, addr, len); cmd_suc = r_core_seek (core, cur_off, 1); core->offset = addr; r_core_block_read (core, 0); } } break; case 'x': if (input[2] == ' ') { input+=2; len = *input ? strlen (input) : 0; bytes = len > 1? malloc (len+1) : NULL; len = bytes ? r_hex_str2bin (input, bytes) : 0; if (len > 0) { ut64 cur_off = core->offset; cmd_suc = r_core_extend_at (core, cur_off, len); if (cmd_suc) { r_core_write_at (core, cur_off, bytes, len); } core->offset = cur_off; r_core_block_read (core, 0); } free (bytes); } break; case 'X': if (input[2] == ' ') { addr = r_num_math (core->num, input+3); input += 3; while (*input && *input != ' ') input++; input++; len = *input ? strlen (input) : 0; bytes = len > 1? malloc (len+1) : NULL; len = bytes ? r_hex_str2bin (input, bytes) : 0; if (len > 0) { //ut64 cur_off = core->offset; cmd_suc = r_core_extend_at (core, addr, len); if (cmd_suc) { r_core_write_at (core, addr, bytes, len); } core->offset = addr; r_core_block_read (core, 0); } free (bytes); } break; case 's': input += 3; while (*input && *input == ' ') input++; len = strlen (input); input_shadow = len > 0? malloc (len+1): 0; // since the distance can be negative, // the r_num_math will perform an unwanted operation // the solution is to tokenize the string :/ if (input_shadow) { strncpy (input_shadow, input, len+1); p = strtok (input_shadow, " "); addr = p && *p ? r_num_math (core->num, p) : 0; p = strtok (NULL, " "); dist = p && *p ? r_num_math (core->num, p) : 0; p = strtok (NULL, " "); b_size = p && *p ? r_num_math (core->num, p) : 0; if (dist != 0){ r_core_shift_block (core, addr, b_size, dist); r_core_seek (core, addr, 1); cmd_suc = R_TRUE; } } free (input_shadow); break; case '?': default: cmd_suc = R_FALSE; } if (cmd_suc == R_FALSE) { r_cons_printf ("|Usage: write extend\n" "wen <num> insert num null bytes at current offset\n" "wex <hex_bytes> insert bytes at current offset\n" "weN <addr> <len> insert bytes at address\n" "weX <addr> <hex_bytes> insert bytes at address\n" "wes <addr> <dist> <block_size> shift a blocksize left or write in the editor\n" ); } } break; case 'p': if (input[1]=='-' || (input[1]==' '&&input[2]=='-')) { const char *tmpfile = ".tmp"; char *out = r_core_editor (core, NULL); if (out) { // XXX hacky .. patch should support str, not only file r_file_dump (tmpfile, (ut8*)out, strlen (out)); r_core_patch (core, tmpfile); r_file_rm (tmpfile); free (out); } } else { if (input[1]==' ' && input[2]) { r_core_patch (core, input+2); } else { eprintf ("Usage: wp [-|r2patch-file]\n" "TODO: rapatch format documentation here\n"); } } break; case 'u': // TODO: implement it in an API RCore.write_unified_hexpatch() is ETOOLONG if (input[1]==' ') { char *data = r_file_slurp (input+2, NULL); if (data) { char sign = ' '; int line = 0, offs = 0, hexa = 0; int newline = 1; for (i=0; data[i]; i++) { switch (data[i]) { case '+': if (newline) sign = 1; break; case '-': if (newline) { sign = 0; offs = i + ((data[i+1]==' ')?2:1); } break; case ' ': data[i] = 0; if (sign) { if (!line) line = i+1; else if (!hexa) hexa = i+1; } break; case '\r': break; case '\n': newline = 1; if (sign == -1) { offs = 0; line = 0; hexa = 0; } else if (sign) { if (offs && hexa) { r_cons_printf ("wx %s @ %s\n", data+hexa, data+offs); } else eprintf ("food\n"); offs = 0; line = 0; } else hexa = 0; sign = -1; continue; } newline = 0; } free (data); } } else { eprintf ("|Usage: wu [unified-diff-patch] # see 'cu'\n"); } break; case 'r': off = r_num_math (core->num, input+1); len = (int)off; if (len>0) { buf = malloc (len); if (buf != NULL) { r_num_irand (); for (i=0; i<len; i++) buf[i] = r_num_rand (256); r_core_write_at (core, core->offset, buf, len); WSEEK (core, len); free (buf); } else eprintf ("Cannot allocate %d bytes\n", len); } break; case 'A': switch (input[1]) { case ' ': if (input[2] && input[3]==' ') { r_asm_set_pc (core->assembler, core->offset); eprintf ("modify (%c)=%s\n", input[2], input+4); len = r_asm_modify (core->assembler, core->block, input[2], r_num_math (core->num, input+4)); eprintf ("len=%d\n", len); if (len>0) { r_core_write_at (core, core->offset, core->block, len); WSEEK (core, len); } else eprintf ("r_asm_modify = %d\n", len); } else eprintf ("Usage: wA [type] [value]\n"); break; case '?': default: r_cons_printf ("|Usage: wA [type] [value]\n" "|Types:\n" "| r raw write value\n" "| v set value (taking care of current address)\n" "| d destination register\n" "| 0 1st src register\n" "| 1 2nd src register\n" "|Example: wA r 0 # e800000000\n"); break; } break; case 'c': switch (input[1]) { case 'i': r_io_cache_commit (core->io); r_core_block_read (core, 0); break; case 'r': r_io_cache_reset (core->io, R_TRUE); /* Before loading the core block we have to make sure that if * the cache wrote past the original EOF these changes are no * longer displayed. */ memset (core->block, 0xff, core->blocksize); r_core_block_read (core, 0); break; case '-': if (input[2]=='*') { r_io_cache_reset (core->io, R_TRUE); } else if (input[2]==' ') { char *p = strchr (input+3, ' '); ut64 to, from = core->offset; if (p) { *p = 0; from = r_num_math (core->num, input+3); to = r_num_math (core->num, input+3); if (to<from) { eprintf ("Invalid range (from>to)\n"); return 0; } } else { from = r_num_math (core->num, input+3); to = from + core->blocksize; } r_io_cache_invalidate (core->io, from, to); } else { eprintf ("Invalidate write cache at 0x%08"PFMT64x"\n", core->offset); r_io_cache_invalidate (core->io, core->offset, core->offset+core->blocksize); } /* See 'r' above. */ memset (core->block, 0xff, core->blocksize); r_core_block_read (core, 0); break; case '?': r_cons_printf ( "|Usage: wc[ir*?]\n" "| wc list all write changes\n" "| wc- [a] [b] remove write op at curseek or given addr\n" "| wc* \"\" in radare commands\n" "| wcr reset all write changes in cache\n" "| wci commit write cache\n" "|NOTE: Requires 'e io.cache=true'\n"); break; case '*': r_io_cache_list (core->io, R_TRUE); break; case '\0': if (!r_config_get_i (core->config, "io.cache")) eprintf ("[warning] e io.cache must be true\n"); r_io_cache_list (core->io, R_FALSE); break; } break; case ' ': /* write string */ len = r_str_unescape (str); r_core_write_at (core, core->offset, (const ut8*)str, len); #if 0 r_io_use_desc (core->io, core->file->desc); r_io_write_at (core->io, core->offset, (const ut8*)str, len); #endif WSEEK (core, len); r_core_block_read (core, 0); break; case 't': if (*str != ' ') { eprintf ("Usage: wt file [size]\n"); } else { tmp = strchr (str+1, ' '); if (tmp) { st64 sz = (st64) r_num_math (core->num, tmp+1); *tmp = 0; if (sz<1) eprintf ("Invalid length\n"); else r_core_dump (core, str+1, core->offset, (ut64)sz); } else r_file_dump (str+1, core->block, core->blocksize); } break; case 'T': eprintf ("TODO: wT // why?\n"); break; case 'f': arg = (const char *)(input+((input[1]==' ')?2:1)); if (!strcmp (arg, "-")) { char *out = r_core_editor (core, NULL); if (out) { r_io_write_at (core->io, core->offset, (ut8*)out, strlen (out)); free (out); } } else if ((buf = (ut8*) r_file_slurp (arg, &size))) { r_io_use_desc (core->io, core->file->desc); r_io_write_at (core->io, core->offset, buf, size); WSEEK (core, size); free (buf); r_core_block_read (core, 0); } else eprintf ("Cannot open file '%s'\n", arg); break; case 'F': arg = (const char *)(input+((input[1]==' ')?2:1)); if (!strcmp (arg, "-")) { int len; ut8 *out; char *in = r_core_editor (core, NULL); if (in) { out = (ut8 *)strdup (in); if (out) { len = r_hex_str2bin (in, out); if (len>0) r_io_write_at (core->io, core->offset, out, len); free (out); } free (in); } } else if ((buf = r_file_slurp_hexpairs (arg, &size))) { r_io_use_desc (core->io, core->file->desc); r_io_write_at (core->io, core->offset, buf, size); WSEEK (core, size); free (buf); r_core_block_read (core, 0); } else eprintf ("Cannot open file '%s'\n", arg); break; case 'w': str++; len = (len-1)<<1; if (len>0) tmp = malloc (len+1); else tmp = NULL; if (tmp) { for (i=0; i<len; i++) { if (i%2) tmp[i] = 0; else tmp[i] = str[i>>1]; } str = tmp; r_io_use_desc (core->io, core->file->desc); r_io_write_at (core->io, core->offset, (const ut8*)str, len); WSEEK (core, len); r_core_block_read (core, 0); free (tmp); } else eprintf ("Cannot malloc %d\n", len); break; case 'x': { int b, len = strlen (input); ut8 *buf = malloc (len+1); len = r_hex_str2bin (input+1, buf); if (len != 0) { if (len<0) len = -len+1; if (len<core->blocksize) { b = core->block[len]&0xf; b |= (buf[len]&0xf0); } else b = buf[len]; buf[len] = b; r_core_write_at (core, core->offset, buf, len); WSEEK (core, len); r_core_block_read (core, 0); } else eprintf ("Error: invalid hexpair string\n"); free (buf); } break; case 'a': switch (input[1]) { case 'o': if (input[2] == ' ') r_core_hack (core, input+3); else r_core_hack_help (core); break; case ' ': case '*': { const char *file = input[1]=='*'? input+2: input+1; RAsmCode *acode; r_asm_set_pc (core->assembler, core->offset); acode = r_asm_massemble (core->assembler, file); if (acode) { if (input[1]=='*') { r_cons_printf ("wx %s\n", acode->buf_hex); } else { if (r_config_get_i (core->config, "scr.prompt")) eprintf ("Written %d bytes (%s) = wx %s\n", acode->len, input+2, acode->buf_hex); r_core_write_at (core, core->offset, acode->buf, acode->len); WSEEK (core, acode->len); r_core_block_read (core, 0); } r_asm_code_free (acode); } } break; case 'f': if ((input[2]==' '||input[2]=='*')) { const char *file = input[2]=='*'? input+4: input+3; RAsmCode *acode; r_asm_set_pc (core->assembler, core->offset); acode = r_asm_assemble_file (core->assembler, file); if (acode) { if (input[2]=='*') { r_cons_printf ("wx %s\n", acode->buf_hex); } else { if (r_config_get_i (core->config, "scr.prompt")) eprintf ("Written %d bytes (%s)=wx %s\n", acode->len, input+1, acode->buf_hex); r_core_write_at (core, core->offset, acode->buf, acode->len); WSEEK (core, acode->len); r_core_block_read (core, 0); } r_asm_code_free (acode); } else eprintf ("Cannot assemble file\n"); } else eprintf ("Wrong argument\n"); break; default: r_cons_printf ("|Usage: wa[of*] [arg]\n" "| wa nop : write nopcode using asm.arch and asm.bits\n" "| wa* mov eax, 33 : show 'wx' op with hexpair bytes of sassembled opcode\n" "| \"wa nop;nop\" : assemble more than one instruction (note the quotes)\n" "| waf foo.asm : assemble file and write bytes\n" "| wao nop : convert current opcode into nops\n" "| wao? : show help for assembler operation on current opcode (hack)\n"); break; } break; case 'b': { int len = strlen (input); ut8 *buf = malloc (len+1); if (buf) { len = r_hex_str2bin (input+1, buf); if (len > 0) { r_mem_copyloop (core->block, buf, core->blocksize, len); r_core_write_at (core, core->offset, core->block, core->blocksize); WSEEK (core, core->blocksize); r_core_block_read (core, 0); } else eprintf ("Wrong argument\n"); free (buf); } else eprintf ("Cannot malloc %d\n", len+1); } break; case 'm': size = r_hex_str2bin (input+1, (ut8*)str); switch (input[1]) { case '\0': eprintf ("Current write mask: TODO\n"); // TODO break; case '?': break; case '-': r_io_set_write_mask (core->io, 0, 0); eprintf ("Write mask disabled\n"); break; case ' ': if (size>0) { r_io_use_desc (core->io, core->file->desc); r_io_set_write_mask (core->io, (const ut8*)str, size); WSEEK (core, size); eprintf ("Write mask set to '"); for (i=0; i<size; i++) eprintf ("%02x", str[i]); eprintf ("'\n"); } else eprintf ("Invalid string\n"); break; } break; case 'v': { int type = 0; ut8 addr1; ut16 addr2; ut32 addr4, addr4_; ut64 addr8; switch (input[1]) { case '?': r_cons_printf ("|Usage: wv[size] [value] # write value of given size\n" "| wv1 234 # write one byte with this value\n" "| wv 0x834002 # write dword with this value\n" "|Supported sizes are: 1, 2, 4, 8\n"); return 0; case '1': type = 1; break; case '2': type = 2; break; case '4': type = 4; break; case '8': type = 8; break; } off = r_num_math (core->num, input+2); r_io_use_desc (core->io, core->file->desc); r_io_seek (core->io, core->offset, R_IO_SEEK_SET); if (type == 0) type = (off&UT64_32U)? 8: 4; switch (type) { case 1: addr1 = (ut8)off; r_io_write (core->io, (const ut8 *)&addr1, 1); WSEEK (core, 1); break; case 2: addr2 = (ut16)off; r_io_write (core->io, (const ut8 *)&addr2, 2); WSEEK (core, 2); break; case 4: addr4_ = (ut32)off; //drop_endian((ut8*)&addr4_, (ut8*)&addr4, 4); /* addr4_ = addr4 */ //endian_memcpy((ut8*)&addr4, (ut8*)&addr4_, 4); /* addr4 = addr4_ */ memcpy ((ut8*)&addr4, (ut8*)&addr4_, 4); // XXX needs endian here too r_io_write (core->io, (const ut8 *)&addr4, 4); WSEEK (core, 4); break; case 8: /* 8 byte addr */ memcpy ((ut8*)&addr8, (ut8*)&off, 8); // XXX needs endian here // endian_memcpy((ut8*)&addr8, (ut8*)&off, 8); r_io_write (core->io, (const ut8 *)&addr8, 8); WSEEK (core, 8); break; } r_core_block_read (core, 0); } break; case 'o': switch (input[1]) { case 'a': case 's': case 'e': case 'A': case 'x': case 'r': case 'l': case 'm': case 'd': case 'o': case 'w': if (input[2]!=' ') { if (input[1]=='e') r_cons_printf ( "Usage: 'woe from-to step'\n"); else r_cons_printf ( "Usage: 'wo%c 00 11 22'\n", input[1]); free (ostr); return 0; } case '2': case '4': r_core_write_op (core, input+3, input[1]); r_core_block_read (core, 0); break; case 'R': r_core_cmd0 (core, "wr $b"); break; case 'n': r_core_write_op (core, "ff", 'x'); r_core_block_read (core, 0); break; case '\0': case '?': default: r_cons_printf ( "|Usage: wo[asmdxoArl24] [hexpairs] @ addr[:bsize]\n" "|Example:\n" "| wox 0x90 ; xor cur block with 0x90\n" "| wox 90 ; xor cur block with 0x90\n" "| wox 0x0203 ; xor cur block with 0203\n" "| woa 02 03 ; add [0203][0203][...] to curblk\n" "| woe 02 03 \n" "|Supported operations:\n" "| wow == write looped value (alias for 'wb')\n" "| woa += addition\n" "| wos -= substraction\n" "| wom *= multiply\n" "| wod /= divide\n" "| wox ^= xor\n" "| woo |= or\n" "| woA &= and\n" "| woR random bytes (alias for 'wr $b'\n" "| wor >>= shift right\n" "| wol <<= shift left\n" "| wo2 2= 2 byte endian swap\n" "| wo4 4= 4 byte endian swap\n" ); break; } break; case 'd': if (input[1]==' ') { char *arg, *inp = strdup (input+2); arg = strchr (inp, ' '); if (arg) { *arg = 0; ut64 addr = r_num_math (core->num, input+2); ut64 len = r_num_math (core->num, arg+1); ut8 *data = malloc (len); r_io_read_at (core->io, addr, data, len); r_io_write_at (core->io, core->offset, data, len); free (data); } else eprintf ("See wd?\n"); free (inp); } else eprintf ("Usage: wd [source-offset] [length] @ [dest-offset]\n"); break; case 's': { ut8 ulen; len = r_str_unescape (str+1); if (len>255) { eprintf ("Too large\n"); } else { ulen = (ut8)len; r_core_write_at (core, core->offset, &ulen, 1); r_core_write_at (core, core->offset+1, (const ut8*)str+1, len); WSEEK (core, len); r_core_block_read (core, 0); } } break; default: case '?': if (core->oobi) { eprintf ("Writing oobi buffer!\n"); r_io_use_desc (core->io, core->file->desc); r_io_write (core->io, core->oobi, core->oobi_len); WSEEK (core, core->oobi_len); r_core_block_read (core, 0); } else r_cons_printf ( "|Usage: w[x] [str] [<file] [<<EOF] [@addr]\n" "| w foobar write string 'foobar'\n" "| wh r2 whereis/which shell command\n" "| wr 10 write 10 random bytes\n" "| ww foobar write wide string 'f\\x00o\\x00o\\x00b\\x00a\\x00r\\x00'\n" "| wa push ebp write opcode, separated by ';' (use '\"' around the command)\n" "| waf file assemble file and write bytes\n" "| wA r 0 alter/modify opcode at current seek (see wA?)\n" "| wb 010203 fill current block with cyclic hexpairs\n" "| wc[ir*?] write cache undo/commit/reset/list (io.cache)\n" "| wd [off] [n] duplicate N bytes from offset at current seek (memcpy) (see y?)\n" "| wx 9090 write two intel nops\n" "| wv eip+34 write 32-64 bit value\n" "| wo? hex write in block with operation. 'wo?' fmi\n" "| wm f0ff set binary mask hexpair to be used as cyclic write mask\n" "| ws pstring write 1 byte for length and then the string\n" "| wf -|file write contents of file at current offset\n" "| wF -|file write contents of hexpairs file here\n" "| wp -|file apply radare patch file. See wp? fmi\n" "| wt file [sz] write to file (from current seek, blocksize or sz bytes)\n" ); //TODO: add support for offset+seek // " wf file o s ; write contents of file from optional offset 'o' and size 's'.\n" break; }
static ut64 num_callback(RNum *userptr, const char *str, int *ok) { RCore *core = (RCore *)userptr; // XXX ? RAnalFunction *fcn; char *ptr, *bptr, *out; RFlagItem *flag; RIOSection *s; RAnalOp op; ut64 ret = 0; if (ok) *ok = R_FALSE; switch (*str) { case '[': { ut64 n = 0LL; int refsz = (core->assembler->bits & R_SYS_BITS_64)? 8: 4; const char *p = NULL; if (strlen (str)>5) p = strchr (str+5, ':'); // TODO: honor LE if (p) { refsz = atoi (str+1); str = p; } // push state { if (str[0] && str[1]) { const char *q; char *o = strdup (str+1); if (o) { q = r_num_calc_index (core->num, NULL); if (q) { if (r_str_replace_char (o, ']', 0)>0) { n = r_num_math (core->num, o); r_num_calc_index (core->num, q); } } free (o); } } } // pop state if (ok) *ok = 1; ut32 num = 0; switch (refsz) { case 8: case 4: case 2: case 1: (void)r_io_read_at (core->io, n, (ut8*)&num, refsz); r_mem_copyendian ((ut8*)&num, (ut8*)&num, refsz, !core->assembler->big_endian); return num; default: eprintf ("Invalid reference size: %d (%s)\n", refsz, str); return 0LL; } } break; case '$': if (ok) *ok = 1; // TODO: group analop-dependant vars after a char, so i can filter r_anal_op (core->anal, &op, core->offset, core->block, core->blocksize); switch (str[1]) { case '.': // can use pc, sp, a0, a1, ... return r_debug_reg_get (core->dbg, str+2); case 'k': if (str[2]!='{') { eprintf ("Expected '{' after 'k'.\n"); break; } bptr = strdup (str+3); ptr = strchr (bptr, '}'); if (ptr == NULL) { // invalid json free (bptr); break; } *ptr = '\0'; ret = 0LL; out = sdb_querys (core->sdb, NULL, 0, bptr); if (out && *out) { if (strstr (out, "$k{")) { eprintf ("Recursivity is not permitted here\n"); } else { ret = r_num_math (core->num, out); } } free (bptr); free (out); return ret; break; case '{': bptr = strdup (str+2); ptr = strchr (bptr, '}'); if (ptr != NULL) { ut64 ret; ptr[0] = '\0'; ret = r_config_get_i (core->config, bptr); free (bptr); return ret; } free (bptr); break; case 'c': return r_cons_get_size (NULL); case 'r': { int rows; r_cons_get_size (&rows); return rows; } case 'e': return r_anal_op_is_eob (&op); case 'j': return op.jump; case 'p': return r_sys_getpid (); case 'P': return (core->dbg->pid>0)? core->dbg->pid: 0; case 'f': return op.fail; case 'm': return op.ptr; // memref case 'v': return op.val; // immediate value case 'l': return op.size; case 'b': return core->blocksize; case 's': if (core->file) { return r_io_desc_size (core->io, core->file->desc); } return 0LL; case 'w': return r_config_get_i (core->config, "asm.bits") / 8; case 'S': s = r_io_section_vget (core->io, core->offset); return s? (str[2]=='S'? s->size: s->vaddr): 3; case '?': return core->num->value; case '$': return core->offset; case 'o': return r_io_section_vaddr_to_offset (core->io, core->offset); case 'C': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_CALL); case 'J': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_CODE); case 'D': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_DATA); case 'X': return getref (core, atoi (str+2), 'x', R_ANAL_REF_TYPE_CALL); case 'I': fcn = r_anal_get_fcn_in (core->anal, core->offset, 0); return fcn? fcn->ninstr: 0; case 'F': fcn = r_anal_get_fcn_in (core->anal, core->offset, 0); return fcn? fcn->size: 0; } break; default: if (*str>'A') { // NOTE: functions override flags RAnalFunction *fcn = r_anal_fcn_find_name (core->anal, str); if (fcn) { if (ok) *ok = R_TRUE; return fcn->addr; } #if 0 ut64 addr = r_anal_fcn_label_get (core->anal, core->offset, str); if (addr != 0) { ret = addr; } else { ... } #endif if ((flag = r_flag_get (core->flags, str))) { ret = flag->offset; if (ok) *ok = R_TRUE; } } break; }
static ut32 readDword (RCoreObjc *objc, ut64 addr) { ut8 buf[4]; (void)r_io_read_at (objc->core->io, addr, buf, sizeof (buf)); return r_read_le32 (buf); }