Add R_SIGN_BYTES to metric search (#18703) ##signatures
This commit is contained in:
parent
0047d8ade8
commit
0657c1f100
|
@ -855,7 +855,7 @@ static int bb_sort_by_addr(const void *x, const void *y) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static RSignBytes *r_sign_fcn_bytes(RAnal *a, RAnalFunction *fcn) {
|
||||
static RSignBytes *r_sign_func_empty_mask(RAnal *a, RAnalFunction *fcn) {
|
||||
r_return_val_if_fail (a && fcn && fcn->bbs && fcn->bbs->head, false);
|
||||
|
||||
// get size
|
||||
|
@ -868,25 +868,26 @@ static RSignBytes *r_sign_fcn_bytes(RAnal *a, RAnalFunction *fcn) {
|
|||
|
||||
// alloc space for signature
|
||||
RSignBytes *sig = R_NEW0 (RSignBytes);
|
||||
if (!sig) {
|
||||
goto bytes_failed;
|
||||
if (sig) {
|
||||
sig->bytes = malloc (size);
|
||||
sig->mask = R_NEWS0 (ut8, size);
|
||||
sig->size = size;
|
||||
if (sig->bytes && sig->mask && a->iob.read_at (a->iob.io, ea, sig->bytes, size)) {
|
||||
return sig;
|
||||
}
|
||||
}
|
||||
if (!(sig->bytes = malloc (size))) {
|
||||
goto bytes_failed;
|
||||
}
|
||||
if (!(sig->mask = malloc (size))) {
|
||||
goto bytes_failed;
|
||||
}
|
||||
memset (sig->mask, 0, size);
|
||||
sig->size = size;
|
||||
r_sign_bytes_free (sig);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// fill in bytes
|
||||
if (!a->iob.read_at (a->iob.io, ea, sig->bytes, size)) {
|
||||
eprintf ("error: failed to read at 0x%08" PFMT64x "\n", ea);
|
||||
goto bytes_failed;
|
||||
}
|
||||
static RSignBytes *r_sign_fcn_bytes(RAnal *a, RAnalFunction *fcn) {
|
||||
r_return_val_if_fail (a && fcn && fcn->bbs && fcn->bbs->head, false);
|
||||
RSignBytes *sig = r_sign_func_empty_mask (a, fcn);
|
||||
|
||||
ut64 ea = fcn->addr;
|
||||
int size = sig->size;
|
||||
ut8 *tmpmask = NULL;
|
||||
RAnalBlock *bb;
|
||||
RListIter *iter;
|
||||
r_list_foreach (fcn->bbs, iter, bb) {
|
||||
if (bb->addr >= ea) {
|
||||
|
@ -903,7 +904,8 @@ static RSignBytes *r_sign_fcn_bytes(RAnal *a, RAnalFunction *fcn) {
|
|||
|
||||
// get mask for block
|
||||
if (!(tmpmask = r_anal_mask (a, rsize, sig->bytes + delta, ea))) {
|
||||
goto bytes_failed;
|
||||
r_sign_bytes_free (sig);
|
||||
return NULL;
|
||||
}
|
||||
if (rsize > 0) {
|
||||
memcpy (sig->mask + delta, tmpmask, rsize);
|
||||
|
@ -911,11 +913,7 @@ static RSignBytes *r_sign_fcn_bytes(RAnal *a, RAnalFunction *fcn) {
|
|||
free (tmpmask);
|
||||
}
|
||||
}
|
||||
|
||||
return sig;
|
||||
bytes_failed:
|
||||
r_sign_bytes_free (sig);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static RSignHash *r_sign_fcn_bbhash(RAnal *a, RAnalFunction *fcn) {
|
||||
|
@ -2200,7 +2198,7 @@ static int matchCount(int a, int b) {
|
|||
return R_ABS (c) < m;
|
||||
}
|
||||
|
||||
static int sig_graph_match(RSignItem *ia, RSignItem *ib) {
|
||||
static int sig_graph_diff(RSignItem *ia, RSignItem *ib) {
|
||||
RSignGraph *a = ia->graph;
|
||||
RSignGraph *b = ib->graph;
|
||||
if (!a || !b) {
|
||||
|
@ -2265,6 +2263,26 @@ static int sig_graph_cmp(RSignItem *ia, RSignItem *ib) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// this is to compare a byte signature to a function, that math is slightly
|
||||
// different
|
||||
static int sig_bytes_diff(RSignItem *isig, RSignItem *ifunc) {
|
||||
RSignBytes *sig = isig->bytes;
|
||||
RSignBytes *func = ifunc->bytes;
|
||||
r_return_val_if_fail (sig && func, 1);
|
||||
|
||||
if (sig->size != func->size) {
|
||||
return 1;
|
||||
}
|
||||
int i;
|
||||
for (i = 0; i < sig->size; i++) {
|
||||
char m = sig->mask[i];
|
||||
if (m && (sig->bytes[i] & m) != (func->bytes[i] & m)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sig_bytes_cmp(RSignItem *ia, RSignItem *ib) {
|
||||
RSignBytes *a = ia->bytes;
|
||||
RSignBytes *b = ib->bytes;
|
||||
|
@ -2338,8 +2356,10 @@ static int match_metrics(RSignItem *it, void *user) {
|
|||
RSignType types[7];
|
||||
int count = 0;
|
||||
|
||||
// only matching alg that is not a cmp, but true/false
|
||||
if (!sig_graph_match (it, fit)) {
|
||||
if (it->bytes && it->bytes->size >= sm->minsz && !sig_bytes_diff (it, fit)) {
|
||||
types[count++] = R_SIGN_BYTES;
|
||||
}
|
||||
if (it->graph && it->graph->cc >= sm->mincc && !sig_graph_diff (it, fit)) {
|
||||
types[count++] = R_SIGN_GRAPH;
|
||||
}
|
||||
if (fit->addr != UT64_MAX && !sig_addr_cmp (it->addr, fit->addr)) {
|
||||
|
@ -2455,7 +2475,7 @@ RSignSorter type_to_cmp(int type, bool exact) {
|
|||
switch (type) {
|
||||
case R_SIGN_GRAPH:
|
||||
if (exact) {
|
||||
return sig_graph_match;
|
||||
return sig_graph_diff;
|
||||
}
|
||||
return sig_graph_cmp;
|
||||
case R_SIGN_BYTES:
|
||||
|
@ -2549,11 +2569,17 @@ R_API int r_sign_fcn_match_metrics(RSignSearchMetrics *sm) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
RSignType t;
|
||||
while ((t = sm->types[i++]) != R_SIGN_END) {
|
||||
r_sign_addto_item (sm->anal, it, sm->fcn, t);
|
||||
RSignType *t = sm->types;
|
||||
while (*t != R_SIGN_END) {
|
||||
if (*t == R_SIGN_BYTES) {
|
||||
// no need for mask
|
||||
it->bytes = r_sign_func_empty_mask (sm->anal, sm->fcn);
|
||||
} else {
|
||||
r_sign_addto_item (sm->anal, it, sm->fcn, *t);
|
||||
}
|
||||
t++;
|
||||
}
|
||||
|
||||
if (it->graph && it->graph->cc < sm->mincc) {
|
||||
r_sign_graph_free (it->graph);
|
||||
it->graph = NULL;
|
||||
|
|
|
@ -38,8 +38,9 @@ static const char *help_msg_zb[] = {
|
|||
};
|
||||
|
||||
static const char *help_msg_z_slash[] = {
|
||||
"Usage:", "z/[*] ", "# Search signatures (see 'e?search' for options)",
|
||||
"Usage:", "z/[f*] ", "# Search signatures (see 'e?search' for options)",
|
||||
"z/ ", "", "search zignatures on range and flag matches",
|
||||
"z/f ", "", "zignature search on known functions",
|
||||
"z/* ", "", "search zignatures on range and output radare commands",
|
||||
NULL
|
||||
};
|
||||
|
@ -605,6 +606,7 @@ static int cmdFlirt(void *data, const char *input) {
|
|||
|
||||
struct ctxSearchCB {
|
||||
RCore *core;
|
||||
bool bytes_only;
|
||||
bool rad;
|
||||
int count;
|
||||
int bytes_count;
|
||||
|
@ -688,12 +690,12 @@ static int searchBytesHitCB(RSignItem *it, RSearchKeyword *kw, ut64 addr, void *
|
|||
apply_flag (ctx->core, it, addr, kw->keyword_length, kw->count, "bytes", ctx->rad);
|
||||
RAnalFunction *fcn = r_anal_get_fcn_in (ctx->core->anal, addr, 0);
|
||||
// TODO: create fcn if it does not exist
|
||||
if (fcn) {
|
||||
if (ctx->bytes_only && fcn) {
|
||||
apply_name (ctx->core, fcn, it, ctx->rad);
|
||||
apply_types (ctx->core, fcn, it);
|
||||
ctx->bytes_count++;
|
||||
ctx->count++;
|
||||
}
|
||||
ctx->bytes_count++;
|
||||
ctx->count++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -785,39 +787,6 @@ static bool searchRange(RCore *core, ut64 from, ut64 to, bool rad, struct ctxSea
|
|||
return retval;
|
||||
}
|
||||
|
||||
static bool searchRange2(RCore *core, RSignSearch *ss, ut64 from, ut64 to, bool rad, struct ctxSearchCB *ctx) {
|
||||
ut8 *buf = malloc (core->blocksize);
|
||||
ut64 at;
|
||||
int rlen;
|
||||
bool retval = true;
|
||||
|
||||
if (!buf) {
|
||||
return false;
|
||||
}
|
||||
r_cons_break_push (NULL, NULL);
|
||||
for (at = from; at < to; at += core->blocksize) {
|
||||
if (r_cons_is_breaked ()) {
|
||||
retval = false;
|
||||
break;
|
||||
}
|
||||
rlen = R_MIN (core->blocksize, to - at);
|
||||
if (!r_io_is_valid_offset (core->io, at, 0)) {
|
||||
retval = false;
|
||||
break;
|
||||
}
|
||||
(void)r_io_read_at (core->io, at, buf, rlen);
|
||||
if (r_sign_search_update (core->anal, ss, &at, buf, rlen) == -1) {
|
||||
eprintf ("search: update read error at 0x%08"PFMT64x"\n", at);
|
||||
retval = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
r_cons_break_pop ();
|
||||
free (buf);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void search_add_to_types(RCore *c, RSignSearchMetrics *sm, RSignType t, const char *str, unsigned int *i) {
|
||||
unsigned int count = *i;
|
||||
r_return_if_fail (count < sizeof (sm->types) / sizeof (RSignType) - 1);
|
||||
|
@ -830,6 +799,8 @@ static void search_add_to_types(RCore *c, RSignSearchMetrics *sm, RSignType t, c
|
|||
|
||||
static bool fill_search_metrics(RSignSearchMetrics *sm, RCore *c, void *user) {
|
||||
unsigned int i = 0;
|
||||
sm->types[0] = R_SIGN_END;
|
||||
search_add_to_types (c, sm, R_SIGN_BYTES, "zign.bytes", &i);
|
||||
search_add_to_types (c, sm, R_SIGN_GRAPH, "zign.graph", &i);
|
||||
search_add_to_types (c, sm, R_SIGN_OFFSET, "zign.offset", &i);
|
||||
search_add_to_types (c, sm, R_SIGN_REFS, "zign.refs", &i);
|
||||
|
@ -840,6 +811,7 @@ static bool fill_search_metrics(RSignSearchMetrics *sm, RCore *c, void *user) {
|
|||
search_add_to_types(c, sm, R_SIGN_VARS, "zign.vars", &i);
|
||||
#endif
|
||||
sm->mincc = r_config_get_i (c->config, "zign.mincc");
|
||||
sm->minsz = r_config_get_i (c->config, "zign.minsz");
|
||||
sm->anal = c->anal;
|
||||
sm->cb = fcnMatchCB;
|
||||
sm->user = user;
|
||||
|
@ -879,24 +851,7 @@ static void print_ctx_hits(struct ctxSearchCB *ctx) {
|
|||
}
|
||||
|
||||
static bool search(RCore *core, bool rad, bool only_func) {
|
||||
RList *list;
|
||||
RListIter *iter;
|
||||
RAnalFunction *fcni = NULL;
|
||||
RIOMap *map;
|
||||
bool retval = true;
|
||||
|
||||
struct ctxSearchCB ctx;
|
||||
memset (&ctx, 0, sizeof (struct ctxSearchCB));
|
||||
ctx.rad = rad;
|
||||
ctx.core = core;
|
||||
const char *mode = r_config_get (core->config, "search.in");
|
||||
bool useBytes = r_config_get_i (core->config, "zign.bytes");
|
||||
const char *zign_prefix = r_config_get (core->config, "zign.prefix");
|
||||
int maxsz = r_config_get_i (core->config, "zign.maxsz");
|
||||
|
||||
RSignSearchMetrics sm;
|
||||
bool metsearch = fill_search_metrics (&sm, core, (void *)&ctx);
|
||||
|
||||
if (rad) {
|
||||
r_cons_printf ("fs+%s\n", zign_prefix);
|
||||
} else {
|
||||
|
@ -906,52 +861,50 @@ static bool search(RCore *core, bool rad, bool only_func) {
|
|||
}
|
||||
}
|
||||
|
||||
struct ctxSearchCB ctx;
|
||||
memset (&ctx, 0, sizeof (struct ctxSearchCB));
|
||||
ctx.rad = rad;
|
||||
ctx.core = core;
|
||||
|
||||
RSignSearchMetrics sm;
|
||||
bool metsearch = fill_search_metrics (&sm, core, (void *)&ctx);
|
||||
if (!metsearch) {
|
||||
eprintf ("No zign types enabled\n");
|
||||
return false;
|
||||
}
|
||||
if (sm.types[0] == R_SIGN_BYTES && sm.types[1] == R_SIGN_END) {
|
||||
ctx.bytes_only = true;
|
||||
}
|
||||
|
||||
// Bytes search
|
||||
if (useBytes && !only_func) {
|
||||
list = r_core_get_boundaries_prot (core, -1, mode, "search");
|
||||
RListIter *iter;
|
||||
if (r_config_get_i (core->config, "zign.bytes") && !only_func) {
|
||||
const char *mode = r_config_get (core->config, "search.in");
|
||||
RList *list = r_core_get_boundaries_prot (core, -1, mode, "search");
|
||||
if (!list) {
|
||||
return false;
|
||||
}
|
||||
RIOMap *map;
|
||||
r_list_foreach (list, iter, map) {
|
||||
eprintf ("[+] searching 0x%08"PFMT64x" - 0x%08"PFMT64x"\n", r_io_map_begin (map), r_io_map_end (map));
|
||||
retval &= searchRange (core, r_io_map_begin (map), r_io_map_end (map), rad, &ctx);
|
||||
searchRange (core, r_io_map_begin (map), r_io_map_end (map), rad, &ctx);
|
||||
}
|
||||
r_list_free (list);
|
||||
}
|
||||
|
||||
// Function search
|
||||
if (metsearch) {
|
||||
if (!ctx.bytes_only) {
|
||||
eprintf ("[+] searching function metrics\n");
|
||||
r_cons_break_push (NULL, NULL);
|
||||
int count = 0;
|
||||
|
||||
RSignSearch *ss = NULL;
|
||||
|
||||
if (useBytes && only_func) {
|
||||
ss = r_sign_search_new ();
|
||||
ss->search->align = r_config_get_i (core->config, "search.align");
|
||||
int minsz = r_config_get_i (core->config, "zign.minsz");
|
||||
r_sign_search_init (core->anal, ss, minsz, searchBytesHitCB, &ctx);
|
||||
}
|
||||
|
||||
RAnalFunction *fcni = NULL;
|
||||
r_list_foreach (core->anal->fcns, iter, fcni) {
|
||||
if (r_cons_is_breaked ()) {
|
||||
break;
|
||||
}
|
||||
if (useBytes && only_func) {
|
||||
eprintf ("Matching func %d / %d (hits %d)\n", count, r_list_length (core->anal->fcns), ctx.count);
|
||||
int fcnlen = r_anal_function_realsize (fcni);
|
||||
int len = R_MIN (core->io->addrbytes * fcnlen, maxsz);
|
||||
retval &= searchRange2 (core, ss, fcni->addr, fcni->addr + len, rad, &ctx);
|
||||
}
|
||||
sm.fcn = fcni;
|
||||
r_sign_fcn_match_metrics (&sm);
|
||||
sm.fcn = NULL;
|
||||
count ++;
|
||||
// TODO: add useXRefs, useName
|
||||
}
|
||||
r_cons_break_pop ();
|
||||
r_sign_search_free (ss);
|
||||
}
|
||||
|
||||
if (rad) {
|
||||
|
@ -964,7 +917,7 @@ static bool search(RCore *core, bool rad, bool only_func) {
|
|||
}
|
||||
|
||||
print_ctx_hits (&ctx);
|
||||
return retval;
|
||||
return ctx.count > 0? true: false;
|
||||
}
|
||||
|
||||
static void print_possible_matches(RList *list) {
|
||||
|
@ -1394,26 +1347,19 @@ static int cmdCompare(void *data, const char *input) {
|
|||
|
||||
static int cmdCheck(void *data, const char *input) {
|
||||
RCore *core = (RCore *) data;
|
||||
RSignSearch *ss;
|
||||
RListIter *iter;
|
||||
RAnalFunction *fcni = NULL;
|
||||
ut64 at = core->offset;
|
||||
bool retval = true;
|
||||
bool rad = input[0] == '*';
|
||||
|
||||
struct ctxSearchCB ctx;
|
||||
memset (&ctx, 0, sizeof (struct ctxSearchCB));
|
||||
ctx.rad = rad;
|
||||
ctx.rad = input[0] == '*';
|
||||
ctx.core = core;
|
||||
|
||||
const char *zign_prefix = r_config_get (core->config, "zign.prefix");
|
||||
int minsz = r_config_get_i (core->config, "zign.minsz");
|
||||
bool useBytes = r_config_get_i (core->config, "zign.bytes");
|
||||
|
||||
RSignSearchMetrics sm;
|
||||
bool metsearch = fill_search_metrics (&sm, core, (void *)&ctx);
|
||||
if (!fill_search_metrics (&sm, core, (void *)&ctx)) {
|
||||
eprintf ("Nothing to search for\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rad) {
|
||||
const char *zign_prefix = r_config_get (core->config, "zign.prefix");
|
||||
if (ctx.rad) {
|
||||
r_cons_printf ("fs+%s\n", zign_prefix);
|
||||
} else {
|
||||
if (!r_flag_space_push (core->flags, zign_prefix)) {
|
||||
|
@ -1422,37 +1368,17 @@ static int cmdCheck(void *data, const char *input) {
|
|||
}
|
||||
}
|
||||
|
||||
// Bytes search
|
||||
if (useBytes) {
|
||||
eprintf ("[+] searching 0x%08"PFMT64x" - 0x%08"PFMT64x"\n", at, at + core->blocksize);
|
||||
ss = r_sign_search_new ();
|
||||
r_sign_search_init (core->anal, ss, minsz, searchBytesHitCB, &ctx);
|
||||
if (r_sign_search_update (core->anal, ss, &at, core->block, core->blocksize) == -1) {
|
||||
eprintf ("search: update read error at 0x%08"PFMT64x"\n", at);
|
||||
retval = false;
|
||||
}
|
||||
r_sign_search_free (ss);
|
||||
}
|
||||
|
||||
// Function search
|
||||
int hits = 0;
|
||||
if (metsearch) {
|
||||
eprintf ("[+] searching function metrics\n");
|
||||
eprintf ("[+] searching function metrics\n");
|
||||
sm.fcn = r_anal_get_function_at (core->anal, core->offset);
|
||||
if (sm.fcn) {
|
||||
r_cons_break_push (NULL, NULL);
|
||||
r_list_foreach (core->anal->fcns, iter, fcni) {
|
||||
if (r_cons_is_breaked ()) {
|
||||
break;
|
||||
}
|
||||
if (fcni->addr == core->offset) {
|
||||
sm.fcn = fcni;
|
||||
hits += r_sign_fcn_match_metrics (&sm);
|
||||
break;
|
||||
}
|
||||
}
|
||||
r_sign_fcn_match_metrics (&sm);
|
||||
r_cons_break_pop ();
|
||||
} else {
|
||||
eprintf ("No function at 0x%08" PFMT64x "\n", core->offset);
|
||||
}
|
||||
|
||||
if (rad) {
|
||||
if (ctx.rad) {
|
||||
r_cons_printf ("fs-\n");
|
||||
} else {
|
||||
if (!r_flag_space_pop (core->flags)) {
|
||||
|
@ -1462,7 +1388,7 @@ static int cmdCheck(void *data, const char *input) {
|
|||
}
|
||||
|
||||
print_ctx_hits (&ctx);
|
||||
return retval;
|
||||
return ctx.count;
|
||||
}
|
||||
|
||||
static int cmdSearch(void *data, const char *input) {
|
||||
|
@ -1470,9 +1396,9 @@ static int cmdSearch(void *data, const char *input) {
|
|||
|
||||
switch (*input) {
|
||||
case 0:
|
||||
case '*':
|
||||
case '*': // "z/*"
|
||||
return search (core, input[0] == '*', false);
|
||||
case 'f':
|
||||
case 'f': // "z/f"
|
||||
switch (input[1]) {
|
||||
case 0:
|
||||
case '*':
|
||||
|
@ -1485,7 +1411,7 @@ static int cmdSearch(void *data, const char *input) {
|
|||
r_core_cmd_help (core, help_msg_z_slash);
|
||||
break;
|
||||
default:
|
||||
eprintf ("Usage: z/[*]\n");
|
||||
eprintf ("Usage: z/[f*]\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -77,6 +77,7 @@ typedef struct r_sign_search_met {
|
|||
*/
|
||||
RSignType types[8];
|
||||
int mincc; // min complexity for graph search
|
||||
int minsz;
|
||||
RAnal *anal;
|
||||
void *user; // user data for callback function
|
||||
RSignMatchCallback cb;
|
||||
|
|
Loading…
Reference in New Issue