1 /* radare - LGPL - Copyright 2010-2020 - nibble, pancake */
2
3 #include <r_anal.h>
4 #include <r_util.h>
5 #include <r_diff.h>
6
r_anal_diff_new(void)7 R_API RAnalDiff *r_anal_diff_new(void) {
8 RAnalDiff *diff = R_NEW0 (RAnalDiff);
9 if (diff) {
10 diff->type = R_ANAL_DIFF_TYPE_NULL;
11 diff->addr = UT64_MAX;
12 diff->dist = 0;
13 diff->name = NULL;
14 diff->size = 0;
15 }
16 return diff;
17 }
18
r_anal_diff_free(RAnalDiff * diff)19 R_API void* r_anal_diff_free(RAnalDiff *diff) {
20 if (diff && diff->name) {
21 R_FREE (diff->name);
22 }
23 free (diff);
24 return NULL;
25 }
26
27 /* 0-1 */
r_anal_diff_setup(RAnal * anal,int doops,double thbb,double thfcn)28 R_API void r_anal_diff_setup(RAnal *anal, int doops, double thbb, double thfcn) {
29 if (doops >= 0) {
30 anal->diff_ops = doops;
31 }
32 anal->diff_thbb = (thbb>=0)? thbb: R_ANAL_THRESHOLDBB;
33 anal->diff_thfcn = (thfcn>=0)? thfcn: R_ANAL_THRESHOLDFCN;
34 }
35
36 /* 0-100 */
r_anal_diff_setup_i(RAnal * anal,int doops,int thbb,int thfcn)37 R_API void r_anal_diff_setup_i(RAnal *anal, int doops, int thbb, int thfcn) {
38 if (doops >= 0) {
39 anal->diff_ops = doops;
40 }
41 anal->diff_thbb = (thbb>=0)? ((double)thbb) / 100: R_ANAL_THRESHOLDBB;
42 anal->diff_thfcn = (thfcn>=0)? ((double)thfcn) / 100: R_ANAL_THRESHOLDFCN;
43 }
44
45 // Fingerprint function basic block
r_anal_diff_fingerprint_bb(RAnal * anal,RAnalBlock * bb)46 R_API int r_anal_diff_fingerprint_bb(RAnal *anal, RAnalBlock *bb) {
47 RAnalOp *op;
48 ut8 *buf;
49 int oplen, idx = 0;
50
51 if (!anal) {
52 return false;
53 }
54 if (anal->cur && anal->cur->fingerprint_bb) {
55 return (anal->cur->fingerprint_bb (anal, bb));
56 }
57 if (!(bb->fingerprint = malloc (1 + bb->size))) {
58 return false;
59 }
60 if (!(buf = malloc (bb->size + 1))) {
61 free (bb->fingerprint);
62 return false;
63 }
64 if (anal->iob.read_at (anal->iob.io, bb->addr, buf, bb->size)) {
65 memcpy (bb->fingerprint, buf, bb->size);
66 if (anal->diff_ops) { // diff using only the opcode
67 if (!(op = r_anal_op_new ())) {
68 free (bb->fingerprint);
69 free (buf);
70 return false;
71 }
72 while (idx < bb->size) {
73 if ((oplen = r_anal_op (anal, op, 0, buf+idx, bb->size-idx, R_ANAL_OP_MASK_BASIC)) < 1) {
74 break;
75 }
76 if (op->nopcode != 0) {
77 memset (bb->fingerprint+idx+op->nopcode, 0, oplen-op->nopcode);
78 }
79 idx += oplen;
80 }
81 free (op);
82 }
83 }
84 free (buf);
85 return bb->size;
86 }
87
r_anal_diff_fingerprint_fcn(RAnal * anal,RAnalFunction * fcn)88 R_API size_t r_anal_diff_fingerprint_fcn(RAnal *anal, RAnalFunction *fcn) {
89 RAnalBlock *bb;
90 RListIter *iter;
91
92 if (anal && anal->cur && anal->cur->fingerprint_fcn) {
93 return (anal->cur->fingerprint_fcn (anal, fcn));
94 }
95
96 fcn->fingerprint = NULL;
97 fcn->fingerprint_size = 0;
98 r_list_foreach (fcn->bbs, iter, bb) {
99 fcn->fingerprint_size += bb->size;
100 fcn->fingerprint = realloc (fcn->fingerprint, fcn->fingerprint_size + 1);
101 if (!fcn->fingerprint) {
102 return 0;
103 }
104 memcpy (fcn->fingerprint + fcn->fingerprint_size - bb->size, bb->fingerprint, bb->size);
105 }
106 return fcn->fingerprint_size;
107 }
108
r_anal_diff_bb(RAnal * anal,RAnalFunction * fcn,RAnalFunction * fcn2)109 R_API bool r_anal_diff_bb(RAnal *anal, RAnalFunction *fcn, RAnalFunction *fcn2) {
110 RAnalBlock *bb, *bb2, *mbb, *mbb2;
111 RListIter *iter, *iter2;
112 double t, ot;
113
114 if (!anal || !fcn || !fcn2) {
115 return false;
116 }
117 if (anal->cur && anal->cur->diff_bb) {
118 return (anal->cur->diff_bb (anal, fcn, fcn2));
119 }
120 fcn->diff->type = fcn2->diff->type = R_ANAL_DIFF_TYPE_MATCH;
121 r_list_foreach (fcn->bbs, iter, bb) {
122 if (bb->diff && bb->diff->type != R_ANAL_DIFF_TYPE_NULL) {
123 continue;
124 }
125 ot = 0;
126 mbb = mbb2 = NULL;
127 r_list_foreach (fcn2->bbs, iter2, bb2) {
128 if (!bb2->diff || bb2->diff->type == R_ANAL_DIFF_TYPE_NULL) {
129 r_diff_buffers_distance (NULL, bb->fingerprint, bb->size,
130 bb2->fingerprint, bb2->size, NULL, &t);
131 if (t > anal->diff_thbb && t > ot) {
132 ot = t;
133 mbb = bb;
134 mbb2 = bb2;
135 if (t == 1) {
136 break;
137 }
138 }
139 }
140 }
141 if (mbb && mbb2) {
142 if (!mbb->diff) {
143 mbb->diff = r_anal_diff_new();
144 }
145 if (!mbb2->diff) {
146 mbb2->diff = r_anal_diff_new();
147 }
148 if (!mbb->diff || !mbb2->diff) {
149 return false;
150 }
151 if (ot == 1 || t > anal->diff_thfcn) {
152 mbb->diff->type = mbb2->diff->type = R_ANAL_DIFF_TYPE_MATCH;
153 } else {
154 mbb->diff->type = mbb2->diff->type = \
155 fcn->diff->type = fcn2->diff->type = \
156 R_ANAL_DIFF_TYPE_UNMATCH;
157 }
158 R_FREE (mbb->fingerprint);
159 R_FREE (mbb2->fingerprint);
160 mbb->diff->addr = mbb2->addr;
161 mbb2->diff->addr = mbb->addr;
162 mbb->diff->size = mbb2->size;
163 mbb2->diff->size = mbb->size;
164 } else {
165 fcn->diff->type = fcn2->diff->type = (fcn->diff->dist >= 0.6)
166 ? R_ANAL_DIFF_TYPE_MATCH
167 : R_ANAL_DIFF_TYPE_UNMATCH;
168 }
169 }
170 return true;
171 }
172
r_anal_diff_fcn(RAnal * anal,RList * fcns,RList * fcns2)173 R_API int r_anal_diff_fcn(RAnal *anal, RList *fcns, RList *fcns2) {
174 RAnalFunction *fcn, *fcn2, *mfcn, *mfcn2;
175 RListIter *iter, *iter2;
176 ut64 maxsize, minsize;
177 double t, ot;
178
179 if (!anal) {
180 return false;
181 }
182 if (anal->cur && anal->cur->diff_fcn) {
183 return (anal->cur->diff_fcn (anal, fcns, fcns2));
184 }
185 /* Compare functions with the same name */
186 if (fcns) {
187 r_list_foreach (fcns, iter, fcn) {
188 r_list_foreach (fcns2, iter2, fcn2) {
189 if (!fcn->name || !fcn2->name || strcmp (fcn->name, fcn2->name)) {
190 continue;
191 }
192 r_diff_buffers_distance (NULL, fcn->fingerprint, fcn->fingerprint_size,
193 fcn2->fingerprint, fcn2->fingerprint_size,
194 NULL, &t);
195 /* Set flag in matched functions */
196 fcn->diff->type = fcn2->diff->type = (t >= 1)
197 ? R_ANAL_DIFF_TYPE_MATCH
198 : R_ANAL_DIFF_TYPE_UNMATCH;
199 fcn->diff->dist = fcn2->diff->dist = t;
200 R_FREE (fcn->fingerprint);
201 R_FREE (fcn2->fingerprint);
202 fcn->diff->addr = fcn2->addr;
203 fcn2->diff->addr = fcn->addr;
204 fcn->diff->size = r_anal_function_linear_size (fcn2);
205 fcn2->diff->size = r_anal_function_linear_size (fcn);
206 R_FREE (fcn->diff->name);
207 if (fcn2->name) {
208 fcn->diff->name = strdup (fcn2->name);
209 }
210 R_FREE (fcn2->diff->name);
211 if (fcn->name) {
212 fcn2->diff->name = strdup (fcn->name);
213 }
214 r_anal_diff_bb (anal, fcn, fcn2);
215 break;
216 }
217 }
218 }
219 /* Compare remaining functions */
220 r_list_foreach (fcns, iter, fcn) {
221 /*
222 if ((fcn->type != R_ANAL_FCN_TYPE_FCN &&
223 fcn->type != R_ANAL_FCN_TYPE_SYM) ||
224 fcn->diff->type != R_ANAL_DIFF_TYPE_NULL) {
225 continue;
226 }
227 */
228 if (fcn->diff->type != R_ANAL_DIFF_TYPE_NULL) {
229 continue;
230 }
231 ot = 0;
232 mfcn = mfcn2 = NULL;
233 r_list_foreach (fcns2, iter2, fcn2) {
234 ut64 fcn_size = r_anal_function_linear_size (fcn);
235 ut64 fcn2_size = r_anal_function_linear_size (fcn2);
236 if (fcn_size > fcn2_size) {
237 maxsize = fcn_size;
238 minsize = fcn2_size;
239 } else {
240 maxsize = fcn2_size;
241 minsize = fcn_size;
242 }
243 if (maxsize * anal->diff_thfcn > minsize) {
244 eprintf ("Exceeded anal threshold while diffing %s and %s\n", fcn->name, fcn2->name);
245 continue;
246 }
247 if (fcn2->diff->type != R_ANAL_DIFF_TYPE_NULL) {
248 eprintf ("Function %s already diffed\n", fcn2->name);
249 continue;
250 }
251 if ((fcn2->type != R_ANAL_FCN_TYPE_FCN && fcn2->type != R_ANAL_FCN_TYPE_SYM)) {
252 eprintf ("Function %s type not supported\n", fcn2->name);
253 continue;
254 }
255 r_diff_buffers_distance (NULL, fcn->fingerprint, fcn->fingerprint_size, fcn2->fingerprint, fcn2->fingerprint_size, NULL, &t);
256 fcn->diff->dist = fcn2->diff->dist = t;
257 if (t > anal->diff_thfcn && t > ot) {
258 ot = t;
259 mfcn = fcn;
260 mfcn2 = fcn2;
261 if (t == 1) {
262 break;
263 }
264 }
265 }
266 if (mfcn && mfcn2) {
267 /* Set flag in matched functions */
268 mfcn->diff->type = mfcn2->diff->type = (ot == 1)
269 ? R_ANAL_DIFF_TYPE_MATCH
270 : R_ANAL_DIFF_TYPE_UNMATCH;
271 R_FREE (mfcn->fingerprint);
272 R_FREE (mfcn2->fingerprint);
273 mfcn->diff->addr = mfcn2->addr;
274 mfcn2->diff->addr = mfcn->addr;
275 mfcn->diff->size = r_anal_function_linear_size (mfcn2);
276 mfcn2->diff->size = r_anal_function_linear_size (mfcn);
277 R_FREE (mfcn->diff->name);
278 if (mfcn2->name) {
279 mfcn->diff->name = strdup (mfcn2->name);
280 }
281 R_FREE (mfcn2->diff->name);
282 if (mfcn->name) {
283 mfcn2->diff->name = strdup (mfcn->name);
284 }
285 r_anal_diff_bb (anal, mfcn, mfcn2);
286 }
287 }
288 return true;
289 }
290
r_anal_diff_eval(RAnal * anal)291 R_API int r_anal_diff_eval(RAnal *anal) {
292 if (anal && anal->cur && anal->cur->diff_eval) {
293 return (anal->cur->diff_eval (anal));
294 }
295 return true; // XXX: shouldn't this be false?
296 }
297