This is one of the first steps to improve analysis. This way we'll have one single place to change if we want to change the meaning of the "size" field. (size -> realsize)
268 lines
7.5 KiB
C
268 lines
7.5 KiB
C
/* radare - LGPL - Copyright 2010-2015 - nibble, pancake */
|
|
|
|
#include <r_anal.h>
|
|
#include <r_util.h>
|
|
#include <r_diff.h>
|
|
|
|
R_API RAnalDiff *r_anal_diff_new() {
|
|
RAnalDiff *diff = R_NEW (RAnalDiff);
|
|
if (diff) {
|
|
diff->type = R_ANAL_DIFF_TYPE_NULL;
|
|
diff->addr = -1;
|
|
diff->dist = 0;
|
|
diff->name = NULL;
|
|
diff->size = 0;
|
|
}
|
|
return diff;
|
|
}
|
|
|
|
R_API void* r_anal_diff_free(RAnalDiff *diff) {
|
|
if (diff && diff->name) {
|
|
free (diff->name);
|
|
diff->name = NULL;
|
|
}
|
|
free (diff);
|
|
return NULL;
|
|
}
|
|
|
|
/* 0-1 */
|
|
R_API void r_anal_diff_setup(RAnal *anal, int doops, double thbb, double thfcn) {
|
|
if (doops>=0) anal->diff_ops = doops;
|
|
anal->diff_thbb = (thbb>=0)? thbb: R_ANAL_THRESHOLDBB;
|
|
anal->diff_thfcn = (thfcn>=0)? thfcn: R_ANAL_THRESHOLDFCN;
|
|
}
|
|
|
|
/* 0-100 */
|
|
R_API void r_anal_diff_setup_i(RAnal *anal, int doops, int thbb, int thfcn) {
|
|
if (doops>=0) anal->diff_ops = doops;
|
|
anal->diff_thbb = (thbb>=0)? ((double)thbb)/100: R_ANAL_THRESHOLDBB;
|
|
anal->diff_thfcn = (thfcn>=0)? ((double)thfcn)/100: R_ANAL_THRESHOLDFCN;
|
|
}
|
|
|
|
// Fingerprint function basic block
|
|
R_API int r_anal_diff_fingerprint_bb(RAnal *anal, RAnalBlock *bb) {
|
|
RAnalOp *op;
|
|
ut8 *buf;
|
|
int oplen, idx = 0;
|
|
|
|
if (!anal) return false;
|
|
if (anal->cur && anal->cur->fingerprint_bb)
|
|
return (anal->cur->fingerprint_bb (anal, bb));
|
|
|
|
if (!(bb->fingerprint = malloc (1+bb->size)))
|
|
return false;
|
|
if (!(buf = malloc (1+bb->size))) {
|
|
free (bb->fingerprint);
|
|
return false;
|
|
}
|
|
if (anal->iob.read_at (anal->iob.io, bb->addr, buf, bb->size) == bb->size) {
|
|
memcpy (bb->fingerprint, buf, bb->size);
|
|
if (anal->diff_ops) { // diff using only the opcode
|
|
if (!(op = r_anal_op_new ())) {
|
|
free (bb->fingerprint);
|
|
free (buf);
|
|
return false;
|
|
}
|
|
while (idx < bb->size) {
|
|
if ((oplen = r_anal_op (anal, op, 0, buf+idx, bb->size-idx)) <1)
|
|
break;
|
|
if (op->nopcode != 0)
|
|
memset (bb->fingerprint+idx+op->nopcode, 0, oplen-op->nopcode);
|
|
idx += oplen;
|
|
}
|
|
free (op);
|
|
}
|
|
}
|
|
free (buf);
|
|
return bb->size;
|
|
}
|
|
|
|
R_API int r_anal_diff_fingerprint_fcn(RAnal *anal, RAnalFunction *fcn) {
|
|
RAnalBlock *bb;
|
|
RListIter *iter;
|
|
int len = 0;
|
|
|
|
if (anal && anal->cur && anal->cur->fingerprint_fcn)
|
|
return (anal->cur->fingerprint_fcn (anal, fcn));
|
|
|
|
fcn->fingerprint = NULL;
|
|
r_list_foreach (fcn->bbs, iter, bb) {
|
|
len += bb->size;
|
|
fcn->fingerprint = realloc (fcn->fingerprint, len);
|
|
if (!fcn->fingerprint)
|
|
return 0;
|
|
memcpy (fcn->fingerprint+len-bb->size, bb->fingerprint, bb->size);
|
|
}
|
|
return len;
|
|
}
|
|
|
|
R_API int r_anal_diff_bb(RAnal *anal, RAnalFunction *fcn, RAnalFunction *fcn2) {
|
|
RAnalBlock *bb, *bb2, *mbb, *mbb2;
|
|
RListIter *iter, *iter2;
|
|
double t, ot;
|
|
|
|
if (!anal) return false;
|
|
if (anal->cur && anal->cur->diff_bb)
|
|
return (anal->cur->diff_bb (anal, fcn, fcn2));
|
|
|
|
fcn->diff->type = fcn2->diff->type = R_ANAL_DIFF_TYPE_MATCH;
|
|
r_list_foreach (fcn->bbs, iter, bb) {
|
|
if (bb->diff && bb->diff->type != R_ANAL_DIFF_TYPE_NULL)
|
|
continue;
|
|
ot = 0;
|
|
mbb = mbb2 = NULL;
|
|
r_list_foreach (fcn2->bbs, iter2, bb2) {
|
|
if (bb2->diff && bb2->diff->type == R_ANAL_DIFF_TYPE_NULL) {
|
|
r_diff_buffers_distance (NULL, bb->fingerprint, bb->size,
|
|
bb2->fingerprint, bb2->size, NULL, &t);
|
|
#if 0
|
|
eprintf ("BB: %llx - %llx => %lli - %lli => %f\n", bb->addr, bb2->addr,
|
|
bb->size, bb->size, t);
|
|
#endif
|
|
if (t > anal->diff_thbb && t > ot) {
|
|
ot = t;
|
|
mbb = bb;
|
|
mbb2 = bb2;
|
|
if (t == 1) break;
|
|
}
|
|
}
|
|
}
|
|
if (mbb != NULL && mbb2 != NULL) {
|
|
if (ot == 1 || t > anal->diff_thfcn )
|
|
mbb->diff->type = mbb2->diff->type = R_ANAL_DIFF_TYPE_MATCH;
|
|
else mbb->diff->type = mbb2->diff->type = \
|
|
fcn->diff->type = fcn2->diff->type = R_ANAL_DIFF_TYPE_UNMATCH;
|
|
R_FREE (mbb->fingerprint);
|
|
R_FREE (mbb2->fingerprint);
|
|
mbb->diff->addr = mbb2->addr;
|
|
mbb2->diff->addr = mbb->addr;
|
|
mbb->diff->size = mbb2->size;
|
|
mbb2->diff->size = mbb->size;
|
|
} else
|
|
fcn->diff->type = fcn2->diff->type = R_ANAL_DIFF_TYPE_UNMATCH;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
R_API int r_anal_diff_fcn(RAnal *anal, RList *fcns, RList *fcns2) {
|
|
RAnalFunction *fcn, *fcn2, *mfcn, *mfcn2;
|
|
RListIter *iter, *iter2;
|
|
ut64 maxsize, minsize;
|
|
double t, ot;
|
|
|
|
if (!anal)
|
|
return false;
|
|
|
|
if (anal->cur && anal->cur->diff_fcn)
|
|
return (anal->cur->diff_fcn (anal, fcns, fcns2));
|
|
|
|
/* Compare functions with the same name */
|
|
if (fcns)
|
|
r_list_foreach (fcns, iter, fcn) {
|
|
if (fcn->type != R_ANAL_FCN_TYPE_SYM || fcn->name == NULL)
|
|
continue;
|
|
r_list_foreach (fcns2, iter2, fcn2) {
|
|
if (fcn2->type != R_ANAL_FCN_TYPE_SYM || fcn2->name == NULL ||
|
|
strcmp (fcn->name, fcn2->name))
|
|
continue;
|
|
r_diff_buffers_distance (NULL, fcn->fingerprint, r_anal_fcn_size (fcn),
|
|
fcn2->fingerprint, r_anal_fcn_size (fcn2), NULL, &t);
|
|
#if 0
|
|
eprintf ("FCN NAME (NAME): %s - %s => %lli - %lli => %f\n", fcn->name, fcn2->name,
|
|
fcn->size, fcn2->size, t);
|
|
#endif
|
|
/* Set flag in matched functions */
|
|
fcn->diff->type = fcn2->diff->type = (t==1)?
|
|
R_ANAL_DIFF_TYPE_MATCH: R_ANAL_DIFF_TYPE_UNMATCH;
|
|
fcn->diff->dist = fcn2->diff->dist = t;
|
|
R_FREE (fcn->fingerprint);
|
|
R_FREE (fcn2->fingerprint);
|
|
fcn->diff->addr = fcn2->addr;
|
|
fcn2->diff->addr = fcn->addr;
|
|
fcn->diff->size = r_anal_fcn_size (fcn2);
|
|
fcn2->diff->size = r_anal_fcn_size (fcn);
|
|
R_FREE (fcn->diff->name);
|
|
if (fcn2->name)
|
|
fcn->diff->name = strdup (fcn2->name);
|
|
R_FREE (fcn2->diff->name);
|
|
if (fcn->name)
|
|
fcn2->diff->name = strdup (fcn->name);
|
|
r_anal_diff_bb (anal, fcn, fcn2);
|
|
break;
|
|
}
|
|
}
|
|
/* Compare remaining functions */
|
|
r_list_foreach (fcns, iter, fcn) {
|
|
if ((fcn->type != R_ANAL_FCN_TYPE_FCN && fcn->type != R_ANAL_FCN_TYPE_SYM) ||
|
|
fcn->diff->type != R_ANAL_DIFF_TYPE_NULL)
|
|
continue;
|
|
ot = 0;
|
|
mfcn = mfcn2 = NULL;
|
|
r_list_foreach (fcns2, iter2, fcn2) {
|
|
int fcn_size = r_anal_fcn_size (fcn);
|
|
int fcn2_size = r_anal_fcn_size (fcn2);
|
|
if (fcn_size > fcn2_size) {
|
|
maxsize = fcn_size;
|
|
minsize = fcn2_size;
|
|
} else {
|
|
maxsize = fcn2_size;
|
|
minsize = fcn_size;
|
|
}
|
|
if ((fcn2->type != R_ANAL_FCN_TYPE_FCN && fcn2->type != R_ANAL_FCN_TYPE_SYM) ||
|
|
fcn2->diff->type != R_ANAL_DIFF_TYPE_NULL || (maxsize * anal->diff_thfcn > minsize))
|
|
continue;
|
|
r_diff_buffers_distance (NULL, fcn->fingerprint, fcn_size,
|
|
fcn2->fingerprint, fcn2_size, NULL, &t);
|
|
fcn->diff->dist = fcn2->diff->dist = t;
|
|
#if 0
|
|
int i;
|
|
eprintf ("FP0 ");
|
|
for (i=0;i<fcn->size;i++)
|
|
eprintf ("%02x", fcn->fingerprint[i]);
|
|
eprintf ("\n");
|
|
|
|
eprintf ("FP1 ");
|
|
for (i=0;i<fcn2->size;i++)
|
|
eprintf ("%02x", fcn2->fingerprint[i]);
|
|
eprintf ("\n");
|
|
eprintf ("FCN: %s - %s => %lli - %lli => %f\n", fcn->name, fcn2->name,
|
|
fcn->size, fcn2->size, t);
|
|
#endif
|
|
if (t > anal->diff_thfcn && t > ot) {
|
|
ot = t;
|
|
mfcn = fcn;
|
|
mfcn2 = fcn2;
|
|
if (t == 1) break;
|
|
}
|
|
}
|
|
if (mfcn && mfcn2) {
|
|
#if 0
|
|
eprintf ("Match => %s - %s\n", mfcn->name, mfcn2->name);
|
|
#endif
|
|
/* Set flag in matched functions */
|
|
mfcn->diff->type = mfcn2->diff->type = (ot==1)?
|
|
R_ANAL_DIFF_TYPE_MATCH: R_ANAL_DIFF_TYPE_UNMATCH;
|
|
R_FREE (mfcn->fingerprint);
|
|
R_FREE (mfcn2->fingerprint);
|
|
mfcn->diff->addr = mfcn2->addr;
|
|
mfcn2->diff->addr = mfcn->addr;
|
|
mfcn->diff->size = r_anal_fcn_size (mfcn2);
|
|
mfcn2->diff->size = r_anal_fcn_size (mfcn);
|
|
R_FREE (mfcn->diff->name);
|
|
if (mfcn2->name)
|
|
mfcn->diff->name = strdup (mfcn2->name);
|
|
R_FREE (mfcn2->diff->name);
|
|
if (mfcn->name)
|
|
mfcn2->diff->name = strdup (mfcn->name);
|
|
r_anal_diff_bb (anal, mfcn, mfcn2);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
R_API int r_anal_diff_eval(RAnal *anal) {
|
|
/*TODO*/
|
|
if (anal && anal->cur && anal->cur->diff_eval)
|
|
return (anal->cur->diff_eval (anal));
|
|
return true; // XXX: shouldnt this be false?
|
|
}
|