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, ®);
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