R_API ut64 r_io_size(RIO *io) { ut64 size, here; if (r_io_is_listener (io)) return UT64_MAX; // XXX. problematic when io.va = 1 int iova = io->va; io->va = 0; //r_io_set_fdn (io, fd); here = r_io_seek (io, 0, R_IO_SEEK_CUR); size = r_io_seek (io, 0, R_IO_SEEK_END); io->va = iova; r_io_seek (io, here, R_IO_SEEK_SET); return size; }
R_API ut64 r_io_size(RIO *io) { int iova; ut64 size, here; if (!io) return 0LL; if (r_io_is_listener (io)) return UT64_MAX; iova = io->va; io->va = 0; here = r_io_seek (io, 0, R_IO_SEEK_CUR); size = r_io_seek (io, 0, R_IO_SEEK_END); io->va = iova; r_io_seek (io, here, R_IO_SEEK_SET); return size; }
R_API int r_io_write(struct r_io_t *io, const ut8 *buf, int len) { int i, ret = -1; ut8 *data = NULL; /* check section permissions */ if (io->enforce_rwx && !(r_io_section_get_rwx (io, io->off) & R_IO_WRITE)) return -1; if (io->cached) { ret = r_io_cache_write (io, io->off, buf, len); if (ret == len) return len; if (ret > 0) { len -= ret; buf += ret; } } /* TODO: implement IO cache here. to avoid dupping work on vm for example */ /* apply write binary mask */ if (io->write_mask_fd != -1) { data = malloc (len); r_io_seek (io, io->off, R_IO_SEEK_SET); r_io_read (io, data, len); r_io_seek (io, io->off, R_IO_SEEK_SET); for (i=0; i<len; i++) data[i] = buf[i] & \ io->write_mask_buf[i%io->write_mask_len]; buf = data; } r_io_map_select(io,io->off); if (io->plugin) { if (io->plugin->write) ret = io->plugin->write (io, io->fd, buf, len); else eprintf ("r_io_write: io handler with no write callback\n"); } else ret = write (io->fd->fd, buf, len); if (ret == -1) eprintf ("r_io_write: cannot write on fd %d\n", io->fd->fd); if (data) free (data); return ret; }
R_API bool r_core_seek(RCore *core, ut64 addr, bool rb) { core->offset = r_io_seek (core->io, addr, R_IO_SEEK_SET); if (rb) { r_core_block_read (core); } return core->offset == addr; }
R_API int r_io_read_at(RIO *io, ut64 addr, ut8 *buf, int len) { #if 0 int ret; if (r_io_seek (io, addr, R_IO_SEEK_SET)==UT64_MAX) { memset (buf, 0xff, len); return -1; } ret = r_io_read_internal (io, buf, len); if (ret<1) memset (buf, 0xff, len); return ret; #else int ret, l, olen = len; int w = 0; #if 1 // HACK?: if io->va == 0 -> call seek+read without checking sections ? if (!io->va) { r_io_seek (io, addr, R_IO_SEEK_SET); return r_io_read_internal (io, buf, len); } #endif while (len>0) { ut64 last = r_io_section_next (io, addr); l = (len > (last-addr))? (last-addr): len; if (l<1) l = len; // ignore seek errors // eprintf ("0x%llx %llx\n", addr+w, r_io_seek (io, addr+w, R_IO_SEEK_SET); ret = r_io_read_internal (io, buf+w, l); if (ret <1) { memset (buf+w, 0xff, l); // reading out of file ret = 1; } else if (ret<l) { // eprintf ("FOUND EOF AT %llx\n", addr+ret); l = ret; } w += l; len -= l; } return olen; #endif }
R_API boolt r_core_seek(RCore *core, ut64 addr, boolt rb) { RIOSection *newsection; ut64 old = core->offset; ut64 ret; /* XXX unnecesary call */ //r_io_set_fd (core->io, core->file->fd); core->io->section = core->section; // HACK ret = r_io_seek (core->io, addr, R_IO_SEEK_SET); newsection = core->io->section; if (ret == UT64_MAX) { //eprintf ("RET =%d %llx\n", ret, addr); /* XXX handle read errors correctly if (core->ffio) { core->offset = addr; } else return R_FALSE; */ //core->offset = addr; if (!core->io->va) return R_FALSE; memset (core->block, 0xff, core->blocksize); } else core->offset = addr; if (rb) { ret = r_core_block_read (core, 0); if (core->ffio) { if (ret<1 || ret > core->blocksize) memset (core->block, 0xff, core->blocksize); else memset (core->block+ret, 0xff, core->blocksize-ret); ret = core->blocksize; core->offset = addr; } else { if (ret<1) { core->offset = old; //eprintf ("Cannot read block at 0x%08"PFMT64x"\n", addr); } } } if (core->section != newsection) {//&& core->io->section->arch) { int bits = 0;// = core->io->section->bits; const char *arch = r_io_section_get_archbits (core->io, core->offset, &bits); if (arch && bits) { r_config_set (core->config, "asm.arch", arch); r_config_set_i (core->config, "asm.bits", bits); } core->section = core->io->section; } return (ret==-1)? R_FALSE: R_TRUE; }
R_API int r_core_block_read(RCore *core, int next) { ut64 off; if (core->file == NULL) { memset (core->block, 0xff, core->blocksize); return -1; } r_io_set_fd (core->io, core->file->fd); off = r_io_seek (core->io, core->offset+((next)?core->blocksize:0), R_IO_SEEK_SET); if (off == UT64_MAX) { memset (core->block, 0xff, core->blocksize); return -1; } return (int)r_io_read (core->io, core->block, core->blocksize); }
R_API int r_io_buffer_load(RIO* io, ut64 addr, int len) { ut64 at; int i, r; ut8 buf[512]; if (len<1) return R_FALSE; io->buffer_enabled = 0; for (i=0; i<len; i+=sizeof (buf)) { at = addr+i; r_io_seek (io, at, R_IO_SEEK_SET); memset (buf, 0xff, sizeof (buf)); r = r_io_read (io, buf, sizeof (buf)); if (r<1) break; r_cache_set (io->buffer, at, buf, sizeof (buf)); } io->buffer_enabled = 1; return R_TRUE; }
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); }
R_API boolt r_core_seek(RCore *core, ut64 addr, boolt rb) { ut64 old = core->offset; ut64 ret; /* XXX unnecesary call */ //r_io_set_fd (core->io, core->file->fd); ret = r_io_seek (core->io, addr, R_IO_SEEK_SET); if (ret == UT64_MAX) { //eprintf ("RET =%d %llx\n", ret, addr); /* XXX handle read errors correctly if (core->ffio) { core->offset = addr; } else return R_FALSE; */ //core->offset = addr; if (!core->io->va) return R_FALSE; memset (core->block, 0xff, core->blocksize); } else core->offset = addr; if (rb) { ret = r_core_block_read (core, 0); if (core->ffio) { if (ret<1 || ret > core->blocksize) memset (core->block, 0xff, core->blocksize); else memset (core->block+ret, 0xff, core->blocksize-ret); ret = core->blocksize; core->offset = addr; } else { if (ret<1) { core->offset = old; //eprintf ("Cannot read block at 0x%08"PFMT64x"\n", addr); } } } return (ret==-1)?R_FALSE:R_TRUE; }
/* 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 'p': if (input[1]==' ' && input[2]) { r_core_patch (core, input+2); } else { eprintf ("Usage: wp [rapatch-file]\n" "TODO: rapatch format documentation here\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': r_io_cache_list (core->io, R_FALSE); break; } break; case ' ': /* write string */ len = r_str_escape (str); r_core_write_at (core, core->offset, (const ut8*)str, len); #if 0 r_io_set_fd (core->io, core->file->fd); 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 ((buf = (ut8*) r_file_slurp (arg, &size))) { r_io_set_fd (core->io, core->file->fd); 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 ((buf = r_file_slurp_hexpairs (arg, &size))) { r_io_set_fd (core->io, core->file->fd); 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_set_fd (core->io, core->file->fd); 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; b = core->block[len]&0xf; b |= (buf[len]&0xf0); 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+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); } } 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: eprintf ("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"); } 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_set_fd (core->io, core->file->fd); 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_set_fd (core->io, core->file->fd); 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 'A': case 'x': case 'r': case 'l': case 'm': case 'd': case 'o': case 'w': if (input[2]!=' ') { r_cons_printf ("Usage: 'wo%c 00 11 22'\n", input[1]); return 0; } case '2': case '4': r_core_write_op (core, input+3, input[1]); r_core_block_read (core, 0); 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" "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 >>= shift right\n" " wol <<= shift left\n" " wo2 2= 2 byte endian swap\n" " wo4 4= 4 byte endian swap\n" ); break; } break; default: case '?': if (core->oobi) { eprintf ("Writing oobi buffer!\n"); r_io_set_fd (core->io, core->file->fd); 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" " 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 commit/reset/list\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" " wf file write contents of file at current offset\n" " wF file write contents of hexpairs file here\n" " wt file [sz] write to file (from current seek, blocksize or sz bytes)\n" " wp file apply radare patch file. See wp? fmi\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 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; }
static void cmd_write_value (RCore *core, const char *input) { int type = 0; ut8 addr1; ut16 addr2; ut32 addr4, addr4_; ut64 addr8, off = 0LL; int wseek = r_config_get_i (core->config, "cfg.wseek"); if (!input) return; if (input[0]) 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; case '1': type = 1; break; case '2': type = 2; break; case '4': type = 4; break; case '8': type = 8; break; } if (input && input[0] && input[1] && input[2]) { off = r_num_math (core->num, input+2); } if (core->file) { 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); }
R_API int r_core_shift_block(RCore *core, ut64 addr, ut64 b_size, st64 dist) { // bstart - block start, fstart file start ut64 fend = 0, fstart = 0, bstart = 0, file_sz = 0; ut8 * shift_buf = NULL; int res = false; if (!core->io || !core->file) { return false; } if (b_size == 0 || b_size == (ut64) -1) { r_io_use_fd (core->io, core->file->fd); file_sz = r_io_size (core->io); if (file_sz == UT64_MAX) { file_sz = 0; } #if 0 bstart = r_io_seek (core->io, addr, R_IO_SEEK_SET); fend = r_io_seek (core->io, 0, R_IO_SEEK_END); if (fend < 1) { fend = 0; } #else bstart = 0; fend = file_sz; #endif fstart = file_sz - fend; b_size = fend > bstart ? fend - bstart: 0; } if ((st64)b_size < 1) { return false; } shift_buf = calloc (b_size, 1); if (!shift_buf) { eprintf ("Cannot allocated %d byte(s)\n", (int)b_size); return false; } // cases // addr + b_size + dist > file_end //if ( (addr+b_size) + dist > file_end ) { // res = false; //} // addr + b_size + dist < file_start (should work since dist is signed) //else if ( (addr+b_size) + dist < 0 ) { // res = false; //} // addr + dist < file_start if (addr + dist < fstart) { res = false; // addr + dist > file_end } else if ( (addr) + dist > fend) { res = false; } else { r_io_use_fd (core->io, core->file->fd); r_io_read_at (core->io, addr, shift_buf, b_size); r_io_write_at (core->io, addr + dist, shift_buf, b_size); res = true; } r_core_seek (core, addr, 1); free (shift_buf); return res; }
R_API int r_io_write_at(RIO *io, ut64 addr, const ut8 *buf, int len) { if (r_io_seek (io, addr, R_IO_SEEK_SET)<0) return -1; return r_io_write (io, buf, len); }
R_API int r_io_read_at(RIO *io, ut64 addr, ut8 *buf, int len) { ut64 paddr, last, last2; int ms, ret, l, olen = len, w = 0; io->off = addr; memset (buf, 0xff, len); // probably unnecessary if (io->buffer_enabled) return r_io_buffer_read (io, addr, buf, len); while (len>0) { last = r_io_section_next (io, addr+w); last2 = r_io_map_next (io, addr+w); // XXX: must use physical address if (last == (addr+w)) last = last2; //else if (last2<last) last = last2; l = (len > (last-addr+w))? (last-addr+w): len; if (l<1) l = len; { paddr = w? r_io_section_vaddr_to_offset (io, addr+w): addr; if (len>0 && l>len) l = len; addr = paddr-w; if (r_io_seek (io, paddr, R_IO_SEEK_SET)==UT64_MAX) { memset (buf+w, 0xff, l); } } #if 0 if (io->zeromap) if (!r_io_map_get (io, addr+w)) { if (addr==0||r_io_section_getv (io, addr+w)) { memset (buf+w, 0xff, l); eprintf ("RETRERET\n"); return -1; } } #endif // XXX is this necessary? ms = r_io_map_select (io, addr+w); ret = r_io_read_internal (io, buf+w, l); //eprintf ("READ %d = %02x %02x %02x\n", ret, buf[w], buf[w+1], buf[w+2]); if (ret<1) { memset (buf+w, 0xff, l); // reading out of file ret = 1; } else if (ret<l) { l = ret; } #if USE_CACHE if (io->cached) { r_io_cache_read (io, addr+w, buf+w, len-w); } else if (r_list_length (io->maps) >1) { if (!io->debug && ms>0) { //eprintf ("FAIL MS=%d l=%d d=%d\n", ms, l, d); /* check if address is vaddred in sections */ ut64 o = r_io_section_offset_to_vaddr (io, addr+w); if (o == UT64_MAX) { ut64 o = r_io_section_vaddr_to_offset (io, addr+w); if (o == UT64_MAX) memset (buf+w, 0xff, l); } break; } } #endif w += l; len -= l; } return olen; }
static void cmd_write_value (RCore *core, const char *input) { int type = 0; ut64 off = 0LL; ut8 buf[sizeof(ut64)]; int wseek = r_config_get_i (core->config, "cfg.wseek"); bool be = r_config_get_i (core->config, "cfg.bigendian"); if (!input) return; if (input[0]) switch (input[1]) { case '?': { const char* help_msg[] = { "Usage:", "wv[size] [value]", "write value of given size", "wv1", " 234", "write one byte with this value", "wv", " 0x834002", "write dword with this value", "Supported sizes are:", "1, 2, 4, 8", "", NULL}; r_core_cmd_help (core, help_msg); return; } case '1': type = 1; break; case '2': type = 2; break; case '4': type = 4; break; case '8': type = 8; break; } if (input && input[0] && input[1] && input[2]) { off = r_num_math (core->num, input+2); } if (core->file) { r_io_use_desc (core->io, core->file->desc); } ut64 res = r_io_seek (core->io, core->offset, R_IO_SEEK_SET); if (res == UT64_MAX) return; if (type == 0) type = (off&UT64_32U)? 8: 4; switch (type) { case 1: r_write_ble8 (buf, (ut8)(off & UT8_MAX)); r_io_write (core->io, buf, 1); WSEEK (core, 1); break; case 2: r_write_ble16 (buf, (ut16)(off & UT16_MAX), be); r_io_write (core->io, buf, 2); WSEEK (core, 2); break; case 4: r_write_ble32 (buf, (ut32)(off & UT32_MAX), be); r_io_write (core->io, buf, 4); WSEEK (core, 4); break; case 8: r_write_ble64 (buf, off, be); r_io_write (core->io, buf, 8); WSEEK (core, 8); break; } r_core_block_read (core); }
static void cmd_write_value (RCore *core, const char *input) { int type = 0; ut64 off = 0LL; ut8 buf[sizeof(ut64)]; int wseek = r_config_get_i (core->config, "cfg.wseek"); bool be = r_config_get_i (core->config, "cfg.bigendian"); if (!input) return; if (input[0]) switch (input[1]) { case '?': r_core_cmd_help (core, help_msg_wv); return; case '1': type = 1; break; case '2': type = 2; break; case '4': type = 4; break; case '8': type = 8; break; } if (input && input[0] && input[1] && input[2]) { off = r_num_math (core->num, input+2); } if (core->file) { r_io_use_fd (core->io, core->file->fd); } ut64 res = r_io_seek (core->io, core->offset, R_IO_SEEK_SET); if (res == UT64_MAX) return; if (type == 0) type = (off&UT64_32U)? 8: 4; switch (type) { case 1: r_write_ble8 (buf, (ut8)(off & UT8_MAX)); if (!r_io_write (core->io, buf, 1)) { cmd_write_fail (); } else { WSEEK (core, 1); } break; case 2: r_write_ble16 (buf, (ut16)(off & UT16_MAX), be); if (!r_io_write (core->io, buf, 2)) { cmd_write_fail (); } else { WSEEK (core, 2); } break; case 4: r_write_ble32 (buf, (ut32)(off & UT32_MAX), be); if (!r_io_write (core->io, buf, 4)) { cmd_write_fail (); } else { WSEEK (core, 4); } break; case 8: r_write_ble64 (buf, off, be); if (!r_io_write (core->io, buf, 8)) { cmd_write_fail (); } else { WSEEK (core, 8); } break; } r_core_block_read (core); }
/* 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 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 int r_io_read_at(RIO *io, ut64 addr, ut8 *buf, int len) { int ret, l, olen = len; int w = 0; #if 0 // HACK?: if io->va == 0 -> call seek+read without checking sections ? if (!io->va) { // r_io_seek (io, addr, R_IO_SEEK_SET); r_io_map_select (io, addr); ret = r_io_read_internal (io, buf, len); if (io->cached) { r_io_cache_read (io, addr, buf, len); } return ret; } #endif // XXX: this is buggy! while (len>0) { int ms; ut64 last = r_io_section_next (io, addr); l = (len > (last-addr))? (last-addr): len; if (l<1) l = len; // ignore seek errors // eprintf ("0x%llx %llx\n", addr+w, //r_io_seek (io, addr+w, R_IO_SEEK_SET); if (r_io_seek (io, addr+w, R_IO_SEEK_SET)==UT64_MAX) { memset (buf+w, 0xff, l); return -1; } ms = r_io_map_select (io, addr+w); ret = r_io_read_internal (io, buf+w, l); if (ret<1) { memset (buf+w, 0xff, l); // reading out of file ret = 1; } else if (ret<l) { // eprintf ("FOUND EOF AT %llx\n", addr+ret); l = ret; } if (io->cached) { r_io_cache_read (io, addr+w, buf+w, l); /* * XXX: The 'else' below is fixing the io.cache * with resized files. That may be wrong */ } else // hide non-mapped files here // do not allow reading on real addresses if mapped != 0 if (!io->debug && ms>0) { //eprintf ("FAIL MS=%d l=%d d=%d\n", ms, l, d); /* check if address is vaddred in sections */ ut64 o = r_io_section_offset_to_vaddr (io, addr); if (o == UT64_MAX) { ut64 o = r_io_section_vaddr_to_offset (io, addr); if (o == UT64_MAX) memset (buf+w, 0xff, l); } break; } w += l; len -= l; } return olen; }