/* radare - LGPL - Copyright 2009-2016 - pancake */ #include #include "r_cons.h" #include "r_core.h" #include "r_util.h" static const char* findBreakChar(const char *s) { while (*s) { if (!r_name_validate_char (*s)) break; s++; } return s; } static char *filter_flags(RCore *core, const char *msg) { const char *dollar, *end; char *word, *buf = NULL; for (;;) { dollar = strchr (msg, '$'); if (!dollar) break; buf = r_str_concatlen (buf, msg, dollar-msg); if (dollar[1]=='{') { // find } end = strchr (dollar+2, '}'); if (end) { word = r_str_newlen (dollar+2, end-dollar-2); end++; } else { msg = dollar+1; buf = r_str_concat (buf, "$"); continue; } } else { end = findBreakChar (dollar+1); if (!end) end = dollar+strlen (dollar); word = r_str_newlen (dollar+1, end-dollar-1); } if (end && word) { ut64 val = r_num_math (core->num, word); char num[32]; snprintf (num, sizeof (num), "0x%"PFMT64x, val); //item->offset); buf = r_str_concat (buf, num); msg = end; } else break; free (word); } buf = r_str_concat (buf, msg); return buf; } static void clippy(const char *msg) { int msglen = strlen (msg); char *l = strdup (r_str_pad ('-', msglen)); char *s = strdup (r_str_pad (' ', msglen)); r_cons_printf ( " .--. .-%s-.\n" " | _| | %s |\n" " | O O < %s |\n" " | | | | %s |\n" " || | / `-%s-'\n" " |`-'|\n" " `---'\n", l, s, msg, s, l); free (l); free (s); } static int cmd_help(void *data, const char *input) { RCore *core = (RCore *)data; const char *k; char *p, out[128] = {0}; ut64 n, n2; int i; RList *tmp; switch (input[0]) { case '0': core->curtab = 0; break; case '1': if (core->curtab < 0) core->curtab = 0; core->curtab ++; break; case ':': { RListIter *iter; RCorePlugin *cp; if (input[1]=='?') { const char* help_msg[] = { "Usage:", ":[plugin] [args]", "", ":", "", "list RCore plugins", ":java", "", "run java plugin", NULL}; r_core_cmd_help (core, help_msg); return 0; } if (input[1]) return r_core_cmd0 (core, input+1); r_list_foreach (core->rcmd->plist, iter, cp) { r_cons_printf ("%s: %s\n", cp->name, cp->desc); } } break; case 'r': { // TODO : Add support for 64bit random numbers ut64 b = 0; ut32 r = UT32_MAX; if (input[1]) { strncpy (out, input+(input[1]==' '? 2: 1), sizeof (out)-1); p = strchr (out+1, ' '); if (p) { *p = 0; b = (ut32)r_num_math (core->num, out); r = (ut32)r_num_math (core->num, p+1)-b; } else r = (ut32)r_num_math (core->num, out); } else r = 0LL; if (r == 0) r = UT32_MAX>>1; core->num->value = (ut64) (b + r_num_rand (r)); r_cons_printf ("0x%"PFMT64x"\n", core->num->value); } break; case 'b': if (input[1] == '6' && input[2] == '4') { //b64 decoding takes at most strlen(str) * 4 const int buflen = (strlen (input+3) * 4) + 1; char* buf = calloc (buflen, sizeof(char)); if (!buf) return false; if (input[3] == '-') r_base64_decode ((ut8*)buf, input+5, strlen (input+5)); else r_base64_encode (buf, (const ut8*)input+4, strlen (input+4)); r_cons_println (buf); free (buf); } else { n = r_num_get (core->num, input+1); r_num_to_bits (out, n); r_cons_printf ("%sb\n", out); } break; case 'B': k = r_str_chop_ro (input+1); tmp = r_core_get_boundaries (core, k, &n, &n2); r_cons_printf ("0x%"PFMT64x" 0x%"PFMT64x"\n", n, n2); r_list_free (tmp); break; case 'd': if (input[1]=='.'){ int cur = R_MAX(core->print->cur, 0); // XXX: we need cmd_xxx.h (cmd_anal.h) core_anal_bytes(core, core->block + cur, core->blocksize, 1, 'd'); } else if (input[1]==' '){ char *d = r_asm_describe (core->assembler, input+2); if (d && *d) { r_cons_println (d); free (d); } else eprintf ("Unknown opcode\n"); } else eprintf ("Use: ?d[.] [opcode] to get the description of the opcode\n"); break; case 'h': if (input[1]==' ') { r_cons_printf ("0x%08x\n", (ut32)r_str_hash (input+2)); } else eprintf ("Usage: ?h [string-to-hash]\n"); break; case 'y': for (input++; input[0]==' '; input++); if (*input) { r_core_yank_set_str (core, R_CORE_FOREIGN_ADDR, input, strlen (input)+1); } else { r_core_yank_cat (core, 0); } break; case 'F': r_cons_flush (); break; case 'f': if (input[1]==' ') { char *q, *p = strdup (input+2); if (!p) { eprintf ("Cannot strdup\n"); return 0; } q = strchr (p, ' '); if (q) { *q = 0; n = r_num_get (core->num, p); r_str_bits (out, (const ut8*)&n, sizeof (n) * 8, q+1); r_cons_println (out); } else eprintf ("Usage: \"?b value bitstring\"\n"); free (p); } else eprintf ("Whitespace expected after '?f'\n"); break; case 'o': n = r_num_math (core->num, input+1); r_cons_printf ("0%"PFMT64o"\n", n); break; case 'T': r_cons_printf("plug.init = %"PFMT64d"\n" "plug.load = %"PFMT64d"\n" "file.load = %"PFMT64d"\n", core->times->loadlibs_init_time, core->times->loadlibs_time, core->times->file_open_time); break; case 'u': { char unit[32]; n = r_num_math (core->num, input+1); r_num_units (unit, n); r_cons_println (unit); } break; case ' ': { char *asnum, unit[32]; ut32 s, a; double d; float f; n = r_num_math (core->num, input + 1); if (core->num->dbz) { eprintf ("RNum ERROR: Division by Zero\n"); } asnum = r_num_as_string (NULL, n); /* decimal, hexa, octal */ s = n>>16<<12; a = n & 0x0fff; r_num_units (unit, n); r_cons_printf ("%"PFMT64d" 0x%"PFMT64x" 0%"PFMT64o " %s %04x:%04x ", n, n, n, unit, s, a); if (n>>32) r_cons_printf ("%"PFMT64d" ", (st64)n); else r_cons_printf ("%d ", (st32)n); if (asnum) { r_cons_printf ("\"%s\" ", asnum); free (asnum); } /* binary and floating point */ r_str_bits64 (out, n); f = d = core->num->fvalue; r_cons_printf ("%s %.01lf %ff %lf\n", out, core->num->fvalue, f, d); } break; case 'v': { const char *space = strchr (input, ' '); if (space) { n = r_num_math (core->num, space+1); } else { n = r_num_math (core->num, "$?"); } } if (core->num->dbz) { eprintf ("RNum ERROR: Division by Zero\n"); } switch (input[1]) { case '?': r_cons_printf ("|Usage: ?v[id][ num] # Show value\n" "|?vi1 200 -> 1 byte size value (char)\n" "|?vi2 0xffff -> 2 byte size value (short)\n" "|?vi4 0xffff -> 4 byte size value (int)\n" "|?vi8 0xffff -> 8 byte size value (st64)\n" "| No argument shows $? value\n" "|?vi will show in decimal instead of hex\n"); break; case '\0': r_cons_printf ("%d\n", (st32)n); break; case 'i': // "?vi" switch (input[2]) { case '1': // byte r_cons_printf ("%d\n", (st8)(n & UT8_MAX)); break; case '2': // word r_cons_printf ("%d\n", (st16)(n & UT16_MAX)); break; case '4': // dword r_cons_printf ("%d\n", (st32)(n & UT32_MAX)); break; case '8': // qword r_cons_printf ("%"PFMT64d"\n", (st64)(n & UT64_MAX)); break; default: r_cons_printf ("%"PFMT64d"\n", n); break; } break; case 'd': r_cons_printf ("%"PFMT64d"\n", n); break; default: r_cons_printf ("0x%"PFMT64x"\n", n); } core->num->value = n; // redundant break; case '=': // set num->value if (input[1]) { r_num_math (core->num, input+1); } else r_cons_printf ("0x%"PFMT64x"\n", core->num->value); break; case '+': if (input[1]) { st64 n = (st64)core->num->value; if (n>0) r_core_cmd (core, input+1, 0); } else r_cons_printf ("0x%"PFMT64x"\n", core->num->value); break; case '-': if (input[1]) { st64 n = (st64)core->num->value; if (n<0) r_core_cmd (core, input+1, 0); } else r_cons_printf ("0x%"PFMT64x"\n", core->num->value); break; case '!': // "?!" if (input[1]) { if (!core->num->value) { if (input[1] == '?') { r_core_sysenv_help (core); return 0; } else { return core->num->value = r_core_cmd (core, input+1, 0); } } } else r_cons_printf ("0x%"PFMT64x"\n", core->num->value); break; case '@': { const char* help_msg[] = { "Usage: [.][#][*] [`cmd`] [@ addr] [~grep] [|syscmd] [>[>]file]", "", "", "0", "", "alias for 's 0'", "0x", "addr", "alias for 's 0x..'", "#", "cmd", "if # is a number repeat the command # times", "/*", "", "start multiline comment", "*/", "", "end multiline comment", ".", "cmd", "execute output of command as r2 script", ".:", "8080", "wait for commands on port 8080", ".!", "rabin2 -re $FILE", "run command output as r2 script", "*", "", "output of command in r2 script format (CC*)", "j", "", "output of command in JSON format (pdj)", "~", "?", "count number of lines (like wc -l)", "~", "??", "show internal grep help", "~", "..", "internal less", "~", "{}", "json indent", "~", "{}..", "json indent and less", "~", "word", "grep for lines matching word", "~", "!word", "grep for lines NOT matching word", "~", "word[2]", "grep 3rd column of lines matching word", "~", "word:3[0]", "grep 1st column from the 4th line matching word", "@", " 0x1024", "temporary seek to this address (sym.main+3)", "@", " addr[!blocksize]", "temporary set a new blocksize", "@a:", "arch[:bits]", "temporary set arch and bits", "@b:", "bits", "temporary set asm.bits", "@e:", "k=v,k=v", "temporary change eval vars", "@r:", "reg", "tmp seek to reg value (f.ex pd@r:PC)", "@f:", "file", "temporary replace block with file contents", "@o:", "fd", "temporary switch to another fd", "@s:", "string", "same as above but from a string", "@x:", "909192", "from hex pairs string", "@..", "from to", "temporary set from and to for commands supporting ranges", "@@=", "1 2 3", "run the previous command at offsets 1, 2 and 3", "@@", " hit*", "run the command on every flag matching 'hit*'", "@@?", "[ktfb..]", "show help for the iterator operator", "@@@", " [type]", "run a command on every [type] (see @@@? for help)", ">", "file", "pipe output of command to file", ">>", "file", "append to file", "`", "pdi~push:0[0]`", "replace output of command inside the line", "|", "cmd", "pipe output to command (pd|less) (.dr*)", NULL}; r_core_cmd_help (core, help_msg); return 0; } case '$': if (input[1] == '?') { const char* help_msg[] = { "Usage: ?v [$.]","","", "$$", "", "here (current virtual seek)", "$?", "", "last comparison value", "$alias", "=value", "Alias commands (simple macros)", "$b", "", "block size", "$B", "", "base address (aligned lowest map address)", "$F", "", "current function size", "$FB", "", "begin of function", "$Fb", "", "address of the current basic block", "$Fs", "", "size of the current basic block", "$FE", "", "end of function", "$FS", "", "function size", "$FI", "", "function instructions", "$c,$r", "", "get width and height of terminal", "$Cn", "", "get nth call of function", "$Dn", "", "get nth data reference in function", "$D", "", "current debug map base address ?v $D @ rsp", "$DD", "", "current debug map size", "$e", "", "1 if end of block, else 0", "$f", "", "jump fail address (e.g. jz 0x10 => next instruction)", "$j", "", "jump address (e.g. jmp 0x10, jz 0x10 => 0x10)", "$Ja", "", "get nth jump of function", "$Xn", "", "get nth xref of function", "$l", "", "opcode length", "$m", "", "opcode memory reference (e.g. mov eax,[0x10] => 0x10)", "$M", "", "map address (lowest map address)", "$o", "", "here (current disk io offset)", "$p", "", "getpid()", "$P", "", "pid of children (only in debug)", "$s", "", "file size", "$S", "", "section offset", "$SS", "", "section size", "$v", "", "opcode immediate value (e.g. lui a0,0x8010 => 0x8010)", "$w", "", "get word size, 4 if asm.bits=32, 8 if 64, ...", "${ev}", "", "get value of eval config variable", "$k{kv}", "", "get value of an sdb query value", "RNum", "", "$variables usable in math expressions", NULL}; r_core_cmd_help (core, help_msg); } else { int i = 0; const char *vars[] = { "$$", "$?", "$b", "$B", "$F", "$FB", "$Fb", "$Fs", "$FE", "$FS", "$FI", "$c", "$r", "$D", "$DD", "$e", "$f", "$j", "$Ja", "$l", "$m", "$M", "$o", "$p", "$P", "$s", "$S", "$SS", "$v", "$w", NULL }; while (vars[i]) { const char *pad = r_str_pad (' ', 6 - strlen (vars[i])); eprintf ("%s %s 0x%08"PFMT64x"\n", vars[i], pad, r_num_math (core->num, vars[i])); i++; } } return true; case 'V': switch (input[1]) { case '?': { const char* help_msg[] = { "Usage: ?V[jq]","","", "?V", "", "show version information", "?Vj", "", "same as above but in JSON", "?Vq", "", "quiet mode, just show the version number", NULL}; r_core_cmd_help (core, help_msg); } break; case 0: if (!strcmp (R2_VERSION, R2_GITTAP)) { r_cons_printf ("%s %d\n", R2_VERSION, R2_VERSION_COMMIT); } else { r_cons_printf ("%s aka %s commit %d\n", R2_VERSION, R2_GITTAP, R2_VERSION_COMMIT); } break; case 'j': r_cons_printf ("{\"system\":\"%s-%s\"", R_SYS_OS, R_SYS_ARCH); r_cons_printf (",\"version\":\"%s\"}\n", R2_VERSION); break; case 'q': r_cons_println (R2_VERSION); break; } break; case 'l': for (input++; input[0]==' '; input++); core->num->value = strlen (input); break; case 'X': for (input++; input[0]==' '; input++); n = r_num_math (core->num, input); r_cons_printf ("%"PFMT64x"\n", n); break; case 'x': for (input++; input[0]==' '; input++); if (*input=='-') { ut8 *out = malloc (strlen (input)+1); int len = r_hex_str2bin (input+1, out); out[len] = 0; r_cons_println ((const char*)out); free (out); } else if (!strncmp (input, "0x", 2) || (*input>='0' && *input<='9')) { ut64 n = r_num_math (core->num, input); int bits = r_num_to_bits (NULL, n) / 8; for (i=0; i>(i*8)) &0xff)); r_cons_newline (); } else { for (i=0; input[i]; i++) r_cons_printf ("%02x", input[i]); r_cons_newline (); } break; case 'E': // clippy echo clippy (r_str_chop_ro (input+1)); break; case 'e': // echo { const char *msg = r_str_chop_ro (input+1); // TODO: replace all ${flagname} by its value in hexa char *newmsg = filter_flags (core, msg); r_str_unescape (newmsg); r_cons_println (newmsg); free (newmsg); } break; case 's': // sequence from to step { ut64 from, to, step; char *p, *p2; for (input++; *input==' '; input++); p = strchr (input, ' '); if (p) { *p = '\0'; from = r_num_math (core->num, input); p2 = strchr (p+1, ' '); if (p2) { *p2 = '\0'; step = r_num_math (core->num, p2+1); } else step = 1; to = r_num_math (core->num, p+1); for (;from<=to; from+=step) r_cons_printf ("%"PFMT64d" ", from); r_cons_newline (); } } break; case 'P': if (core->io->va) { ut64 o, n = (input[0] && input[1])? r_num_math (core->num, input+2): core->offset; o = r_io_section_maddr_to_vaddr (core->io, n); r_cons_printf ("0x%08"PFMT64x"\n", o); } else eprintf ("io.va is false\n"); break; case 'p': if (core->io->va) { // physical address ut64 o, n = (input[0] && input[1])? r_num_math (core->num, input+2): core->offset; o = r_io_section_vaddr_to_maddr (core->io, n); r_cons_printf ("0x%08"PFMT64x"\n", o); } else eprintf ("Virtual addresses not enabled!\n"); break; case 'S': { // section name RIOSection *s; ut64 n = (input[0] && input[1])? r_num_math (core->num, input+2): core->offset; n = r_io_section_vaddr_to_maddr_try (core->io, n); s = r_io_section_mget_in (core->io, n); if (s && *(s->name)) { r_cons_println (s->name); } break; } case '_': // hud input r_core_yank_hud_file (core, input+1); break; case 'i': // "?i" input num r_cons_set_raw(0); if (!r_config_get_i (core->config, "scr.interactive")) { eprintf ("Not running in interactive mode\n"); } else switch (input[1]) { case 'f': // "?if" core->num->value = !r_num_conditional (core->num, input+2); eprintf ("%s\n", r_str_bool (!core->num->value)); break; case 'm': r_cons_message (input+2); break; case 'p': { core->num->value = r_core_yank_hud_path (core, input+2, 0) == true; } break; case 'k': // "?ik" r_cons_any_key (NULL); break; case 'y': // "?iy" for (input+=2; *input==' '; input++); core->num->value = r_cons_yesno (1, "%s? (Y/n)", input); break; case 'n': // "?in" for (input+=2; *input==' '; input++); core->num->value = r_cons_yesno (0, "%s? (y/N)", input); break; default: { char foo[1024]; r_cons_flush (); for (input++; *input==' '; input++); // TODO: r_cons_input() snprintf (foo, sizeof (foo) - 1, "%s: ", input); r_line_set_prompt (foo); r_cons_fgets (foo, sizeof (foo)-1, 0, NULL); foo[strlen (foo)] = 0; r_core_yank_set_str (core, R_CORE_FOREIGN_ADDR, foo, strlen (foo) + 1); core->num->value = r_num_math (core->num, foo); } break; } r_cons_set_raw (0); break; case 'w': { ut64 addr = r_num_math (core->num, input + 1); const char *rstr = core->print->hasrefs (core->print->user, addr); r_cons_println (rstr); } break; case 't': { struct r_prof_t prof; r_prof_start (&prof); r_core_cmd (core, input+1, 0); r_prof_end (&prof); core->num->value = (ut64)(int)prof.result; eprintf ("%lf\n", prof.result); } break; case '?': // ??? if (input[1]=='?') { if (input[2]=='?') { clippy ("What are you doing?"); return 0; } if (input[2]) { if (core->num->value) r_core_cmd (core, input+1, 0); break; } const char* help_msg[] = { "Usage: ?[?[?]] expression", "", "", "?", " eip-0x804800", "show hex and dec result for this math expr", "?:", "", "list core cmd plugins", "?!", " [cmd]", "? != 0", "?+", " [cmd]", "? > 0", "?-", " [cmd]", "? < 0", "?=", " eip-0x804800", "hex and dec result for this math expr", "??", "", "show value of operation", "??", " [cmd]", "? == 0 run command when math matches", "?B", " [elem]", "show range boundaries like 'e?search.in", "?P", " paddr", "get virtual address for given physical one", "?S", " addr", "return section name of given address", "?T", "", "show loading times", "?V", "", "show library version of r_core", "?X", " num|expr", "returns the hexadecimal value numeric expr", "?_", " hudfile", "load hud menu with given file", "?b", " [num]", "show binary value of number", "?b64[-]", " [str]", "encode/decode in base64", "?d[.]", " opcode", "describe opcode for asm.arch", "?e", " string", "echo string", "?f", " [num] [str]", "map each bit of the number as flag string index", "?h", " [str]", "calculate hash for given string", "?i", "[ynmkp] arg", "prompt for number or Yes,No,Msg,Key,Path and store in $$?", "?ik", "", "press any key input dialog", "?im", " message", "show message centered in screen", "?in", " prompt", "noyes input prompt", "?iy", " prompt", "yesno input prompt", "?l", " str", "returns the length of string", "?o", " num", "get octal value", "?p", " vaddr", "get physical address for given virtual address", "?r", " [from] [to]", "generate random number between from-to", "?s", " from to step", "sequence of numbers from to by steps", "?t", " cmd", "returns the time to run a command", "?u", " num", "get value in human units (KB, MB, GB, TB)", "?v", " eip-0x804800", "show hex value of math expr", "?vi", " rsp-rbp", "show decimal value of math expr", "?w", " addr", "show what's in this address (like pxr/pxq does)", "?x", " num|str|-hexst", "returns the hexpair of number or string", "?y", " [str]", "show contents of yank buffer, or set with string", NULL}; r_core_cmd_help (core, help_msg); return 0; } else if (input[1]) { if (core->num->value) { core->num->value = r_core_cmd (core, input+1, 0); } } else { if (core->num->dbz) { eprintf ("RNum ERROR: Division by Zero\n"); } r_cons_printf ("%"PFMT64d"\n", core->num->value); } break; case '\0': default:{ const char* help_message[] = { "%var", "=value", "Alias for 'env' command", "*", "off[=[0x]value]", "Pointer read/write data/values (see ?v, wx, wv)", "(macro arg0 arg1)", "", "Manage scripting macros", ".", "[-|(m)|f|!sh|cmd]", "Define macro or load r2, cparse or rlang file", "="," [cmd]", "Run this command via rap://", "/","", "Search for bytes, regexps, patterns, ..", "!"," [cmd]", "Run given command as in system(3)", "#"," [algo] [len]", "Calculate hash checksum of current block", "#","!lang [..]", "Hashbang to run an rlang script", "a","", "Perform analysis of code", "b","", "Get or change block size", "c"," [arg]", "Compare block with given data", "C","", "Code metadata management", "d","", "Debugger commands", "e"," [a[=b]]", "List/get/set config evaluable vars", "f"," [name][sz][at]", "Set flag at current address", "g"," [arg]", "Go compile shellcodes with r_egg", "i"," [file]", "Get info about opened file", "k"," [sdb-query]", "Run sdb-query. see k? for help, 'k *', 'k **' ...", "m","", "Mountpoints commands", "o"," [file] ([offset])", "Open file at optional address", "p"," [len]", "Print current block with format and length", "P","", "Project management utilities", "q"," [ret]", "Quit program with a return value", "r"," [len]", "Resize file", "s"," [addr]", "Seek to address (also for '0x', '0x1' == 's 0x1')", "S","", "Io section manipulation information", "t","", "Cparse types management", "T"," [-] [num|msg]", "Text log utility", "u","", "uname/undo seek/write", "V","", "Enter visual mode (vcmds=visualvisual keystrokes)", "w"," [str]", "Multiple write operations", "x"," [len]", "Alias for 'px' (print hexadecimal)", "y"," [len] [[[@]addr", "Yank/paste bytes from/to memory", "z", "", "Zignatures management", "?[??]","[expr]", "Help or evaluate math expression", "?$?", "", "Show available '$' variables and aliases", "?@?", "", "Misc help for '@' (seek), '~' (grep) (see ~?""?)", "?:?", "", "List and manage core plugins", NULL }; r_cons_printf("Usage: [.][times][cmd][~grep][@[@iter]addr!size][|>pipe] ; ...\n" "Append '?' to any char command to get detailed help\n" "Prefix with number to repeat command N times (f.ex: 3x)\n"); r_core_cmd_help (core, help_message); } break; } return 0; }