/* radare - LGPL - Copyright 2009-2024 - pancake */ #if R_INCLUDE_BEGIN static RCoreHelpMessage help_msg_w = { "Usage:", "w[x] [str] [", "extend the underlying file inserting NUM null bytes at current offset", "weN", " ", "extend current file and insert bytes at address", "wes", " ", "shift a blocksize left or write in the editor", "wex", " ", "insert bytes at current offset by extending the file", "weX", " ", "insert bytes at address by extending the file", NULL }; static RCoreHelpMessage help_msg_wo = { "Usage:", "wo[asmdxoArl24]", " [hexpairs] @ addr[!bsize] write operation in current block", "wo2", "", "2= 2 byte endian swap (word)", "wo4", "", "4= 4 byte endian swap (dword)", "wo8", "", "8= 8 byte endian swap (qword)", "woa", " [hexpair]", "+= addition (f.ex: woa 0102)", "woA", " [hexpair]", "&= and", "wod", " [hexpair]", "/= divide", "woD", " [algo] [key] [IV]", "decrypt current block with given algo and key", "woE", " [algo] [key] [IV]", "encrypt current block with given algo and key", "woe", " [from] ([to] [step] [wsz=1])", "write enumeration sequence i0 01 02 ..", "woi", "", "inverse bytes in current block", "wol", " [val]", "<<= shift left", "wom", " [val]", "*= multiply", "woo", " [val]", "|= or", "wop[DO]", " [arg]", "De Bruijn Patterns", "wor", " [val]", ">>= shift right", "woR", "", "random bytes (alias for 'wr $b')", "wos", " [val]", "-= substraction", "woS", " [algo] [key]", "sign the current block with given algo and key", "wow", " [val]", "== write looped value (alias for 'wb')", "wox", " [val]", "^= xor (f.ex: wox 0x90)", NULL }; static RCoreHelpMessage help_msg_wop = { "Usage:", "wop[DO]", " len @ addr | value", "wopD", " len [@ addr]", "write a De Bruijn Pattern of length 'len' at address 'addr'", "wopD*", " len [@ addr]", "show wx command that creates a debruijn pattern of a specific length", "wopO", " value", "finds the given value into a De Bruijn Pattern at current offset", NULL }; // TODO static RCoreHelpMessage help_msg_wp = { "Usage:", "wp", "[-|r2patch-file]", "^#", "", "comments", ".", "", "execute command", "!", "", "execute command", "", "", "OFFSET { code block }", "", "", "OFFSET \"string\"", "", "", "OFFSET 01020304", "", "", "OFFSET : assembly", "", "", "+ {code}|\"str\"|0210|: asm", NULL }; static RCoreHelpMessage help_msg_wt = { "Usage:", "wt[afs] [filename] [size]", " Write current block or [size] bytes from offset to file", "wta", " [filename]", "append to 'filename'", "wtf", " [filename] [size]", "write to file (see also 'wxf' and 'wf?')", "wtf!", " [filename]", "write to file from current address to eof (ignores given size)", "wtff", " [prefix] [size]", "write block from current seek to \"-\"", "wts", " host:port [size]", "send data to remote socket at tcp://host:port", "NOTE:", "", "filename defaults to \".\"", NULL }; static RCoreHelpMessage help_msg_wf = { "Usage:", "wf[fs] [-|args ..]", " Write from (file, swap, offset)", "wf", " 10 20", "write 20 bytes from offset 10 into current seek", "wff", " file [len]", "write contents of file into current offset", "wfs", " host:port [len]", "write from socket (tcp listen in port for N bytes)", "wfx", " 10 20", "exchange 20 bytes betweet current offset and 10", NULL }; static RCoreHelpMessage help_msg_wv = { "Usage:", "wv[size] [value]", " Write value of given size", "wv", " 0x834002", "write dword with this value", "wv1", " 234", "write one byte with this value", "wv2", " 234", "write unsigned short (2 bytes) with this number", "wv4", " 1 2 3", "write N space-separated dword (4 bytes)", "wv8", " 234", "write qword (8 bytes) with this number", "wvp", " 934", "write 4 or 8 byte pointer, depending on asm.bits", "wvf", " 3.14", "write float value (4 bytes)", "wvF", " 3.14", "write double value (8 bytes)", "wvG", " 3.14", "write long double value (10/16 bytes)", "Supported sizes are:", "1, 2, 4, 8", "", NULL }; static RCoreHelpMessage help_msg_wx = { "Usage:", "wx[f] [arg]", "", "wx", " 3.", "write the left nibble of the current byte", "wx", " .5", "write the right nibble of the current byte", "wx+", " 9090", "write hexpairs and seek forward", "wxf", " -|file", "write contents of hexpairs file here", NULL }; static void cmd_write_fail(RCore *core) { R_LOG_ERROR ("Cannot write. Use `omf`, `io.cache` or reopen the file in rw with `oo+`"); r_core_return_value (core, R_CMD_RC_FAILURE); } R_API int cmd_write_hexpair(RCore* core, const char* pairs) { R_RETURN_VAL_IF_FAIL (core && pairs, 0); ut8 *buf = malloc (strlen (pairs) + 1); if (!buf) { return 0; } int len = r_hex_str2bin (pairs, buf); if (len != 0) { if (len < 0) { len = -len; if (len < core->blocksize) { buf[len - 1] |= core->block[len - 1] & 0xf; } } r_core_return_value (core, R_CMD_RC_SUCCESS); if (!r_core_write_at (core, core->offset, buf, len)) { cmd_write_fail (core); r_core_return_value (core, R_CMD_RC_FAILURE); } // call WSEEK for consistency? if (r_config_get_b (core->config, "cfg.wseek")) { r_core_seek_delta (core, len); } r_core_block_read (core); } else { R_LOG_ERROR ("invalid hexpair string"); r_core_return_value (core, R_CMD_RC_FAILURE); } free (buf); return len; } static void write_encrypted_block(RCore *core, const char *algo, const char *key, int direction, const char *iv) { int keylen = 0; ut8 *binkey = NULL; if (!strncmp (key, "s:", 2)) { binkey = (ut8*)strdup (key + 2); keylen = strlen (key + 2); } else { binkey = (ut8 *)strdup (key); keylen = r_hex_str2bin (key, binkey); } if (!binkey) { return; } if (keylen < 1) { const char *mode = (direction == R_CRYPTO_DIR_ENCRYPT)? "Encryption": "Decryption"; R_LOG_ERROR ("%s key not defined. Use -S [key]", mode); free (binkey); return; } RCryptoJob *cj = r_crypto_use (core->crypto, algo); if (cj && cj->h->type == R_CRYPTO_TYPE_ENCRYPT) { if (r_crypto_job_set_key (cj, binkey, keylen, 0, direction)) { if (iv) { ut8 *biniv = malloc (strlen (iv) + 1); int ivlen = r_hex_str2bin (iv, biniv); if (ivlen < 1) { ivlen = strlen(iv); strcpy ((char *)biniv, iv); } if (!r_crypto_job_set_iv (cj, biniv, ivlen)) { R_LOG_ERROR ("Invalid IV"); return; } } r_crypto_job_update (cj, (const ut8*)core->block, core->blocksize); int result_size = 0; ut8 *result = r_crypto_job_get_output (cj, &result_size); if (result) { if (!r_core_write_at (core, core->offset, result, result_size)) { R_LOG_ERROR ("write failed at 0x%08"PFMT64x, core->offset); } R_LOG_INFO ("Written %d byte(s)", result_size); free (result); } } free (cj); } else { R_LOG_ERROR ("Unknown %s algorithm '%s'", ((direction == R_CRYPTO_DIR_ENCRYPT)? "encryption": "decryption"), algo); } free (binkey); return; } static void write_block_signature(RCore *core, const char *algo, const char *key) { int keylen = 0; ut8 *binkey = NULL; if (!strncmp (key, "s:", 2)) { binkey = (ut8 *)strdup (key + 2); keylen = strlen (key + 2); } else { binkey = (ut8 *)strdup (key); keylen = r_hex_str2bin (key, binkey); } if (!binkey) { return; } if (keylen < 1) { R_LOG_ERROR ("Private key not defined"); free (binkey); return; } RCryptoJob *cj = r_crypto_use (core->crypto, algo); if (cj && cj->h->type == R_CRYPTO_TYPE_SIGNATURE) { if (r_crypto_job_set_key (cj, binkey, keylen, 0, R_CRYPTO_DIR_ENCRYPT)) { r_crypto_job_update (cj, (const ut8 *)core->block, core->blocksize); int result_size = 0; ut8 *result = r_crypto_job_get_output (cj, &result_size); if (result) { if (!r_core_write_at (core, core->offset, result, result_size)) { R_LOG_ERROR ("write failed at 0x%08" PFMT64x, core->offset); } R_LOG_INFO ("Written %d byte(s)", result_size); free (result); } } free (binkey); return; } else { R_LOG_ERROR ("Unknown signature algorithm '%s'", algo); } return; } 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 (core); } } static void cmd_write_inc(RCore *core, int size, st64 num) { ut64 *v64; ut32 *v32; ut16 *v16; ut8 *v8; switch (size) { case 1: v8 = (ut8*)core->block; *v8 += num; break; case 2: v16 = (ut16*)core->block; *v16 += num; break; case 4: v32 = (ut32*)core->block; *v32 += num; break; case 8: v64 = (ut64*)core->block; *v64 += num; break; } // TODO: obey endian here if (!r_core_write_at (core, core->offset, core->block, size)) { cmd_write_fail (core); } } static int cmd_wo(void *data, const char *input) { RCore *core = (RCore *)data; ut8 *buf; int len; int value; switch (input[0]) { case 'e': // "woe" if (input[1]!=' ') { r_core_cmd_help_match (core, help_msg_wo, "woe"); return -1; } /* fallthrough */ case 'a': // "woa" case 's': // "wos" case 'A': // "woA" case 'x': // "wox" case 'r': // "wor" case 'l': // "wol" case 'm': // "wom" case 'i': // "woi" case 'd': // "wod" case 'o': // "woo" case 'w': // "wow" case '2': // "wo2" case '4': // "wo4" case '8': // "wo8" if (input[1] == '?') { // parse val from arg r_core_cmd_help_match_spec (core, help_msg_wo, "wo", input[0]); } else if (input[1]) { // parse val from arg r_core_write_op (core, r_str_trim_head_ro (input + 1), input[0]); } else { // use clipboard instead of val r_core_write_op (core, NULL, input[0]); } r_core_block_read (core); break; case 'R': r_core_cmd_call (core, "wr $b"); break; case 'n': r_core_write_op (core, "ff", 'x'); r_core_block_read (core); break; case 'E': // "woE" encrypt case 'D': // "woD" decrypt { int direction = (input[0] == 'E') ? R_CRYPTO_DIR_ENCRYPT : R_CRYPTO_DIR_DECRYPT; const char *algo = NULL; const char *key = NULL; const char *iv = NULL; char *space, *args = strdup (r_str_trim_head_ro (input+1)); space = strchr (args, ' '); if (space) { *space++ = 0; key = space; space = strchr (key, ' '); if (space) { *space++ = 0; iv = space; } } algo = args; if (R_STR_ISNOTEMPTY (algo) && key) { write_encrypted_block (core, algo, key, direction, iv); } else { r_crypto_list (core->crypto, r_cons_printf, 0 | (int)R_CRYPTO_TYPE_ENCRYPT << 8); r_core_cmd_help_match_spec (core, help_msg_wo, "wo", input[0]); } free (args); } break; case 'S': // "woS" sign { const char *algo = NULL; const char *key = NULL; char *space, *args = strdup (r_str_trim_head_ro (input + 1)); space = strchr (args, ' '); if (space) { *space++ = 0; key = space; space = strchr (key, ' '); } algo = args; if (R_STR_ISNOTEMPTY (algo) && key) { write_block_signature (core, algo, key); } else { r_crypto_list (core->crypto, r_cons_printf, 0 | (int)R_CRYPTO_TYPE_SIGNATURE << 8); r_core_cmd_help_match_spec (core, help_msg_wo, "wo", input[0]); } free (args); } break; case 'p': // debruijn patterns switch (input[1]) { case 'D': // "wopD" { char *sp = strchr (input, ' '); len = sp? r_num_math (core->num, sp + 1): core->blocksize; } if (len > 0) { /* XXX This seems to fail at generating long patterns (wopD 512K) */ buf = (ut8*)r_debruijn_pattern (len, 0, NULL); //debruijn_charset); if (buf) { const ut8 *ptr = buf; ut64 addr = core->offset; if (input[2] == '*') { int i; r_cons_printf ("wx "); for (i = 0; i < len; i++) { r_cons_printf ("%02x", buf[i]); } r_cons_newline (); } else { if (!r_core_write_at (core, addr, ptr, len)) { cmd_write_fail (core); } } free (buf); } else { R_LOG_ERROR ("Couldn't generate pattern of length %d", len); } } break; case 'O': // "wopO" if (strlen (input) > 3 && strncmp (input + 3, "0x", 2)) { R_LOG_ERROR ("Need hex value with `0x' prefix e.g. 0x41414142"); } else if (input[2] == ' ') { value = r_num_get (core->num, input + 3); int offset = r_debruijn_offset (value, r_config_get_i (core->config, "cfg.bigendian")); r_core_return_value (core, offset); r_cons_printf ("%"PFMT64d"\n", core->num->value); } break; case '\0': case '?': default: r_core_cmd_help (core, help_msg_wop); break; } break; case '\0': case '?': default: r_core_cmd_help (core, help_msg_wo); break; } return 0; } #define WSEEK(x,y) if (r_config_get_b (core->config, "cfg.wseek")) { r_core_seek_delta ((x),(y)); } static void cmd_write_value_float(RCore *core, const char *input) { float v = 0.0; sscanf (input, "%f", &v); r_io_write_at (core->io, core->offset, (const ut8*)&v, sizeof (float)); } static void cmd_write_value_long_double(RCore *core, const char *input) { long double v = 0.0; sscanf (input, "%Lf", &v); r_io_write_at (core->io, core->offset, (const ut8*)&v, sizeof (long double)); } static void cmd_write_value_double(RCore *core, const char *input) { double v = 0.0; sscanf (input, "%lf", &v); r_io_write_at (core->io, core->offset, (const ut8*)&v, sizeof (double)); } static void cmd_write_value(RCore *core, const char *input) { int type = 0; ut64 off = 0LL; ut8 buf[sizeof (ut64)]; bool be = r_config_get_b (core->config, "cfg.bigendian"); r_core_return_value (core, R_CMD_RC_SUCCESS); char op = input[0]; if (op == 'p') { op = (r_config_get_i (core->config, "asm.bits") == 64)? '8': '4'; } switch (op) { case '?': // "wv?" r_core_cmd_help (core, help_msg_wv); return; case 'f': // "wvf" cmd_write_value_float (core, r_str_trim_head_ro (input + 1)); return; case 'F': // "wvF" cmd_write_value_double (core, r_str_trim_head_ro (input + 1)); return; case 'G': // "wvG" cmd_write_value_long_double (core, r_str_trim_head_ro (input + 1)); return; case '1': type = 1; break; case '2': type = 2; break; case '4': type = 4; break; case '8': type = 8; break; } ut64 addr = core->offset; char *inp = r_str_trim_dup (input[0] ? input + 1: input); RList *list = r_str_split_list (inp, " ", 0); // or maybe comma :? char *cinp; RListIter *iter; r_list_foreach (list, iter, cinp) { if (input[0] && input[1]) { off = r_num_math (core->num, cinp); } if (core->io->desc) { r_io_use_fd (core->io, core->io->desc->fd); } ut64 res = r_io_seek (core->io, addr, 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 (core); } 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 (core); } 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 (core); } else { WSEEK (core, 4); } break; case 8: r_write_ble64 (buf, off, be); if (!r_io_write (core->io, buf, 8)) { cmd_write_fail (core); } else { WSEEK (core, 8); } break; } addr += type; } r_list_free (list); free (inp); r_core_block_read (core); } static bool cmd_wff(RCore *core, const char *input) { ut8 *buf = NULL; size_t size = 0; const char *arg = input + ((input[0] == ' ') ? 1 : 0); char *p, *a = r_str_trim_dup (arg); p = strchr (a, ' '); if (p) { *p++ = 0; } if (*arg == '?' || !*arg) { r_core_cmd_help_contains (core, help_msg_w, "wf"); } else if (!strcmp (arg, "-")) { char *out = r_core_editor (core, NULL, NULL); if (out) { if (!r_io_write_at (core->io, core->offset, (ut8*)out, strlen (out))) { R_LOG_ERROR ("write fail at 0x%08"PFMT64x, core->offset); } r_core_block_read (core); free (out); } } if (*a == '$' && !a[1]) { R_LOG_ERROR ("No alias name given"); } else if (*a == '$') { RCmdAliasVal *v = r_cmd_alias_get (core->rcmd, a+1); if (v) { buf = malloc (v->sz); if (buf) { size = v->sz; memcpy (buf, v->data, size); } else { size = 0; } } else { R_LOG_ERROR ("No such alias \"$%s\"", a + 1); } } else { buf = (ut8*) r_file_slurp (a, &size); } if (size < 1) { // nothing to write } else if (buf) { int u_offset = 0; ut64 u_size = r_num_math (core->num, p); if (u_size < 1) u_size = (ut64)size; if (p) { *p++ = 0; u_offset = r_num_math (core->num, p); if (u_offset > size) { R_LOG_ERROR ("Invalid offset"); free (a); free (buf); return false; } } r_io_use_fd (core->io, core->io->desc->fd); if (!r_io_write_at (core->io, core->offset, buf + u_offset, (int)u_size)) { R_LOG_ERROR ("write fail at 0x%08"PFMT64x, core->offset); } WSEEK (core, size); r_core_block_read (core); } else { R_LOG_ERROR ("Cannot open file '%s'", arg); } free (a); 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 { R_LOG_ERROR ("write failed at 0x%08"PFMT64x, dst); } } else { R_LOG_ERROR ("write failed at 0x%08"PFMT64x, src); } free (buf); } } return ret; } static bool cmd_wfx(RCore *core, const char *input) { char * args = r_str_trim_dup (input); char *arg = strchr (args, ' '); int len = core->blocksize; if (arg) { *arg = 0; len = r_num_math (core->num, arg + 1); } ut64 dst = core->offset; ut64 src = r_num_math (core->num, args); if (len > 0) { // cache dest, memcpy, write cache ut8 *buf = calloc (1, len); if (buf) { if (r_io_read_at (core->io, dst, buf, len)) { ioMemcpy (core, core->offset, src, len); if (r_io_write_at (core->io, src, buf, len)) { r_core_block_read (core); } else { R_LOG_ERROR ("Failed to write at 0x%08"PFMT64x, src); } } else { R_LOG_ERROR ("cmd_wfx: failed to read at 0x%08"PFMT64x, dst); } free (buf); } } free (args); return true; } static bool cmd_wfs(RCore *core, const char *input) { char *str = strdup (input); if (str[0] != ' ') { r_core_cmd_help_contains (core, help_msg_wf, "wfs"); free (str); return false; } ut64 addr = 0; char *host = str + 1; char *port = strchr (host, ':'); if (!port) { r_core_cmd_help_match (core, help_msg_wf, "wfs"); free (str); return false; } ut64 sz = core->blocksize; *port ++= 0; char *space = strchr (port, ' '); if (space) { *space++ = 0; sz = r_num_math (core->num, space); addr = core->offset; } ut8 *buf = calloc (1, sz); if (!buf) { free (str); return false; } r_io_read_at (core->io, addr, buf, sz); RSocket *s = r_socket_new (false); if (!r_socket_listen (s, port, NULL)) { R_LOG_ERROR ("Cannot listen on port %s", port); r_socket_free (s); free (str); free (buf); return false; } int done = 0; RSocket *c = r_socket_accept (s); if (c) { R_LOG_INFO ("Receiving data from client"); while (done < sz) { int rc = r_socket_read (c, buf + done, sz - done); if (rc < 1) { R_LOG_ERROR ("socket read oops"); break; } done += rc; } r_socket_free (c); if (r_io_write_at (core->io, core->offset, buf, done)) { R_LOG_INFO ("Written %d bytes", done); } else { cmd_write_fail (core); } } r_socket_free (s); free (buf); free (str); return true; } static int cmd_wf(void *data, const char *input) { RCore *core = (RCore *)data; if (!core || !*input) { return -1; } if (input[0] == '?') { r_core_cmd_help (core, help_msg_wf); return -1; } if (input[0] == 's') { // "wfs" return cmd_wfs (core, input + 1); } if (input[0] == 'x') { // "wfx" return cmd_wfx (core, input + 1); } if (input[0] == 'f') { // "wff" return cmd_wff (core, input + 1); } char *args = r_str_trim_dup (input); char *arg = strchr (args, ' '); int len = core->blocksize; if (arg) { *arg++ = 0; len = r_num_math (core->num, arg); } ut64 addr = r_num_math (core->num, args); ioMemcpy (core, core->offset, addr, len); free (args); r_core_block_read (core); return 0; } static void squash_write_cache(RCore *core, const char *input) { R_LOG_TODO ("Squash is not implemented for the for the new io-cache"); #if 0 void **iter; RPVector *v = &core->io->cache; ut64 end = UT64_MAX; RIOCache *oc = NULL; RPVector *nv = r_pvector_new (NULL); int pos = 0; int squashed = 0; r_pvector_foreach (v, iter) { RIOCache *c = *iter; const ut64 a = r_itv_begin (c->itv); const ut64 s = r_itv_size (c->itv); if (oc && end == a) { squashed ++; oc->itv.size += s; } else { r_pvector_insert (nv, pos, c); oc = c; pos++; } end = a + s; } R_LOG_INFO ("Squashed %d write caches", squashed); // r_pvector_clear (&core->io->cache); memcpy (&(core->io->cache), nv, sizeof (RIOCache)); #endif } static void cmd_write_pcache(RCore *core, const char *input) { RIODesc *desc; RList *caches; int fd; bool rad = false; if (core && core->io && core->io->p_cache && core->print && core->print->cb_printf) { switch (input[0]) { case 'i' : if (input[1]) { fd = (int)r_num_math (core->num, input + 1); desc = r_io_desc_get (core->io, fd); } else { desc = core->io->desc; } r_io_desc_cache_commit (desc); break; case '*': rad = true; case ' ': //fall-o-through case '\0': if (input[0] && input[1]) { fd = (int)r_num_math (core->num, input + 1); desc = r_io_desc_get (core->io, fd); } else { desc = core->io->desc; } if ((caches = r_io_desc_cache_list (desc))) { R_LOG_TODO ("pcache listing not working for the new io-cache (%d)", rad); #if 0 int i; RIOCache *c; RListIter *iter; if (rad) { core->print->cb_printf ("e io.va = false\n"); r_list_foreach (caches, iter, c) { core->print->cb_printf ("wx %02x", c->data[0]); const int cacheSize = r_itv_size (c->itv); for (i = 1; i < cacheSize; i++) { core->print->cb_printf ("%02x", c->data[i]); } core->print->cb_printf (" @ 0x%08"PFMT64x" \n", r_itv_begin (c->itv)); } } else { r_list_foreach (caches, iter, c) { core->print->cb_printf ("0x%08"PFMT64x": %02x", r_itv_begin (c->itv), c->odata[0]); const int cacheSize = r_itv_size (c->itv); for (i = 1; i < cacheSize; i++) { core->print->cb_printf ("%02x", c->odata[i]); } core->print->cb_printf (" -> %02x", c->data[0]); for (i = 1; i < cacheSize; i++) { core->print->cb_printf ("%02x", c->data[i]); } core->print->cb_printf ("\n"); } } #endif r_list_free (caches); } break; default: break; } } } static int cmd_wB(void *data, const char *input) { RCore *core = (RCore *)data; switch (input[0]) { case ' ': cmd_write_bits (core, 1, r_num_math (core->num, input + 1)); break; case '-': cmd_write_bits (core, 0, r_num_math (core->num, input + 1)); break; default: r_core_cmd_help_match (core, help_msg_w, "wB"); break; } return 0; } static int cmd_w0(void *data, const char *input) { int res = 0; RCore *core = (RCore *)data; ut64 len = r_num_math (core->num, input); if ((st64)len > 0 && len < ALLOC_SIZE_LIMIT) { ut8 *buf = calloc (1, len); if (buf) { if (!r_io_write_at (core->io, core->offset, buf, len)) { R_LOG_ERROR ("write failed at 0x%08" PFMT64x, core->offset); res = -1; } r_core_block_read (core); free (buf); } else { res = -1; } } else { R_LOG_ERROR ("invalid length"); } return res; } static int w_incdec_handler(void *data, const char *input, int inc) { RCore *core = (RCore *)data; st64 num = 1; if (input[0] && input[1]) { num = r_num_math (core->num, input + 1); } switch (input[0]) { case '+': cmd_write_inc (core, inc, num); break; case '-': cmd_write_inc (core, inc, -num); break; default: r_core_cmd_help_match (core, help_msg_w, "w"); break; } return 0; } static int cmd_w6(void *data, const char *input) { RCore *core = (RCore *)data; bool fail = false; ut8 *buf = NULL; int len = 0, str_len; if (input[0] && input[1] != ' ') { if (input[0] != 'e' && input[0] != 'd') { fail = true; } } const char *str = (input[0] && input[1] && input[2])? input + 2: ""; str_len = strlen (str) + 1; if (!fail) { switch (input[0]) { case 'd': // "w6d" buf = malloc (str_len); if (buf) { len = r_base64_decode (buf, str, -1); if (len < 0) { R_LOG_WARN ("Invalid hexpair string"); R_FREE (buf); fail = true; } } break; case 'x': { // "w6x" ut8 *bin_buf = malloc (str_len); if (!bin_buf) { break; } const int bin_len = r_hex_str2bin (str, bin_buf); if (bin_len <= 0) { fail = true; } else { buf = calloc (str_len + 1, 4); len = r_base64_encode ((char *)buf, bin_buf, bin_len); if (len == 0) { R_FREE (buf); fail = true; } } free (bin_buf); } break; case 'e': { // "w6e" ut8 *bin_buf = malloc (str_len); if (!bin_buf) { break; } char *s = r_str_trim_dup (input + 1); int slen = strlen (s); free (buf); buf = malloc ((4+slen) * 4); len = r_base64_encode ((char *)buf, (const ut8*)s, slen); if (len == 0) { R_FREE (buf); fail = true; } free (bin_buf); free (s); break; } default: fail = 1; break; } } if (!fail) { if (!r_core_write_at (core, core->offset, buf, len)) { cmd_write_fail (core); } WSEEK (core, len); r_core_block_read (core); free (buf); } else { r_core_cmd_help_match (core, help_msg_w, "w6"); } return 0; } static int cmd_wh(void *data, const char *input) { R_RETURN_VAL_IF_FAIL (data && input, -1); char *space = strchr (input, ' '); const char *arg = space? r_str_trim_head_ro (space): NULL; if (arg) { char *path = r_file_path (arg); if (path) { r_cons_println (path); free (path); return 0; } } return 1; } static int cmd_we(void *data, const char *input) { RCore *core = (RCore *)data; ut64 addr = 0, len = 0, b_size = 0; st64 dist = 0; ut8* bytes = NULL; int cmd_suc = false; char *input_shadow = NULL, *p = NULL; char *save_ptr = NULL; switch (input[0]) { case 'n': // "wen" if (input[1] == ' ') { len = *input ? r_num_math (core->num, input + 2) : 0; if (len > 0) { const ut64 cur_off = core->offset; cmd_suc = r_core_extend_at (core, core->offset, len); if (cmd_suc) { core->offset = cur_off; r_core_block_read (core); } else { R_LOG_ERROR ("r_io_extend failed"); cmd_suc = true; } } } else { r_core_cmd_help_match (core, help_msg_we, "wen"); cmd_suc = true; } break; case 'N': // "weN" if (input[1] == ' ') { input = r_str_trim_head_ro (input + 2); addr = r_num_math (core->num, input); while (*input && *input != ' ') { input++; } if (*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); if (cmd_suc) { r_core_seek (core, cur_off, true); core->offset = addr; r_core_block_read (core); } else { R_LOG_ERROR ("r_io_extend failed"); } } cmd_suc = true; } break; case 'x': // "wex" if (input[1] == ' ') { input += 1; 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) { if (!r_core_write_at (core, cur_off, bytes, len)) { cmd_write_fail (core); } } core->offset = cur_off; r_core_block_read (core); } free (bytes); } break; case 's': // "wes" input += 2; while (*input && *input == ' ') { input++; } len = strlen (input); // since the distance can be negative, // the r_num_math will perform an unwanted operation // the solution is to tokenize the string :/ if (len > 0) { input_shadow = strdup (input); p = r_str_tok_r (input_shadow, " ", &save_ptr); addr = p && *p ? r_num_math (core->num, p) : 0; p = r_str_tok_r (NULL, " ", &save_ptr); dist = p && *p ? r_num_math (core->num, p) : 0; p = r_str_tok_r (NULL, " ", &save_ptr); 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, true); cmd_suc = true; } } free (input_shadow); break; case 'X': // "weX" if (input[1] == ' ') { input = r_str_trim_head_ro (input + 2); addr = r_num_math (core->num, input); while (*input && *input != ' ') { input++; } if (*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) { if (!r_core_write_at (core, addr, bytes, len)) { cmd_write_fail (core); } } else { R_LOG_ERROR ("r_io_extend failed"); } core->offset = addr; r_core_block_read (core); } free (bytes); } break; case '?': // "we?" default: cmd_suc = false; break; } if (cmd_suc == false) { r_core_cmd_help (core, help_msg_we); } return 0; } static int cmd_wp(void *data, const char *input) { RCore *core = (RCore *)data; if (input[0] == '-' || (input[0] == ' ' && input[1] == '-')) { char *out = r_core_editor (core, NULL, NULL); if (out) { r_core_patch (core, out); free (out); } } else { if (input[0] == ' ' && input[1]) { char *data = r_file_slurp (input + 1, NULL); if (data) { r_core_patch (core, data); free (data); } } else { r_core_cmd_help (core, help_msg_wp); } } return 0; } static int cmd_wu(RCore *core, const char *input) { // TODO: implement it in an API RCore.write_unified_hexpatch() is ETOOLONG if (input[0] == ' ') { char *data = r_file_slurp (input + 1, NULL); if (data) { int i; 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 == ' ') { offs = 0; line = 0; hexa = 0; } else if (sign) { if (offs && hexa) { r_cons_printf ("wx %s @ %s\n", data+hexa, data+offs); } else { R_LOG_ERROR ("Oops"); } offs = 0; line = 0; } else { hexa = 0; } sign = -1; continue; } newline = 0; } free (data); } } else { r_core_cmd_help_match (core, help_msg_we, "wu"); } return 0; } static int cmd_wr(void *data, const char *input) { RCore *core = (RCore *)data; ut64 off = r_num_math (core->num, input); int len = (int)off; if (len > 0) { ut8 *buf = malloc (len); if (buf) { int i; r_num_irand (); for (i = 0; i < len; i++) buf[i] = r_num_rand (256); if (!r_core_write_at (core, core->offset, buf, len)) { cmd_write_fail (core); } WSEEK (core, len); free (buf); } else { R_LOG_ERROR ("Cannot allocate %d byte(s)", len); } } return 0; } #if 0 static RCoreHelpMessage help_msg_wA = { "Usage:", " wA", "[type] [value]", "Types", "", "", "r", "", "raw write value", "v", "", "set value (taking care of current address)", "d", "", "destination register", "0", "", "1st src register", "1", "", "2nd src register", "Example:", "wA r 0", "# e800000000", NULL }; // RAsm.modify() was unused therefor this is kind of attempt to move the asmhacks into the arch plugins static int cmd_wA(void *data, const char *input) { RCore *core = (RCore *)data; int len; switch (input[0]) { case ' ': if (input[1] && input[2] == ' ') { r_asm_set_pc (core->rasm, core->offset); eprintf ("modify (%c)=%s\n", input[1], input + 3); len = r_asm_modify (core->rasm, core->block, input[1], r_num_math (core->num, input + 3)); eprintf ("len=%d\n", len); if (len > 0) { if (!r_core_write_at (core, core->offset, core->block, len)) { cmd_write_fail (core); } WSEEK (core, len); } else { eprintf ("r_asm_modify = %d\n", len); } } else { r_core_cmd_help_match (core, help_msg_w, "wA"); } break; case '?': default: r_core_cmd_help (core, help_msg_wA); break; } return 0; } #endif static char *__current_filename(RCore *core) { RIOMap *map = r_io_map_get_at (core->io, core->offset); if (map) { RIODesc *desc = r_io_desc_get (core->io, map->fd); if (desc) { return strdup (desc->uri); } } return NULL; } static ut64 __va2pa(RCore *core, ut64 va) { RIOMap *map = r_io_map_get_at (core->io, va); if (map) { return va - map->itv.addr + map->delta; } return va; } static void cmd_wcf(RCore *core, const char *dfn) { char *sfn = __current_filename (core); if (!sfn) { R_LOG_ERROR ("Cannot determine source file"); return; } // XXX. apply all layers? RIOCacheLayer *layer = r_list_last (core->io->cache.layers); if (!layer) { R_LOG_ERROR ("Cache is empty"); return; } size_t sfs; ut8 *sfb = (ut8*)r_file_slurp (sfn, &sfs); if (sfb) { void **iter; r_pvector_foreach (layer->vec, iter) { RIOCacheItem *c = *iter; const ut64 ps = r_itv_size (c->itv); const ut64 va = r_itv_begin (c->itv); const ut64 pa = __va2pa (core, va); if (pa + ps < sfs) { memcpy (sfb + pa, c->data, ps); } else { R_LOG_ERROR ("Out of bounds patch at 0x%08"PFMT64x, pa); } } // patch buffer r_file_dump (dfn, sfb, sfs, false); free (sfb); } free (sfn); } static int cmd_wc(void *data, const char *input) { RCore *core = (RCore *)data; switch (input[0]) { case '\0': // "wc" r_io_cache_list (core->io, 0, false); break; case 'd': { RIOCacheLayer *layer; RListIter *liter; r_list_foreach (core->io->cache.layers, liter, layer) { void **iter; // list (io, layer, pj, rad); r_pvector_foreach (layer->vec, iter) { RIOCacheItem *ci = *iter; r_cons_printf ("0x%08"PFMT64x":\n", ci->itv.addr); char *a = r_hex_bin2strdup (ci->data, ci->itv.size); char *b = r_hex_bin2strdup (ci->odata, ci->itv.size); char *a0 = r_core_cmd_strf (core, "pad %s", b); char *b0 = r_core_cmd_strf (core, "pad %s", a); char *a1 = r_str_prefix_all (a0, "- "); char *b1 = r_str_prefix_all (b0, "+ "); r_str_trim (a1); r_str_trim (b1); if (r_config_get_i (core->config, "scr.color") > 0) { r_cons_printf (Color_RED"%s\n"Color_GREEN"%s\n"Color_RESET, a1, b1); } else { r_cons_printf ("%s\n%s\n", a1, b1); } free (a); free (b); free (a0); free (b0); free (a1); free (b1); } } } break; case 'a': if (input[1] == 'j') { r_io_cache_list (core->io, 'j', true); } else { r_io_cache_list (core->io, 0, true); } break; case 'l': // "wcl" if (r_list_empty (core->io->cache.layers)) { R_LOG_INFO ("No layers"); } else { RIOCacheLayer *layer; RListIter *iter; int i = 0; int last = r_list_length (core->io->cache.layers) - 1; r_list_foreach (core->io->cache.layers, iter, layer) { int count = r_pvector_length (layer->vec); const char ch = (i == last)? '*': '-'; r_cons_printf ("%c %d cache layer with %d patches\n", ch, i, count); i++; } } break; case '?': // "wc?" r_core_cmd_help (core, help_msg_wc); break; case 'u': // "wcu" r_io_cache_undo (core->io); break; case 'U': // "wcU" r_io_cache_redo (core->io); break; case 'f': // "wcf" if (input[1] == ' ') { cmd_wcf (core, r_str_trim_head_ro (input + 1)); } else { r_core_cmd_help_match (core, help_msg_wc, "wcf"); } break; case '*': // "wc*" r_io_cache_list (core->io, 1, input[1] == '*'); break; case '+': // "wc+" if (input[1] == '+') { // "wc++" r_io_cache_push (core->io); } else if (input[1] == '?') { r_core_cmd_help_contains (core, help_msg_wc, "wc+"); } else if (input[1] == ' ') { // "wc+ " ut64 to; ut64 from = r_num_math (core->num, input + 2); char *p = strchr (input + 2, ' '); if (p) { *p = 0; to = r_num_math (core->num, input + 2); if (to < from) { R_LOG_ERROR ("Invalid range (from > to)"); return 0; } } else { to = from + core->blocksize; } r_io_cache_commit (core->io, from, to, false); } else { R_LOG_ERROR ("Invalidate write cache at 0x%08"PFMT64x, core->offset); r_io_cache_commit (core->io, core->offset, core->offset + 1, false); } break; case '-': // "wc-" if (input[1] == '-') { // "wc--" if (input[2] == '*') { while (r_io_cache_pop (core->io)) { // nothing here } } else { r_io_cache_pop (core->io); } } else if (input[1] == '?') { r_core_cmd_help_contains (core, help_msg_wc, "wc-"); } else { ut64 from, to; if (input[1] == ' ') { // "wc- " char *p = strchr (input + 2, ' '); if (p) { *p = 0; from = r_num_math (core->num, input+2); to = r_num_math (core->num, p+1); if (to < from) { R_LOG_ERROR ("Invalid range (from > to)"); return 0; } } else { from = r_num_math (core->num, input+2); to = from + core->blocksize; } } else { R_LOG_INFO ("Invalidate write cache at 0x%08"PFMT64x, core->offset); from = core->offset; to = core->offset + core->blocksize; } R_LOG_INFO ("Invalidated %d cache(s)", r_io_cache_invalidate (core->io, from, to, false)); r_core_block_read (core); } break; case 'i': // "wci" r_io_cache_commit (core->io, 0, UT64_MAX, false); r_core_block_read (core); break; case 'j': // "wcj" r_io_cache_list (core->io, 2, false); break; case 'p': // "wcp" cmd_write_pcache (core, &input[1]); break; case 'r': // "wcr" r_io_cache_reset (core->io); /* 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); break; case 's': // "wcs" -- write cache squash squash_write_cache (core, input + 1); break; } return 0; } static int cmd_w(RCore *core, const char *input) { char *str = strdup (input); /* write string */ int len = r_str_unescape (str); if (r_config_get_b (core->config, "cmd.undo")) { ut8 *buf = malloc (len); r_io_read_at (core->io, core->offset, buf, len); char *bufstr = r_hex_bin2strdup (buf, len); char *a = r_str_newf ("wx %s", bufstr); char *b = r_str_newf ("w %s", str); RCoreUndo *uc = r_core_undo_new (core->offset, b, a); r_core_undo_push (core, uc); free (a); free (b); free (bufstr); free (buf); } // handle charset logic here if (!r_core_write_at (core, core->offset, (const ut8 *)str, len)) { cmd_write_fail (core); } free (str); WSEEK (core, len); r_core_block_read (core); r_core_return_value (core, len); return 0; } static int cmd_wget(RCore *core, const char *input) { while (*input && *input != ' ') { input++; } input = r_str_trim_head_ro (input); if (!r_str_startswith (input, "http://")) { R_LOG_ERROR ("wget/wg command only accepts http:// urls"); return 0; } const char *fname = r_str_lchr (input, '/'); if (!fname || !*fname) { fname = "index.html"; } else { fname ++; } int len = 0; char *data = r_socket_http_get (input, NULL, &len); if (data) { if (!r_file_dump (fname, (const ut8*)data, len, 0)) { R_LOG_ERROR ("Cannot save file to disk"); r_core_return_value (core, 1); } else { r_core_return_value (core, 0); R_LOG_INFO ("Saved %d bytes in %s", len, fname); } free (data); } else { R_LOG_ERROR ("Cannot retrieve file"); r_core_return_value (core, 1); } return 0; } static int cmd_wz(RCore *core, const char *input) { char *str = strdup (input + 1); int len = r_str_unescape (str) + 1; /* write zero-terminated string */ if (*input == '?' || *input != ' ' || len < 1) { free (str); r_core_cmd_help_match (core, help_msg_w, "wz"); r_core_return_value (core, 0); return 0; } if (!r_core_write_at (core, core->offset, (const ut8 *)str, len)) { cmd_write_fail (core); } r_core_return_value (core, len); WSEEK (core, len + 1); r_core_block_read (core); free (str); return 0; } static int cmd_wt(RCore *core, const char *input) { R_BORROW const char *prefix = r_config_get (core->config, "cfg.prefixdump"); R_BORROW char *filename = NULL; char default_filename_sep = '.'; char fn_local[32] = {0}; // for using snprintf instead of str_newf; doesnt need free() int ret = 0; bool append = false; st64 sz = core->blocksize; ut64 poff = core->offset; // physical address; for writing arbitrary sizes int argc; char **argv; argv = r_str_argv (input, &argc); fn_local[0] = 0; filename = argv[1]; // NULL if argc < 2 input++; switch (*input) { case 's': { // "wts" ut64 addr = 0; char *host_port; R_BORROW char *host; R_BORROW char *port; ut8 *buf; RSocket *sock; if (argc < 2) { r_core_cmd_help_match (core, help_msg_wt, "wts"); ret = 1; goto leave; } sz = r_io_size (core->io); if (sz < 0) { R_LOG_ERROR ("Unknown file size"); ret = 1; goto leave; } host_port = strdup (argv[1]); host = host_port; port = strchr (host_port, ':'); if (!port) { r_core_cmd_help_match (core, help_msg_wt, "wts"); free (host_port); ret = 1; goto leave; } *port++ = 0; if (argc > 2) { sz = r_num_math (core->num, argv[2]); if (sz < 0) { R_LOG_ERROR ("%s is not a valid size", argv[2]); free (host_port); ret = 1; goto leave; } addr = core->offset; } buf = malloc (sz); r_io_read_at (core->io, addr, buf, sz); sock = r_socket_new (false); if (r_socket_connect (sock, host, port, R_SOCKET_PROTO_TCP, 0)) { ut64 sent = 0; R_LOG_INFO ("Connection created. Sending data to TCP socket"); while (sent < sz) { bool sockret = r_socket_write (sock, buf + sent, sz - sent); if (!sockret) { R_LOG_ERROR ("Socket write error"); ret = 1; break; } } } else { R_LOG_ERROR ("Connection to %s failed", host_port); ret = 1; } free (host_port); free (buf); r_socket_free (sock); goto leave; } case 'f': // "wtf" switch (input[1]) { case '\0': case '?': // "wtf?" r_core_cmd_help_match (core, help_msg_wt, "wtf"); ret = 1; goto leave; case '!': { // "wtf!" RIOMap *map; if (input[2] == '?') { r_core_cmd_help_match (core, help_msg_wt, "wtf!"); ret = 1; goto leave; } map = r_io_map_get_at (core->io, poff); if (map) { // convert vaddr to paddr poff = poff - r_io_map_begin (map) + map->delta; } sz = r_io_fd_size (core->io, core->io->desc->fd) - core->offset; // ignore given size if (argc > 2) { argc = 2; } break; } case 'f': // "wtff" if (input[2] == '?') { r_core_cmd_help_match (core, help_msg_wt, "wtff"); ret = 1; goto leave; } if (argc > 1) { prefix = argv[1]; } default_filename_sep = '-'; break; default: // "wtf" if (input[2] == '?') { r_core_cmd_help_match (core, help_msg_wt, "wtf"); ret = 1; goto leave; } if (r_str_startswith (filename, "base64:")) { const char *encoded = filename + 7; int len; if (strlen (encoded) > 31) { R_LOG_ERROR ("Base64 blob must be fewer than 32 characters"); ret = 1; goto leave; } len = r_base64_decode ((ut8 *)fn_local, encoded, -1); filename = fn_local; if (len < 0) { R_LOG_ERROR ("Couldn't decode b64 filename"); ret = 1; goto leave; } } break; } break; case 'a': append = true; break; case '\0': // "wt" case ' ': // "wt " break; case '?': // "wt?" default: r_core_cmd_help (core, help_msg_wt); goto leave; } // default filename is prefix.addr if (R_STR_ISEMPTY (filename)) { snprintf (fn_local, sizeof (fn_local), "%s%c0x%08" PFMT64x, prefix, default_filename_sep, poff); filename = fn_local; } // don't overwrite forced size if (sz == core->blocksize && argc > 2) { sz = (st64)r_num_math (core->num, argv[2]); } // Don't attempt to write 0 bytes if (sz < 1) { R_LOG_ERROR ("%s is not a valid size", argv[2]); goto leave; } if (*filename == '$') { ut8 *buf = core->block; bool free_buf = false; filename++; // manual buffer if given arbitrary size if (sz > core->blocksize) { buf = malloc (sz); if (!buf) { R_LOG_ERROR ("malloc() failure"); ret = 1; goto leave; } r_io_read_at (core->io, poff, buf, sz); free_buf = true; } if (append) { if (r_cmd_alias_append_raw (core->rcmd, filename, buf, sz)) { R_LOG_ERROR ("Will not append to command alias \"$%s\"", filename); ret = 1; } } else { r_cmd_alias_set_raw (core->rcmd, filename, buf, sz); } if (free_buf) { free (buf); } if (!ret) { R_LOG_INFO ("Dumped %" PFMT64d " bytes from 0x%08" PFMT64x" into $%s", sz, poff, filename); } goto leave; } // use core if reading past end of block if (sz <= core->blocksize) { ret = r_file_dump (filename, core->block, sz, append); } else { ret = r_core_dump (core, filename, poff, (ut64)sz, append); } // dump functions return bool; true on success if (ret) { R_LOG_INFO ("Dumped %" PFMT64d " bytes from 0x%08" PFMT64x" into %s", sz, poff, filename); ret = 0; } leave: r_str_argv_free (argv); return ret; } static int cmd_ww(void *data, const char *input) { RCore *core = (RCore *)data; char *ostr = strdup (input); char *str = ostr; int len = r_str_unescape (str); if (len < 1) { free (ostr); return 0; } len++; str++; len = (len - 1) << 1; char *tmp = (len > 0) ? malloc (len + 1) : NULL; if (tmp) { int i; for (i = 0; i < len; i++) { if (i % 2) { tmp[i] = 0; } else { tmp[i] = str[i >> 1]; } } str = tmp; if (core->io->desc) { r_io_use_fd (core->io, core->io->desc->fd); } if (!r_io_write_at (core->io, core->offset, (const ut8 *)str, len)) { R_LOG_ERROR ("write failed at 0x%08" PFMT64x, core->offset); } WSEEK (core, len); r_core_block_read (core); free (tmp); } else { R_LOG_ERROR ("Cannot malloc %d", len); } free (ostr); return 0; } static int cmd_wx(void *data, const char *input) { RCore *core = (RCore *)data; const char *arg; ut8 *buf; int size; switch (input[0]) { case ' ': // "wx " cmd_write_hexpair (core, r_str_trim_head_ro (input)); break; case 'f': // "wxf" 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) { if (!r_io_write_at (core->io, core->offset, out, len)) { R_LOG_ERROR ("r_io_write_at failed at 0x%08"PFMT64x, core->offset); } r_core_return_value (core, len); } else { r_core_return_value (core, 0); } free (out); } free (in); } } else if (r_file_exists (arg)) { if ((buf = r_file_slurp_hexpairs (arg, &size))) { r_io_use_fd (core->io, core->io->desc->fd); if (r_io_write_at (core->io, core->offset, buf, size) > 0) { r_core_return_value (core, size); WSEEK (core, size); } else { R_LOG_ERROR ("r_io_write_at failed at 0x%08"PFMT64x, core->offset); } free (buf); r_core_block_read (core); } else { R_LOG_ERROR ("This file doesnt contains hexpairs"); } } else { R_LOG_ERROR ("Cannot open file '%s'", arg); } break; case 's': // "wxs" R_LOG_WARN ("wxs has been renamed to wx+"); // fallthrough case '+': // "wx+" { int len = cmd_write_hexpair (core, input + 1); if (len > 0) { r_core_seek_delta (core, len); r_core_return_value (core, len); } else { r_core_return_value (core, 0); } } break; default: r_core_cmd_help (core, help_msg_wx); break; } return 0; } static int cmd_wa(void *data, const char *input) { RCore *core = (RCore *)data; switch (input[0]) { case 'o': // "wao" if (input[1] == ' ' || input[1] == '+') { r_core_hack (core, r_str_trim_head_ro (input + 1)); } else { r_core_cmd_help (core, help_msg_wao); } break; case ' ': case '+': case 'i': case 'n': case '*': { const char *file = r_str_trim_head_ro (input + 1); r_asm_set_pc (core->rasm, core->offset); RAsmCode *acode = r_asm_massemble (core->rasm, file); if (acode) { if (input[0] == 'n') { // "wan" int delta = 0; RAnalOp analop; ut64 at = core->offset; repeat: if (!r_anal_op (core->anal, &analop, at, core->block + delta, core->blocksize - delta, R_ARCH_OP_MASK_BASIC)) { R_LOG_DEBUG ("Invalid instruction?"); r_anal_op_fini (&analop); r_asm_code_free (acode); break; } if (delta < acode->len) { delta += analop.size; at += analop.size; r_anal_op_fini (&analop); r_core_cmdf (core, "wao nop @ 0x%08"PFMT64x, at); goto repeat; } r_anal_op_fini (&analop); r_core_cmd_call (core, "wao nop"); input++; } else if (input[0] == 'i') { // "wai" RAnalOp analop; if (!r_anal_op (core->anal, &analop, core->offset, core->block, core->blocksize, R_ARCH_OP_MASK_BASIC)) { R_LOG_DEBUG ("Invalid instruction?"); r_anal_op_fini (&analop); r_asm_code_free (acode); break; } if (analop.size < acode->len) { R_LOG_DEBUG ("Doesnt fit"); r_anal_op_fini (&analop); r_asm_code_free (acode); break; } r_anal_op_fini (&analop); r_core_cmd_call (core, "wao nop"); } if (acode->len > 0) { char* hex = r_asm_code_get_hex (acode); if (input[0] == '*') { r_cons_printf ("wx %s\n", hex); } else { if (!r_core_write_at (core, core->offset, acode->bytes, acode->len)) { cmd_write_fail (core); } else { if (r_config_get_b (core->config, "scr.prompt")) { // maybe check interactive? R_LOG_INFO ("Written %d byte(s) (%s) = wx %s @ 0x%08"PFMT64x, acode->len, input + 1, hex, core->offset); } WSEEK (core, acode->len); } r_core_block_read (core); } free (hex); } else { R_LOG_WARN ("Nothing to do"); } if (*input == '+') { r_core_seek (core, core->offset + acode->len, true); } r_asm_code_free (acode); } } break; case 'f': // "waf" if ((input[1] == ' ' || input[1] == '*')) { const char *file = input + ((input[1] == '*')? 3: 2); r_asm_set_pc (core->rasm, core->offset); char *src = r_file_slurp (file, NULL); if (src) { ut64 addr = core->offset, nextaddr = addr; char *a, *b = src; do { a = strstr (b, ".offset "); if (a) { *a = 0; a += strlen (".offset "); nextaddr = r_num_math (core->num, a); char *nl = strchr (a, '\n'); if (nl) { *nl = 0; a = nl + 1; } else { break; } } if (*b) { RAsmCode *ac = r_asm_massemble (core->rasm, b); if (ac) { r_io_write_at (core->io, addr, ac->bytes, ac->len); r_asm_code_free (ac); } } b = a; addr = nextaddr; } while (a); free (src); } else { R_LOG_ERROR ("Cannot open '%s'", file); } } else { R_LOG_ERROR ("Wrong argument"); } break; case 'F': // "waF" if ((input[1] == ' ' || input[1] == '*')) { const char *file = input + ((input[1] == '*')? 3: 2); r_asm_set_pc (core->rasm, core->offset); char *f = r_file_slurp (file, NULL); if (f) { RAsmCode *acode = r_asm_massemble (core->rasm, f); if (acode) { char* hex = r_asm_code_get_hex (acode); if (input[1] == '*') { r_cons_printf ("wx %s\n", hex); } else { if (r_config_get_b (core->config, "scr.prompt")) { R_LOG_INFO ("Written %d byte(s) (%s)=wx %s", acode->len, input, hex); } if (!r_core_write_at (core, core->offset, acode->bytes, acode->len)) { cmd_write_fail (core); } else { WSEEK (core, acode->len); } r_core_block_read (core); } free (hex); r_asm_code_free (acode); } else { R_LOG_ERROR ("Cannot assemble file"); } } else { R_LOG_ERROR ("Cannot slurp '%s'", file); } } else { R_LOG_ERROR ("Wrong argument"); } break; default: r_core_cmd_help (core, help_msg_wa); break; } return 0; } static int cmd_wb(void *data, const char *input) { RCore *core = (RCore *)data; int uil = strlen (input); char c; int i; // Check that user provided some input if (uil == 0) { r_core_cmd_help_match (core, help_msg_w, "wb"); return 0; } // Check that user input only contains binary data for (i = 0; i < uil; i++) { c = input[i]; // Ignore whitespaces if (isspace(c)) { continue; } // Check that user input only contains ones and zeros if (c != '0' && c != '1') { R_LOG_ERROR ("wb operates only on binary data"); return 0; } } // Iterate user input bitwise and write output every 8 bits int bits_read = 0; int block_offset = 0; ut8 byte = 0; for (i = 0; i < uil; i++) { // Read a bit c = input[i]; // Ignore whitespaces if (isspace(c)) { continue; } if (c == '1') { // Bits are read and bytes constructed from most to // least significant. byte |= (1 << (7 - bits_read)); } bits_read++; // Write a byte if we've read 8 bits if (bits_read % 8 == 0) { r_io_write_at ( core->io, core->offset + block_offset, &byte, 1 ); block_offset++; bits_read = 0; byte = 0; } } // Write any possible remaining ui bits if (bits_read != 0) { ut8 b = core->block[block_offset]; // Shift left and right to zero bits_read most significant bits b <<= bits_read; b >>= bits_read; // Overwrite bits_read most significant bits and keep the rest b |= byte; r_io_write_at (core->io, core->offset + block_offset, &b, 1); } return 0; } static int cmd_wX(void *data, const char *input) { RCore *core = (RCore *)data; size_t len = strlen (input); const size_t buf_size = len + 2; ut8 *buf = malloc (buf_size); if (!buf) { return 0; } int slen = r_hex_str2bin (input, buf); if (slen > 0) { r_mem_copyloop (core->block, buf, core->blocksize, slen); if (!r_core_write_at (core, core->offset, core->block, core->blocksize)) { cmd_write_fail (core); } else { WSEEK (core, core->blocksize); } r_core_block_read (core); } else { R_LOG_ERROR ("Wrong argument"); } free (buf); return 0; } static int cmd_wm(void *data, const char *input) { RCore *core = (RCore *)data; char *str = strdup (input); int size = r_hex_str2bin (input, (ut8 *)str); switch (input[0]) { case '\0': R_LOG_TODO ("Display current write mask"); break; case '?': break; case '-': r_io_set_write_mask (core->io, 0, 0); R_LOG_INFO ("Write mask disabled"); break; case ' ': if (size > 0) { r_io_use_fd (core->io, core->io->desc->fd); r_io_set_write_mask (core->io, (const ut8 *)str, size); WSEEK (core, size); eprintf ("Write mask set to '"); size_t i; for (i = 0; i < size; i++) { eprintf ("%02x", str[i]); } eprintf ("'\n"); } else { R_LOG_ERROR ("Invalid string"); } break; } free (str); return 0; } static int cmd_wd(void *data, const char *input) { RCore *core = (RCore *)data; if (input[0] && input[0] == ' ') { char *arg, *inp = strdup (input + 1); arg = strchr (inp, ' '); if (arg) { *arg = 0; ut64 addr = r_num_math (core->num, input + 1); st64 len = r_num_math (core->num, arg + 1); if (len < 1) { R_LOG_ERROR ("Invalid length for wd"); return 0; } if (len > 0xfffff) { R_LOG_TODO ("Region is too large for wd, implement block copy"); return 0; } ut8 *data = malloc (len); if (data) { if (r_io_read_at (core->io, addr, data, len)) { if (!r_io_write_at (core->io, core->offset, data, len)) { R_LOG_ERROR ("r_io_write_at failed at 0x%08" PFMT64x, core->offset); } } else { R_LOG_ERROR ("r_io_read_at: cannot read bytes"); } free (data); } } else { r_core_cmd_help_match (core, help_msg_w, "wd"); } free (inp); } else { r_core_cmd_help_match (core, help_msg_w, "wd"); } return 0; } static int cmd_ws(void *data, const char *input) { RCore *core = (RCore *)data; char *str = strdup (input); if (str && *str) { char *arg = str; int pss = 1; int maxlen = 255; if (*str == ' ') { arg++; } else switch (*str) { case '1': pss = 1; break; case '2': pss = 2; maxlen = UT16_MAX; break; case '4': pss = 4; maxlen = UT32_MAX; break; default: pss = 0; break; } arg = strchr (str, ' '); if (!arg || !pss) { r_core_cmd_help (core, help_msg_ws); free (str); return 0; } arg = (char *)r_str_trim_head_ro (arg + 1); ut64 len = r_str_unescape ((char *)arg); if (len > maxlen) { R_LOG_ERROR ("Too large"); } else { ut8 lenbuf[4] = {0}; // write string length switch (pss) { case 1: r_write_ble8 (lenbuf, len); r_io_write_at (core->io, core->offset, lenbuf, 1); break; case 2: r_write_ble16 (lenbuf, len, R_ARCH_CONFIG_IS_BIG_ENDIAN (core->anal->config)); r_io_write_at (core->io, core->offset, lenbuf, 2); break; case 4: r_write_ble32 (lenbuf, len, R_ARCH_CONFIG_IS_BIG_ENDIAN (core->anal->config)); r_io_write_at (core->io, core->offset, lenbuf, 4); break; } if (!r_core_write_at (core, core->offset + pss, (const ut8 *)arg, len)) { cmd_write_fail (core); } WSEEK (core, len); r_core_block_read (core); } } else { r_core_cmd_help (core, help_msg_ws); } free (str); return 0; } /* TODO: simplify using r_write */ static int cmd_write(void *data, const char *input) { RCore *core = (RCore *)data; if (!input) { return 0; } switch (*input) { case '0': // "w0" cmd_w0 (data, input + 1); break; case '1': // "w1" case '2': // "w2" case '4': // "w4" case '8': // "w8" w_incdec_handler (data, input + 1, *input - '0'); break; case '6': // "w6" cmd_w6 (core, input + 1); break; case 'a': // "wa" cmd_wa (core, input + 1); break; case 'b': // "wb" cmd_wb (core, input + 1); break; case 'X': // "wX" cmd_wX (core, input + 1); break; case 'B': // "wB" cmd_wB (data, input + 1); break; case 'c': // "wc" cmd_wc (core, input + 1); break; case 'h': // "wh" if (!strcmp (input, "hoami")) { char *ui = r_sys_whoami (); r_cons_printf ("%s\n", ui); free (ui); } else { cmd_wh (core, input + 1); } break; case 'e': // "we" cmd_we (core, input + 1); break; case 'p': // "wp" cmd_wp (core, input + 1); break; case 'u': // "wu" cmd_wu (core, input + 1); break; case 'r': // "wr" cmd_wr (core, input + 1); break; #if 0 case 'A': // "wA" cmd_wA (core, input + 1); break; #endif case ' ': // "w" case '+': // "w+" { size_t len = core->blocksize; const char *curcs = r_config_get (core->config, "cfg.charset"); char *str = strdup (input); #if !SHELLFILTER r_str_trim_args (str); #endif r_str_trim_tail (str); ut64 addr = core->offset; if (R_STR_ISEMPTY (curcs)) { r_core_return_value (core, 0); cmd_w (core, str + 1); addr += core->num->value; } else { if (len > 0) { size_t in_len = strlen (str + 1); int max = core->print->charset->encode_maxkeylen; int out_len = in_len * max; int new_len = 0; ut8 *out = malloc (in_len * max); //suppose in len = out len TODO: change it if (out) { *out = 0; new_len = r_charset_decode_str (core->print->charset, out, out_len, (const ut8*) str + 1, in_len); cmd_w (core, (const char *)out); free (out); } addr += new_len; } } free (str); if (*input == '+') { r_core_seek (core, addr, true); } break; } case 'g': // "wg" cmd_wget (core, input + 1); break; case 'z': // "wz" cmd_wz (core, input + 1); break; case 't': // "wt" cmd_wt (core, input); break; case 'f': // "wf" cmd_wf (core, input + 1); break; case 'w': // "ww" cmd_ww (core, input + 1); break; case 'x': // "wx" cmd_wx (core, input + 1); break; case 'm': // "wm" cmd_wm (core, input + 1); break; case 'v': // "wv" cmd_write_value (core, input + 1); break; case 'o': // "wo" cmd_wo (core, input + 1); break; case 'd': // "wd" cmd_wd (core, input + 1); break; case 's': // "ws" cmd_ws (core, input + 1); break; case '?': // "w?" r_core_cmd_help (core, help_msg_w); break; default: r_core_return_invalid_command (core, "w", *input); break; } r_core_block_read (core); return 0; } #endif