1 /* radare - LGPL - Copyright 2009-2020 - pancake */
2
3 #include <r_core.h>
4 #include <r_main.h>
5
6 enum {
7 MODE_DIFF,
8 MODE_DIFF_STRS,
9 MODE_DIFF_IMPORTS,
10 MODE_DIST_MYERS,
11 MODE_DIST_LEVENSHTEIN,
12 MODE_CODE,
13 MODE_GRAPH,
14 MODE_COLS,
15 MODE_COLSII
16 };
17
18 enum {
19 GRAPH_DEFAULT_MODE,
20 GRAPH_SDB_MODE,
21 GRAPH_JSON_MODE,
22 GRAPH_JSON_DIS_MODE,
23 GRAPH_TINY_MODE,
24 GRAPH_INTERACTIVE_MODE,
25 GRAPH_DOT_MODE,
26 GRAPH_STAR_MODE,
27 GRAPH_GML_MODE
28 };
29
30 typedef struct {
31 ut64 gdiff_start;
32 bool zignatures;
33 const char *file;
34 const char *file2;
35 ut32 count;
36 int showcount;
37 int useva;
38 int delta;
39 int showbare;
40 bool json_started;
41 int diffmode;
42 int diffops;
43 int mode;
44 int gmode;
45 bool disasm;
46 bool pdc;
47 bool quiet;
48 RCore *core;
49 const char *arch;
50 const char *runcmd;
51 int bits;
52 int anal_all;
53 int threshold;
54 bool verbose;
55 RList *evals;
56 PJ *pj;
57 } RadiffOptions;
58
opencore(RadiffOptions * ro,const char * f)59 static RCore *opencore(RadiffOptions *ro, const char *f) {
60 RListIter *iter;
61 const ut64 baddr = UT64_MAX;
62 const char *e;
63 RCore *c = r_core_new ();
64 if (!c) {
65 return NULL;
66 }
67 r_core_loadlibs (c, R_CORE_LOADLIBS_ALL, NULL);
68 r_config_set_i (c->config, "io.va", ro->useva);
69 r_config_set_i (c->config, "scr.interactive", false);
70 r_list_foreach (ro->evals, iter, e) {
71 r_config_eval (c->config, e, false);
72 }
73 if (f) {
74 RIODesc * rfile = NULL;
75 #if __WINDOWS__
76 char *winf = r_acp_to_utf8 (f);
77 rfile = r_core_file_open (c, winf, 0, 0);
78 free (winf);
79 #else
80 rfile = r_core_file_open (c, f, 0, 0);
81 #endif
82
83 if (!rfile) {
84 r_core_free (c);
85 return NULL;
86 }
87 (void) r_core_bin_load (c, NULL, baddr);
88 (void) r_core_bin_update_arch_bits (c);
89
90 // force PA mode when working with raw bins
91 if (r_list_empty (r_bin_get_sections (c->bin))) {
92 r_config_set_i (c->config, "io.va", false);
93 }
94 if (ro->anal_all) {
95 const char *cmd = "aac";
96 switch (ro->anal_all) {
97 case 1: cmd = "aaa"; break;
98 case 2: cmd = "aaaa"; break;
99 }
100 r_core_cmd0 (c, cmd);
101 }
102 if (ro->runcmd) {
103 r_core_cmd0 (c, ro->runcmd);
104 }
105 // generate zignaturez?
106 if (ro->zignatures) {
107 r_core_cmd0 (c, "zg");
108 }
109 r_cons_flush ();
110 }
111 // TODO: must enable io.va here if wanted .. r_config_set_i (c->config, "io.va", va);
112 return c;
113 }
114
readstr(char * s,int sz,const ut8 * buf,int len)115 static void readstr(char *s, int sz, const ut8 *buf, int len) {
116 *s = 0;
117 int last = R_MIN (len, sz);
118 if (last < 1) {
119 return;
120 }
121 s[sz - 1] = 0;
122 while (*s && *s == '\n') {
123 s++;
124 }
125 strncpy (s, (char *) buf, last);
126 }
127
cb(RDiff * d,void * user,RDiffOp * op)128 static int cb(RDiff *d, void *user, RDiffOp *op) {
129 int i;
130 RadiffOptions *ro = user;
131 char s[256] = {0};
132 if (ro->showcount) {
133 ro->count++;
134 return 1;
135 }
136 switch (ro->diffmode) {
137 case 'U': // 'U' in theory never handled here
138 case 'u':
139 if (op->a_len > 0) {
140 readstr (s, sizeof (s), op->a_buf, op->a_len);
141 if (*s) {
142 if (!ro->quiet) {
143 printf (Color_RED);
144 }
145 printf ("-0x%08"PFMT64x":", op->a_off);
146 int len = op->a_len; // R_MIN (op->a_len, strlen (op->a_buf));
147 for (i = 0; i < len; i++) {
148 printf ("%02x ", op->a_buf[i]);
149 }
150 if (!ro->quiet) {
151 char *p = r_str_escape ((const char*)op->a_buf);
152 printf (" \"%s\"", p);
153 free (p);
154 printf (Color_RESET);
155 }
156 printf ("\n");
157 }
158 }
159 if (op->b_len > 0) {
160 readstr (s, sizeof (s), op->b_buf, op->b_len);
161 if (*s) {
162 if (!ro->quiet) {
163 printf (Color_GREEN);
164 }
165 printf ("+0x%08"PFMT64x":", op->b_off);
166 for (i = 0; i < op->b_len; i++) {
167 printf ("%02x ", op->b_buf[i]);
168 }
169 if (!ro->quiet) {
170 char *p = r_str_escape ((const char*)op->b_buf);
171 printf (" \"%s\"", p);
172 free (p);
173 printf (Color_RESET);
174 }
175 printf ("\n");
176 }
177 }
178 break;
179 case 'r':
180 if (ro->disasm) {
181 eprintf ("r2cmds (-r) + disasm (-D) not yet implemented\n");
182 }
183 if (op->a_len == op->b_len) {
184 printf ("wx ");
185 for (i = 0; i < op->b_len; i++) {
186 printf ("%02x", op->b_buf[i]);
187 }
188 printf (" @ 0x%08"PFMT64x "\n", op->b_off);
189 } else {
190 if (op->a_len > 0) {
191 printf ("r-%d @ 0x%08"PFMT64x "\n",
192 op->a_len, op->a_off + ro->delta);
193 }
194 if (op->b_len > 0) {
195 printf ("r+%d @ 0x%08"PFMT64x "\n",
196 op->b_len, op->b_off + ro->delta);
197 printf ("wx ");
198 for (i = 0; i < op->b_len; i++) {
199 printf ("%02x", op->b_buf[i]);
200 }
201 printf (" @ 0x%08"PFMT64x "\n", op->b_off + ro->delta);
202 }
203 ro->delta += (op->b_off - op->a_off);
204 }
205 return 1;
206 case 'j':
207 // TODO PJ
208 if (ro->disasm) {
209 eprintf ("JSON (-j) + disasm (-D) not yet implemented\n");
210 }
211 {
212 PJ *pj = ro->pj;
213 pj_o (pj);
214 pj_kn (pj, "addr", op->a_off);
215 char *hex_from = r_hex_bin2strdup (op->a_buf, op->a_len);
216 pj_ks (pj, "from", hex_from);
217 char *hex_to = r_hex_bin2strdup (op->b_buf, op->b_len);
218 pj_ks (pj, "to", hex_to);
219 pj_end (pj);
220 }
221 return 1;
222 case 0:
223 default:
224 if (ro->disasm) {
225 int i;
226 printf ("--- 0x%08"PFMT64x " ", op->a_off);
227 if (!ro->core) {
228 ro->core = opencore (ro, ro->file);
229 if (ro->arch) {
230 r_config_set (ro->core->config, "asm.arch", ro->arch);
231 }
232 if (ro->bits) {
233 r_config_set_i (ro->core->config, "asm.bits", ro->bits);
234 }
235 }
236 for (i = 0; i < op->a_len; i++) {
237 printf ("%02x", op->a_buf[i]);
238 }
239 printf ("\n");
240 if (ro->core) {
241 int len = R_MAX (4, op->a_len);
242 RAsmCode *ac = r_asm_mdisassemble (ro->core->rasm, op->a_buf, len);
243 char *acbufasm = strdup (ac->assembly);
244 if (ro->quiet) {
245 char *bufasm = r_str_prefix_all (acbufasm, "- ");
246 printf ("%s\n", bufasm);
247 free (bufasm);
248 } else {
249 char *bufasm = r_str_prefix_all (acbufasm, Color_RED"- ");
250 printf ("%s"Color_RESET, bufasm);
251 free (bufasm);
252 }
253 free (acbufasm);
254 r_asm_code_free (ac);
255 }
256 } else {
257 printf ("0x%08"PFMT64x " ", op->a_off);
258 for (i = 0; i < op->a_len; i++) {
259 printf ("%02x", op->a_buf[i]);
260 }
261 }
262 if (ro->disasm) {
263 int i;
264 printf ("+++ 0x%08"PFMT64x " ", op->b_off);
265 if (!ro->core) {
266 ro->core = opencore (ro, NULL);
267 }
268 for (i = 0; i < op->b_len; i++) {
269 printf ("%02x", op->b_buf[i]);
270 }
271 printf ("\n");
272 if (ro->core) {
273 int len = R_MAX (4, op->b_len);
274 RAsmCode *ac = r_asm_mdisassemble (ro->core->rasm, op->b_buf, len);
275 char *acbufasm = strdup (ac->assembly);
276 if (ro->quiet) {
277 char *bufasm = r_str_prefix_all (acbufasm, "+ ");
278 printf ("%s\n", bufasm);
279 free (bufasm);
280 free (acbufasm);
281 } else {
282 char *bufasm = r_str_prefix_all (acbufasm, Color_GREEN"+ ");
283 printf ("%s\n" Color_RESET, bufasm);
284 free (bufasm);
285 free (acbufasm);
286 }
287 // r_asm_code_free (ac);
288 }
289 } else {
290 printf (" => ");
291 for (i = 0; i < op->b_len; i++) {
292 printf ("%02x", op->b_buf[i]);
293 }
294 printf (" 0x%08"PFMT64x "\n", op->b_off);
295 }
296 return 1;
297 }
298 return 0;
299 }
300
print_bytes(const void * p,size_t len,bool big_endian)301 void print_bytes(const void *p, size_t len, bool big_endian) {
302 size_t i;
303 for (i = 0; i < len; i++) {
304 ut8 ch = ((ut8*) p)[big_endian ? (len - i - 1) : i];
305 if (write (1, &ch, 1) != 1) {
306 break;
307 }
308 }
309 }
310
bcb(RDiff * d,void * user,RDiffOp * op)311 static int bcb(RDiff *d, void *user, RDiffOp *op) {
312 RadiffOptions *ro = user;
313 ut64 offset_diff = op->a_off - ro->gdiff_start;
314 unsigned char opcode;
315 unsigned short USAddr = 0;
316 int IAddr = 0;
317 unsigned char UCLen = 0;
318 unsigned short USLen = 0;
319 int ILen = 0;
320
321 // we copy from gdiff_start to a_off
322 if (offset_diff > 0) {
323
324 // size for the position
325 if (ro->gdiff_start <= USHRT_MAX) {
326 opcode = 249;
327 USAddr = (unsigned short) ro->gdiff_start;
328 } else if (ro->gdiff_start <= INT_MAX) {
329 opcode = 252;
330 IAddr = (int) ro->gdiff_start;
331 } else {
332 opcode = 255;
333 }
334
335 // size for the length
336 if (opcode != 255 && offset_diff <= UCHAR_MAX) {
337 UCLen = (unsigned char) offset_diff;
338 } else if (opcode != 255 && offset_diff <= USHRT_MAX) {
339 USLen = (unsigned short) offset_diff;
340 opcode += 1;
341 } else if (opcode != 255 && offset_diff <= INT_MAX) {
342 ILen = (int) offset_diff;
343 opcode += 2;
344 } else if (offset_diff > INT_MAX) {
345 int times = offset_diff / INT_MAX;
346 int max = INT_MAX;
347 size_t i;
348 for (i = 0; i < times; i++) {
349 print_bytes (&opcode, sizeof (opcode), true);
350 // XXX this is overflowingly wrong
351 // XXX print_bytes (&gdiff_start + i * max, sizeof (gdiff_start), true);
352 print_bytes (&max, sizeof (max), true);
353 }
354 }
355
356 // print opcode for COPY
357 print_bytes (&opcode, sizeof (opcode), true);
358
359 // print position for COPY
360 if (opcode <= 251) {
361 print_bytes (&USAddr, sizeof (USAddr), true);
362 } else if (opcode < 255) {
363 print_bytes (&IAddr, sizeof (IAddr), true);
364 } else {
365 print_bytes (&ro->gdiff_start, sizeof (ro->gdiff_start), true);
366 }
367
368 // print length for COPY
369 switch (opcode) {
370 case 249:
371 case 252:
372 print_bytes (&UCLen, sizeof (UCLen), true);
373 break;
374 case 250:
375 case 253:
376 print_bytes (&USLen, sizeof (USLen), true);
377 break;
378 case 251:
379 case 254:
380 case 255:
381 print_bytes (&ILen, sizeof (ILen), true);
382 break;
383 }
384 }
385
386 // we append data
387 if (op->b_len <= 246) {
388 ut8 data = op->b_len;
389 (void) write (1, &data, 1);
390 } else if (op->b_len <= USHRT_MAX) {
391 USLen = (ut16) op->b_len;
392 ut8 data = 247;
393 (void) write (1, &data, 1);
394 print_bytes (&USLen, sizeof (USLen), true);
395 } else if (op->b_len <= INT_MAX) {
396 ut8 data = 248;
397 (void) write (1, &data, 1);
398 ILen = (int) op->b_len;
399 print_bytes (&ILen, sizeof (ILen), true);
400 } else {
401 // split into multiple DATA, because op->b_len is greater than INT_MAX
402 int times = op->b_len / INT_MAX;
403 int max = INT_MAX;
404 size_t i;
405 for (i = 0; i < times; i++) {
406 ut8 data = 248;
407 if (write (1, &data, 1) != 1) {
408 break;
409 }
410 print_bytes (&max, sizeof (max), true);
411 print_bytes (op->b_buf, max, false);
412 op->b_buf += max;
413 }
414 op->b_len = op->b_len % max;
415
416 // print the remaining size
417 int remain_size = op->b_len;
418 print_bytes (&remain_size, sizeof (remain_size), true);
419 }
420 print_bytes (op->b_buf, op->b_len, false);
421 ro->gdiff_start = op->b_off + op->b_len;
422 return 0;
423 }
424
show_help(int v)425 static int show_help(int v) {
426 printf ("Usage: radiff2 [-abBcCdeGhijnrOpqsSxuUvVzZ] [-A[A]] [-g sym] [-m graph_mode][-t %%] [file] [file]\n");
427 if (v) {
428 printf (
429 " -a [arch] specify architecture plugin to use (x86, arm, ..)\n"
430 " -A [-A] run aaa or aaaa after loading each binary (see -C)\n"
431 " -b [bits] specify register size for arch (16 (thumb), 32, 64, ..)\n"
432 " -B output in binary diff (GDIFF)\n"
433 " -c count of changes\n"
434 " -C graphdiff code (columns: off-A, match-ratio, off-B) (see -A)\n"
435 " -d use delta diffing\n"
436 " -D show disasm instead of hexpairs\n"
437 " -e [k=v] set eval config var value for all RCore instances\n"
438 " -g [sym|off1,off2] graph diff of given symbol, or between two offsets\n"
439 " -G [cmd] run an r2 command on every RCore instance created\n"
440 " -i diff imports of target files (see -u, -U and -z)\n"
441 " -j output in json format\n"
442 " -n print bare addresses only (diff.bare=1)\n"
443 " -m [aditsjJ] choose the graph output mode\n"
444 " -O code diffing with opcode bytes only\n"
445 " -p use physical addressing (io.va=0)\n"
446 " -q quiet mode (disable colors, reduce output)\n"
447 " -r output in radare commands\n"
448 " -s compute edit distance (no substitution, Eugene W. Myers' O(ND) diff algorithm)\n"
449 " -ss compute Levenshtein edit distance (substitution is allowed, O(N^2))\n"
450 " -S [name] sort code diff (name, namelen, addr, size, type, dist) (only for -C or -g)\n"
451 " -t [0-100] set threshold for code diff (default is 70%%)\n"
452 " -x show two column hexdump diffing\n"
453 " -X show two column hexII diffing\n"
454 " -u unified output (---+++)\n"
455 " -U unified output using system 'diff'\n"
456 " -v show version information\n"
457 " -V be verbose (current only for -s)\n"
458 " -z diff on extracted strings\n"
459 " -Z diff code comparing zignatures\n\n"
460 "Graph Output formats: (-m [mode])\n"
461 " <blank/a> Ascii art\n"
462 " s r2 commands\n"
463 " d Graphviz dot\n"
464 " g Graph Modelling Language (gml)\n"
465 " j json\n"
466 " J json with disarm\n"
467 " k SDB key-value\n"
468 " t Tiny ascii art\n"
469 " i Interactive ascii art\n");
470 }
471 return 1;
472 }
473
474 #define DUMP_CONTEXT 2
dump_cols(ut8 * a,int as,ut8 * b,int bs,int w)475 static void dump_cols(ut8 *a, int as, ut8 *b, int bs, int w) {
476 ut32 sz = R_MIN (as, bs);
477 ut32 i, j;
478 int ctx = DUMP_CONTEXT;
479 int pad = 0;
480 if (!a || !b || as < 0 || bs < 0) {
481 return;
482 }
483 switch (w) {
484 case 8:
485 r_cons_printf (" offset 0 1 2 3 4 5 6 7 01234567 0 1 2 3 4 5 6 7 01234567\n");
486 break;
487 case 16:
488 r_cons_printf (" offset "
489 "0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF "
490 "0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF\n");
491 break;
492 default:
493 eprintf ("Invalid column width\n");
494 return;
495 }
496 r_cons_break_push (NULL, NULL);
497 for (i = 0; i < sz; i += w) {
498 if (r_cons_is_breaked()) {
499 break;
500 }
501 if (i + w >= sz) {
502 pad = w - sz + i;
503 w = sz - i;
504 }
505 bool eq = !memcmp (a + i, b + i, w);
506 if (eq) {
507 ctx--;
508 if (ctx == -1) {
509 r_cons_printf ("...\n");
510 continue;
511 }
512 if (ctx < 0) {
513 ctx = -1;
514 continue;
515 }
516 } else {
517 ctx = DUMP_CONTEXT;
518 }
519 r_cons_printf (eq? Color_GREEN: Color_RED);
520 r_cons_printf ("0x%08x%c ", i, eq? ' ': '!');
521 r_cons_printf (Color_RESET);
522 for (j = 0; j < w; j++) {
523 bool eq2 = a[i + j] == b[i + j];
524 if (!eq) {
525 r_cons_printf (eq2? Color_GREEN: Color_RED);
526 }
527 r_cons_printf ("%02x", a[i + j]);
528 if (!eq) {
529 r_cons_printf (Color_RESET);
530 }
531 }
532 for (j = 0; j < pad; j++) {
533 r_cons_printf (" ");
534 }
535 r_cons_printf (" ");
536 for (j = 0; j < w; j++) {
537 bool eq2 = a[i + j] == b[i + j];
538 if (!eq) {
539 r_cons_printf (eq2? Color_GREEN: Color_RED);
540 }
541 r_cons_printf ("%c", IS_PRINTABLE (a[i + j])? a[i + j]: '.');
542 if (!eq) {
543 r_cons_printf (Color_RESET);
544 }
545 }
546 for (j = 0; j < pad; j++) {
547 r_cons_printf (" ");
548 }
549 r_cons_printf (" ");
550 for (j = 0; j < w; j++) {
551 bool eq2 = a[i + j] == b[i + j];
552 if (!eq) {
553 r_cons_printf (eq2? Color_GREEN: Color_RED);
554 }
555 r_cons_printf ("%02x", b[i + j]);
556 if (!eq) {
557 r_cons_printf (Color_RESET);
558 }
559 }
560 for (j = 0; j < pad; j++) {
561 r_cons_printf (" ");
562 }
563 r_cons_printf (" ");
564 for (j = 0; j < w; j++) {
565 bool eq2 = a[i + j] == b[i + j];
566 if (!eq) {
567 r_cons_printf (eq2? Color_GREEN: Color_RED);
568 }
569 r_cons_printf ("%c", IS_PRINTABLE (b[i + j])? b[i + j]: '.');
570 if (!eq) {
571 r_cons_printf (Color_RESET);
572 }
573 }
574 r_cons_printf ("\n");
575 r_cons_flush ();
576 }
577 r_cons_break_end ();
578 r_cons_printf ("\n"Color_RESET);
579 r_cons_flush ();
580 if (as != bs) {
581 r_cons_printf ("...\n");
582 }
583 }
584
dump_cols_hexii(ut8 * a,int as,ut8 * b,int bs,int w)585 static void dump_cols_hexii(ut8 *a, int as, ut8 *b, int bs, int w) {
586 bool spacy = false;
587 ut32 sz = R_MIN (as, bs);
588 ut32 i, j;
589 int ctx = DUMP_CONTEXT;
590 int pad = 0;
591 if (!a || !b || as < 0 || bs < 0) {
592 return;
593 }
594 PrintfCallback p = r_cons_printf;
595 r_cons_break_push (NULL, NULL);
596 for (i = 0; i < sz; i += w) {
597 if (r_cons_is_breaked()) {
598 break;
599 }
600 if (i + w >= sz) {
601 pad = w - sz + i;
602 w = sz - i;
603 }
604 bool eq = !memcmp (a + i, b + i, w);
605 if (eq) {
606 ctx--;
607 if (ctx == -1) {
608 r_cons_printf ("...\n");
609 continue;
610 }
611 if (ctx < 0) {
612 ctx = -1;
613 continue;
614 }
615 } else {
616 ctx = DUMP_CONTEXT;
617 }
618 r_cons_printf (eq? Color_GREEN: Color_RED);
619 r_cons_printf ("0x%08x%c ", i, eq? ' ': '!');
620 r_cons_printf (Color_RESET);
621 for (j = 0; j < w; j++) {
622 bool eq2 = a[i + j] == b[i + j];
623 if (!eq) {
624 r_cons_printf (eq2? Color_GREEN: Color_RED);
625 }
626 ut8 ch = a[i + j];
627 if (spacy) {
628 p (" ");
629 }
630 if (ch == 0x00) {
631 p (" ");
632 } else if (ch == 0xff) {
633 p ("##");
634 } else if (IS_PRINTABLE (ch)) {
635 p (".%c", ch);
636 } else {
637 p ("%02x", ch);
638 }
639 if (!eq) {
640 r_cons_printf (Color_RESET);
641 }
642 }
643 for (j = 0; j < pad; j++) {
644 r_cons_printf (" ");
645 }
646 for (j = 0; j < pad; j++) {
647 r_cons_printf (" ");
648 }
649 r_cons_printf (" ");
650 for (j = 0; j < w; j++) {
651 bool eq2 = a[i + j] == b[i + j];
652 if (!eq) {
653 r_cons_printf (eq2? Color_GREEN: Color_RED);
654 }
655 ut8 ch = b[i + j];
656 if (spacy) {
657 p (" ");
658 }
659 if (ch == 0x00) {
660 p (" ");
661 } else if (ch == 0xff) {
662 p ("##");
663 } else if (IS_PRINTABLE (ch)) {
664 p (".%c", ch);
665 } else {
666 p ("%02x", ch);
667 }
668 if (!eq) {
669 r_cons_printf (Color_RESET);
670 }
671 }
672 for (j = 0; j < pad; j++) {
673 r_cons_printf (" ");
674 }
675 r_cons_printf ("\n");
676 r_cons_flush ();
677 }
678 r_cons_break_end ();
679 r_cons_printf ("\n"Color_RESET);
680 r_cons_flush ();
681 if (as != bs) {
682 r_cons_printf ("...\n");
683 }
684 }
685
handle_sha256(const ut8 * block,int len)686 static char *handle_sha256(const ut8 *block, int len) {
687 int i = 0;
688 char *p = malloc (128);
689 RHash *ctx = r_hash_new (true, R_HASH_SHA256);
690 const ut8 *c = r_hash_do_sha256 (ctx, block, len);
691 if (!c) {
692 r_hash_free (ctx);
693 free (p);
694 return NULL;
695 }
696 char *r = p;
697 for (i = 0; i < R_HASH_SIZE_SHA256; i++) {
698 snprintf (r + (i * 2), 3, "%02x", c[i]);
699 }
700 r_hash_free (ctx);
701 return p;
702 }
703
slurp(RadiffOptions * ro,RCore ** c,const char * file,size_t * sz)704 static ut8 *slurp(RadiffOptions *ro, RCore **c, const char *file, size_t *sz) {
705 RIODesc *d;
706 RIO *io;
707 if (c && file && strstr (file, "://")) {
708 ut8 *data = NULL;
709 ut64 size;
710 if (!*c) {
711 *c = opencore (ro, NULL);
712 }
713 if (!*c) {
714 eprintf ("opencore failed\n");
715 return NULL;
716 }
717 io = (*c)->io;
718 d = r_io_open (io, file, 0, 0);
719 if (!d) {
720 return NULL;
721 }
722 size = r_io_size (io);
723 if (size > 0 && size < ST32_MAX) {
724 data = calloc (1, size);
725 if (r_io_read_at (io, 0, data, size)) {
726 if (sz) {
727 *sz = size;
728 }
729 } else {
730 eprintf ("slurp: read error\n");
731 R_FREE (data);
732 }
733 } else {
734 eprintf ("slurp: Invalid file size\n");
735 }
736 r_io_desc_close (d);
737 return data;
738 }
739 return (ut8 *) r_file_slurp (file, sz);
740 }
741
import_cmp(const RBinImport * a,const RBinImport * b)742 static int import_cmp(const RBinImport *a, const RBinImport *b) {
743 return strcmp (a->name, b->name);
744 }
745
get_imports(RCore * c,int * len)746 static ut8 *get_imports(RCore *c, int *len) {
747 RListIter *iter;
748 RBinImport *str, *old = NULL;
749 ut8 *buf, *ptr;
750
751 if (!c || !len) {
752 return NULL;
753 }
754
755 RList *list = r_bin_get_imports (c->bin);
756 r_list_sort (list, (RListComparator) import_cmp);
757
758 *len = 0;
759
760 r_list_foreach (list, iter, str) {
761 if (!old || (old && import_cmp (old, str) != 0)) {
762 *len += strlen (str->name) + 1;
763 old = str;
764 }
765 }
766 ptr = buf = malloc (*len + 1);
767 if (!ptr) {
768 return NULL;
769 }
770
771 old = NULL;
772
773 r_list_foreach (list, iter, str) {
774 if (old && !import_cmp (old, str)) {
775 continue;
776 }
777 int namelen = strlen (str->name);
778 memcpy (ptr, str->name, namelen);
779 ptr += namelen;
780 *ptr++ = '\n';
781 old = str;
782 }
783 *ptr = 0;
784
785 *len = strlen ((const char *) buf);
786 return buf;
787 }
788
bs_cmp(const RBinString * a,const RBinString * b)789 static int bs_cmp(const RBinString *a, const RBinString *b) {
790 int diff = a->length - b->length;
791 return diff == 0? strncmp (a->string, b->string, a->length): diff;
792 }
793
get_strings(RCore * c,int * len)794 static ut8 *get_strings(RCore *c, int *len) {
795 RList *list = r_bin_get_strings (c->bin);
796 RListIter *iter;
797 RBinString *str, *old = NULL;
798 ut8 *buf, *ptr;
799
800 r_list_sort (list, (RListComparator) bs_cmp);
801
802 *len = 0;
803
804 r_list_foreach (list, iter, str) {
805 if (!old || (old && bs_cmp (old, str) != 0)) {
806 *len += str->length + 1;
807 old = str;
808 }
809 }
810
811 ptr = buf = malloc (*len + 1);
812 if (!ptr) {
813 return NULL;
814 }
815
816 old = NULL;
817
818 r_list_foreach (list, iter, str) {
819 if (old && bs_cmp (old, str) == 0) {
820 continue;
821 }
822 memcpy (ptr, str->string, str->length);
823 ptr += str->length;
824 *ptr++ = '\n';
825 old = str;
826 }
827 *ptr = 0;
828
829 *len = strlen ((const char *) buf);
830 return buf;
831 }
832
get_graph_commands(RCore * c,ut64 off)833 static char *get_graph_commands(RCore *c, ut64 off) {
834 bool tmp_html = r_cons_singleton ()->is_html;
835 r_cons_singleton ()->is_html = false;
836 r_cons_push ();
837 r_core_anal_graph (c, off, R_CORE_ANAL_GRAPHBODY | R_CORE_ANAL_GRAPHDIFF | R_CORE_ANAL_STAR);
838 const char *static_str = r_cons_get_buffer ();
839 char *retstr = strdup (r_str_get (static_str));
840 r_cons_pop ();
841 r_cons_echo (NULL);
842 r_cons_singleton ()->is_html = tmp_html;
843 return retstr;
844 }
845
__generate_graph(RCore * c,ut64 off)846 static void __generate_graph(RCore *c, ut64 off) {
847 r_return_if_fail (c);
848 char *ptr = get_graph_commands (c, off);
849 char *str = ptr;
850 r_cons_break_push (NULL, NULL);
851 if (str) {
852 for (;;) {
853 if (r_cons_is_breaked ()) {
854 break;
855 }
856 char *eol = strchr (ptr, '\n');
857 if (eol) {
858 *eol = '\0';
859 }
860 if (*ptr) {
861 char *p = strdup (ptr);
862 if (!p) {
863 free (str);
864 return;
865 }
866 r_core_cmd0 (c, p);
867 free (p);
868 }
869 if (!eol) {
870 break;
871 }
872 ptr = eol + 1;
873 }
874 free (str);
875 }
876 r_cons_break_pop ();
877 }
878
__print_diff_graph(RCore * c,ut64 off,int gmode)879 static void __print_diff_graph(RCore *c, ut64 off, int gmode) {
880 int opts = R_CORE_ANAL_GRAPHBODY | R_CORE_ANAL_GRAPHDIFF;
881 int use_utf8 = r_config_get_i (c->config, "scr.utf8");
882 r_agraph_reset(c->graph);
883 switch (gmode) {
884 case GRAPH_DOT_MODE:
885 r_core_anal_graph (c, off, opts);
886 break;
887 case GRAPH_STAR_MODE:
888 r_core_anal_graph (c, off, opts | R_CORE_ANAL_STAR);
889 break;
890 case GRAPH_TINY_MODE:
891 __generate_graph (c, off);
892 r_core_agraph_print (c, use_utf8, "t");
893 break;
894 case GRAPH_INTERACTIVE_MODE:
895 __generate_graph (c, off);
896 r_core_agraph_print (c, use_utf8, "v");
897 r_cons_reset_colors ();
898 break;
899 case GRAPH_SDB_MODE:
900 __generate_graph (c, off);
901 r_core_agraph_print (c, use_utf8, "k");
902 break;
903 case GRAPH_GML_MODE:
904 __generate_graph (c, off);
905 r_core_agraph_print (c, use_utf8, "g");
906 break;
907 case GRAPH_JSON_MODE:
908 r_core_anal_graph (c, off, opts | R_CORE_ANAL_JSON);
909 break;
910 case GRAPH_JSON_DIS_MODE:
911 r_core_anal_graph (c, off, opts | R_CORE_ANAL_JSON | R_CORE_ANAL_JSON_FORMAT_DISASM);
912 break;
913 case GRAPH_DEFAULT_MODE:
914 default:
915 __generate_graph (c, off);
916 r_core_agraph_print (c, use_utf8, "");
917 r_cons_reset_colors ();
918 break;
919 }
920 }
921
radiff_options_init(RadiffOptions * ro)922 static void radiff_options_init(RadiffOptions *ro) {
923 memset (ro, 0, sizeof (RadiffOptions));
924 ro->threshold = -1;
925 ro->useva = true;
926 ro->evals = r_list_newf (NULL);
927 ro->mode = MODE_DIFF;
928 ro->gmode = GRAPH_DEFAULT_MODE;
929 }
930
radiff_options_fini(RadiffOptions * ro)931 static void radiff_options_fini(RadiffOptions *ro) {
932 r_list_free (ro->evals);
933 r_core_free (ro->core);
934 r_cons_free ();
935 }
936
fileobj(RadiffOptions * ro,const char * ro_file,const ut8 * buf,size_t sz)937 static void fileobj(RadiffOptions *ro, const char *ro_file, const ut8 *buf, size_t sz) {
938 PJ *pj = ro->pj;
939 pj_o (pj);
940 pj_ks (pj, "filename", ro_file);
941 pj_kn (pj, "size", sz);
942 char *hasha = handle_sha256 (buf, (int)sz);
943 pj_ks (pj, "sha256", hasha);
944 free (hasha);
945 pj_end (pj);
946 }
947
r_main_radiff2(int argc,const char ** argv)948 R_API int r_main_radiff2(int argc, const char **argv) {
949 RadiffOptions ro;
950 const char *columnSort = NULL;
951 const char *addr = NULL;
952 RCore *c = NULL, *c2 = NULL;
953 ut8 *bufa = NULL, *bufb = NULL;
954 int o, /*diffmode = 0,*/ delta = 0;
955 ut64 sza = 0, szb = 0;
956 double sim = 0.0;
957 RDiff *d;
958 RGetopt opt;
959
960 radiff_options_init (&ro);
961
962 r_getopt_init (&opt, argc, argv, "Aa:b:BCDe:npg:m:G:OijrhcdsS:uUvVxXt:zqZ");
963 while ((o = r_getopt_next (&opt)) != -1) {
964 switch (o) {
965 case 'a':
966 ro.arch = opt.arg;
967 break;
968 case 'A':
969 ro.anal_all++;
970 break;
971 case 'b':
972 ro.bits = atoi (opt.arg);
973 break;
974 case 'B':
975 ro.diffmode = 'B';
976 break;
977 case 'e':
978 r_list_append (ro.evals, (void*)opt.arg);
979 break;
980 case 'p':
981 ro.useva = false;
982 break;
983 case 'r':
984 ro.diffmode = 'r';
985 break;
986 case 'g':
987 ro.mode = MODE_GRAPH;
988 addr = opt.arg;
989 break;
990 case 'm':{
991 const char *tmp = opt.arg;
992 switch (tmp[0]) {
993 case 'i': ro.gmode = GRAPH_INTERACTIVE_MODE; break;
994 case 'k': ro.gmode = GRAPH_SDB_MODE; break;
995 case 'j': ro.gmode = GRAPH_JSON_MODE; break;
996 case 'J': ro.gmode = GRAPH_JSON_DIS_MODE; break;
997 case 't': ro.gmode = GRAPH_TINY_MODE; break;
998 case 'd': ro.gmode = GRAPH_DOT_MODE; break;
999 case 's': ro.gmode = GRAPH_STAR_MODE; break;
1000 case 'g': ro.gmode = GRAPH_GML_MODE; break;
1001 case 'a':
1002 default: ro.gmode = GRAPH_DEFAULT_MODE; break;
1003 }
1004 } break;
1005 case 'G':
1006 ro.runcmd = opt.arg;
1007 break;
1008 case 'c':
1009 ro.showcount = 1;
1010 break;
1011 case 'C':
1012 ro.mode = MODE_CODE;
1013 break;
1014 case 'i':
1015 ro.mode = MODE_DIFF_IMPORTS;
1016 break;
1017 case 'n':
1018 ro.showbare = true;
1019 break;
1020 case 'O':
1021 ro.diffops = 1;
1022 break;
1023 case 't':
1024 ro.threshold = atoi (opt.arg);
1025 printf ("%s\n", opt.arg);
1026 break;
1027 case 'd':
1028 delta = 1;
1029 break;
1030 case 'D':
1031 if (ro.disasm) {
1032 ro.pdc = true;
1033 ro.disasm = false;
1034 ro.mode = MODE_CODE;
1035 } else {
1036 ro.disasm = true;
1037 }
1038 break;
1039 case 'h':
1040 return show_help (1);
1041 case 's':
1042 if (ro.mode == MODE_DIST_MYERS) {
1043 ro.mode = MODE_DIST_LEVENSHTEIN;
1044 } else {
1045 ro.mode = MODE_DIST_MYERS;
1046 }
1047 break;
1048 case 'S':
1049 columnSort = opt.arg;
1050 break;
1051 case 'x':
1052 ro.mode = MODE_COLS;
1053 break;
1054 case 'X':
1055 ro.mode = MODE_COLSII;
1056 break;
1057 case 'u':
1058 ro.diffmode = 'u';
1059 break;
1060 case 'U':
1061 ro.diffmode = 'U';
1062 break;
1063 case 'v':
1064 return r_main_version_print ("radiff2");
1065 case 'q':
1066 ro.quiet = true;
1067 break;
1068 case 'V':
1069 ro.verbose = true;
1070 break;
1071 case 'j':
1072 ro.diffmode = 'j';
1073 ro.pj = pj_new ();
1074 break;
1075 case 'z':
1076 ro.mode = MODE_DIFF_STRS;
1077 break;
1078 case 'Z':
1079 ro.zignatures = true;
1080 break;
1081 default:
1082 return show_help (0);
1083 }
1084 }
1085
1086 if (argc < 3 || opt.ind + 2 > argc) {
1087 return show_help (0);
1088 }
1089 ro.file = (opt.ind < argc)? argv[opt.ind]: NULL;
1090 ro.file2 = (opt.ind + 1 < argc)? argv[opt.ind + 1]: NULL;
1091
1092 if (R_STR_ISEMPTY (ro.file) || R_STR_ISEMPTY (ro.file2)) {
1093 eprintf ("Cannot open empty path\n");
1094 return 1;
1095 }
1096
1097 switch (ro.mode) {
1098 case MODE_GRAPH:
1099 case MODE_CODE:
1100 case MODE_DIFF_STRS:
1101 case MODE_DIFF_IMPORTS:
1102 c = opencore (&ro, ro.file);
1103 if (!c) {
1104 eprintf ("Cannot open '%s'\n", r_str_getf (ro.file));
1105 }
1106 c2 = opencore (&ro, ro.file2);
1107 if (!c2) {
1108 eprintf ("Cannot open '%s'\n", r_str_getf (ro.file2));
1109 }
1110 if (!c || !c2) {
1111 return 1;
1112 }
1113 c->c2 = c2;
1114 c2->c2 = c;
1115 r_core_parse_radare2rc (c);
1116 if (ro.arch) {
1117 r_config_set (c->config, "asm.arch", ro.arch);
1118 r_config_set (c2->config, "asm.arch", ro.arch);
1119 }
1120 if (ro.bits) {
1121 r_config_set_i (c->config, "asm.bits", ro.bits);
1122 r_config_set_i (c2->config, "asm.bits", ro.bits);
1123 }
1124 if (columnSort) {
1125 r_config_set (c->config, "diff.sort", columnSort);
1126 r_config_set (c2->config, "diff.sort", columnSort);
1127 }
1128 r_config_set_i (c->config, "diff.bare", ro.showbare);
1129 r_config_set_i (c2->config, "diff.bare", ro.showbare);
1130 r_anal_diff_setup_i (c->anal, ro.diffops, ro.threshold, ro.threshold);
1131 r_anal_diff_setup_i (c2->anal, ro.diffops, ro.threshold, ro.threshold);
1132 if (ro.pdc) {
1133 if (!addr) {
1134 //addr = "entry0";
1135 addr = "main";
1136 }
1137 /* should be in mode not in bool pdc */
1138 r_config_set_i (c->config, "scr.color", COLOR_MODE_DISABLED);
1139 r_config_set_i (c2->config, "scr.color", COLOR_MODE_DISABLED);
1140
1141 ut64 addra = r_num_math (c->num, addr);
1142 bufa = (ut8 *) r_core_cmd_strf (c, "af;pdc @ 0x%08"PFMT64x, addra);
1143 sza = (ut64)strlen ((const char *) bufa);
1144
1145 ut64 addrb = r_num_math (c2->num, addr);
1146 bufb = (ut8 *) r_core_cmd_strf (c2, "af;pdc @ 0x%08"PFMT64x, addrb);
1147 szb = (ut64)strlen ((const char *) bufb);
1148 ro.mode = MODE_DIFF;
1149 } else if (ro.mode == MODE_GRAPH) {
1150 int depth = r_config_get_i (c->config, "anal.depth");
1151 if (depth < 1) {
1152 depth = 64;
1153 }
1154 char *words = strdup (r_str_get_fail (addr, "0"));
1155 char *second = strchr (words, ',');
1156 if (second) {
1157 *second++ = 0;
1158 ut64 off = r_num_math (c->num, words);
1159 // define the same function at each offset
1160 r_core_anal_fcn (c, off, UT64_MAX, R_ANAL_REF_TYPE_NULL, depth);
1161 r_core_anal_fcn (c2, r_num_math (c2->num, second),
1162 UT64_MAX, R_ANAL_REF_TYPE_NULL, depth);
1163 r_core_gdiff (c, c2);
1164 __print_diff_graph (c, off, ro.gmode);
1165 } else {
1166 r_core_anal_fcn (c, r_num_math (c->num, words),
1167 UT64_MAX, R_ANAL_REF_TYPE_NULL, depth);
1168 r_core_anal_fcn (c2, r_num_math (c2->num, words),
1169 UT64_MAX, R_ANAL_REF_TYPE_NULL, depth);
1170 r_core_gdiff (c, c2);
1171 __print_diff_graph (c, r_num_math (c->num, addr), ro.gmode);
1172 }
1173 free (words);
1174 } else if (ro.mode == MODE_CODE) {
1175 if (ro.zignatures) {
1176 r_core_cmd0 (c, "z~?");
1177 r_core_cmd0 (c2, "z~?");
1178 r_core_zdiff (c, c2);
1179 } else {
1180 r_core_gdiff (c, c2);
1181 r_core_diff_show (c, c2);
1182 }
1183 } else if (ro.mode == MODE_DIFF_IMPORTS) {
1184 int sz;
1185 bufa = get_imports (c, &sz);
1186 sza = sz;
1187 bufb = get_imports (c2, &sz);
1188 szb = sz;
1189 } else if (ro.mode == MODE_DIFF_STRS) {
1190 int sz;
1191 bufa = get_strings (c, &sz);
1192 sza = sz;
1193 bufb = get_strings (c2, &sz);
1194 szb = sz;
1195 }
1196 if (ro.mode == MODE_CODE || ro.mode == MODE_GRAPH) {
1197 r_cons_flush ();
1198 }
1199 r_core_free (c);
1200 r_core_free (c2);
1201
1202 if (ro.mode == MODE_CODE || ro.mode == MODE_GRAPH) {
1203 return 0;
1204 }
1205 break;
1206 default: {
1207 size_t fsz;
1208 bufa = slurp (&ro, &c, ro.file, &fsz);
1209 sza = fsz;
1210 if (!bufa) {
1211 eprintf ("radiff2: Cannot open %s\n", r_str_getf (ro.file));
1212 return 1;
1213 }
1214 bufb = slurp (&ro, &c, ro.file2, &fsz);
1215 szb = fsz;
1216 if (!bufb) {
1217 eprintf ("radiff2: Cannot open: %s\n", r_str_getf (ro.file2));
1218 free (bufa);
1219 return 1;
1220 }
1221 if (sza != szb) {
1222 eprintf ("File size differs %"PFMT64u" vs %"PFMT64u"\n", (ut64)sza, (ut64)szb);
1223 }
1224 break;
1225 }
1226 }
1227
1228 // initialize RCons
1229 (void)r_cons_new ();
1230
1231 switch (ro.mode) {
1232 case MODE_COLSII:
1233 if (!c && !r_list_empty (ro.evals)) {
1234 c = opencore (&ro, NULL);
1235 }
1236 dump_cols_hexii (bufa, (int)sza, bufb, (int)szb, (r_cons_get_size (NULL) > 112)? 16: 8);
1237 break;
1238 case MODE_COLS:
1239 if (!c && !r_list_empty (ro.evals)) {
1240 c = opencore (&ro, NULL);
1241 }
1242 dump_cols (bufa, (int)sza, bufb, (int)szb, (r_cons_get_size (NULL) > 112)? 16: 8);
1243 break;
1244 case MODE_DIFF:
1245 case MODE_DIFF_STRS:
1246 case MODE_DIFF_IMPORTS:
1247 d = r_diff_new ();
1248 r_diff_set_delta (d, delta);
1249 if (ro.diffmode == 'j') {
1250 pj_o (ro.pj);
1251 pj_ka (ro.pj, "files");
1252 fileobj (&ro, ro.file, bufa, sza);
1253 fileobj (&ro, ro.file2, bufb, szb);
1254 pj_end (ro.pj);
1255 pj_ka (ro.pj, "changes");
1256 }
1257 if (ro.diffmode == 'B') {
1258 (void) write (1, "\xd1\xff\xd1\xff\x04", 5);
1259 }
1260 if (ro.diffmode == 'U') {
1261 char *res = r_diff_buffers_unified (d, bufa, (int)sza, bufb, (int)szb);
1262 if (res) {
1263 printf ("%s", res);
1264 free (res);
1265 }
1266 } else if (ro.diffmode == 'B') {
1267 r_diff_set_callback (d, &bcb, &ro);
1268 r_diff_buffers (d, bufa, (ut32)sza, bufb, (ut32)szb);
1269 (void) write (1, "\x00", 1);
1270 } else {
1271 r_diff_set_callback (d, &cb, &ro);
1272 r_diff_buffers (d, bufa, (ut32)sza, bufb, (ut32)szb);
1273 }
1274 if (ro.diffmode == 'j') {
1275 pj_end (ro.pj);
1276 }
1277 r_diff_free (d);
1278 break;
1279 case MODE_DIST_MYERS:
1280 case MODE_DIST_LEVENSHTEIN:
1281 {
1282 RDiff *d = r_diff_new ();
1283 if (d) {
1284 d->verbose = ro.verbose;
1285 if (ro.mode == MODE_DIST_MYERS) {
1286 d->type = 'm';
1287 } else {
1288 d->type = 'l';
1289 }
1290 r_diff_buffers_distance (d, bufa, (ut32)sza, bufb, (ut32)szb, &ro.count, &sim);
1291 r_diff_free (d);
1292 }
1293 }
1294 printf ("similarity: %.3f\n", sim);
1295 printf ("distance: %d\n", ro.count);
1296 break;
1297 }
1298
1299 if (ro.diffmode == 'j' && ro.showcount) {
1300 pj_kd (ro.pj, "count", ro.count);
1301 } else if (ro.showcount && ro.diffmode != 'j') {
1302 printf ("%d\n", ro.count);
1303 }
1304 if (ro.pj) {
1305 pj_end (ro.pj);
1306 char *s = pj_drain (ro.pj);
1307 printf ("%s\n", s);
1308 free (s);
1309 ro.pj = NULL;
1310 }
1311 free (bufa);
1312 free (bufb);
1313 radiff_options_fini (&ro);
1314
1315 return 0;
1316 }
1317