/* radare - LGPL - Copyright 2009-2013 - pancake */ static int preludecnt = 0; static int searchflags = 0; static int searchshow = 0; static int searchhits = 0; static const char *cmdhit = NULL; static const char *searchprefix = NULL; static unsigned int searchcount = 0; static int __prelude_cb_hit(RSearchKeyword *kw, void *user, ut64 addr) { RCore *core = (RCore *)user; int depth = r_config_get_i (core->config, "anal.depth"); //eprintf ("ap: Found function prelude %d at 0x%08"PFMT64x"\n", preludecnt, addr); searchhits ++; //= kw->count+1; r_core_anal_fcn (core, addr, -1, R_ANAL_REF_TYPE_NULL, depth); preludecnt++; return R_TRUE; } R_API int r_core_search_prelude(RCore *core, ut64 from, ut64 to, const ut8 *buf, int blen, const ut8 *mask, int mlen) { int ret; ut64 at; ut8 *b = (ut8 *)malloc (core->blocksize); // TODO: handle sections ? r_search_reset (core->search, R_SEARCH_KEYWORD); r_search_kw_add (core->search, r_search_keyword_new (buf, blen, mask, mlen, NULL)); r_search_begin (core->search); r_search_set_callback (core->search, &__prelude_cb_hit, core); preludecnt = 0; for (at = from; at < to; at += core->blocksize) { if (r_cons_singleton ()->breaked) break; ret = r_io_read_at (core->io, at, b, core->blocksize); if (ret != core->blocksize) break; if (r_search_update (core->search, &at, b, ret) == -1) { eprintf ("search: update read error at 0x%08"PFMT64x"\n", at); break; } } eprintf ("Analized %d functions based on preludes\n", preludecnt); free (b); return preludecnt; } R_API int r_core_search_preludes(RCore *core) { int ret = -1; const char *prelude = r_config_get (core->config, "anal.prelude"); const char *arch = r_config_get (core->config, "asm.arch"); int bits = r_config_get_i (core->config, "asm.bits"); ut64 from = core->offset; ut64 to = core->offset+0xffffff; // hacky! // TODO: this is x86 only if (prelude && *prelude) { ut8 *kw = malloc (strlen (prelude)); int kwlen = r_hex_str2bin (prelude, kw); ret = r_core_search_prelude (core, from, to, kw, kwlen, NULL, 0); free (kw); } else if (strstr (arch, "mips")) { ret = r_core_search_prelude (core, from, to, (const ut8 *)"\x27\xbd\x00", 3, NULL, 0); } else if (strstr (arch, "x86")) { switch (bits) { case 32: ret = r_core_search_prelude (core, from, to, (const ut8 *)"\x55\x89\xe5", 3, NULL, 0); break; case 64: ret = r_core_search_prelude (core, from, to, (const ut8 *)"\x55\x48\x89\xe5", 3, NULL, 0); //r_core_cmd0 (core, "./x 554989e5"); break; default: eprintf ("ap: Unsupported bits: %d\n", bits); } } else eprintf ("ap: Unsupported asm.arch and asm.bits\n"); return ret; } static int __cb_hit(RSearchKeyword *kw, void *user, ut64 addr) { RCore *core = (RCore *)user; searchhits ++ ;///= kw->count+1; if (searchcount) { if (!--searchcount) { //eprintf ("\nsearch stop: search.count reached\n"); return R_FALSE; } } if (searchshow) { int len, i; ut8 buf[64]; char str[128], *p; switch (kw->type) { case R_SEARCH_KEYWORD_TYPE_STRING: len = sizeof (str); r_core_read_at (core, addr, (ut8*)str+1, len-2); *str = '"'; r_str_filter_zeroline (str, len); strcpy (str+strlen (str), "\""); break; default: len = kw->keyword_length + 8; // 8 byte context if (len>=sizeof (str)) len = sizeof (str)-1; r_core_read_at (core, addr, buf, sizeof (buf)); for (i=0, p=str; ikwidx, kw->count, str); } else { if (searchflags) r_cons_printf ("%s%d_%d\n", searchprefix, kw->kwidx, kw->count); else r_cons_printf ("f %s%d_%d %d 0x%08"PFMT64x"\n", searchprefix, kw->kwidx, kw->count, kw->keyword_length, addr); } if (searchflags) { char flag[64]; snprintf (flag, sizeof (flag), "%s%d_%d", searchprefix, kw->kwidx, kw->count); r_flag_set (core->flags, flag, addr, kw->keyword_length, 1); } if (!strnull (cmdhit)) { ut64 here = core->offset; r_core_seek (core, addr, R_FALSE); r_core_cmd (core, cmdhit, 0); r_core_seek (core, here, R_TRUE); } return R_TRUE; } static int c = 0; static inline void print_search_progress(ut64 at, ut64 to, int n) { if ((++c%64)) return; eprintf ("\r[ ] 0x%08"PFMT64x" < 0x%08"PFMT64x" hits = %d \r%s", at, to, n, (c%2)?"[ #]":"[# ]"); } R_API void r_core_get_boundaries (RCore *core, const char *mode, ut64 *from, ut64 *to) { if (!strcmp (mode, "block")) { *from = core->offset; *to = core->offset + core->blocksize; } else if (!strcmp (mode, "file")) { if (core->io->va) { RListIter *iter; RIOSection *s; *from = *to = core->offset; r_list_foreach (core->io->sections, iter, s) { if (((s->vaddr) < *from) && s->vaddr) *from = s->vaddr; if ((s->vaddr+s->size) > *to && *from>=s->vaddr) *to = s->vaddr+s->size; } if (*to == 0LL || *to == UT64_MAX || *to == UT32_MAX) *to = r_io_size (core->io); } else { RIOMap *map = r_io_map_get (core->io, core->offset); *from = core->offset; *to = r_io_size (core->io) + (map? map->to:0); } } else if (!strcmp (mode, "section")) { if (core->io->va) { RListIter *iter; RIOSection *s; *from = *to = core->offset; r_list_foreach (core->io->sections, iter, s) { if (*from >= s->vaddr && *from < (s->vaddr+s->size)) { *to = s->vaddr+s->size; break; } } } else { *from = core->offset; *to = r_io_size (core->io); } } else { //if (!strcmp (mode, "raw")) { /* obey temporary seek if defined '/x 8080 @ addr:len' */ if (core->tmpseek) { *from = core->offset; *to = core->offset + core->blocksize; } else { // TODO: repeat last search doesnt works for /a *from = r_config_get_i (core->config, "search.from"); if (*from == UT64_MAX) *from = core->offset; *to = r_config_get_i (core->config, "search.to"); if (*to == UT64_MAX) { if (core->io->va) { /* TODO: section size? */ } else { *to = core->file->size; } } } } } static int cmd_search(void *data, const char *input) { int i, len, ret, dosearch = R_FALSE; RCore *core = (RCore *)data; int aes_search = R_FALSE; int ignorecase = R_FALSE; int inverse = R_FALSE; ut64 at, from, to; const char *mode; char *inp; ut64 n64, __from, __to; ut32 n32; ut16 n16; ut8 *buf; c = 0; __from = r_config_get_i (core->config, "search.from"); __to = r_config_get_i (core->config, "search.to"); searchshow = r_config_get_i (core->config, "search.show"); mode = r_config_get (core->config, "search.in"); r_core_get_boundaries (core, mode, &from, &to); if (__from != UT64_MAX) from = __from; if (__to != UT64_MAX) to = __to; if (__to < __from) { eprintf ("Invalid search range. Check 'e search.{from|to}'\n"); return R_FALSE; } core->search->align = r_config_get_i (core->config, "search.align"); searchflags = r_config_get_i (core->config, "search.flags"); //TODO: handle section ranges if from&&to==0 /* section = r_io_section_get (core->io, core->offset); if (section) { from += section->vaddr; //fin = ini + s->size; } */ searchprefix = r_config_get (core->config, "search.prefix"); // TODO: get ranges from current IO section /* XXX: Think how to get the section ranges here */ if (from == 0LL) from = core->offset; if (to == 0LL) to = UT32_MAX; // XXX? reread: switch (*input) { case '!': input++; inverse = R_TRUE; goto reread; break; case 'r': if (input[1]==' ') r_core_anal_search (core, from, to, r_num_math (core->num, input+2)); else r_core_anal_search (core, from, to, core->offset); break; case 'a': { char *kwd; if (!(kwd = r_core_asm_search (core, input+2, from, to))) return R_FALSE; r_search_reset (core->search, R_SEARCH_KEYWORD); r_search_set_distance (core->search, (int) r_config_get_i (core->config, "search.distance")); r_search_kw_add (core->search, r_search_keyword_new_hexmask (kwd, NULL)); r_search_begin (core->search); free (kwd); dosearch = R_TRUE; } break; case 'A': dosearch = aes_search = R_TRUE; break; case '/': r_search_begin (core->search); dosearch = R_TRUE; break; case 'm': dosearch = R_FALSE; if (input[1]==' ' || input[1]=='\0') { const char *file = input[1]? input+2: NULL; ut64 addr = from; r_cons_break (NULL, NULL); for (; addrbreaked) break; r_core_magic_at (core, file, addr, 99, R_FALSE); } r_cons_break_end (); } else eprintf ("Usage: /m [file]\n"); break; case 'p': { int ps = atoi (input+1); if (ps>1) { r_search_pattern_size (core->search, ps); r_search_pattern (core->search, from, to); } else eprintf ("Invalid pattern size (must be >0)\n"); } break; case 'v': r_search_reset (core->search, R_SEARCH_KEYWORD); r_search_set_distance (core->search, (int) r_config_get_i (core->config, "search.distance")); switch (input[1]) { case '?': eprintf ("Usage: /v[2|4|8] [value]\n"); return R_TRUE; case '8': n64 = r_num_math (core->num, input+2); r_search_kw_add (core->search, r_search_keyword_new ((const ut8*)&n64, 8, NULL, 0, NULL)); break; case '2': n16 = (ut16)r_num_math (core->num, input+2); r_search_kw_add (core->search, r_search_keyword_new ((const ut8*)&n16, 2, NULL, 0, NULL)); break; default: // default size case '4': n32 = (ut32)r_num_math (core->num, input+1); r_search_kw_add (core->search, r_search_keyword_new ((const ut8*)&n32, 4, NULL, 0, NULL)); break; } // TODO: Add support for /v4 /v8 /v2 r_search_begin (core->search); dosearch = R_TRUE; break; case 'w': /* search wide string */ if (input[1]==' ') { int len = strlen (input+2); const char *p2; char *p, *str = malloc ((len+1)*2); for (p2=input+2, p=str; *p2; p+=2, p2++) { p[0] = *p2; p[1] = 0; } r_search_reset (core->search, R_SEARCH_KEYWORD); r_search_set_distance (core->search, (int) r_config_get_i (core->config, "search.distance")); r_search_kw_add (core->search, r_search_keyword_new ((const ut8*)str, len*2, NULL, 0, NULL)); r_search_begin (core->search); dosearch = R_TRUE; } break; case 'i': if (input[1]!= ' ') { eprintf ("Missing ' ' after /i\n"); return R_FALSE; } ignorecase = R_TRUE; case ' ': /* search string */ inp = strdup (input+1+ignorecase); if (ignorecase) for (i=1; inp[i]; i++) inp[i] = tolower (inp[i]); len = r_str_escape (inp); eprintf ("Searching %d bytes from 0x%08"PFMT64x" to 0x%08"PFMT64x": ", len, from, to); for (i=0; isearch, R_SEARCH_KEYWORD); r_search_set_distance (core->search, (int) r_config_get_i (core->config, "search.distance")); { RSearchKeyword *skw; skw = r_search_keyword_new ((const ut8*)inp, len, NULL, 0, NULL); if (skw) { skw->icase = ignorecase; skw->type = R_SEARCH_KEYWORD_TYPE_STRING; r_search_kw_add (core->search, skw); } else { eprintf ("Invalid keyword\n"); } } r_search_begin (core->search); dosearch = R_TRUE; break; case 'e': /* match regexp */ { char *inp = strdup (input+2); char *res = r_str_lchr (inp+1, inp[0]); char *opt = NULL; if (res > inp) { opt = strdup (res+1); res[1]='\0'; } r_search_reset (core->search, R_SEARCH_REGEXP); r_search_set_distance (core->search, (int) r_config_get_i (core->config, "search.distance")); r_search_kw_add (core->search, r_search_keyword_new_str (inp, opt, NULL, 0)); r_search_begin (core->search); dosearch = R_TRUE; free (inp); free (opt); } break; case 'd': /* search delta key */ r_search_reset (core->search, R_SEARCH_DELTAKEY); r_search_kw_add (core->search, r_search_keyword_new_hexmask (input+2, NULL)); r_search_begin (core->search); dosearch = R_TRUE; break; case 'x': /* search hex */ r_search_reset (core->search, R_SEARCH_KEYWORD); r_search_set_distance (core->search, (int) r_config_get_i (core->config, "search.distance")); // TODO: add support for binmask here { char *s, *p = strdup (input+2); s = strchr (p, ' '); if (!s) s = strchr (p, ':'); if (s) { *s++ = 0; r_search_kw_add (core->search, r_search_keyword_new_hex (p, s, NULL)); } else { r_search_kw_add (core->search, r_search_keyword_new_hexmask (input+2, NULL)); } } r_search_begin (core->search); dosearch = R_TRUE; break; case 'c': /* search asm */ { RCoreAsmHit *hit; RListIter *iter; int count = 0; RList *hits; if ((hits = r_core_asm_strsearch (core, input+2, from, to))) { r_list_foreach (hits, iter, hit) { r_cons_printf ("f %s_%i @ 0x%08"PFMT64x" # %i: %s\n", searchprefix, count, hit->addr, hit->len, hit->code); count++; } r_list_destroy (hits); } dosearch = 0; } break; case 'z': /* search asm */ { char *p; ut32 min, max; if (!input[1]) { eprintf ("Usage: /z min max\n"); break; } if ((p = strchr (input+2, ' '))) { *p = 0; max = r_num_math (core->num, p+1); } else { eprintf ("Usage: /z min max\n"); break; } min = r_num_math (core->num, input+2); if (!r_search_set_string_limits (core->search, min, max)) { eprintf ("Error: min must be lower than max\n"); break; } r_search_reset (core->search, R_SEARCH_STRING); r_search_set_distance (core->search, (int) r_config_get_i (core->config, "search.distance")); r_search_kw_add (core->search, r_search_keyword_new_hexmask ("00", NULL)); //XXX r_search_begin (core->search); dosearch = R_TRUE; } break; default: r_cons_printf ( "Usage: /[amx/] [arg]\n" " / foo\\x00 ; search for string 'foo\\0'\n" " /w foo ; search for wide string 'f\\0o\\0o\\0'\n" " /! ff ; search for first occurrence not matching\n" " /i foo ; search for string 'foo' ignoring case\n" " /e /E.F/i ; match regular expression\n" " /x ff0033 ; search for hex string\n" " /x ff..33 ; search for hex string ignoring some nibbles\n" " /x ff43 ffd0 ; search for hexpair with mask\n" " /d 101112 ; search for a deltified sequence of bytes\n" " /!x 00 ; inverse hexa search (find first byte != 0x00)\n" " /c jmp [esp] ; search for asm code (see search.asmstr)\n" " /a jmp eax ; assemble opcode and search its bytes\n" " /A ; search for AES expanded keys\n" " /r sym.printf ; analyze opcode reference an offset\n" " /m magicfile ; search for matching magic file (use blocksize)\n" " /p patternsize ; search for pattern of given size\n" " /z min max ; search for strings of given size\n" " /v[?248] num ; look for a asm.bigendian 32bit value\n" " // ; repeat last search\n" " ./ hello ; search 'hello string' and import flags\n" "Configuration:\n" " e cmd.hit = x ; command to execute on every search hit\n" " e search.distance = 0 ; search string distance\n" " e search.in = [foo] ; boundaries to raw, block, file, section)\n" " e search.align = 4 ; only catch aligned search hits\n" " e search.from = 0 ; start address\n" " e search.to = 0 ; end address\n" " e search.asmstr = 0 ; search string instead of assembly\n" " e search.flags = true ; if enabled store flags on keyword hits\n"); break; } searchhits = 0; r_config_set_i (core->config, "search.kwidx", core->search->n_kws); if (dosearch) { if (!searchflags) r_cons_printf ("fs hits\n"); core->search->inverse = inverse; searchcount = r_config_get_i (core->config, "search.count"); if (searchcount) searchcount++; if (core->search->n_kws>0 || aes_search) { RSearchKeyword aeskw; if (aes_search) { memset (&aeskw, 0, sizeof (aeskw)); aeskw.keyword_length = 31; } /* set callback */ /* TODO: handle last block of data */ /* TODO: handle ^C */ /* TODO: launch search in background support */ // REMOVE OLD FLAGS r_core_cmdf (core, "f-%s*", r_config_get (core->config, "search.prefix")); buf = (ut8 *)malloc (core->blocksize); r_search_set_callback (core->search, &__cb_hit, core); cmdhit = r_config_get (core->config, "cmd.hit"); r_cons_break (NULL, NULL); // XXX required? imho nor_io_set_fd (core->io, core->file->fd); for (at = from; at < to; at += core->blocksize) { print_search_progress (at, to, searchhits); if (r_cons_singleton ()->breaked) { eprintf ("\n\n"); break; } //ret = r_core_read_at (core, at, buf, core->blocksize); // ret = r_io_read_at (core->io, at, buf, core->blocksize); r_io_seek (core->io, at, R_IO_SEEK_SET); ret = r_io_read (core->io, buf, core->blocksize); /* if (ignorecase) { int i; for (i=0; iblocksize; i++) buf[i] = tolower (buf[i]); } */ if (ret <1) break; if (aes_search) { int delta = r_search_aes_update (core->search, at, buf, ret); if (delta != -1) { if (!r_search_hit_new (core->search, &aeskw, at+delta)) { break; } aeskw.count++; } } else if (r_search_update (core->search, &at, buf, ret) == -1) { //eprintf ("search: update read error at 0x%08"PFMT64x"\n", at); break; } } print_search_progress (at, to, searchhits); r_cons_break_end (); free (buf); //r_cons_clear_line (); if (searchflags && searchcount>0) { eprintf ("hits: %d %s%d_0 .. %s%d_%d\n", searchhits, searchprefix, core->search->n_kws-1, searchprefix, core->search->n_kws-1, searchcount-1); } else eprintf ("hits: %d\n", searchhits); } else eprintf ("No keywords defined\n"); } return R_TRUE; }