static void visual_repeat(RCore *core) { int atport = r_config_get_i (core->config, "scr.atport"); if (atport) { #if __UNIX__ && !__APPLE__ int port = r_config_get_i (core->config, "http.port"); if (!r_core_rtr_http (core, '&', NULL)) { const char *xterm = r_config_get (core->config, "cmd.xterm"); // TODO: this must be configurable r_sys_cmdf ("%s 'r2 -C http://localhost:%d/cmd/V;sleep 1' &", xterm, port); //xterm -bg black -fg gray -e 'r2 -C http://localhost:%d/cmd/;sleep 1' &", port); } else { r_cons_any_key (NULL); } #else eprintf ("Unsupported on this platform\n"); r_cons_any_key (NULL); #endif } else { RThread *th = r_th_new (visual_repeat_thread, core, 0); r_th_start (th, 1); r_cons_break (NULL, NULL); r_cons_any_key (NULL); eprintf ("^C \n"); core->cons->breaked = true; r_th_wait (th); r_cons_break_end (); } }
static void __init_seek_line(RCore *core) { ut64 from, to; r_config_bump (core->config, "lines.to"); from = r_config_get_i (core->config, "lines.from"); to = r_config_get_i (core->config, "lines.to"); if (r_core_lines_initcache (core, from, to) == -1) { eprintf ("ERROR: \"lines.from\" and \"lines.to\" must be set\n"); } }
static int bin_strings (RCore *r, int mode, ut64 baddr, int va) { char *p, *q, str[R_FLAG_NAME_SIZE]; RBinSection *section; int hasstr, minstr, rawstr; RBinString *string; RListIter *iter; RList *list; RBin *bin = r->bin; RBinFile * binfile = r_core_bin_cur (r); RBinPlugin *plugin = r_bin_file_cur_plugin (binfile); if (!binfile) return R_FALSE; minstr = r_config_get_i (r->config, "bin.minstr"); rawstr = r_config_get_i (r->config, "bin.rawstr"); binfile->rawstr = rawstr; if (!(hasstr = r_config_get_i (r->config, "bin.strings"))) return 0; if (!plugin) return 0; if (!plugin->info) { if (!rawstr) { eprintf ("WARN: Use '-e bin.rawstr=true' or 'rabin2 -zz'" " to find strings on unknown file types\n"); return R_FALSE; } } if (bin->minstrlen == 0) bin->minstrlen = plugin->minstrlen? plugin->minstrlen: 4; if (minstr > 0 || bin->minstrlen <= 0) bin->minstrlen = R_MIN (minstr, 4); if ((list = r_bin_get_strings (bin)) == NULL) return R_FALSE; if ((mode & R_CORE_BIN_JSON)) { r_cons_printf ("["); r_list_foreach (list, iter, string) { ut64 vaddr = r_bin_get_vaddr (bin, baddr, string->vaddr, string->paddr); ut64 paddr = string->paddr; q = strdup (string->string); for (p=q; *p; p++) { if (*p=='"') *p = '\''; if (*p=='\\') *p = '/'; } r_cons_printf ("%s{\"vaddr\":%"PFMT64d ",\"paddr\":%"PFMT64d ",\"length\":%d,\"size\":%d," "\"type\":\"%s\",\"string\":\"%s\"}", iter->p? ",": "", vaddr, paddr, string->length, string->size, string->type=='w'?"wide":"ascii", q); free (q); }
R_API int r_core_bin_set_env (RCore *r, RBinFile *binfile) { RBinObject *binobj = binfile ? binfile->o: NULL; RBinInfo *info = binobj ? binobj->info: NULL; if (info) { int va = info->has_va; const char * arch = info->arch; ut16 bits = info->bits; ut64 loadaddr = r_config_get_i (r->config, "bin.laddr"); ut64 baseaddr = binobj->baddr; /* Hack to make baddr work on some corner */ r_config_set_i (r->config, "io.va", (binobj->info)? binobj->info->has_va: 0); r_config_set_i (r->config, "bin.laddr", loadaddr); r_config_set_i (r->config, "bin.baddr", baseaddr); r_config_set (r->config, "asm.arch", arch); r_config_set_i (r->config, "asm.bits", bits); r_config_set (r->config, "anal.arch", arch); if (strlen(info->cpu)) r_config_set (r->config, "anal.cpu", info->cpu); else r_config_set (r->config, "anal.cpu", arch); r_asm_use (r->assembler, arch); r_core_bin_info (r, R_CORE_BIN_ACC_ALL, R_CORE_BIN_SET, va, NULL, loadaddr, NULL); r_core_bin_set_cur (r, binfile); return R_TRUE; } return R_FALSE; }
static void r_core_magic(RCore *core, const char *file, int v) { ut64 addr = core->offset; magicdepth = r_config_get_i (core->config, "magic.depth"); // TODO: do not use global var here r_core_magic_at (core, file, addr, magicdepth, v); if (addr != core->offset) r_core_seek (core, addr, R_TRUE); }
static int readline_callback(void *_a, const char *str) { RCoreVisualAsm *a = _a; int xlen; r_cons_clear00 (); r_cons_printf ("Write your favourite %s-%d opcode...\n\n", r_config_get (a->core->config, "asm.arch"), r_config_get_i (a->core->config, "asm.bits")); if (*str == '?') { r_cons_printf ("0> ?\n\n" "Visual assembler help:\n\n" " assemble input while typing using asm.arch, asm.bits and cfg.bigendian\n" " press enter to quit (prompt if there are bytes to be written)\n" " this assembler supports various directives like .hex ...\n" ); } else { r_asm_code_free (a->acode); a->acode = r_asm_massemble (a->core->assembler, str); r_cons_printf ("%d> %s\n", a->acode? a->acode->len: 0, str); if (a->acode && a->acode->len) r_cons_printf ("* %s\n\n", a->acode->buf_hex); else r_cons_printf ("\n\n"); if (a->acode) { xlen = strlen (a->acode->buf_hex); strcpy (a->codebuf, a->blockbuf); memcpy (a->codebuf, a->acode->buf_hex, xlen); } r_core_cmdf (a->core, "pd 7@b:%s @0x%"PFMT64x, a->codebuf, a->off); } r_cons_flush (); return 1; }
R_API void r_core_visual_seek_animation (RCore *core, ut64 addr) { if (r_config_get_i (core->config, "scr.feedback")<1) return; #if 0 int i, ns = 90000; const char *scmd = (addr > core->offset)? "so": "s-4"; for (i=0;i<5;i++) { r_core_cmd0 (core, scmd); r_core_visual_refresh (core); r_cons_flush(); r_sys_usleep (ns); ns -= 1000; } r_core_seek (core, addr, 1); #else if (core->offset == addr) return; r_cons_gotoxy (1, 2); if (addr>core->offset) { r_cons_printf (".----.\n"); r_cons_printf ("| \\/ |\n"); r_cons_printf ("'----'\n"); } else { r_cons_printf (".----.\n"); r_cons_printf ("| /\\ |\n"); r_cons_printf ("'----'\n"); } r_cons_flush(); r_sys_usleep (90000); #endif r_core_seek (core, addr, 1); }
R_API RAnalHint *r_core_hint_begin (RCore *core, RAnalHint* hint, ut64 at) { // XXX not here static char *hint_arch = NULL; static int hint_bits = 0; if (hint) { r_anal_hint_free (hint); hint = NULL; } hint = r_anal_hint_get (core->anal, at); if (hint_arch) { r_config_set (core->config, "asm.arch", hint_arch); hint_arch = NULL; } if (hint_bits) { r_config_set_i (core->config, "asm.bits", hint_bits); hint_bits = 0; } if (hint) { /* arch */ if (hint->arch) { if (!hint_arch) hint_arch = strdup ( r_config_get (core->config, "asm.arch")); r_config_set (core->config, "asm.arch", hint->arch); } /* bits */ if (hint->bits) { if (!hint_bits) hint_bits = r_config_get_i (core->config, "asm.bits"); r_config_set_i (core->config, "asm.bits", hint->bits); } } return hint; }
R_API int r_core_lines_initcache(RCore *core, ut64 start_addr, ut64 end_addr) { int i, line_count; int bsz = core->blocksize; char *buf; ut64 off = start_addr; ut64 baddr; if (start_addr == UT64_MAX || end_addr == UT64_MAX) { return -1; } free (core->print->lines_cache); core->print->lines_cache = R_NEWS0 (ut64, bsz); if (!core->print->lines_cache) { return -1; } { RIOSection *s = r_io_section_mget_in (core->io, core->offset); baddr = s? s->paddr: r_config_get_i (core->config, "bin.baddr"); } line_count = start_addr? 0: 1; core->print->lines_cache[0] = start_addr? 0: baddr; buf = malloc (bsz); if (!buf) { return -1; } r_cons_break_push (NULL, NULL); while (off < end_addr) { if (r_cons_is_breaked ()) { break; } r_io_read_at (core->io, off, (ut8 *) buf, bsz); for (i = 0; i < bsz; i++) { if (buf[i] == '\n') { core->print->lines_cache[line_count] = start_addr? off + i + 1: off + i + 1 + baddr; line_count++; if (line_count % bsz == 0) { ut64 *tmp = realloc (core->print->lines_cache, (line_count + bsz) * sizeof (ut64)); if (tmp) { core->print->lines_cache = tmp; } else { R_FREE (core->print->lines_cache); goto beach; } } } } off += bsz; } free (buf); r_cons_break_pop (); return line_count; beach: free (buf); r_cons_break_pop (); return -1; }
R_API void r_core_fortune_print_random(RCore *core) { // TODO: use file.fortunes // can be dangerous in sandbox mode char *line = getrandomline (core); if (!line) { line = getrandomline (core); } if (line) { if (r_config_get_i (core->config, "cfg.fortunes.clippy")) { r_core_clippy (line); } else { r_cons_printf (" -- %s\n", line); } if (r_config_get_i (core->config, "cfg.fortunes.tts")) { r_sys_tts (line, true); } free (line); } }
static void objc_analyze(RCore *core) { eprintf ("[+] Analyzing searching references to selref\n"); r_core_cmd0 (core, "aar"); if (!strcmp ("arm", r_config_get (core->config, "asm.arch"))) { bool emu_lazy = r_config_get_i (core->config, "emu.lazy"); r_config_set_i (core->config, "emu.lazy", true); r_core_cmd0 (core, "aae"); r_config_set_i (core->config, "emu.lazy", emu_lazy); } }
static bool r_anal_emul_init(RCore *core, bool *state) { state[ROMEM] = r_config_get_i (core->config, "esil.romem"); r_config_set (core->config, "esil.romem", "true"); state[ASM_TRACE] = r_config_get_i (core->config, "asm.trace"); r_config_set (core->config, "asm.trace", "true"); state[ANAL_TRACE] = r_config_get_i (core->config, "anal.trace"); r_config_set (core->config, "anal.trace", "true"); state[DBG_TRACE] = r_config_get_i (core->config, "dbg.trace"); r_config_set (core->config, "dbg.trace", "true"); state[NONULL] = r_config_get_i (core->config, "esil.nonull"); r_config_set (core->config, "esil.nonull", "true"); const char *bp = r_reg_get_name (core->anal->reg, R_REG_NAME_BP); const char *sp = r_reg_get_name (core->anal->reg, R_REG_NAME_SP); if ((bp && !r_reg_getv (core->anal->reg, bp)) || (sp && !r_reg_getv (core->anal->reg, sp))) { eprintf ("Stack isn't initiatized.\n"); eprintf ("Try running aei and aeim commands before aftm for default stack initialization\n"); return false; } return (core->anal->esil != NULL); }
static int bin_dwarf(RCore *core, int mode) { RBinDwarfRow *row; RListIter *iter; RList *list = NULL; RBinFile *binfile = r_core_bin_cur (core); RBinPlugin * plugin = r_bin_file_cur_plugin (binfile); if (!binfile) return false; if (plugin && plugin->lines) { list = plugin->lines (binfile); } else if (core->bin) { // TODO: complete and speed-up support for dwarf if (r_config_get_i (core->config, "bin.dwarf")) { RBinDwarfDebugAbbrev *da = NULL; da = r_bin_dwarf_parse_abbrev (core->bin, mode); r_bin_dwarf_parse_info (da, core->bin, mode); r_bin_dwarf_parse_aranges (core->bin, mode); list = r_bin_dwarf_parse_line (core->bin, mode); r_bin_dwarf_free_debug_abbrev (da); free (da); } } if (!list) return false; r_cons_break (NULL, NULL); r_list_foreach (list, iter, row) { if (r_cons_singleton()->breaked) break; if (mode) { // TODO: use 'Cl' instead of CC const char *path = row->file; char *line = r_file_slurp_line (path, row->line-1, 0); if (line) { r_str_filter (line, strlen (line)); line = r_str_replace (line, "\"", "\\\"", 1); line = r_str_replace (line, "\\\\", "\\", 1); } // TODO: implement internal : if ((mode & R_CORE_BIN_SET)) if ((mode & R_CORE_BIN_SET)) { char *cmt = r_str_newf ("%s:%d %s", row->file, row->line, line?line:""); r_meta_set_string (core->anal, R_META_TYPE_COMMENT, row->address, cmt); free (cmt); } else { r_cons_printf ("\"CC %s:%d %s\"@0x%"PFMT64x"\n", row->file, row->line, line?line:"", row->address); } free (line); } else { r_cons_printf ("0x%08"PFMT64x"\t%s\t%d\n", row->address, row->file, row->line); } } r_cons_break_end (); r_list_free (list); return true; }
static int bin_strings (RCore *r, int mode, ut64 baddr, int va) { char *p, *q, str[R_FLAG_NAME_SIZE]; RBinSection *section; int hasstr, minstr; RBinString *string; RListIter *iter; RList *list; int i = 0; if (!(hasstr = r_config_get_i (r->config, "bin.strings"))) return 0; if (!r->bin->cur.curplugin) return 0; if (!r->bin->cur.curplugin->info) { if (!r_config_get_i (r->config, "bin.rawstr")) { eprintf ("WARN: Use '-e bin.rawstr=true' or 'rabin2 -zz'" " to find strings on unknown file types\n"); return 0; } } minstr = r_config_get_i (r->config, "bin.minstr"); //if (r->bin->minstrlen == 0 && minstr>0) r->bin->minstrlen = minstr; //else if (r->bin->minstrlen > 0) r_config_set_i (r->config, "bin.minstr", r->bin->minstrlen); if (r->bin->minstrlen <=0) return -1; /* code */ if ((list = r_bin_get_strings (r->bin)) == NULL) return R_FALSE; if ((mode & R_CORE_BIN_JSON)) { r_cons_printf ("["); r_list_foreach (list, iter, string) { ut64 addr = va? r_bin_get_vaddr (r->bin, baddr, string->rva, string->offset): string->offset; q = strdup (string->string); //r_name_filter (str, 128); for (p=q; *p; p++) if(*p=='"')*p='\''; r_cons_printf ("%s{\"offset\":%"PFMT64d ",\"length\":%d,\"string\":\"%s\"}", iter->p? ",": "", addr, string->size, q); free (q); }
R_API void r_core_visual_show_char (RCore *core, char ch) { if (r_config_get_i (core->config, "scr.feedback")<2) return; if (!IS_PRINTABLE (ch)) return; r_cons_gotoxy (1, 2); r_cons_printf (".---.\n"); r_cons_printf ("| %c |\n", ch); r_cons_printf ("'---'\n"); r_cons_flush (); r_sys_sleep (1); }
static void objc_analyze(RCore *core) { static const char *oldstr = NULL; oldstr = r_print_rowlog (core->print, "Analyzing searching references to selref"); r_core_cmd0 (core, "aar"); if (!strcmp ("arm", r_config_get (core->config, "asm.arch"))) { bool emu_lazy = r_config_get_i (core->config, "emu.lazy"); r_config_set_i (core->config, "emu.lazy", true); r_core_cmd0 (core, "aae"); r_config_set_i (core->config, "emu.lazy", emu_lazy); } r_print_rowlog_done (core->print, oldstr); }
R_API int r_core_setup_debugger (RCore *r, const char *debugbackend, bool attach) { int pid, *p = NULL; bool is_gdb = !strcmp (debugbackend, "gdb"); RIODesc * fd = r->file ? r_io_desc_get (r->io, r->file->fd) : NULL; const char *prompt = NULL; p = fd ? fd->data : NULL; r_config_set_i (r->config, "cfg.debug", 1); if (!p) { eprintf ("Invalid debug io\n"); return false; } r_config_set (r->config, "io.ff", "true"); r_core_cmdf (r, "dL %s", debugbackend); if (!is_gdb) { pid = r_io_desc_get_pid (fd); r_core_cmdf (r, "dp=%d", pid); if (attach) { r_core_cmdf (r, "dpa %d", pid); } } //this makes to attach twice showing warnings in the output //we get "resource busy" so it seems isn't an issue r_core_cmd (r, ".dr*", 0); /* honor dbg.bep */ { const char *bep = r_config_get (r->config, "dbg.bep"); if (bep) { if (!strcmp (bep, "loader")) { /* do nothing here */ } else if (!strcmp (bep, "entry")) { r_core_cmd (r, "dcu entry0", 0); } else { r_core_cmdf (r, "dcu %s", bep); } } } r_core_cmd (r, "sr PC", 0); /* set the prompt if it's not been set already by the callbacks */ prompt = r_config_get (r->config, "cmd.prompt"); if (prompt && !strcmp (prompt, "")) { if (r_config_get_i (r->config, "dbg.status")) { r_config_set (r->config, "cmd.prompt", ".dr*;drd;sr PC;pi 1;s-"); } else { r_config_set (r->config, "cmd.prompt", ".dr*"); } } r_config_set (r->config, "cmd.vprompt", ".dr*"); return true; }
static void showcursor(RCore *core, int x) { if (core && core->vmode) { r_cons_show_cursor (x); if (x) { // TODO: cache this int wheel = r_config_get_i (core->config, "scr.wheel"); if (wheel) r_cons_enable_mouse (true); else r_cons_enable_mouse (false); } else { r_cons_enable_mouse (false); } } else r_cons_enable_mouse (false); r_cons_flush (); }
R_API void r_core_print_func_args(RCore *core) { RListIter *iter; bool color = r_config_get_i (core->config, "scr.color"); if (!core->anal) { return; } if (!core->anal->reg) { return; } const char *pc = r_reg_get_name (core->anal->reg, R_REG_NAME_PC); ut64 cur_addr = r_reg_getv (core->anal->reg, pc); RAnalOp *op = r_core_anal_op (core, cur_addr, R_ANAL_OP_MASK_BASIC); if (!op) { return; } if (op->type == R_ANAL_OP_TYPE_CALL) { RAnalFunction *fcn; RAnalFuncArg *arg; int i; int nargs = 0; bool onstack = false; const char *fcn_name = NULL; ut64 pcv = op->jump; if (pcv == UT64_MAX) { pcv = op->ptr; } fcn = r_anal_get_fcn_at (core->anal, pcv, 0); if (fcn) { fcn_name = fcn->name; } else { if (core->flags) { RFlagItem *item = r_flag_get_i (core->flags, pcv); if (item) { fcn_name = item->name; } } } RList *list = r_core_get_func_args (core, fcn_name); if (!r_list_empty (list)) { int argcnt = 0; r_list_foreach (list, iter, arg) { if (arg->cc_source && !strncmp (arg->cc_source, "stack", 5)) { onstack = true; } print_arg_str (argcnt, arg->name, color); print_format_values (core, arg->fmt, onstack, arg->src, color); argcnt++; } } else {
R_API int r_core_rtr_cmds (RCore *core, const char *port) { unsigned char buf[4097]; RSocket *ch, *s; int i, ret; char *str; if (!port || port[0]=='?') { r_cons_printf ("Usage: .:[tcp-port] run r2 commands for clients\n"); return R_FALSE; } s = r_socket_new (0); if (!r_socket_listen (s, port, NULL)) { eprintf ("Error listening on port %s\n", port); r_socket_free (s); return R_FALSE; } eprintf ("Listening for commands on port %s\n", port); listenport = port; for (;;) { r_cons_break ((RConsBreak)http_break, core); ch = r_socket_accept (s); buf[0] = 0; ret = r_socket_read (ch, buf, sizeof (buf) - 1); if (ret>0) { buf[ret] = 0; for (i=0; buf[i]; i++) if (buf[i] == '\n') buf[i] = buf[i+1]? ';': '\0'; if (!r_config_get_i (core->config, "scr.prompt") \ && !strcmp ((char*)buf, "q!")) break; str = r_core_cmd_str (core, (const char *)buf); if (str &&*str) { r_socket_write (ch, str, strlen (str)); } else r_socket_write (ch, "\n", 1); free (str); } if (r_cons_singleton()->breaked) break; r_socket_close (ch); r_cons_break_end (); } r_socket_free(s); r_socket_free(ch); return 0; }
static bool cmd_wff(RCore *core, const char *input) { ut8 *buf; int size; // XXX: file names cannot contain spaces const char *arg = input + ((input[1] == ' ') ? 2 : 1); int wseek = r_config_get_i (core->config, "cfg.wseek"); char *p, *a = r_str_trim (strdup (arg)); p = strchr (a, ' '); if (p) { *p++ = 0; } if (*arg =='?' || !*arg) { eprintf ("Usage: wf [file] ([size] ([offset]))\n"); } if (!strcmp (arg, "-")) { char *out = r_core_editor (core, NULL, NULL); if (out) { r_io_write_at (core->io, core->offset, (ut8*)out, strlen (out)); r_core_block_read (core); free (out); } } if ((buf = (ut8*) r_file_slurp (a, &size))) { int u_size = size; int u_offset = 0; u_size = r_num_math (core->num, p); if (u_size < 1) u_size = size; if (p) { *p++ = 0; u_offset = r_num_math (core->num, p); if (u_offset > size) { eprintf ("Invalid offset\n"); free (buf); return false; } } r_io_use_fd (core->io, core->file->fd); r_io_write_at (core->io, core->offset, buf + u_offset, u_size); WSEEK (core, size); free (buf); r_core_block_read (core); } else { eprintf ("Cannot open file '%s'\n", arg); } return true; }
R_API int cmd_write_hexpair(RCore* core, const char* pairs) { ut8 *buf = malloc (strlen (pairs)); int len = r_hex_str2bin (pairs, buf); if (len != 0) { if (len < 0) len = -len + 1; if (len<core->blocksize) buf[len] = (core->block[len] & 0xf) | (buf[len] & 0xf0); r_core_write_at (core, core->offset, buf, len); if (r_config_get_i (core->config, "cfg.wseek")) r_core_seek_delta (core, len); r_core_block_read (core, 0); } else eprintf ("Error: invalid hexpair string\n"); free (buf); return !!!len; }
static int cmd_hash_bang (RCore *core, const char *input) { char *p; const char *lang = input+1; if (r_sandbox_enable (0)) { eprintf ("hashbang disabled in sandbox mode\n"); return R_FALSE; } if (*lang=='/') { const char *ptr = lang+1; while (*lang) { if (*lang=='/') ptr = lang+1; lang++; } RLangPlugin *p = r_lang_get_by_extension (core->lang, ptr); if (p && p->name) lang = p->name; } if (*lang==' ') { RLangPlugin *p = r_lang_get_by_extension (core->lang, input+2); if (p && p->name) lang = p->name; } else if (input[1]=='?' || input[1]=='*' || input[1]=='\0') { r_lang_list (core->lang); return R_TRUE; } p = strchr (input, ' '); if (p) *p=0; // TODO: set argv here if (r_lang_use (core->lang, lang)) { r_lang_setup (core->lang); if (p) { r_lang_run_file (core->lang, p+1); } else { if (r_config_get_i (core->config, "scr.interactive")) { r_lang_prompt (core->lang); } else eprintf ("Cannot enter into the rlang prompt in non-interactive mode\n"); } } else { if (!p || *p==' ') eprintf ("Invalid hashbang. See '#!' for help.\n"); } return R_TRUE; }
R_API int cmd_write_hexpair(RCore* core, const char* pairs) { ut8 *buf = malloc (strlen (pairs) + 1); 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_write_at (core, core->offset, buf, len); if (r_config_get_i (core->config, "cfg.wseek")) { r_core_seek_delta (core, len); } r_core_block_read (core); } else { eprintf ("Error: invalid hexpair string\n"); } free (buf); return len; }
static int cmd_seek(void *data, const char *input) { RCore *core = (RCore *) data; char *cmd, *p; ut64 off; if (!*input) { r_cons_printf ("0x%"PFMT64x "\n", core->offset); return 0; } char *ptr; if ((ptr = strstr (input, "+.")) != NULL) { char *dup = strdup (input); dup[ptr - input] = '\x00'; off = r_num_math (core->num, dup + 1); core->offset = off; free (dup); } const char *inputnum = strchr (input, ' '); { const char *u_num = inputnum? inputnum + 1: input + 1; off = r_num_math (core->num, u_num); if (*u_num == '-') { off = -off; } } int sign = 1; if (input[0] == ' ') { switch (input[1]) { case '-': sign = -1; /* pass thru */ case '+': input++; break; } } bool silent = false; if (*input == 's') { silent = true; input++; if (*input == '?') { const char *help_message[] = { "Usage: ss", "", " # Seek silently (not recorded in the seek history)", "s?", "", "Works with all s subcommands", NULL }; r_core_cmd_help (core, help_message); return 0; } } switch (*input) { case 'r': if (input[1] && input[2]) { seek_to_register (core, input + 2, silent); } else { eprintf ("|Usage| 'sr PC' seek to program counter register\n"); } break; case 'C': if (input[1] == '*') { r_core_cmd0 (core, "C*~^\"CC"); } else if (input[1] == ' ') { typedef struct { ut64 addr; char *str; } MetaCallback; int count = 0; MetaCallback cb = { 0, NULL }; ut64 addr; char key[128]; const char *val, *comma; char *list = sdb_get (core->anal->sdb_meta, "meta.C", 0); char *str, *next, *cur = list; if (list) { for (;;) { cur = sdb_anext (cur, &next); addr = sdb_atoi (cur); snprintf (key, sizeof (key) - 1, "meta.C.0x%"PFMT64x, addr); val = sdb_const_get (core->anal->sdb_meta, key, 0); if (val) { comma = strchr (val, ','); if (comma) { str = (char *) sdb_decode (comma + 1, 0); if (strstr (str, input + 2)) { r_cons_printf ("0x%08"PFMT64x " %s\n", addr, str); count++; cb.addr = addr; free (cb.str); cb.str = str; } else { free (str); } } } else { eprintf ("sdb_const_get key not found '%s'\n", key); } if (!next) { break; } cur = next; } } switch (count) { case 0: eprintf ("No matching comments\n"); break; case 1: off = cb.addr; if (!silent) { r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print)); } r_core_seek (core, off, 1); r_core_block_read (core); break; default: eprintf ("Too many results\n"); break; } free (cb.str); } else { const char *help_msg[] = { "Usage:", "sC", "Comment grep", "sC", "*", "List all comments", "sC", " str", "Seek to the first comment matching 'str'", NULL }; r_core_cmd_help (core, help_msg); } break; case ' ': if (!silent) { r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print)); } r_core_seek (core, off * sign, 1); r_core_block_read (core); break; case '/': { const char *pfx = r_config_get (core->config, "search.prefix"); ut64 from = r_config_get_i (core->config, "search.from"); // kwidx cfg var is ignored int kwidx = core->search->n_kws; // (int)r_config_get_i (core->config, "search.kwidx")-1; if (kwidx < 0) { kwidx = 0; } switch (input[1]) { case ' ': case 'v': case 'V': case 'w': case 'W': case 'z': case 'm': case 'c': case 'A': case 'e': case 'E': case 'i': case 'R': case 'r': case '/': case 'x': r_config_set_i (core->config, "search.from", core->offset + 1); r_config_set_i (core->config, "search.count", 1); r_core_cmdf (core, "s+1; %s; s-1; s %s%d_0; f-%s%d_0", input, pfx, kwidx, pfx, kwidx, pfx, kwidx); r_config_set_i (core->config, "search.from", from); r_config_set_i (core->config, "search.count", 0); break; case '?': eprintf ("Usage: s/.. arg.\n"); r_cons_printf ("/?\n"); break; default: eprintf ("unknown search method\n"); break; } } break; case '.': for (input++; *input == '.'; input++) { ; } r_core_seek_base (core, input); break; case 'j': // sj { RList /*<ut64 *>*/ *addrs = r_list_newf (free); RList /*<char *>*/ *names = r_list_newf (free); RList *list = r_io_sundo_list (core->io, '!'); ut64 lsz = 0; ut64 i; RListIter *iter; RIOUndos *undo; if (list) { r_list_foreach (list, iter, undo) { char *name = NULL; core->flags->space_strict = true; RFlagItem *f = r_flag_get_at (core->flags, undo->off, true); core->flags->space_strict = false; if (f) { if (f->offset != undo->off) { name = r_str_newf ("%s + %d\n", f->name, (int)(undo->off- f->offset)); } else { name = strdup (f->name); } } if (!name) { name = strdup (""); } ut64 *val = malloc (sizeof (ut64)); if (!val) { free (name); break; } *val = undo->off; r_list_append (addrs, val); r_list_append (names, strdup (name)); lsz++; free (name); } r_list_free (list); } r_cons_printf ("["); for (i = 0; i < lsz; ++i) { ut64 *addr = r_list_get_n (addrs, i); const char *name = r_list_get_n (names, i); // XXX(should the "name" field be optional? That might make // a bit more sense. r_cons_printf ("{\"offset\":%"PFMT64d",\"symbol\":\"%s\"}", *addr, name); if (i != lsz - 1) { r_cons_printf (","); } } r_cons_printf ("]\n"); r_list_free (addrs); r_list_free (names); } break; case '*': case '=': case '!': { RList *list = r_io_sundo_list (core->io, input[0]); RListIter *iter; RIOUndos *undo; if (list) { r_list_foreach (list, iter, undo) { char *name = NULL; core->flags->space_strict = true; RFlagItem *f = r_flag_get_at (core->flags, undo->off, true); core->flags->space_strict = false; if (f) { if (f->offset != undo->off) { name = r_str_newf ("%s + %d\n", f->name, (int)(undo->off- f->offset)); } else { name = strdup (f->name); } } if (!name) { name = strdup (""); } r_cons_printf ("0x%"PFMT64x" %s\n", undo->off, name); free (name); } r_list_free (list); } }
static void cmd_write_op (RCore *core, const char *input) { ut8 *buf; int len; int value; if (!input[0]) return; switch (input[1]) { case 'e': if (input[2]!=' ') { r_cons_printf ("Usage: 'woe from-to step'\n"); return; } /* fallthru */ case 'a': case 's': case 'A': case 'x': case 'r': case 'l': case 'm': case 'd': case 'o': case 'w': case '2': case '4': if (input[2]) { // parse val from arg r_core_write_op (core, input+3, input[1]); r_core_block_read (core); } else { // use clipboard instead of val r_core_write_op (core, NULL, input[1]); r_core_block_read (core); } break; case 'R': r_core_cmd0 (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[1] == 'E') ? 0 : 1; const char *algo = NULL; const char *key = NULL; const char *iv = NULL; char *space, *args = strdup (r_str_trim_ro (input+2)); space = strchr (args, ' '); if (space) { *space++ = 0; key = space; space = strchr (key, ' '); if (space) { *space++ = 0; iv = space; } } algo = args; if (algo && *algo && key) { encrypt_or_decrypt_block (core, algo, key, direction, iv); } else { eprintf ("Usage: wo%c [algo] [key] [IV]\n", ((!direction)?'E':'D')); eprintf ("Currently supported hashes:\n"); ut64 bits; int i; for (i = 0; ; i++) { bits = ((ut64)1) << i; const char *name = r_hash_name (bits); if (!name || !*name) break; printf (" %s\n", name); } eprintf ("Available Encoders/Decoders: \n"); // TODO: do not hardcode eprintf (" base64\n"); eprintf (" base91\n"); eprintf (" punycode\n"); eprintf ("Currently supported crypto algos:\n"); for (i = 0; ; i++) { bits = ((ut64)1) << i; const char *name = r_crypto_name (bits); if (!name || !*name) break; printf (" %s\n", name); } } free (args); } break; case 'p': // debrujin patterns switch (input[2]) { case 'D': // "wopD" len = (int)(input[3]==' ') ? r_num_math (core->num, input + 3) : 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[3] == '*') { int i; r_cons_printf ("wx "); for (i = 0; i < len; i++) { r_cons_printf ("%02x", buf[i]); } r_cons_newline (); } else { while (true) { int res = r_core_write_at (core, addr, ptr, len); if (res < 1 || len == res) { break; } if (res < len) { ptr += res; len -= res; addr += res; } } } free (buf); } else { eprintf ("Couldn't generate pattern of length %d\n", len); } } break; case 'O': // "wopO" if (strlen (input) > 4 && strncmp (input + 4, "0x", 2)) { eprintf ("Need hex value with `0x' prefix e.g. 0x41414142\n"); } else if (input[3] == ' ') { value = r_num_get (core->num, input + 4); core->num->value = r_debruijn_offset (value, r_config_get_i (core->config, "cfg.bigendian")); 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; } }
static ut64 num_callback(RNum *userptr, const char *str, int *ok) { RCore *core = (RCore *)userptr; // XXX ? RAnalFunction *fcn; char *ptr, *bptr, *out; RFlagItem *flag; RIOSection *s; RAnalOp op; ut64 ret = 0; if (ok) *ok = R_FALSE; switch (*str) { case '[': { ut64 n = 0LL; int refsz = (core->assembler->bits & R_SYS_BITS_64)? 8: 4; const char *p = NULL; if (strlen (str)>5) p = strchr (str+5, ':'); // TODO: honor LE if (p) { refsz = atoi (str+1); str = p; } // push state { if (str[0] && str[1]) { const char *q; char *o = strdup (str+1); if (o) { q = r_num_calc_index (core->num, NULL); if (q) { if (r_str_replace_char (o, ']', 0)>0) { n = r_num_math (core->num, o); r_num_calc_index (core->num, q); } } free (o); } } } // pop state if (ok) *ok = 1; ut32 num = 0; switch (refsz) { case 8: case 4: case 2: case 1: (void)r_io_read_at (core->io, n, (ut8*)&num, refsz); r_mem_copyendian ((ut8*)&num, (ut8*)&num, refsz, !core->assembler->big_endian); return num; default: eprintf ("Invalid reference size: %d (%s)\n", refsz, str); return 0LL; } } break; case '$': if (ok) *ok = 1; // TODO: group analop-dependant vars after a char, so i can filter r_anal_op (core->anal, &op, core->offset, core->block, core->blocksize); switch (str[1]) { case '.': // can use pc, sp, a0, a1, ... return r_debug_reg_get (core->dbg, str+2); case 'k': if (str[2]!='{') { eprintf ("Expected '{' after 'k'.\n"); break; } bptr = strdup (str+3); ptr = strchr (bptr, '}'); if (ptr == NULL) { // invalid json free (bptr); break; } *ptr = '\0'; ret = 0LL; out = sdb_querys (core->sdb, NULL, 0, bptr); if (out && *out) { if (strstr (out, "$k{")) { eprintf ("Recursivity is not permitted here\n"); } else { ret = r_num_math (core->num, out); } } free (bptr); free (out); return ret; break; case '{': bptr = strdup (str+2); ptr = strchr (bptr, '}'); if (ptr != NULL) { ut64 ret; ptr[0] = '\0'; ret = r_config_get_i (core->config, bptr); free (bptr); return ret; } free (bptr); break; case 'c': return r_cons_get_size (NULL); case 'r': { int rows; r_cons_get_size (&rows); return rows; } case 'e': return r_anal_op_is_eob (&op); case 'j': return op.jump; case 'p': return r_sys_getpid (); case 'P': return (core->dbg->pid>0)? core->dbg->pid: 0; case 'f': return op.fail; case 'm': return op.ptr; // memref case 'v': return op.val; // immediate value case 'l': return op.size; case 'b': return core->blocksize; case 's': if (core->file) { return r_io_desc_size (core->io, core->file->desc); } return 0LL; case 'w': return r_config_get_i (core->config, "asm.bits") / 8; case 'S': s = r_io_section_vget (core->io, core->offset); return s? (str[2]=='S'? s->size: s->vaddr): 3; case '?': return core->num->value; case '$': return core->offset; case 'o': return r_io_section_vaddr_to_offset (core->io, core->offset); case 'C': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_CALL); case 'J': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_CODE); case 'D': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_DATA); case 'X': return getref (core, atoi (str+2), 'x', R_ANAL_REF_TYPE_CALL); case 'I': fcn = r_anal_get_fcn_in (core->anal, core->offset, 0); return fcn? fcn->ninstr: 0; case 'F': fcn = r_anal_get_fcn_in (core->anal, core->offset, 0); return fcn? fcn->size: 0; } break; default: if (*str>'A') { // NOTE: functions override flags RAnalFunction *fcn = r_anal_fcn_find_name (core->anal, str); if (fcn) { if (ok) *ok = R_TRUE; return fcn->addr; } #if 0 ut64 addr = r_anal_fcn_label_get (core->anal, core->offset, str); if (addr != 0) { ret = addr; } else { ... } #endif if ((flag = r_flag_get (core->flags, str))) { ret = flag->offset; if (ok) *ok = R_TRUE; } } break; }
static 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_core_visual_cmd(RCore *core, int ch) { RAsmOp op; ut64 offset = core->offset; char buf[4096]; int i, ret, offscreen, cols = core->print->cols, delta = 0; ch = r_cons_arrow_to_hjkl (ch); ch = visual_nkey (core, ch); if (ch<2) return 1; // do we need hotkeys for data references? not only calls? if (ch>='0'&& ch<='9') { ut64 off = core->asmqjmps[ch-'0']; if (off != UT64_MAX) { int delta = R_ABS ((st64)off-(st64)offset); r_io_sundo_push (core->io, offset); if (curset && delta<100) { cursor = delta; } else { r_core_visual_seek_animation (core, off); //r_core_seek (core, off, 1); } r_core_block_read (core, 1); } } else switch (ch) { case 0x0d: { r_cons_enable_mouse (R_TRUE); RAnalOp *op = r_core_anal_op (core, core->offset+cursor); if (op) { if (op->type == R_ANAL_OP_TYPE_JMP || op->type == R_ANAL_OP_TYPE_CJMP || op->type == R_ANAL_OP_TYPE_CALL) { r_io_sundo_push (core->io, offset); r_core_visual_seek_animation(core, op->jump); } } r_anal_op_free (op); } break; case 90: // shift+tab if (!strcmp (printfmt[0], "x")) printfmt[0] = "pxa"; else printfmt[0] = "x"; break; case 9: // tab { // XXX: unify diff mode detection ut64 f = r_config_get_i (core->config, "diff.from"); ut64 t = r_config_get_i (core->config, "diff.to"); if (f == t && f == 0) { core->print->col = core->print->col==1? 2: 1; } else { ut64 delta = offset - f; r_core_seek (core, t+delta, 1); r_config_set_i (core->config, "diff.from", t); r_config_set_i (core->config, "diff.to", f); } } break; case 'a': if (core->file && !(core->file->rwx & 2)) { r_cons_printf ("\nFile has been opened in read-only mode. Use -w flag\n"); r_cons_any_key (); return R_TRUE; } r_cons_printf ("Enter assembler opcodes separated with ';':\n"); showcursor (core, R_TRUE); r_cons_flush (); r_cons_set_raw (R_FALSE); strcpy (buf, "wa "); r_line_set_prompt (":> "); if (r_cons_fgets (buf+3, 1000, 0, NULL) <0) buf[0]='\0'; if (*buf) { if (curset) r_core_seek (core, core->offset + cursor, 0); r_core_cmd (core, buf, R_TRUE); if (curset) r_core_seek (core, core->offset - cursor, 1); } showcursor (core, R_FALSE); r_cons_set_raw (R_TRUE); break; case '!': r_cons_2048(); break; case 'o': visual_offset (core); break; case 'A': { int oc = curset; ut64 off = curset? core->offset+cursor : core->offset; curset = 0; r_core_visual_asm (core, off); curset = oc; } break; case 'c': setcursor (core, curset?0:1); break; case 'C': color = color? 0: 1; r_config_set_i (core->config, "scr.color", color); break; case 'd': r_core_visual_define (core); break; case 'D': setdiff (core); break; case 'f': { int range, min, max; char name[256], *n; r_line_set_prompt ("flag name: "); showcursor (core, R_TRUE); if (r_cons_fgets (name, sizeof (name), 0, NULL) >=0 && *name) { n = r_str_chop (name); if (*name=='-') { if (*n) r_flag_unset (core->flags, n+1, NULL); } else { if (ocursor != -1) { min = R_MIN (cursor, ocursor); max = R_MAX (cursor, ocursor); } else { min = max = cursor; } range = max-min+1; if (range<1) range = 1; if (*n) r_flag_set (core->flags, n, core->offset + min, range, 1); } } } showcursor (core, R_FALSE); break; case 'F': r_flag_unset_i (core->flags, core->offset + cursor, NULL); break; case 'n': r_core_seek_next (core, r_config_get (core->config, "scr.nkey")); break; case 'N': r_core_seek_previous (core, r_config_get (core->config, "scr.nkey")); break; case 'i': case 'I': if (core->file && !(core->file->rwx & 2)) { r_cons_printf ("\nFile has been opened in read-only mode. Use -w flag\n"); r_cons_any_key (); return R_TRUE; } showcursor (core, R_TRUE); r_cons_flush (); r_cons_set_raw (0); if (ch=='I') { strcpy (buf, "wow "); r_line_set_prompt ("insert hexpair block: "); if (r_cons_fgets (buf+4, sizeof (buf)-5, 0, NULL) <0) buf[0]='\0'; char *p = strdup (buf); int cur = core->print->cur; if (cur>=core->blocksize) cur = core->print->cur-1; snprintf (buf, sizeof (buf), "%s @ $$0!%i", p, core->blocksize-cursor); r_core_cmd (core, buf, 0); free (p); break; } delta = (ocursor!=-1)? R_MIN (cursor, ocursor): cursor; if (core->print->col==2) { strcpy (buf, "\"w "); r_line_set_prompt ("insert string: "); if (r_cons_fgets (buf+3, sizeof (buf)-4, 0, NULL) <0) buf[0]='\0'; strcat (buf, "\""); } else { r_line_set_prompt ("insert hex: "); if (ocursor != -1) { int bs = R_ABS (cursor-ocursor)+1; core->blocksize = bs; strcpy (buf, "wow "); } else { strcpy (buf, "wx "); } if (r_cons_fgets (buf+strlen (buf), sizeof (buf)-strlen (buf), 0, NULL) <0) buf[0]='\0'; } if (curset) r_core_seek (core, core->offset + delta, 0); r_core_cmd (core, buf, 1); if (curset) r_core_seek (core, offset, 1); r_cons_set_raw (1); showcursor (core, R_FALSE); break; case 'R': r_core_cmd0 (core, "ecr"); break; case 'e': r_core_visual_config (core); break; case 'E': r_core_visual_colors (core); break; case 'M': r_core_visual_mounts (core); break; case 't': r_core_visual_trackflags (core); break; case 'x': { int count = 0; RList *xrefs = NULL; RAnalRef *refi; RListIter *iter; RAnalFunction *fun; if ((xrefs = r_anal_xref_get (core->anal, core->offset))) { r_cons_gotoxy (1, 1); r_cons_printf ("[GOTO XREF]> \n"); if (r_list_empty (xrefs)) { r_cons_printf ("\tNo XREF found at 0x%"PFMT64x"\n", core->offset); r_cons_any_key (); r_cons_clear00 (); } else { r_list_foreach (xrefs, iter, refi) { fun = r_anal_fcn_find (core->anal, refi->addr, R_ANAL_FCN_TYPE_NULL); r_cons_printf (" [%i] 0x%08"PFMT64x" %s XREF 0x%08"PFMT64x" (%s) \n", count, refi->at, refi->type==R_ANAL_REF_TYPE_CODE?"CODE (JMP)": refi->type==R_ANAL_REF_TYPE_CALL?"CODE (CALL)":"DATA", refi->addr, fun?fun->name:"unk"); if (++count > 9) break; } } } else xrefs = NULL;
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); }