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