1 /* radare - LGPL - Copyright 2009-2019 - pancake */
2
3 #include "r_core.h"
4
5 static const char *help_msg_c[] = {
6 "Usage:", "c[?dfx] [argument]", " # Compare",
7 "c", " [string]", "Compare a plain with escaped chars string",
8 "c*", " [string]", "Same as above, but printing r2 commands instead",
9 "c1", " [addr]", "Compare 8 bits from current offset",
10 "c2", " [value]", "Compare a word from a math expression",
11 "c4", " [value]", "Compare a doubleword from a math expression",
12 "c8", " [value]", "Compare a quadword from a math expression",
13 "cat", " [file]", "Show contents of file (see pwd, ls)",
14 "cc", " [at]", "Compares in two hexdump columns of block size",
15 "ccc", " [at]", "Same as above, but only showing different lines",
16 "ccd", " [at]", "Compares in two disasm columns of block size",
17 "ccdd", " [at]", "Compares decompiler output (e cmd.pdc=pdg|pdd)",
18 "cd", " [dir]", "chdir",
19 // "cc", " [offset]", "code bindiff current block against offset"
20 // "cD", " [file]", "like above, but using radiff -b",
21 "cf", " [file]", "Compare contents of file at current seek",
22 "cg", "[?] [o] [file]", "Graphdiff current file and [file]",
23 "cl|cls|clear", "", "Clear screen, (clear0 to goto 0, 0 only)",
24 "cu", "[?] [addr] @at", "Compare memory hexdumps of $$ and dst in unified diff",
25 "cud", " [addr] @at", "Unified diff disasm from $$ and given address",
26 "cv", "[1248] [hexpairs] @at", "Compare 1,2,4,8-byte (silent return in $?)",
27 "cV", "[1248] [addr] @at", "Compare 1,2,4,8-byte address contents (silent, return in $?)",
28 "cw", "[?] [us?] [...]", "Compare memory watchers",
29 "cx", " [hexpair]", "Compare hexpair string (use '.' as nibble wildcard)",
30 "cx*", " [hexpair]", "Compare hexpair string (output r2 commands)",
31 "cX", " [addr]", "Like 'cc' but using hexdiff output",
32 NULL
33 };
34
cmd_cmp_init(RCore * core,RCmdDesc * parent)35 static void cmd_cmp_init(RCore *core, RCmdDesc *parent) {
36 DEFINE_CMD_DESCRIPTOR (core, c);
37 }
38
r_core_cmpwatch_free(RCoreCmpWatcher * w)39 R_API void r_core_cmpwatch_free(RCoreCmpWatcher *w) {
40 free (w->ndata);
41 free (w->odata);
42 free (w);
43 }
44
r_core_cmpwatch_get(RCore * core,ut64 addr)45 R_API RCoreCmpWatcher *r_core_cmpwatch_get(RCore *core, ut64 addr) {
46 RListIter *iter;
47 RCoreCmpWatcher *w;
48 r_list_foreach (core->watchers, iter, w) {
49 if (addr == w->addr) {
50 return w;
51 }
52 }
53 return NULL;
54 }
55
r_core_cmpwatch_add(RCore * core,ut64 addr,int size,const char * cmd)56 R_API int r_core_cmpwatch_add(RCore *core, ut64 addr, int size, const char *cmd) {
57 RCoreCmpWatcher *cmpw;
58 if (size < 1) {
59 return false;
60 }
61 cmpw = r_core_cmpwatch_get (core, addr);
62 if (!cmpw) {
63 cmpw = R_NEW (RCoreCmpWatcher);
64 if (!cmpw) {
65 return false;
66 }
67 cmpw->addr = addr;
68 }
69 cmpw->size = size;
70 snprintf (cmpw->cmd, sizeof (cmpw->cmd), "%s", cmd);
71 cmpw->odata = NULL;
72 cmpw->ndata = malloc (size);
73 if (!cmpw->ndata) {
74 free (cmpw);
75 return false;
76 }
77 r_io_read_at (core->io, addr, cmpw->ndata, size);
78 r_list_append (core->watchers, cmpw);
79 return true;
80 }
81
r_core_cmpwatch_del(RCore * core,ut64 addr)82 R_API int r_core_cmpwatch_del(RCore *core, ut64 addr) {
83 int ret = false;
84 RCoreCmpWatcher *w;
85 RListIter *iter, *iter2;
86 r_list_foreach_safe (core->watchers, iter, iter2, w) {
87 if (w->addr == addr || addr == UT64_MAX) {
88 r_list_delete (core->watchers, iter);
89 ret = true;
90 }
91 }
92 return ret;
93 }
94
r_core_cmpwatch_show(RCore * core,ut64 addr,int mode)95 R_API int r_core_cmpwatch_show(RCore *core, ut64 addr, int mode) {
96 char cmd[128];
97 RListIter *iter;
98 RCoreCmpWatcher *w;
99 r_list_foreach (core->watchers, iter, w) {
100 int is_diff = w->odata? memcmp (w->odata, w->ndata, w->size): 0;
101 switch (mode) {
102 case '*':
103 r_cons_printf ("cw 0x%08"PFMT64x " %d %s%s\n",
104 w->addr, w->size, w->cmd, is_diff? " # differs": "");
105 break;
106 case 'd': // diff
107 if (is_diff) {
108 r_cons_printf ("0x%08"PFMT64x " has changed\n", w->addr);
109 }
110 break;
111 case 'o': // old contents
112 // use tmpblocksize
113 default:
114 r_cons_printf ("0x%08"PFMT64x "%s\n", w->addr, is_diff? " modified": "");
115 snprintf (cmd, sizeof (cmd), "%s@%"PFMT64d "!%d",
116 w->cmd, w->addr, w->size);
117 r_core_cmd0 (core, cmd);
118 break;
119 }
120 }
121 return false;
122 }
123
r_core_cmpwatch_update(RCore * core,ut64 addr)124 R_API int r_core_cmpwatch_update(RCore *core, ut64 addr) {
125 RCoreCmpWatcher *w;
126 RListIter *iter;
127 r_list_foreach (core->watchers, iter, w) {
128 free (w->odata);
129 w->odata = w->ndata;
130 w->ndata = malloc (w->size);
131 if (!w->ndata) {
132 return false;
133 }
134 r_io_read_at (core->io, w->addr, w->ndata, w->size);
135 }
136 return !r_list_empty (core->watchers);
137 }
138
r_core_cmpwatch_revert(RCore * core,ut64 addr)139 R_API int r_core_cmpwatch_revert(RCore *core, ut64 addr) {
140 RCoreCmpWatcher *w;
141 int ret = false;
142 RListIter *iter;
143 r_list_foreach (core->watchers, iter, w) {
144 if (w->addr == addr || addr == UT64_MAX) {
145 if (w->odata) {
146 free (w->ndata);
147 w->ndata = w->odata;
148 w->odata = NULL;
149 ret = true;
150 }
151 }
152 }
153 return ret;
154 }
155
radare_compare_words(RCore * core,ut64 of,ut64 od,int len,int ws)156 static int radare_compare_words(RCore *core, ut64 of, ut64 od, int len, int ws) {
157 int i;
158 bool useColor = r_config_get_i (core->config, "scr.color") != 0;
159 utAny v0, v1;
160 RConsPrintablePalette *pal = &r_cons_singleton ()->context->pal;
161 for (i = 0; i < len; i+=ws) {
162 memset (&v0, 0, sizeof (v0));
163 memset (&v1, 0, sizeof (v1));
164 r_io_read_at (core->io, of + i, (ut8*)&v0, ws);
165 r_io_read_at (core->io, od + i, (ut8*)&v1, ws);
166 char ch = (v0.v64 == v1.v64)? '=': '!';
167 const char *color = useColor? ch == '='? "": pal->graph_false: "";
168 const char *colorEnd = useColor? Color_RESET: "";
169
170 if (useColor) {
171 r_cons_printf ("%s0x%08" PFMT64x" "Color_RESET, pal->offset, of + i);
172 } else {
173 r_cons_printf ("0x%08" PFMT64x" ", of + i);
174 }
175 switch (ws) {
176 case 1:
177 r_cons_printf ("%s0x%02x %c 0x%02x%s\n", color,
178 (ut32)(v0.v8 & 0xff), ch, (ut32)(v1.v8 & 0xff), colorEnd);
179 break;
180 case 2:
181 r_cons_printf ("%s0x%04hx %c 0x%04hx%s\n", color,
182 v0.v16, ch, v1.v16, colorEnd);
183 break;
184 case 4:
185 r_cons_printf ("%s0x%08"PFMT32x" %c 0x%08"PFMT32x"%s\n", color,
186 v0.v32, ch, v1.v32, colorEnd);
187 //r_core_cmdf (core, "fd@0x%"PFMT64x, v0.v32);
188 if (v0.v32 != v1.v32) {
189 // r_core_cmdf (core, "fd@0x%"PFMT64x, v1.v32);
190 }
191 break;
192 case 8:
193 r_cons_printf ("%s0x%016"PFMT64x" %c 0x%016"PFMT64x"%s\n",
194 color, v0.v64, ch, v1.v64, colorEnd);
195 //r_core_cmdf (core, "fd@0x%"PFMT64x, v0.v64);
196 if (v0.v64 != v1.v64) {
197 // r_core_cmdf (core, "fd@0x%"PFMT64x, v1.v64);
198 }
199 break;
200 }
201 }
202 return 0;
203 }
204
radare_compare_unified(RCore * core,ut64 of,ut64 od,int len)205 static int radare_compare_unified(RCore *core, ut64 of, ut64 od, int len) {
206 int i, min, inc = 16;
207 ut8 *f, *d;
208 if (len < 1) {
209 return false;
210 }
211 f = malloc (len);
212 if (!f) {
213 return false;
214 }
215 d = malloc (len);
216 if (!d) {
217 free (f);
218 return false;
219 }
220 r_io_read_at (core->io, of, f, len);
221 r_io_read_at (core->io, od, d, len);
222 int headers = B_IS_SET (core->print->flags, R_PRINT_FLAGS_HEADER);
223 if (headers) {
224 B_UNSET (core->print->flags, R_PRINT_FLAGS_HEADER);
225 }
226 for (i = 0; i < len; i += inc) {
227 min = R_MIN (16, (len - i));
228 if (!memcmp (f + i, d + i, min)) {
229 r_cons_printf (" ");
230 r_print_hexdiff (core->print, of + i, f + i, of + i, f + i, min, 0);
231 } else {
232 r_cons_printf ("- ");
233 r_print_hexdiff (core->print, of + i, f + i, od + i, d + i, min, 0);
234 r_cons_printf ("+ ");
235 r_print_hexdiff (core->print, od + i, d + i, of + i, f + i, min, 0);
236 }
237 }
238 if (headers) {
239 B_SET (core->print->flags, R_PRINT_FLAGS_HEADER);
240 }
241 return true;
242 }
243
radare_compare(RCore * core,const ut8 * f,const ut8 * d,int len,int mode)244 static int radare_compare(RCore *core, const ut8 *f, const ut8 *d, int len, int mode) {
245 int i, eq = 0;
246 PJ *pj = NULL;
247 if (len < 1) {
248 return 0;
249 }
250 if (mode == 'j') {
251 pj = pj_new ();
252 if (!pj) {
253 return -1;
254 }
255 pj_o (pj);
256 pj_k (pj, "diff_bytes");
257 pj_a (pj);
258 }
259 for (i = 0; i < len; i++) {
260 if (f[i] == d[i]) {
261 eq++;
262 continue;
263 }
264 switch (mode)
265 {
266 case 0:
267 r_cons_printf ("0x%08"PFMT64x " (byte=%.2d) %02x '%c' -> %02x '%c'\n",
268 core->offset + i, i + 1,
269 f[i], (IS_PRINTABLE (f[i]))? f[i]: ' ',
270 d[i], (IS_PRINTABLE (d[i]))? d[i]: ' ');
271 break;
272 case '*':
273 r_cons_printf ("wx %02x @ 0x%08"PFMT64x "\n",
274 d[i],
275 core->offset + i);
276 break;
277 case 'j':
278 pj_o (pj);
279 pj_kn (pj, "offset", core->offset + i);
280 pj_ki (pj, "rel_offset", i);
281 pj_ki (pj, "value", (int)f[i]);
282 pj_ki (pj, "cmp_value", (int)d[i]);
283 pj_end (pj);
284 break;
285
286 }
287 }
288 if (mode == 0) {
289 eprintf ("Compare %d/%d equal bytes (%d%%)\n", eq, len, (eq / len) * 100);
290 } else if (mode == 'j') {
291 pj_end (pj);
292 pj_ki (pj, "equal_bytes", eq);
293 pj_ki (pj, "total_bytes", len);
294 pj_end (pj); // End array
295 pj_end (pj); // End object
296 r_cons_println (pj_string (pj));
297 }
298 return len - eq;
299 }
300
cmd_cmp_watcher(RCore * core,const char * input)301 static void cmd_cmp_watcher(RCore *core, const char *input) {
302 char *p, *q, *r = NULL;
303 int size = 0;
304 ut64 addr = 0;
305 switch (*input) {
306 case ' ':
307 p = strdup (input + 1);
308 q = strchr (p, ' ');
309 if (q) {
310 *q++ = 0;
311 addr = r_num_math (core->num, p);
312 r = strchr (q, ' ');
313 if (r) {
314 *r++ = 0;
315 size = atoi (q);
316 }
317 r_core_cmpwatch_add (core, addr, size, r);
318 // eprintf ("ADD (%llx) %d (%s)\n", addr, size, r);
319 } else {
320 eprintf ("Missing parameters\n");
321 }
322 free (p);
323 break;
324 case 'r':
325 addr = input[1]? r_num_math (core->num, input + 1): UT64_MAX;
326 r_core_cmpwatch_revert (core, addr);
327 break;
328 case 'u':
329 addr = input[1]? r_num_math (core->num, input + 1): UT64_MAX;
330 r_core_cmpwatch_update (core, addr);
331 break;
332 case '*':
333 r_core_cmpwatch_show (core, UT64_MAX, '*');
334 break;
335 case '\0':
336 r_core_cmpwatch_show (core, UT64_MAX, 0);
337 break;
338 case '?': {
339 const char *help_message[] = {
340 "Usage: cw", "", "Watcher commands",
341 "cw", "", "List all compare watchers",
342 "cw", " addr", "List all compare watchers",
343 "cw", " addr sz cmd", "Add a memory watcher",
344 // "cws", " [addr]", "Show watchers",
345 "cw", "*", "List compare watchers in r2 cmds",
346 "cwr", " [addr]", "Reset/revert watchers",
347 "cwu", " [addr]", "Update watchers",
348 NULL
349 };
350 r_core_cmd_help (core, help_message);
351 }
352 break;
353 }
354 }
355
cmd_cmp_disasm(RCore * core,const char * input,int mode)356 static int cmd_cmp_disasm(RCore *core, const char *input, int mode) {
357 RAsmOp op, op2;
358 int i, j;
359 char colpad[80];
360 int hascolor = r_config_get_i (core->config, "scr.color");
361 int cols = r_config_get_i (core->config, "hex.cols") * 2;
362 ut64 off = r_num_math (core->num, input);
363 ut8 *buf = calloc (core->blocksize + 32, 1);
364 RConsPrintablePalette *pal = &r_cons_singleton ()->context->pal;
365 if (!buf) {
366 return false;
367 }
368 r_io_read_at (core->io, off, buf, core->blocksize + 32);
369 switch (mode) {
370 case 'd': // decompiler
371 {
372 #if 0
373 char *a = r_core_cmd_strf (core, "pdc @ 0x%"PFMT64x, off);
374 char *b = r_core_cmd_strf (core, "pdc @ 0x%"PFMT64x, core->offset);
375 RDiff *d = r_diff_new ();
376 char *s = r_diff_buffers_unified (d, a, strlen(a), b, strlen(b));
377 r_cons_printf ("%s\n", s);
378 free (a);
379 free (b);
380 free (s);
381 r_diff_free (d);
382 #else
383 r_core_cmdf (core, "pdc @ 0x%"PFMT64x">$a", off);
384 r_core_cmdf (core, "pdc @ 0x%"PFMT64x">$b", core->offset);
385 r_core_cmd0 (core, "diff $a $b;rm $a;rm $b");
386 #endif
387 }
388 break;
389 case 'c': // columns
390 for (i = j = 0; i < core->blocksize && j < core->blocksize;) {
391 // dis A
392 r_asm_set_pc (core->rasm, core->offset + i);
393 (void) r_asm_disassemble (core->rasm, &op,
394 core->block + i, core->blocksize - i);
395
396 // dis B
397 r_asm_set_pc (core->rasm, off + i);
398 (void) r_asm_disassemble (core->rasm, &op2,
399 buf + j, core->blocksize - j);
400
401 // show output
402 bool iseq = r_strbuf_equals (&op.buf_asm, &op2.buf_asm);
403 memset (colpad, ' ', sizeof (colpad));
404 {
405 int pos = strlen (r_strbuf_get (&op.buf_asm));
406 pos = (pos > cols)? 0: cols - pos;
407 colpad[pos] = 0;
408 }
409 if (hascolor) {
410 r_cons_print (iseq? pal->graph_true: pal->graph_false);
411 }
412 r_cons_printf (" 0x%08"PFMT64x " %s %s",
413 core->offset + i, r_strbuf_get (&op.buf_asm), colpad);
414 r_cons_printf ("%c 0x%08"PFMT64x " %s\n",
415 iseq? '=': '!', off + j, r_strbuf_get (&op2.buf_asm));
416 if (hascolor) {
417 r_cons_print (Color_RESET);
418 }
419 if (op.size < 1) {
420 op.size = 1;
421 }
422 i += op.size;
423 if (op2.size < 1) {
424 op2.size = 1;
425 }
426 j += op2.size;
427 }
428 break;
429 case 'u': // unified
430 for (i = j = 0; i < core->blocksize && j < core->blocksize;) {
431 // dis A
432 r_asm_set_pc (core->rasm, core->offset + i);
433 (void) r_asm_disassemble (core->rasm, &op,
434 core->block + i, core->blocksize - i);
435
436 // dis B
437 r_asm_set_pc (core->rasm, off + i);
438 (void) r_asm_disassemble (core->rasm, &op2,
439 buf + j, core->blocksize - j);
440
441 // show output
442 bool iseq = r_strbuf_equals (&op.buf_asm, &op2.buf_asm); // (!strcmp (op.buf_asm, op2.buf_asm));
443 if (iseq) {
444 r_cons_printf (" 0x%08"PFMT64x " %s\n",
445 core->offset + i, r_strbuf_get (&op.buf_asm));
446 } else {
447 if (hascolor) {
448 r_cons_print (pal->graph_false);
449 }
450 r_cons_printf ("-0x%08"PFMT64x " %s\n",
451 core->offset + i, r_strbuf_get (&op.buf_asm));
452 if (hascolor) {
453 r_cons_print (pal->graph_true);
454 }
455 r_cons_printf ("+0x%08"PFMT64x " %s\n",
456 off + j, r_strbuf_get (&op2.buf_asm));
457 if (hascolor) {
458 r_cons_print (Color_RESET);
459 }
460 }
461 if (op.size < 1) {
462 op.size = 1;
463 }
464 i += op.size;
465 if (op2.size < 1) {
466 op2.size = 1;
467 }
468 j += op2.size;
469 }
470 break;
471 }
472 return 0;
473 }
474
cmd_cp(void * data,const char * input)475 static int cmd_cp(void *data, const char *input) {
476 RCore *core = (RCore *)data;
477 if (input[1] == '.') {
478 char *file = r_core_cmd_strf (core, "ij~{core.file}");
479 r_str_trim (file);
480 char *newfile = r_str_newf ("%s.%s", file, input + 2);
481 r_file_copy (file, newfile);
482 free (file);
483 free (newfile);
484 return true;
485 }
486 if (strlen (input) < 3) {
487 eprintf ("Usage: cp src dst\n");
488 eprintf ("Usage: cp.orig # cp $file $file.orig\n");
489 return false;
490 }
491 char *cmd = strdup (input + 2);
492 if (cmd) {
493 char **files = r_str_argv (cmd, NULL);
494 if (files[0] && files[1]) {
495 bool rc = r_file_copy (files[0], files[1]);
496 free (cmd);
497 r_str_argv_free (files);
498 return rc;
499 }
500 r_str_argv_free (files);
501 }
502 eprintf ("Usage: cp src dst\n");
503 return false;
504 }
505
__core_cmp_bits(RCore * core,ut64 addr)506 static void __core_cmp_bits (RCore *core, ut64 addr) {
507 const bool scr_color = r_config_get_i (core->config, "scr.color");
508 int i;
509 ut8 a, b;
510 r_io_read_at (core->io, core->offset, &a, 1);
511 r_io_read_at (core->io, addr, &b, 1);
512 RConsPrintablePalette *pal = &r_cons_singleton ()->context->pal;
513 const char *color = scr_color? pal->offset: "";
514 const char *color_end = scr_color? Color_RESET: "";
515 if (r_config_get_i (core->config, "hex.header")) {
516 char *n = r_str_newf ("0x%08"PFMT64x, core->offset);
517 const char *extra = r_str_pad (' ', strlen (n) - 10);
518 free (n);
519 r_cons_printf ("%s- offset -%s 7 6 5 4 3 2 1 0%s\n", color, extra, color_end);
520 }
521 color = scr_color? pal->graph_false: "";
522 color_end = scr_color? Color_RESET: "";
523
524 r_cons_printf ("%s0x%08"PFMT64x"%s ", color, core->offset, color_end);
525 for (i = 7; i >= 0; i--) {
526 bool b0 = (a & 1<<i)? 1: 0;
527 bool b1 = (b & 1<<i)? 1: 0;
528 color = scr_color? (b0 == b1)? "": b0? pal->graph_true:pal->graph_false: "";
529 color_end = scr_color ? Color_RESET: "";
530 r_cons_printf ("%s%d%s ", color, b0, color_end);
531 }
532 color = scr_color? pal->graph_true: "";
533 color_end = scr_color? Color_RESET: "";
534 r_cons_printf ("\n%s0x%08"PFMT64x"%s ", color, addr, color_end);
535 for (i = 7; i >= 0; i--) {
536 bool b0 = (a & 1<<i)? 1: 0;
537 bool b1 = (b & 1<<i)? 1: 0;
538 color = scr_color? (b0 == b1)? "": b1? pal->graph_true: pal->graph_false: "";
539 color_end = scr_color ? Color_RESET: "";
540 r_cons_printf ("%s%d%s ", color, b1, color_end);
541 }
542 r_cons_newline ();
543 }
544
cmd_cmp(void * data,const char * input)545 static int cmd_cmp(void *data, const char *input) {
546 static char *oldcwd = NULL;
547 int ret = 0, i, mode = 0;
548 RCore *core = (RCore *)data;
549 ut64 val = UT64_MAX;
550 char *filled;
551 ut8 *buf;
552 ut16 v16;
553 ut32 v32;
554 ut64 v64;
555 FILE *fd;
556 const ut8* block = core->block;
557
558 switch (*input) {
559 case 'p':
560 return cmd_cp (data, input);
561 break;
562 case 'a': // "cat"
563 if (input[1] == 't') {
564 const char *path = r_str_trim_head_ro (input + 2);
565 if (*path == '$') {
566 const char *oldText = r_cmd_alias_get (core->rcmd, path, 1);
567 if (oldText) {
568 r_cons_printf ("%s\n", oldText + 1);
569 }
570 } else {
571 if (r_fs_check (core->fs, path)) {
572 r_core_cmdf (core, "mg %s", path);
573 } else {
574 char *res = r_syscmd_cat (path);
575 if (res) {
576 r_cons_print (res);
577 free (res);
578 }
579 }
580 }
581 }
582 break;
583 case 'w':
584 cmd_cmp_watcher (core, input + 1);
585 break;
586 case '*':
587 if (!input[2]) {
588 eprintf ("Usage: cx* 00..22'\n");
589 return 0;
590 }
591
592 val = radare_compare (core, block, (ut8 *) input + 2,
593 strlen (input + 2) + 1, '*');
594 break;
595 case ' ':
596 {
597 char *str = strdup (input + 1);
598 int len = r_str_unescape (str);
599 val = radare_compare (core, block, (ut8 *) str, len, 0);
600 free (str);
601 }
602 break;
603 case 'j':
604 {
605 if (input[1] != ' ') {
606 eprintf ("Usage: cj [string]\n");
607 } else {
608 char *str = strdup (input + 2);
609 int len = r_str_unescape (str);
610 val = radare_compare (core, block, (ut8 *) str, len, 'j');
611 free (str);
612 }
613 }
614 break;
615 case 'x':
616 switch (input[1]) {
617 case ' ':
618 mode = 0;
619 input += 2;
620 break;
621 case '*':
622 if (input[2] != ' ') {
623 eprintf ("Usage: cx* 00..22'\n");
624 return 0;
625 }
626 mode = '*';
627 input += 3;
628 break;
629 default:
630 eprintf ("Usage: cx 00..22'\n");
631 return 0;
632 }
633 if (!(filled = (char *) malloc (strlen (input) + 1))) {
634 return false;
635 }
636 memcpy (filled, input, strlen (input) + 1);
637 if (!(buf = (ut8 *) malloc (strlen (input) + 1))) {
638 free (filled);
639 return false;
640 }
641 ret = r_hex_bin2str (block, strlen (input) / 2, (char *) buf);
642 for (i = 0; i < ret * 2; i++) {
643 if (filled[i] == '.') {
644 filled[i] = buf[i];
645 }
646 }
647
648 ret = r_hex_str2bin (filled, buf);
649 if (ret < 1) {
650 eprintf ("Cannot parse hexpair\n");
651 } else {
652 val = radare_compare (core, block, buf, ret, mode);
653 }
654 free (buf);
655 free (filled);
656 break;
657 case 'X':
658 buf = malloc (core->blocksize);
659 if (buf) {
660 if (!r_io_read_at (core->io, r_num_math (core->num,
661 input + 1), buf, core->blocksize)) {
662 eprintf ("Cannot read hexdump\n");
663 } else {
664 val = radare_compare (core, block, buf, ret, mode);
665 }
666 free (buf);
667 }
668 return false;
669 break;
670 case 'f':
671 if (input[1] != ' ') {
672 eprintf ("Please. use 'cf [file]'\n");
673 return false;
674 }
675 fd = r_sandbox_fopen (input + 2, "rb");
676 if (!fd) {
677 eprintf ("Cannot open file '%s'\n", input + 2);
678 return false;
679 }
680 buf = (ut8 *) malloc (core->blocksize);
681 if (buf) {
682 if (fread (buf, 1, core->blocksize, fd) < 1) {
683 eprintf ("Cannot read file %s\n", input + 2);
684 } else {
685 val = radare_compare (core, block, buf, core->blocksize, 0);
686 }
687 fclose (fd);
688 free (buf);
689 } else {
690 fclose (fd);
691 return false;
692 }
693 break;
694 case 'd': // "cd"
695 while (input[1] == ' ') input++;
696 if (input[1]) {
697 if (!strcmp (input + 1, "-")) {
698 if (oldcwd) {
699 char *newdir = oldcwd;
700 oldcwd = r_sys_getdir ();
701 if (r_sandbox_chdir (newdir) == -1) {
702 eprintf ("Cannot chdir to %s\n", newdir);
703 free (oldcwd);
704 oldcwd = newdir;
705 } else {
706 free (newdir);
707 }
708 } else {
709 // nothing to do here
710 }
711 } else if (input[1] == '~' && input[2] == '/') {
712 char *homepath = r_str_home (input + 3);
713 if (homepath) {
714 if (*homepath) {
715 free (oldcwd);
716 oldcwd = r_sys_getdir ();
717 if (r_sandbox_chdir (homepath) == -1) {
718 eprintf ("Cannot chdir to %s\n", homepath);
719 }
720 }
721 free (homepath);
722 } else {
723 eprintf ("Cannot find home\n");
724 }
725 } else {
726 free (oldcwd);
727 oldcwd = r_sys_getdir ();
728 if (r_sandbox_chdir (input + 1) == -1) {
729 eprintf ("Cannot chdir to %s\n", input + 1);
730 }
731 }
732 } else {
733 char *home = r_sys_getenv (R_SYS_HOME);
734 if (!home || r_sandbox_chdir (home) == -1) {
735 eprintf ("Cannot find home.\n");
736 }
737 free (home);
738 }
739 break;
740 case '1': // "c1"
741 __core_cmp_bits (core, r_num_math (core->num, input + 1));
742 break;
743 case '2': // "c2"
744 v16 = (ut16) r_num_math (core->num, input + 1);
745 val = radare_compare (core, block, (ut8 *) &v16, sizeof (v16), 0);
746 break;
747 case '4': // "c4"
748 v32 = (ut32) r_num_math (core->num, input + 1);
749 val = radare_compare (core, block, (ut8 *) &v32, sizeof (v32), 0);
750 break;
751 case '8': // "c8"
752 v64 = (ut64) r_num_math (core->num, input + 1);
753 val = radare_compare (core, block, (ut8 *) &v64, sizeof (v64), 0);
754 break;
755 case 'c': // "cc"
756 if (input[1] == '?') { // "cc?"
757 r_core_cmd0 (core, "c?~cc");
758 } else if (input[1] == 'd') { // "ccd"
759 if (input[2] == 'd') { // "ccdd"
760 cmd_cmp_disasm (core, input + 3, 'd');
761 } else {
762 cmd_cmp_disasm (core, input + 2, 'c');
763 }
764 } else {
765 ut32 oflags = core->print->flags;
766 ut64 addr = 0; // TOTHINK: Not sure what default address should be
767 if (input[1] == 'c') { // "ccc"
768 core->print->flags |= R_PRINT_FLAGS_DIFFOUT;
769 addr = r_num_math (core->num, input + 2);
770 } else {
771 if (*input && input[1]) {
772 addr = r_num_math (core->num, input + 2);
773 }
774 }
775 int col = core->cons->columns > 123;
776 ut8 *b = malloc (core->blocksize);
777 if (b != NULL) {
778 memset (b, 0xff, core->blocksize);
779 r_io_read_at (core->io, addr, b, core->blocksize);
780 r_print_hexdiff (core->print, core->offset, block,
781 addr, b, core->blocksize, col);
782 free (b);
783 }
784 core->print->flags = oflags;
785 }
786 break;
787 case 'g': // "cg"
788 { // XXX: this is broken
789 int diffops = 0;
790 RCore *core2;
791 char *file2 = NULL;
792 switch (input[1]) {
793 case 'o': // "cgo"
794 file2 = (char *) r_str_trim_head_ro (input + 2);
795 r_anal_diff_setup (core->anal, true, -1, -1);
796 break;
797 case 'f': // "cgf"
798 eprintf ("TODO: agf is experimental\n");
799 r_anal_diff_setup (core->anal, true, -1, -1);
800 r_core_gdiff_fcn (core, core->offset,
801 r_num_math (core->num, input + 2));
802 return false;
803 case ' ':
804 file2 = (char *) r_str_trim_head_ro (input + 2);
805 r_anal_diff_setup (core->anal, false, -1, -1);
806 break;
807 default: {
808 const char *help_message[] = {
809 "Usage: cg", "", "Graph code commands",
810 "cg", "", "diff ratio among functions (columns: off-A, match-ratio, off-B)",
811 "cgf", "[fcn]", "Compare functions (curseek vs fcn)",
812 "cgo", "", "Opcode-bytes code graph diff",
813 NULL
814 };
815 r_core_cmd_help (core, help_message);
816 return false;
817 }
818 }
819
820 if (r_file_size (file2) <= 0) {
821 eprintf ("Cannot compare with file %s\n", file2);
822 return false;
823 }
824
825 if (!(core2 = r_core_new ())) {
826 eprintf ("Cannot init diff core\n");
827 return false;
828 }
829 r_core_loadlibs (core2, R_CORE_LOADLIBS_ALL, NULL);
830 core2->io->va = core->io->va;
831 if (!r_core_file_open (core2, file2, 0, 0LL)) {
832 eprintf ("Cannot open diff file '%s'\n", file2);
833 r_core_free (core2);
834 r_core_bind_cons (core);
835 return false;
836 }
837 // TODO: must replicate on core1 too
838 r_config_set_i (core2->config, "io.va", true);
839 r_anal_diff_setup (core->anal, diffops, -1, -1);
840 r_anal_diff_setup (core2->anal, diffops, -1, -1);
841
842 r_core_bin_load (core2, file2,
843 r_config_get_i (core->config, "bin.baddr"));
844 r_core_gdiff (core, core2);
845 r_core_diff_show (core, core2);
846 /* exchange a segfault with a memleak */
847 core2->config = NULL;
848 r_core_free (core2);
849 r_core_bind_cons (core);
850 }
851 break;
852 case 'u': // "cu"
853 switch (input[1]) {
854 case '.':
855 case ' ':
856 radare_compare_unified (core, core->offset,
857 r_num_math (core->num, input + 2),
858 core->blocksize);
859 break;
860 case '1':
861 case '2':
862 case '4':
863 case '8':
864 radare_compare_words (core, core->offset,
865 r_num_math (core->num, input + 2),
866 core->blocksize, input[1] - '0');
867 break;
868 case 'd':
869 cmd_cmp_disasm (core, input + 2, 'u');
870 break;
871 default: {
872 const char *help_msg[] = {
873 "Usage: cu", " [offset]", "# Prints unified comparison to make hexpatches",
874 "cu", " $$+1 > p", "Compare hexpairs from current seek and +1",
875 "cu1", " $$+1 > p", "Compare bytes from current seek and +1",
876 "cu2", " $$+1 > p", "Compare words (half, 16bit) from current seek and +1",
877 "cu4", " $$+1 > p", "Compare dwords from current seek and +1",
878 "cu8", " $$+1 > p", "Compare qwords from current seek and +1",
879 "cud", " $$+1 > p", "Compare disasm current seek and +1",
880 "wu", " p", "Apply unified hex patch (see output of cu)",
881 NULL
882 };
883 r_core_cmd_help (core, help_msg);
884 }
885 }
886 break;
887 case '?':
888 r_core_cmd_help (core, help_msg_c);
889 break;
890 case 'v': { // "cv"
891 int sz = input[1];
892 if (sz == ' ') {
893 switch (r_config_get_i (core->config, "asm.bits")) {
894 case 8: sz = '1'; break;
895 case 16: sz = '2'; break;
896 case 32: sz = '4'; break;
897 case 64: sz = '8'; break;
898 default: sz = '4'; break; // default
899 }
900 }
901 // TODO: honor endian
902 switch (sz) {
903 case '1': { // "cv1"
904 ut8 n = (ut8) r_num_math (core->num, input + 2);
905 core->num->value = 1;
906 if (block[0] == n) {
907 r_cons_printf ("0x%08"PFMT64x "\n", core->offset);
908 core->num->value = 0;
909 }
910 break;
911 }
912 case '2': { // "cv2"
913 ut16 n = (ut16) r_num_math (core->num, input + 2);
914 core->num->value = 1;
915 if (core->blocksize >= 2 && *(ut16*)block == n) {
916 r_cons_printf ("0x%08"PFMT64x "\n", core->offset);
917 core->num->value = 0;
918 }
919 break;
920 }
921 case '4': { // "cv4"
922 ut32 n = (ut32) r_num_math (core->num, input + 2);
923 core->num->value = 1;
924 if (core->blocksize >= 4 && *(ut32*)block == n) {
925 r_cons_printf ("0x%08"PFMT64x "\n", core->offset);
926 core->num->value = 0;
927 }
928 break;
929 }
930 case '8': { // "cv8"
931 ut64 n = (ut64) r_num_math (core->num, input + 2);
932 core->num->value = 1;
933 if (core->blocksize >= 8 && *(ut64*)block == n) {
934 r_cons_printf ("0x%08"PFMT64x "\n", core->offset);
935 core->num->value = 0;
936 }
937 break;
938 }
939 default:
940 case '?':
941 eprintf ("Usage: cv[1248] [num]\n"
942 "Show offset if current value equals to the one specified\n"
943 " /v 18312 # serch for a known value\n"
944 " dc\n"
945 " cv4 18312 @@ hit*\n"
946 " dc\n");
947 break;
948 }
949 }
950 break;
951 case 'V': { // "cV"
952 int sz = input[1];
953 if (sz == ' ') {
954 switch (r_config_get_i (core->config, "asm.bits")) {
955 case 8: sz = '1'; break;
956 case 16: sz = '2'; break;
957 case 32: sz = '4'; break;
958 case 64: sz = '8'; break;
959 default: sz = '4'; break; // default
960 }
961 } else if (sz == '?') {
962 eprintf ("Usage: cV[1248] [addr] @ addr2\n"
963 "Compare n bytes from one address to current one and return in $? 0 or 1\n");
964 }
965 sz -= '0';
966 if (sz > 0) {
967 ut64 at = r_num_math (core->num, input + 2);
968 ut8 buf[8] = {0};
969 r_io_read_at (core->io, at, buf, sizeof (buf));
970 core->num->value = memcmp (buf, core->block, sz)? 1: 0;
971 }
972 break;
973 }
974 case 'l': // "cl"
975 if (strchr (input, 'f')) {
976 r_cons_flush ();
977 } else if (input[1] == 0) {
978 r_cons_fill_line ();
979 // r_cons_clear_line (0);
980 } else if (!strchr (input, '0')) {
981 r_cons_clear00 ();
982 }
983 break;
984 default:
985 r_core_cmd_help (core, help_msg_c);
986 }
987 if (val != UT64_MAX) {
988 core->num->value = val;
989 }
990 return 0;
991 }
992