1 /* radare - LGPL - Copyright 2015-2020 - pancake, rkx1209 */
2 
3 #include <r_anal.h>
4 
5 #define DB esil->trace->db
6 #define KEY(x) sdb_fmt ("%d."x, esil->trace->idx)
7 #define KEYAT(x,y) sdb_fmt ("%d."x".0x%"PFMT64x, esil->trace->idx, y)
8 #define KEYREG(x,y) sdb_fmt ("%d."x".%s", esil->trace->idx, y)
9 #define CMP_REG_CHANGE(x, y) ((x) - ((RAnalEsilRegChange *)y)->idx)
10 #define CMP_MEM_CHANGE(x, y) ((x) - ((RAnalEsilMemChange *)y)->idx)
11 
12 static int ocbs_set = false;
13 static RAnalEsilCallbacks ocbs = {0};
14 
htup_vector_free(HtUPKv * kv)15 static void htup_vector_free(HtUPKv *kv) {
16 	r_vector_free (kv->value);
17 }
18 
r_anal_esil_trace_new(RAnalEsil * esil)19 R_API RAnalEsilTrace *r_anal_esil_trace_new(RAnalEsil *esil) {
20 	r_return_val_if_fail (esil && esil->stack_addr && esil->stack_size, NULL);
21 	size_t i;
22 	RAnalEsilTrace *trace = R_NEW0 (RAnalEsilTrace);
23 	if (!trace) {
24 		return NULL;
25 	}
26 	trace->registers = ht_up_new (NULL, htup_vector_free, NULL);
27 	if (!trace->registers) {
28 		goto error;
29 	}
30 	trace->memory = ht_up_new (NULL, htup_vector_free, NULL);
31 	if (!trace->memory) {
32 		goto error;
33 	}
34 	trace->db = sdb_new0 ();
35 	if (!trace->db) {
36 		goto error;
37 	}
38 	// Save initial ESIL stack memory
39 	trace->stack_addr = esil->stack_addr;
40 	trace->stack_size = esil->stack_size;
41 	trace->stack_data = malloc (esil->stack_size);
42 	if (!trace->stack_data) {
43 		goto error;
44 	}
45 	esil->anal->iob.read_at (esil->anal->iob.io, trace->stack_addr,
46 		trace->stack_data, trace->stack_size);
47 	// Save initial registers arenas
48 	for (i = 0; i < R_REG_TYPE_LAST; i++) {
49 		RRegArena *a = esil->anal->reg->regset[i].arena;
50 		RRegArena *b = r_reg_arena_new (a->size);
51 		if (!b) {
52 			goto error;
53 		}
54 		memcpy (b->bytes, a->bytes, b->size);
55 		trace->arena[i] = b;
56 	}
57 	return trace;
58 error:
59 	eprintf ("error\n");
60 	r_anal_esil_trace_free (trace);
61 	return NULL;
62 }
63 
r_anal_esil_trace_free(RAnalEsilTrace * trace)64 R_API void r_anal_esil_trace_free(RAnalEsilTrace *trace) {
65 	size_t i;
66 	if (trace) {
67 		ht_up_free (trace->registers);
68 		ht_up_free (trace->memory);
69 		for (i = 0; i < R_REG_TYPE_LAST; i++) {
70 			r_reg_arena_free (trace->arena[i]);
71 		}
72 		free (trace->stack_data);
73 		sdb_free (trace->db);
74 		R_FREE (trace);
75 	}
76 }
77 
add_reg_change(RAnalEsilTrace * trace,int idx,RRegItem * ri,ut64 data)78 static void add_reg_change(RAnalEsilTrace *trace, int idx, RRegItem *ri, ut64 data) {
79 	ut64 addr = ri->offset | (ri->arena << 16);
80 	RVector *vreg = ht_up_find (trace->registers, addr, NULL);
81 	if (!vreg) {
82 		vreg = r_vector_new (sizeof (RAnalEsilRegChange), NULL, NULL);
83 		if (!vreg) {
84 			eprintf ("Error: creating a register vector.\n");
85 			return;
86 		}
87 		ht_up_insert (trace->registers, addr, vreg);
88 	}
89 	RAnalEsilRegChange reg = { idx, data };
90 	r_vector_push (vreg, &reg);
91 }
92 
add_mem_change(RAnalEsilTrace * trace,int idx,ut64 addr,ut8 data)93 static void add_mem_change(RAnalEsilTrace *trace, int idx, ut64 addr, ut8 data) {
94 	RVector *vmem = ht_up_find (trace->memory, addr, NULL);
95 	if (!vmem) {
96 		vmem = r_vector_new (sizeof (RAnalEsilMemChange), NULL, NULL);
97 		if (!vmem) {
98 			eprintf ("Error: creating a memory vector.\n");
99 			return;
100 		}
101 		ht_up_insert (trace->memory, addr, vmem);
102 	}
103 	RAnalEsilMemChange mem = { idx, data };
104 	r_vector_push (vmem, &mem);
105 }
106 
trace_hook_reg_read(RAnalEsil * esil,const char * name,ut64 * res,int * size)107 static int trace_hook_reg_read(RAnalEsil *esil, const char *name, ut64 *res, int *size) {
108 	int ret = 0;
109 	if (*name == '0') {
110 		//eprintf ("Register not found in profile\n");
111 		return 0;
112 	}
113 	if (ocbs.hook_reg_read) {
114 		RAnalEsilCallbacks cbs = esil->cb;
115 		esil->cb = ocbs;
116 		ret = ocbs.hook_reg_read (esil, name, res, size);
117 		esil->cb = cbs;
118 	}
119 	if (!ret && esil->cb.reg_read) {
120 		ret = esil->cb.reg_read (esil, name, res, size);
121 	}
122 	if (ret) {
123 		ut64 val = *res;
124 		//eprintf ("[ESIL] REG READ %s 0x%08"PFMT64x"\n", name, val);
125 		sdb_array_add (DB, KEY ("reg.read"), name, 0);
126 		sdb_num_set (DB, KEYREG ("reg.read", name), val, 0);
127 	} //else {
128 		//eprintf ("[ESIL] REG READ %s FAILED\n", name);
129 	//}
130 	return ret;
131 }
132 
trace_hook_reg_write(RAnalEsil * esil,const char * name,ut64 * val)133 static int trace_hook_reg_write(RAnalEsil *esil, const char *name, ut64 *val) {
134 	int ret = 0;
135 	//eprintf ("[ESIL] REG WRITE %s 0x%08"PFMT64x"\n", name, *val);
136 	sdb_array_add (DB, KEY ("reg.write"), name, 0);
137 	sdb_num_set (DB, KEYREG ("reg.write", name), *val, 0);
138 	RRegItem *ri = r_reg_get (esil->anal->reg, name, -1);
139 	add_reg_change (esil->trace, esil->trace->idx + 1, ri, *val);
140 	if (ocbs.hook_reg_write) {
141 		RAnalEsilCallbacks cbs = esil->cb;
142 		esil->cb = ocbs;
143 		ret = ocbs.hook_reg_write (esil, name, val);
144 		esil->cb = cbs;
145 	}
146 	return ret;
147 }
148 
trace_hook_mem_read(RAnalEsil * esil,ut64 addr,ut8 * buf,int len)149 static int trace_hook_mem_read(RAnalEsil *esil, ut64 addr, ut8 *buf, int len) {
150 	char *hexbuf = calloc ((1 + len), 4);
151 	int ret = 0;
152 	if (esil->cb.mem_read) {
153 		ret = esil->cb.mem_read (esil, addr, buf, len);
154 	}
155 	sdb_array_add_num (DB, KEY ("mem.read"), addr, 0);
156 	r_hex_bin2str (buf, len, hexbuf);
157 	sdb_set (DB, KEYAT ("mem.read.data", addr), hexbuf, 0);
158 	//eprintf ("[ESIL] MEM READ 0x%08"PFMT64x" %s\n", addr, hexbuf);
159 	free (hexbuf);
160 
161 	if (ocbs.hook_mem_read) {
162 		RAnalEsilCallbacks cbs = esil->cb;
163 		esil->cb = ocbs;
164 		ret = ocbs.hook_mem_read (esil, addr, buf, len);
165 		esil->cb = cbs;
166 	}
167 	return ret;
168 }
169 
trace_hook_mem_write(RAnalEsil * esil,ut64 addr,const ut8 * buf,int len)170 static int trace_hook_mem_write(RAnalEsil *esil, ut64 addr, const ut8 *buf, int len) {
171 	size_t i;
172 	int ret = 0;
173 	char *hexbuf = malloc ((1+len)*3);
174 	sdb_array_add_num (DB, KEY ("mem.write"), addr, 0);
175 	r_hex_bin2str (buf, len, hexbuf);
176 	sdb_set (DB, KEYAT ("mem.write.data", addr), hexbuf, 0);
177 	//eprintf ("[ESIL] MEM WRITE 0x%08"PFMT64x" %s\n", addr, hexbuf);
178 	free (hexbuf);
179 	for (i = 0; i < len; i++) {
180 		add_mem_change (esil->trace, esil->trace->idx + 1, addr + i, buf[i]);
181 	}
182 
183 	if (ocbs.hook_mem_write) {
184 		RAnalEsilCallbacks cbs = esil->cb;
185 		esil->cb = ocbs;
186 		ret = ocbs.hook_mem_write (esil, addr, buf, len);
187 		esil->cb = cbs;
188 	}
189 	return ret;
190 }
191 
r_anal_esil_trace_op(RAnalEsil * esil,RAnalOp * op)192 R_API void r_anal_esil_trace_op(RAnalEsil *esil, RAnalOp *op) {
193 	r_return_if_fail (esil && op);
194 	const char *expr = r_strbuf_get (&op->esil);
195 	if (R_STR_ISEMPTY (expr)) {
196 		// do nothing
197 		return;
198 	}
199 	if (!esil->trace) {
200 		esil->trace = r_anal_esil_trace_new (esil);
201 		if (!esil->trace) {
202 			return;
203 		}
204 	}
205 	/* restore from trace when `idx` is not at the end */
206 	if (esil->trace->idx != esil->trace->end_idx) {
207 		r_anal_esil_trace_restore (esil, esil->trace->idx + 1);
208 		return;
209 	}
210 	/* save old callbacks */
211 	int esil_verbose = esil->verbose;
212 	if (ocbs_set) {
213 		eprintf ("cannot call recursively\n");
214 	}
215 	ocbs = esil->cb;
216 	ocbs_set = true;
217 	sdb_num_set (DB, "idx", esil->trace->idx, 0);
218 	sdb_num_set (DB, KEY ("addr"), op->addr, 0);
219 	RRegItem *pc_ri = r_reg_get (esil->anal->reg, "PC", -1);
220 	add_reg_change (esil->trace, esil->trace->idx, pc_ri, op->addr);
221 //	sdb_set (DB, KEY ("opcode"), op->mnemonic, 0);
222 //	sdb_set (DB, KEY ("addr"), expr, 0);
223 	//eprintf ("[ESIL] ADDR 0x%08"PFMT64x"\n", op->addr);
224 	//eprintf ("[ESIL] OPCODE %s\n", op->mnemonic);
225 	//eprintf ("[ESIL] EXPR = %s\n", expr);
226 	/* set hooks */
227 	esil->verbose = 0;
228 	esil->cb.hook_reg_read = trace_hook_reg_read;
229 	esil->cb.hook_reg_write = trace_hook_reg_write;
230 	esil->cb.hook_mem_read = trace_hook_mem_read;
231 	esil->cb.hook_mem_write = trace_hook_mem_write;
232 	/* evaluate esil expression */
233 	r_anal_esil_parse (esil, expr);
234 	r_anal_esil_stack_free (esil);
235 	/* restore hooks */
236 	esil->cb = ocbs;
237 	ocbs_set = false;
238 	esil->verbose = esil_verbose;
239 	/* increment idx */
240 	esil->trace->idx++;
241 	esil->trace->end_idx++;
242 }
243 
244 
restore_memory_cb(void * user,const ut64 key,const void * value)245 static bool restore_memory_cb(void *user, const ut64 key, const void *value) {
246 	size_t index;
247 	RAnalEsil *esil = user;
248 	RVector *vmem = (RVector *)value;
249 
250 	r_vector_upper_bound (vmem, esil->trace->idx, index, CMP_MEM_CHANGE);
251 	if (index > 0 && index <= vmem->len) {
252 		RAnalEsilMemChange *c = r_vector_index_ptr (vmem, index - 1);
253 		esil->anal->iob.write_at (esil->anal->iob.io, key, &c->data, 1);
254 	}
255 	return true;
256 }
257 
restore_register(RAnalEsil * esil,RRegItem * ri,int idx)258 static bool restore_register(RAnalEsil *esil, RRegItem *ri, int idx) {
259 	size_t index;
260 	RVector *vreg = ht_up_find (esil->trace->registers, ri->offset | (ri->arena << 16), NULL);
261 	if (vreg) {
262 		r_vector_upper_bound (vreg, idx, index, CMP_REG_CHANGE);
263 		if (index > 0 && index <= vreg->len) {
264 			RAnalEsilRegChange *c = r_vector_index_ptr (vreg, index - 1);
265 			r_reg_set_value (esil->anal->reg, ri, c->data);
266 		}
267 	}
268 	return true;
269 }
270 
r_anal_esil_trace_restore(RAnalEsil * esil,int idx)271 R_API void r_anal_esil_trace_restore(RAnalEsil *esil, int idx) {
272 	size_t i;
273 	RAnalEsilTrace *trace = esil->trace;
274 	// Restore initial state when going backward
275 	if (idx < esil->trace->idx) {
276 		// Restore initial registers value
277 		for (i = 0; i < R_REG_TYPE_LAST; i++) {
278 			RRegArena *a = esil->anal->reg->regset[i].arena;
279 			RRegArena *b = trace->arena[i];
280 			if (a && b) {
281 				memcpy (a->bytes, b->bytes, a->size);
282 			}
283 		}
284 		// Restore initial stack memory
285 		esil->anal->iob.write_at (esil->anal->iob.io, trace->stack_addr,
286 			trace->stack_data, trace->stack_size);
287 	}
288 	// Apply latest changes to registers and memory
289 	esil->trace->idx = idx;
290 	RListIter *iter;
291 	RRegItem *ri;
292 	r_list_foreach (esil->anal->reg->allregs, iter, ri) {
293 		restore_register (esil, ri, idx);
294 	}
295 	ht_up_foreach (trace->memory, restore_memory_cb, esil);
296 }
297 
cmp_strings_by_leading_number(void * data1,void * data2)298 static int cmp_strings_by_leading_number(void *data1, void *data2) {
299 	const char* a = sdbkv_key ((const SdbKv *)data1);
300 	const char* b = sdbkv_key ((const SdbKv *)data2);
301 	int i = 0;
302 	int j = 0;
303 	int k = 0;
304 	while (a[i] >= '0' && a[i] <= '9') {
305 		i++;
306 	}
307 	while (b[j] >= '0' && b[j] <= '9') {
308 		j++;
309 	}
310 	if (!i) {
311 		return 1;
312 	}
313 	if (!j) {
314 		return -1;
315 	}
316 	i--;
317 	j--;
318 	if (i > j) {
319 		return 1;
320 	}
321 	if (j > i) {
322 		return -1;
323 	}
324 	while (k <= i) {
325 		if (a[k] < b[k]) {
326 			return -1;
327 		}
328 		if (a[k] > b[k]) {
329 			return 1;
330 		}
331 		k++;
332 	}
333 	for (; a[i] && b[i]; i++) {
334 		if (a[i] > b[i]) {
335 			return 1;
336 		}
337 		if (a[i] < b[i]) {
338 			return -1;
339 		}
340 	}
341 	if (!a[i] && b[i]) {
342 		return -1;
343 	}
344 	if (!b[i] && a[i]) {
345 		return 1;
346 	}
347 	return 0;
348 }
349 
r_anal_esil_trace_list(RAnalEsil * esil)350 R_API void r_anal_esil_trace_list (RAnalEsil *esil) {
351 	PrintfCallback p = esil->anal->cb_printf;
352 	SdbKv *kv;
353 	SdbListIter *iter;
354 	SdbList *list = sdb_foreach_list (esil->trace->db, true);
355 	ls_sort (list, (SdbListComparator) cmp_strings_by_leading_number);
356 	ls_foreach (list, iter, kv) {
357 		p ("%s=%s\n", sdbkv_key (kv), sdbkv_value (kv));
358 	}
359 	ls_free (list);
360 }
361 
r_anal_esil_trace_show(RAnalEsil * esil,int idx)362 R_API void r_anal_esil_trace_show(RAnalEsil *esil, int idx) {
363 	PrintfCallback p = esil->anal->cb_printf;
364 	const char *str2;
365 	const char *str;
366 	int trace_idx = esil->trace->idx;
367 	esil->trace->idx = idx;
368 
369 	str2 = sdb_const_get (DB, KEY ("addr"), 0);
370 	if (!str2) {
371 		return;
372 	}
373 	p ("ar PC = %s\n", str2);
374 	/* registers */
375 	str = sdb_const_get (DB, KEY ("reg.read"), 0);
376 	if (str) {
377 		char regname[32];
378 		const char *next, *ptr = str;
379 		if (ptr && *ptr) {
380 			do {
381 				next = sdb_const_anext (ptr);
382 				int len = next? (int)(size_t)(next-ptr)-1 : strlen (ptr);
383 				if (len <sizeof(regname)) {
384 					memcpy (regname, ptr, len);
385 					regname[len] = 0;
386 					str2 = sdb_const_get (DB, KEYREG ("reg.read", regname), 0);
387 					p ("ar %s = %s\n", regname, str2);
388 				} else {
389 					eprintf ("Invalid entry in reg.read\n");
390 				}
391 				ptr = next;
392 			} while (next);
393 		}
394 	}
395 	/* memory */
396 	str = sdb_const_get (DB, KEY ("mem.read"), 0);
397 	if (str) {
398 		char addr[64];
399 		const char *next, *ptr = str;
400 		if (ptr && *ptr) {
401 			do {
402 				next = sdb_const_anext (ptr);
403 				int len = next? (int)(size_t)(next-ptr)-1 : strlen (ptr);
404 				if (len <sizeof(addr)) {
405 					memcpy (addr, ptr, len);
406 					addr[len] = 0;
407 					str2 = sdb_const_get (DB, KEYAT ("mem.read.data",
408 						r_num_get (NULL, addr)), 0);
409 					p ("wx %s @ %s\n", str2, addr);
410 				} else {
411 					eprintf ("Invalid entry in reg.read\n");
412 				}
413 				ptr = next;
414 			} while (next);
415 		}
416 	}
417 
418 	esil->trace->idx = trace_idx;
419 }
420