radare2/binr/radiff2/radiff2.c

265 lines
6.2 KiB
C

/* radare - LGPL - Copyright 2009-2014 - pancake */
#include <r_diff.h>
#include <r_core.h>
enum {
MODE_DIFF,
MODE_DIST,
MODE_CODE,
MODE_GRAPH,
MODE_COLS
};
static ut32 count = 0;
static int showcount = 0;
static int useva = R_TRUE;
static int delta = 0;
static int cb(RDiff *d, void *user, RDiffOp *op) {
int i, rad = (int)(size_t)user;
if (showcount) {
count++;
return 1;
}
if (rad) {
if (op->a_len == op->b_len) {
printf ("wx ");
for (i=0; i<op->b_len; i++)
printf ("%02x", op->b_buf[i]);
printf (" @ 0x%08"PFMT64x"\n", op->b_off);
} else {
if ((op->a_len)>0)
printf ("r-%d @ 0x%08"PFMT64x"\n",
op->a_len, op->a_off+delta);
if (op->b_len> 0) {
printf ("r+%d @ 0x%08"PFMT64x"\n",
op->b_len, op->b_off+delta);
printf ("wx ");
for (i=0; i<op->b_len; i++)
printf ("%02x", op->b_buf[i]);
printf (" @ 0x%08"PFMT64x"\n", op->b_off+delta);
}
delta += (op->b_off - op->a_off);
}
} else {
printf ("0x%08"PFMT64x" ", op->a_off);
for (i = 0;i<op->a_len;i++)
printf ("%02x", op->a_buf[i]);
printf (" => ");
for (i=0; i<op->b_len; i++)
printf ("%02x", op->b_buf[i]);
printf (" 0x%08"PFMT64x"\n", op->b_off);
}
return 1;
}
static RCore* opencore(const char *f) {
const ut64 baddr = 0;
RCore *c = r_core_new ();
r_core_loadlibs (c, R_CORE_LOADLIBS_ALL, NULL);
r_config_set_i (c->config, "io.va", useva);
r_config_set_i (c->config, "anal.split", R_TRUE);
if (r_core_file_open (c, f, 0, 0) == NULL) {
r_core_free (c);
return NULL;
}
r_core_bin_load (c, NULL, baddr);
// TODO: must enable io.va here if wanted .. r_config_set_i (c->config, "io.va", va);
return c;
}
static int show_help(int v) {
printf ("Usage: radiff2 [-abcCdrspOv] [-g sym] [-t %%] [file] [file]\n");
if (v) printf (
" -a [arch] specify architecture plugin to use (x86, arm, ..)\n"
" -b [bits] specify register size for arch (16 (thumb), 32, 64, ..)\n"
" -c count of changes\n"
" -C graphdiff code (columns: off-A, match-ratio, off-B)\n"
" -d use delta diffing\n"
" -g [sym|off1,off2] graph diff of given symbol, or between two offsets\n"
" -O code diffing with opcode bytes only\n"
" -p use physical addressing (io.va=0)\n"
" -r output in radare commands\n"
" -s compute text distance\n"
" -t [0-100] set threshold for code diff (default is 70%%)\n"
" -v show version information\n");
return 1;
}
static void dump_cols (ut8 *a, int as, ut8 *b, int bs) {
ut32 sz = R_MIN (as, bs);
ut32 i, j;
printf (" offset 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8\n");
for (i=0; i<sz; i++) {
printf ("0x%08x%c ", i, (memcmp (a+i, b+i, 8))? ' ': '!');
for (j=0; j<8; j++)
printf ("%02x", a[i+j]);
printf (" ");
for (j=0; j<8; j++)
printf ("%c", IS_PRINTABLE (a[i+j])?a[i+j]:'.');
printf (" ");
for (j=0; j<8; j++)
printf ("%02x", b[i+j]);
printf (" ");
for (j=0; j<8; j++)
printf ("%c", IS_PRINTABLE (b[i+j])? b[i+j]:'.');
printf ("\n");
}
if (as != bs)
printf ("...\n");
}
int main(int argc, char **argv) {
const char *addr = NULL;
RCore *c, *c2;
RDiff *d;
const char *arch = NULL;
int bits = 0;
char *file, *file2;
ut8 *bufa, *bufb;
int o, sza, szb, rad = 0, delta = 0;
int mode = MODE_DIFF;
int diffops = 0;
int threshold = -1;
double sim;
while ((o = getopt (argc, argv, "a:b:Cpg:Orhcdsvxt:")) != -1) {
switch (o) {
case 'a':
arch = optarg;
break;
case 'b':
bits = atoi (optarg);
break;
case 'p':
useva = R_FALSE;
break;
case 'r':
rad = 1;
break;
case 'g':
mode = MODE_GRAPH;
addr = optarg;
break;
case 'c':
showcount = 1;
break;
case 'C':
mode = MODE_CODE;
break;
case 'O':
diffops = 1;
break;
case 't':
threshold = atoi (optarg);
break;
case 'd':
delta = 1;
break;
case 'h':
return show_help (1);
case 's':
mode = MODE_DIST;
break;
case 'x':
mode = MODE_COLS;
break;
case 'v':
printf ("radiff2 v"R2_VERSION"\n");
return 0;
default:
return show_help (0);
}
}
if (argc<3 || optind+2>argc)
return show_help (0);
file = argv[optind];
file2 = argv[optind+1];
switch (mode) {
case MODE_GRAPH:
case MODE_CODE:
c = opencore (file);
if (!c) eprintf ("Cannot open '%s'\n", file);
c2 = opencore (file2);
if (!c||!c2) {
eprintf ("Cannot open '%s'\n", file2);
return 1;
}
if (arch) {
r_config_set (c->config, "asm.arch", arch);
r_config_set (c2->config, "asm.arch", arch);
}
if (bits) {
r_config_set_i (c->config, "asm.bits", bits);
r_config_set_i (c2->config, "asm.bits", bits);
}
r_anal_diff_setup_i (c->anal, diffops, threshold, threshold);
r_anal_diff_setup_i (c2->anal, diffops, threshold, threshold);
if (mode == MODE_GRAPH) {
const char* second = strstr (addr, ",");
if (!second) {
r_core_gdiff (c, c2, R_TRUE);
r_core_anal_graph (c, r_num_math (c->num, addr),
R_CORE_ANAL_GRAPHBODY|R_CORE_ANAL_GRAPHDIFF);
} else {
const ut64 off = strtoull(addr, 0, 16);
// define the same function at each offset
r_core_anal_fcn (c, off, UT64_MAX, R_ANAL_REF_TYPE_NULL, 0);
r_core_anal_fcn (c2, strtoull (second+1, 0, 16),
UT64_MAX, R_ANAL_REF_TYPE_NULL, 0);
r_core_gdiff (c, c2, R_FALSE); // compute the diff
r_core_anal_graph (c, off, R_CORE_ANAL_GRAPHBODY|R_CORE_ANAL_GRAPHDIFF);
}
} else {
r_core_gdiff (c, c2, R_TRUE);
r_core_diff_show (c, c2);
}
return 0;
}
bufa = (ut8*)r_file_slurp (file, &sza);
if (!bufa) {
eprintf ("radiff2: Can not open %s\n", bufa);
return 1;
}
bufb = (ut8*)r_file_slurp (file2, &szb);
if (!bufb) {
eprintf ("radiff2: Cannot open: %s\n", bufb);
free (bufa);
return 1;
}
switch (mode) {
case MODE_COLS:
dump_cols (bufa, sza, bufb, szb);
break;
case MODE_DIFF:
d = r_diff_new (0LL, 0LL);
r_diff_set_delta (d, delta);
r_diff_set_callback (d, &cb, (void *)(size_t)rad);
r_diff_buffers (d, bufa, sza, bufb, szb);
r_diff_free (d);
break;
case MODE_DIST:
r_diff_buffers_distance (NULL, bufa, sza, bufb, szb, &count, &sim);
printf ("similarity: %.2f\n", sim);
printf ("distance: %d\n", count);
break;
}
if (showcount)
printf ("%d\n", count);
free (bufa);
free (bufb);
return 0;
}