Rizin
unix-like reverse engineering framework and cli tools
diff.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2010-2020 nibble <nibble.ds@gmail.com>
2 // SPDX-FileCopyrightText: 2010-2020 pancake <pancake@nopcode.org>
3 // SPDX-License-Identifier: LGPL-3.0-only
4 
5 #include <rz_analysis.h>
6 #include <rz_util.h>
7 #include <rz_diff.h>
8 
11  if (!diff) {
12  return NULL;
13  }
15  diff->addr = UT64_MAX;
16  diff->dist = 0;
17  diff->name = NULL;
18  diff->size = 0;
19  return diff;
20 }
21 
23  if (!diff) {
24  return;
25  }
26  free(diff->name);
27  free(diff);
28 }
29 
30 /* 0-1 */
31 RZ_API void rz_analysis_diff_setup(RzAnalysis *analysis, int doops, double thbb, double thfcn) {
32  if (doops >= 0) {
33  analysis->diff_ops = doops;
34  }
35  analysis->diff_thbb = (thbb >= 0) ? thbb : RZ_ANALYSIS_THRESHOLDBB;
36  analysis->diff_thfcn = (thfcn >= 0) ? thfcn : RZ_ANALYSIS_THRESHOLDFCN;
37 }
38 
39 /* 0-100 */
40 RZ_API void rz_analysis_diff_setup_i(RzAnalysis *analysis, int doops, int thbb, int thfcn) {
41  if (doops >= 0) {
42  analysis->diff_ops = doops;
43  }
44  analysis->diff_thbb = (thbb >= 0) ? ((double)thbb) / 100 : RZ_ANALYSIS_THRESHOLDBB;
45  analysis->diff_thfcn = (thfcn >= 0) ? ((double)thfcn) / 100 : RZ_ANALYSIS_THRESHOLDFCN;
46 }
47 
48 // Fingerprint function basic block
51  ut8 *buf;
52  int oplen, idx = 0;
53 
54  if (!analysis) {
55  return -1;
56  }
57  if (analysis->cur && analysis->cur->fingerprint_bb) {
58  return (analysis->cur->fingerprint_bb(analysis, bb));
59  }
60  if (!(bb->fingerprint = malloc(1 + bb->size))) {
61  return -1;
62  }
63  if (!(buf = malloc(bb->size + 1))) {
64  free(bb->fingerprint);
65  return -1;
66  }
67  if (analysis->iob.read_at(analysis->iob.io, bb->addr, buf, bb->size)) {
68  memcpy(bb->fingerprint, buf, bb->size);
69  if (analysis->diff_ops) { // diff using only the opcode
70  if (!(op = rz_analysis_op_new())) {
71  free(bb->fingerprint);
72  free(buf);
73  return -1;
74  }
75  while (idx < bb->size) {
76  if ((oplen = rz_analysis_op(analysis, op, 0, buf + idx, bb->size - idx, RZ_ANALYSIS_OP_MASK_BASIC)) < 1) {
77  break;
78  }
79  if (op->nopcode != 0) {
80  memset(bb->fingerprint + idx + op->nopcode, 0, oplen - op->nopcode);
81  }
82  idx += oplen;
83  }
84  free(op);
85  }
86  }
87  free(buf);
88  return bb->size;
89 }
90 
92  RzAnalysisBlock *bb;
94 
95  if (analysis && analysis->cur && analysis->cur->fingerprint_fcn) {
96  return (analysis->cur->fingerprint_fcn(analysis, fcn));
97  }
98 
99  fcn->fingerprint = NULL;
100  fcn->fingerprint_size = 0;
101  rz_list_foreach (fcn->bbs, iter, bb) {
102  fcn->fingerprint_size += bb->size;
103  fcn->fingerprint = realloc(fcn->fingerprint, fcn->fingerprint_size + 1);
104  if (!fcn->fingerprint) {
105  return 0;
106  }
107  memcpy(fcn->fingerprint + fcn->fingerprint_size - bb->size, bb->fingerprint, bb->size);
108  }
109  return fcn->fingerprint_size;
110 }
111 
113  RzAnalysisBlock *bb, *bb2, *mbb, *mbb2;
114  RzListIter *iter, *iter2;
115  double t, ot;
116 
117  if (!analysis || !fcn || !fcn2) {
118  return false;
119  }
120  if (analysis->cur && analysis->cur->diff_bb) {
121  return (analysis->cur->diff_bb(analysis, fcn, fcn2));
122  }
123  fcn->diff->type = fcn2->diff->type = RZ_ANALYSIS_DIFF_TYPE_MATCH;
124  rz_list_foreach (fcn->bbs, iter, bb) {
125  if (bb->diff && bb->diff->type != RZ_ANALYSIS_DIFF_TYPE_NULL) {
126  continue;
127  }
128  ot = 0;
129  mbb = mbb2 = NULL;
130  rz_list_foreach (fcn2->bbs, iter2, bb2) {
131  if (!bb2->diff || bb2->diff->type == RZ_ANALYSIS_DIFF_TYPE_NULL) {
133  if (t > analysis->diff_thbb && t > ot) {
134  ot = t;
135  mbb = bb;
136  mbb2 = bb2;
137  if (t == 1) {
138  break;
139  }
140  }
141  }
142  }
143  if (mbb && mbb2) {
144  if (!mbb->diff) {
145  mbb->diff = rz_analysis_diff_new();
146  }
147  if (!mbb2->diff) {
148  mbb2->diff = rz_analysis_diff_new();
149  }
150  if (!mbb->diff || !mbb2->diff) {
151  return false;
152  }
153  if (ot == 1 || t > analysis->diff_thfcn) {
154  mbb->diff->type = mbb2->diff->type = RZ_ANALYSIS_DIFF_TYPE_MATCH;
155  } else {
156  mbb->diff->type = mbb2->diff->type =
157  fcn->diff->type = fcn2->diff->type =
159  }
160  mbb->diff->dist = mbb2->diff->dist = ot;
161  RZ_FREE(mbb->fingerprint);
162  RZ_FREE(mbb2->fingerprint);
163  mbb->diff->addr = mbb2->addr;
164  mbb2->diff->addr = mbb->addr;
165  mbb->diff->size = mbb2->size;
166  mbb2->diff->size = mbb->size;
167  } else {
168  fcn->diff->type = fcn2->diff->type = (fcn->diff->dist >= RZ_ANALYSIS_DIFF_THRESHOLD)
171  }
172  }
173  return true;
174 }
175 
176 RZ_API int rz_analysis_diff_fcn(RzAnalysis *analysis, RzList /*<RzAnalysisFunction *>*/ *fcns1, RzList /*<RzAnalysisFunction *>*/ *fcns2) {
177  RzAnalysisFunction *fcn, *fcn2, *mfcn, *mfcn2;
178  RzListIter *iter, *iter2;
179  double t, ot, sizes_div;
180 
181  if (!analysis) {
182  return false;
183  }
184  if (analysis->cur && analysis->cur->diff_fcn) {
185  return (analysis->cur->diff_fcn(analysis, fcns1, fcns2));
186  }
187  /* Compare functions with the same name */
188  rz_list_foreach (fcns1, iter, fcn) {
189  rz_list_foreach (fcns2, iter2, fcn2) {
190  if (fcn->name && fcn2->name && strcmp(fcn->name, fcn2->name)) {
191  continue;
192  }
194  fcn2->fingerprint, fcn2->fingerprint_size, NULL, &t);
195  /* Set flag in matched functions */
196  fcn->diff->type = fcn2->diff->type = (t >= RZ_ANALYSIS_DIFF_THRESHOLD)
199  fcn->diff->dist = fcn2->diff->dist = t;
200  RZ_FREE(fcn->fingerprint);
201  RZ_FREE(fcn2->fingerprint);
202  fcn->diff->addr = fcn2->addr;
203  fcn2->diff->addr = fcn->addr;
204  fcn->diff->size = fcn2->fingerprint_size;
205  fcn2->diff->size = fcn->fingerprint_size;
206  RZ_FREE(fcn->diff->name);
207  if (fcn2->name) {
208  fcn->diff->name = strdup(fcn2->name);
209  }
210  RZ_FREE(fcn2->diff->name);
211  if (fcn->name) {
212  fcn2->diff->name = strdup(fcn->name);
213  }
214  rz_analysis_diff_bb(analysis, fcn, fcn2);
215  break;
216  }
217  }
218  /* Compare remaining functions */
219  rz_list_foreach (fcns1, iter, fcn) {
220  if (fcn->diff->type != RZ_ANALYSIS_DIFF_TYPE_NULL) {
221  continue;
222  } else if (!fcn->fingerprint_size) {
223  continue;
224  } else if (fcn->type != RZ_ANALYSIS_FCN_TYPE_FCN && fcn->type != RZ_ANALYSIS_FCN_TYPE_SYM) {
225  continue;
226  }
227  ot = 0.0;
228  mfcn = mfcn2 = NULL;
229  rz_list_foreach (fcns2, iter2, fcn2) {
230  if (fcn2->diff->type != RZ_ANALYSIS_DIFF_TYPE_NULL) {
231  continue;
232  } else if (!fcn2->fingerprint_size) {
233  continue;
234  } else if (fcn2->type != RZ_ANALYSIS_FCN_TYPE_FCN && fcn2->type != RZ_ANALYSIS_FCN_TYPE_SYM) {
235  continue;
236  }
237  if (fcn->fingerprint_size > fcn2->fingerprint_size) {
238  sizes_div = fcn2->fingerprint_size;
239  sizes_div /= fcn->fingerprint_size;
240  } else {
241  sizes_div = fcn->fingerprint_size;
242  sizes_div /= fcn2->fingerprint_size;
243  }
244  if (sizes_div < RZ_ANALYSIS_DIFF_THRESHOLD) {
245  continue;
246  }
248  if (t > ot) {
249  ot = t;
250  mfcn = fcn;
251  mfcn2 = fcn2;
252  if (ot >= RZ_ANALYSIS_DIFF_THRESHOLD) {
253  break;
254  }
255  }
256  }
257  if (mfcn && mfcn2) {
258  mfcn->diff->dist = mfcn2->diff->dist = ot;
259  /* Set flag in matched functions */
260  mfcn->diff->type = mfcn2->diff->type = (ot > RZ_ANALYSIS_DIFF_THRESHOLD)
263  RZ_FREE(mfcn->fingerprint);
264  RZ_FREE(mfcn2->fingerprint);
265  mfcn->diff->addr = mfcn2->addr;
266  mfcn2->diff->addr = mfcn->addr;
267  mfcn->diff->size = mfcn2->fingerprint_size;
268  mfcn2->diff->size = mfcn->fingerprint_size;
269  RZ_FREE(mfcn->diff->name);
270  if (mfcn2->name) {
271  mfcn->diff->name = strdup(mfcn2->name);
272  }
273  RZ_FREE(mfcn2->diff->name);
274  if (mfcn->name) {
275  mfcn2->diff->name = strdup(mfcn->name);
276  }
277  rz_analysis_diff_bb(analysis, mfcn, mfcn2);
278  }
279  }
280  return true;
281 }
282 
284  if (analysis && analysis->cur && analysis->cur->diff_eval) {
285  return (analysis->cur->diff_eval(analysis));
286  }
287  return true; // XXX: shouldn't this be false?
288 }
ut8 op
Definition: 6502dis.c:13
RZ_API void rz_analysis_diff_free(RzAnalysisDiff *diff)
Definition: diff.c:22
RZ_API size_t rz_analysis_diff_fingerprint_fcn(RzAnalysis *analysis, RzAnalysisFunction *fcn)
Definition: diff.c:91
RZ_API int rz_analysis_diff_fingerprint_bb(RzAnalysis *analysis, RzAnalysisBlock *bb)
Definition: diff.c:49
RZ_API RZ_OWN RzAnalysisDiff * rz_analysis_diff_new(void)
Definition: diff.c:9
RZ_API int rz_analysis_diff_eval(RzAnalysis *analysis)
Definition: diff.c:283
RZ_API void rz_analysis_diff_setup(RzAnalysis *analysis, int doops, double thbb, double thfcn)
Definition: diff.c:31
RZ_API void rz_analysis_diff_setup_i(RzAnalysis *analysis, int doops, int thbb, int thfcn)
Definition: diff.c:40
RZ_API int rz_analysis_diff_fcn(RzAnalysis *analysis, RzList *fcns1, RzList *fcns2)
Definition: diff.c:176
RZ_API bool rz_analysis_diff_bb(RzAnalysis *analysis, RzAnalysisFunction *fcn, RzAnalysisFunction *fcn2)
Definition: diff.c:112
#define RZ_API
#define NULL
Definition: cris-opc.c:27
RZ_API bool rz_diff_levenstein_distance(RZ_NONNULL const ut8 *a, ut32 la, RZ_NONNULL const ut8 *b, ut32 lb, RZ_NULLABLE ut32 *distance, RZ_NULLABLE double *similarity)
Calculates the distance between two buffers using the Levenshtein algorithm.
Definition: distance.c:68
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void uLong size
Definition: ioapi.h:138
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
return memset(p, 0, total)
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
void * realloc(void *ptr, size_t size)
Definition: malloc.c:144
void * malloc(size_t size)
Definition: malloc.c:123
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")
int idx
Definition: setup.py:197
RZ_API RzAnalysisOp * rz_analysis_op_new(void)
Definition: op.c:9
RZ_API int rz_analysis_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8 *data, int len, RzAnalysisOpMask mask)
Definition: op.c:96
#define RZ_ANALYSIS_DIFF_THRESHOLD
Definition: rz_analysis.h:202
@ RZ_ANALYSIS_DIFF_TYPE_MATCH
Definition: rz_analysis.h:206
@ RZ_ANALYSIS_DIFF_TYPE_UNMATCH
Definition: rz_analysis.h:207
@ RZ_ANALYSIS_DIFF_TYPE_NULL
Definition: rz_analysis.h:205
@ RZ_ANALYSIS_FCN_TYPE_SYM
Definition: rz_analysis.h:195
@ RZ_ANALYSIS_FCN_TYPE_FCN
Definition: rz_analysis.h:193
@ RZ_ANALYSIS_OP_MASK_BASIC
Definition: rz_analysis.h:440
#define RZ_OWN
Definition: rz_types.h:62
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_FREE(x)
Definition: rz_types.h:369
#define UT64_MAX
Definition: rz_types_base.h:86
RzAnalysisDiff * diff
Definition: rz_analysis.h:872
RzAnalysisDiff * diff
Definition: rz_analysis.h:263
RzAnalysisDiffEvalCallback diff_eval
Definition: rz_analysis.h:1264
RzAnalysisFPBBCallback fingerprint_bb
Definition: rz_analysis.h:1260
RzAnalysisDiffFcnCallback diff_fcn
Definition: rz_analysis.h:1263
RzAnalysisDiffBBCallback diff_bb
Definition: rz_analysis.h:1262
RzAnalysisFPFcnCallback fingerprint_fcn
Definition: rz_analysis.h:1261
double diff_thfcn
Definition: rz_analysis.h:573
struct rz_analysis_plugin_t * cur
Definition: rz_analysis.h:586
double diff_thbb
Definition: rz_analysis.h:572
RzIOBind iob
Definition: rz_analysis.h:574
RzIOReadAt read_at
Definition: rz_io.h:240
RzIO * io
Definition: rz_io.h:232
Definition: dis.c:32