Rizin
unix-like reverse engineering framework and cli tools
cmp.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2021 Dhruv Maroo <dhruvmaru007@gmail.com>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_cmp.h>
5 #include <rz_asm.h>
6 #include <rz_list.h>
7 
19 
20  ut8 *buf1 = malloc(len * sizeof(ut8));
21  ut8 *buf2 = malloc(len * sizeof(ut8));
22  if (!buf1 || !buf2) {
23  goto error_goto;
24  }
25  if (!(rz_io_nread_at(core->io, addr1, buf1, len) == len && rz_io_nread_at(core->io, addr2, buf2, len) == len)) {
26  RZ_LOG_ERROR("Cannot read %u bytes at provided addresses: 0x%" PFMT64x " 0x%" PFMT64x "\n", len, addr1, addr2);
27  goto error_goto;
28  }
30  if (!cmp) {
31  goto error_goto;
32  }
33  cmp->len = len;
34  cmp->data1 = buf1;
35  cmp->addr1 = addr1;
36  cmp->data2 = buf2;
37  cmp->addr2 = addr2;
38  cmp->same = rz_mem_eq(cmp->data1, cmp->data2, len);
39  return cmp;
40 
41 error_goto:
42  free(buf1);
43  free(buf2);
44  return NULL;
45 }
46 
57  rz_return_val_if_fail(core && data, NULL);
58 
59  ut8 *buf1 = malloc(len * sizeof(ut8));
60  if (!buf1) {
61  RZ_LOG_ERROR("Cannot read at address: 0x%" PFMT64x "\n", addr);
62  goto error_goto;
63  }
64  if (rz_io_nread_at(core->io, addr, buf1, len) != len) {
65  RZ_LOG_ERROR("Cannot read %u bytes at provided address: 0x%" PFMT64x "\n", len, addr);
66  goto error_goto;
67  }
69  if (!cmp) {
70  goto error_goto;
71  }
72  cmp->len = len;
73  cmp->data1 = buf1;
74  cmp->addr1 = addr;
75  cmp->data2 = rz_mem_dup(data, len);
76  cmp->addr2 = UT64_MAX;
77  cmp->same = rz_mem_eq(cmp->data1, cmp->data2, len);
78  return cmp;
79 
80 error_goto:
81  free(buf1);
82  return NULL;
83 }
84 
94  rz_return_val_if_fail(core && cmp, -1);
95 
96  int i, eq = 0;
97  bool data_str = cmp->addr2 == UT64_MAX;
98  if (cmp->len == UT8_MAX) {
99  return -1;
100  }
102  PJ *pj = NULL;
103  if (state) {
104  mode = state->mode;
105  pj = state->d.pj;
106  }
107  if (mode == RZ_OUTPUT_MODE_JSON) {
108  pj_o(pj);
109  pj_k(pj, "diff_bytes");
110  pj_a(pj);
111  }
112  for (i = 0; i < cmp->len; i++) {
113  if (cmp->data1[i] == cmp->data2[i]) {
114  eq++;
115  continue;
116  }
117  switch (mode) {
119  rz_cons_printf("0x%08" PFMT64x, cmp->addr1 + i);
120  if (!data_str) {
121  rz_cons_printf(" -> 0x%08" PFMT64x, cmp->addr2 + i);
122  }
123  rz_cons_printf(" (byte=%.2d) %02x '%c' -> %02x '%c'\n", i + 1,
124  cmp->data1[i], (IS_PRINTABLE(cmp->data1[i])) ? cmp->data1[i] : ' ',
125  cmp->data2[i], (IS_PRINTABLE(cmp->data2[i])) ? cmp->data2[i] : ' ');
126  break;
127  case RZ_OUTPUT_MODE_JSON:
128  pj_o(pj);
129  pj_kn(pj, "offset1", cmp->addr1 + i);
130  pj_kn(pj, "offset2", data_str ? i : cmp->addr2 + i);
131  pj_ki(pj, "rel_offset", i);
132  pj_ki(pj, "value1", (int)cmp->data1[i]);
133  pj_ki(pj, "value2", (int)cmp->data2[i]);
134  pj_end(pj);
135  break;
136  default:
138  }
139  }
140  if (mode == RZ_OUTPUT_MODE_STANDARD) {
141  rz_cons_printf("Compare %d/%d equal bytes (%d%%)\n", eq, cmp->len, (int)(100.0 * eq / cmp->len));
142  } else if (mode == RZ_OUTPUT_MODE_JSON) {
143  pj_end(pj);
144  pj_ki(pj, "equal_bytes", eq);
145  pj_ki(pj, "total_bytes", cmp->len);
146  pj_end(pj); // End array
147  pj_end(pj); // End object
148  }
149  return cmp->len - eq;
150 }
151 
161 RZ_API RZ_OWN RzList /*<RzCompareData *>*/ *rz_core_cmp_disasm(RzCore *core, ut64 addr1, ut64 addr2, ut32 len) {
163 
164  RzList *cmp_list = rz_list_new();
165  if (!cmp_list) {
166  goto error_goto;
167  }
168  cmp_list->free = (RzListFree)&rz_core_cmp_free;
169  RzAsmOp op, op2;
170  int i, j;
171  ut8 *buf = calloc(len + 32, 1);
172  if (!buf) {
173  goto error_goto;
174  }
175  rz_io_nread_at(core->io, addr2, buf, len + 32);
176  RzCompareData *comp;
177 
178  for (i = j = 0; i < len && j < len;) {
179  comp = RZ_NEW0(RzCompareData);
180  if (!comp) {
181  continue;
182  }
183 
184  // dis A
185  rz_asm_set_pc(core->rasm, addr1 + i);
186  (void)rz_asm_disassemble(core->rasm, &op,
187  core->block + i, len - i);
188 
189  // dis B
190  rz_asm_set_pc(core->rasm, addr2 + i);
191  (void)rz_asm_disassemble(core->rasm, &op2,
192  buf + j, len - j);
193 
194  comp->len = UT8_MAX;
195  comp->data1 = (ut8 *)strdup(rz_strbuf_get(&op.buf_asm));
196  comp->addr1 = addr1 + i;
197  comp->data2 = (ut8 *)strdup(rz_strbuf_get(&op2.buf_asm));
198  comp->addr2 = addr2 + j;
199  comp->same = !strcmp((char *)comp->data1, (char *)comp->data2); // we can assume that instructions can be represented as plain chars
200  rz_list_append(cmp_list, comp);
201 
202  if (op.size < 1) {
203  op.size = 1;
204  }
205  i += op.size;
206  if (op2.size < 1) {
207  op2.size = 1;
208  }
209  j += op2.size;
210  }
211 
212  free(buf);
213  return cmp_list;
214 
215 error_goto:
216  rz_list_free(cmp_list);
217  return NULL;
218 }
219 
227  if (!cmp) {
228  return;
229  }
230  RZ_FREE(cmp->data1);
231  RZ_FREE(cmp->data2);
232  free(cmp);
233 }
234 
243 RZ_API bool rz_core_cmp_disasm_print(RzCore *core, const RzList /*<RzCompareData *>*/ *compare, bool unified) {
244  rz_return_val_if_fail(core && compare, false);
245  char colpad[80];
246  int hascolor = rz_config_get_i(core->config, "scr.color");
247  int cols = rz_config_get_i(core->config, "hex.cols") * 2;
249  RzListIter *it;
251 
252  if (unified) {
253  rz_list_foreach (compare, it, cmp) {
254  if (cmp->same) {
255  rz_cons_printf(" 0x%08" PFMT64x " %s\n",
256  cmp->addr1, cmp->data1);
257  } else {
258  if (hascolor) {
259  rz_cons_print(pal->graph_false);
260  }
261  rz_cons_printf("-0x%08" PFMT64x " %s\n",
262  cmp->addr1, cmp->data1);
263  if (hascolor) {
264  rz_cons_print(pal->graph_true);
265  }
266  rz_cons_printf("+0x%08" PFMT64x " %s\n",
267  cmp->addr2, cmp->data2);
268  if (hascolor) {
269  rz_cons_print(Color_RESET);
270  }
271  }
272  }
273  } else {
274  rz_list_foreach (compare, it, cmp) {
275  memset(colpad, ' ', sizeof(colpad));
276  int pos = strlen((char *)cmp->data1);
277  pos = (pos > cols) ? 0 : cols - pos;
278  colpad[pos] = 0;
279  if (hascolor) {
280  rz_cons_print(cmp->same ? pal->graph_true : pal->graph_false);
281  }
282  rz_cons_printf(" 0x%08" PFMT64x " %s %s",
283  cmp->addr1, cmp->data1, colpad);
284  rz_cons_printf("%c 0x%08" PFMT64x " %s\n",
285  cmp->same ? '=' : '!', cmp->addr2, cmp->data2);
286  if (hascolor) {
287  rz_cons_print(Color_RESET);
288  }
289  }
290  }
291 
292  return true;
293 }
294 
301  if (!w) {
302  return;
303  }
304  free(w->ndata);
305  free(w->odata);
306  free(w);
307 }
308 
318  RzListIter *iter;
320  rz_list_foreach (core->watchers, iter, w) {
321  if (addr == w->addr) {
322  return w;
323  }
324  }
325  return NULL;
326 }
327 
337 RZ_API bool rz_core_cmpwatch_add(RzCore *core, ut64 addr, int size, const char *cmd) {
338  rz_return_val_if_fail(core, false);
339  RzCoreCmpWatcher *cmpw;
340  bool to_add = false;
341  if (size < 1) {
342  return false;
343  }
344  cmpw = rz_core_cmpwatch_get(core, addr);
345  if (!cmpw) {
346  to_add = true;
347  cmpw = RZ_NEW(RzCoreCmpWatcher);
348  if (!cmpw) {
349  return false;
350  }
351  cmpw->addr = addr;
352  }
353  cmpw->size = size;
354  snprintf(cmpw->cmd, sizeof(cmpw->cmd), "%s", cmd);
355  cmpw->odata = NULL;
356  cmpw->ndata = malloc(size);
357  if (!cmpw->ndata) {
358  free(cmpw);
359  return false;
360  }
361  rz_io_nread_at(core->io, addr, cmpw->ndata, size);
362  if (to_add) {
363  rz_list_append(core->watchers, cmpw);
364  }
365  return true;
366 }
367 
376  rz_return_val_if_fail(core, false);
377  int ret = false;
379  RzListIter *iter, *iter2;
380  rz_list_foreach_safe (core->watchers, iter, iter2, w) {
381  if (w->addr == addr || addr == UT64_MAX) {
382  rz_list_delete(core->watchers, iter);
383  ret = true;
384  }
385  }
386  return ret;
387 }
388 
398  rz_return_if_fail(core);
399  char cmd[128];
400  RzListIter *iter;
402  rz_list_foreach (core->watchers, iter, w) {
403  if (addr != UT64_MAX && w->addr != addr) {
404  continue;
405  }
406  int is_diff = w->odata ? memcmp(w->odata, w->ndata, w->size) : 0;
407  switch (mode) {
409  rz_cons_printf("cw %d '%s' @ 0x%08" PFMT64x "%s\n",
410  w->size, w->cmd, w->addr, is_diff ? " # differs" : "");
411  break;
413  rz_cons_printf("0x%08" PFMT64x "%s\n", w->addr, is_diff ? " modified" : "");
414  snprintf(cmd, sizeof(cmd), "%s @ %" PFMT64d " @!%d", w->cmd, w->addr, w->size);
415  rz_core_cmd0(core, cmd);
416  break;
417  default:
419  }
420  }
421 }
422 
431  rz_return_val_if_fail(core, false);
433  RzListIter *iter;
434  bool ret = false;
435  rz_list_foreach (core->watchers, iter, w) {
436  if (addr != UT64_MAX && w->addr != addr) {
437  continue;
438  }
439  free(w->odata);
440  w->odata = w->ndata;
441  w->ndata = malloc(w->size);
442  if (!w->ndata) {
443  return false;
444  }
445  rz_io_nread_at(core->io, w->addr, w->ndata, w->size);
446  ret = true;
447  }
448  return ret;
449 }
450 
459  rz_return_val_if_fail(core, false);
461  int ret = false;
462  RzListIter *iter;
463  rz_list_foreach (core->watchers, iter, w) {
464  if (w->addr == addr || addr == UT64_MAX) {
465  if (w->odata) {
466  free(w->ndata);
467  w->ndata = w->odata;
468  w->odata = NULL;
469  ret = true;
470  }
471  }
472  }
473  return ret;
474 }
size_t len
Definition: 6502dis.c:15
ut8 op
Definition: 6502dis.c:13
lzma_index ** i
Definition: index.h:629
static RzILOpEffect * cmp(cs_insn *insn, bool is_thumb)
Definition: arm_il32.c:942
RZ_API int rz_asm_set_pc(RzAsm *a, ut64 pc)
Definition: asm.c:533
RZ_API int rz_asm_disassemble(RzAsm *a, RzAsmOp *op, const ut8 *buf, int len)
Definition: asm.c:543
RZ_API int rz_core_cmd0(RzCore *core, const char *cmd)
Definition: cmd.c:5428
RZ_API bool rz_core_cmp_disasm_print(RzCore *core, const RzList *compare, bool unified)
Print the instruction comparison data compare.
Definition: cmp.c:243
RZ_API void rz_core_cmp_free(RzCompareData *cmp)
Free RzCompareData object.
Definition: cmp.c:226
RZ_API RZ_OWN RzList * rz_core_cmp_disasm(RzCore *core, ut64 addr1, ut64 addr2, ut32 len)
Compare the instructions at addr1 and addr2.
Definition: cmp.c:161
RZ_API RZ_OWN RzCompareData * rz_core_cmp_mem_mem(RzCore *core, ut64 addr1, ut64 addr2, ut32 len)
Compare memory at addr1 with the memory at addr2.
Definition: cmp.c:17
RZ_API RZ_OWN RzCompareData * rz_core_cmp_mem_data(RzCore *core, ut64 addr, RZ_NONNULL const ut8 *data, ut32 len)
Compare mem at addr with data data.
Definition: cmp.c:56
RZ_API int rz_core_cmp_print(RzCore *core, RZ_NONNULL const RzCompareData *cmp, RzCmdStateOutput *state)
Print a comparison cmp according to the print mode mode.
Definition: cmp.c:93
RZ_API ut64 rz_config_get_i(RzConfig *cfg, RZ_NONNULL const char *name)
Definition: config.c:119
RZ_API RzCons * rz_cons_singleton(void)
Definition: cons.c:300
RZ_API int rz_cons_printf(const char *format,...)
Definition: cons.c:1202
#define RZ_API
#define NULL
Definition: cris-opc.c:27
#define w
Definition: crypto_rc6.c:13
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags cmd
Definition: sflib.h:79
uint32_t ut32
RZ_API void rz_core_cmpwatch_show(RzCore *core, ut64 addr, RzOutputMode mode)
Show/print the memory watcher present at address addr.
Definition: cmp.c:397
RZ_API bool rz_core_cmpwatch_update(RzCore *core, ut64 addr)
Update the memory watcher at address addr.
Definition: cmp.c:430
RZ_API bool rz_core_cmpwatch_del(RzCore *core, ut64 addr)
Delete a memory watcher at address addr.
Definition: cmp.c:375
RZ_API bool rz_core_cmpwatch_add(RzCore *core, ut64 addr, int size, const char *cmd)
Add a memory watcher at address addr od size size and command cmd.
Definition: cmp.c:337
RZ_API void rz_core_cmpwatch_free(RzCoreCmpWatcher *w)
Definition: cmp.c:300
RZ_API RzCoreCmpWatcher * rz_core_cmpwatch_get(RzCore *core, ut64 addr)
Get the memory watcher at address addr.
Definition: cmp.c:316
RZ_API bool rz_core_cmpwatch_revert(RzCore *core, ut64 addr)
Revert/reset a memory watcher at address addr.
Definition: cmp.c:458
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void uLong size
Definition: ioapi.h:138
const char int mode
Definition: ioapi.h:137
voidpf void * buf
Definition: ioapi.h:138
snprintf
Definition: kernel.h:364
uint8_t ut8
Definition: lh5801.h:11
return memset(p, 0, total)
static int compare(const char *s1, const char *s2, int l1, int l2)
Definition: chmd.c:864
RZ_API void rz_list_delete(RZ_NONNULL RzList *list, RZ_NONNULL RzListIter *iter)
Removes an entry in the list by using the RzListIter pointer.
Definition: list.c:162
RZ_API RZ_OWN RzList * rz_list_new(void)
Returns a new initialized RzList pointer (free method is not initialized)
Definition: list.c:235
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
void * malloc(size_t size)
Definition: malloc.c:123
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
static uint32_t const uint8_t * buf2
Definition: memcmplen.h:43
#define rz_warn_if_reached()
Definition: rz_assert.h:29
#define rz_return_if_fail(expr)
Definition: rz_assert.h:100
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
#define Color_RESET
Definition: rz_cons.h:617
RZ_API int rz_io_nread_at(RzIO *io, ut64 addr, ut8 *buf, int len)
Definition: io.c:338
void(* RzListFree)(void *ptr)
Definition: rz_list.h:11
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
RZ_API void * rz_mem_dup(const void *s, int l)
Definition: mem.c:319
RZ_API int rz_mem_eq(const ut8 *a, const ut8 *b, int len)
Compares memory a with b over len bytes.
Definition: mem.c:31
RZ_API PJ * pj_ki(PJ *j, const char *k, int d)
Definition: pj.c:149
RZ_API PJ * pj_k(PJ *j, const char *k)
Definition: pj.c:104
RZ_API PJ * pj_end(PJ *j)
Definition: pj.c:87
RZ_API PJ * pj_o(PJ *j)
Definition: pj.c:75
RZ_API PJ * pj_kn(PJ *j, const char *k, ut64 n)
Definition: pj.c:121
RZ_API PJ * pj_a(PJ *j)
Definition: pj.c:81
#define IS_PRINTABLE(x)
Definition: rz_str_util.h:10
RZ_API char * rz_strbuf_get(RzStrBuf *sb)
Definition: strbuf.c:321
#define PFMT64d
Definition: rz_types.h:394
#define RZ_OWN
Definition: rz_types.h:62
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_NONNULL
Definition: rz_types.h:64
#define RZ_NEW(x)
Definition: rz_types.h:285
RzOutputMode
Enum to describe the way data are printed.
Definition: rz_types.h:38
@ RZ_OUTPUT_MODE_JSON
Definition: rz_types.h:40
@ RZ_OUTPUT_MODE_RIZIN
Definition: rz_types.h:41
@ RZ_OUTPUT_MODE_STANDARD
Definition: rz_types.h:39
#define RZ_FREE(x)
Definition: rz_types.h:369
#define PFMT64x
Definition: rz_types.h:393
#define UT64_MAX
Definition: rz_types_base.h:86
#define UT8_MAX
ut64 addr2
Definition: rz_cmp.h:20
ut32 len
Definition: rz_cmp.h:15
bool same
Definition: rz_cmp.h:16
ut64 addr1
Definition: rz_cmp.h:19
ut8 * data1
Definition: rz_cmp.h:17
ut8 * data2
Definition: rz_cmp.h:18
Watcher which executes a command when listed.
Definition: rz_pj.h:12
RzStrBuf buf_asm
Definition: rz_asm.h:72
int size
Definition: rz_asm.h:67
Represent the output state of a command handler.
Definition: rz_cmd.h:91
RzConsPrintablePalette pal
Definition: rz_cons.h:491
RzConsContext * context
Definition: rz_cons.h:502
RzAsm * rasm
Definition: rz_core.h:323
RzIO * io
Definition: rz_core.h:313
RzList * watchers
Definition: rz_core.h:360
ut8 * block
Definition: rz_core.h:305
RzConfig * config
Definition: rz_core.h:300
RzListFree free
Definition: rz_list.h:21
Definition: dis.h:43
int pos
Definition: main.c:11
Definition: dis.c:32
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int addr
Definition: z80asm.c:58