mirror of
https://github.com/radareorg/radare2.git
synced 2024-12-13 16:18:33 +00:00
dd301cd6a7
- Handle ^C in searches - Safer progerssbar for small terminals - Add 'ws' command to write pascal/dalvik/java strings - Fix visual refresh on terminal resize - Partially fix dex negative section issue
463 lines
13 KiB
C
463 lines
13 KiB
C
/* radare - LGPL - Copyright 2009-2013 - pancake */
|
|
|
|
/* 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;
|
|
case 's':
|
|
{
|
|
ut8 ulen;
|
|
len = r_str_escape (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_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"
|
|
" 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"
|
|
" 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;
|
|
}
|
|
free (ostr);
|
|
return 0;
|
|
}
|
|
|