1 /* radare2 - LGPL - Copyright 2009-2019 - pancake, nibble, dso */
2
3 #include <r_bin.h>
4 #include <r_hash.h>
5 #include "i/private.h"
6
7 // maybe too big sometimes? 2KB of stack eaten here..
8 #define R_STRING_SCAN_BUFFER_SIZE 2048
9 #define R_STRING_MAX_UNI_BLOCKS 4
10
__getClass(RBinFile * bf,const char * name)11 static RBinClass *__getClass(RBinFile *bf, const char *name) {
12 r_return_val_if_fail (bf && bf->o && bf->o->classes_ht && name, NULL);
13 return ht_pp_find (bf->o->classes_ht, name, NULL);
14 }
15
__getMethod(RBinFile * bf,const char * klass,const char * method)16 static RBinSymbol *__getMethod(RBinFile *bf, const char *klass, const char *method) {
17 r_return_val_if_fail (bf && bf->o && bf->o->methods_ht && klass && method, NULL);
18 const char *name = sdb_fmt ("%s::%s", klass, method);
19 return ht_pp_find (bf->o->methods_ht, name, NULL);
20 }
21
__stringAt(RBinFile * bf,RList * ret,ut64 addr)22 static RBinString *__stringAt(RBinFile *bf, RList *ret, ut64 addr) {
23 if (addr != 0 && addr != UT64_MAX) {
24 return ht_up_find (bf->o->strings_db, addr, NULL);
25 }
26 return NULL;
27 }
28
binobj_a2b(RBinObject * o,ut64 addr)29 static ut64 binobj_a2b(RBinObject *o, ut64 addr) {
30 return o ? addr + o->baddr_shift : addr;
31 }
32
print_string(RBinFile * bf,RBinString * string,int raw,PJ * pj)33 static void print_string(RBinFile *bf, RBinString *string, int raw, PJ *pj) {
34 r_return_if_fail (bf && string);
35
36 int mode = bf->strmode;
37 ut64 addr, vaddr;
38 RBin *bin = bf->rbin;
39 if (!bin) {
40 return;
41 }
42 const char *section_name, *type_string;
43 RIO *io = bin->iob.io;
44 if (!io) {
45 return;
46 }
47 RBinSection *s = r_bin_get_section_at (bf->o, string->paddr, false);
48 if (s) {
49 string->vaddr = s->vaddr + (string->paddr - s->paddr);
50 }
51 section_name = s ? s->name : "";
52 type_string = r_bin_string_type (string->type);
53 vaddr = addr = r_bin_get_vaddr (bin, string->paddr, string->vaddr);
54
55 // If raw string dump mode, use printf to dump directly to stdout.
56 // PrintfCallback temp = io->cb_printf;
57 switch (mode) {
58 case R_MODE_JSON:
59 {
60 if (pj) {
61 pj_o (pj);
62 pj_kn (pj, "vaddr", vaddr);
63 pj_kn (pj, "paddr", string->paddr);
64 pj_kn (pj, "ordinal", string->ordinal);
65 pj_kn (pj, "size", string->size);
66 pj_kn (pj, "length", string->length);
67 pj_ks (pj, "section", section_name);
68 pj_ks (pj, "type", type_string);
69 pj_ks (pj, "string", string->string);
70 pj_end (pj);
71 }
72 }
73 break;
74 case R_MODE_SIMPLEST:
75 io->cb_printf ("%s\n", string->string);
76 break;
77 case R_MODE_SIMPLE:
78 if (raw == 2) {
79 io->cb_printf ("0x%08"PFMT64x" %s\n", addr, string->string);
80 } else {
81 io->cb_printf ("%s\n", string->string);
82 }
83 break;
84 case R_MODE_RADARE: {
85 char *f_name = strdup (string->string);
86 r_name_filter (f_name, 32);
87 if (bin->prefix) {
88 io->cb_printf ("f %s.str.%s %u @ 0x%08"PFMT64x"\n"
89 "Cs %u @ 0x%08"PFMT64x"\n",
90 bin->prefix, f_name, string->size, addr,
91 string->size, addr);
92 } else {
93 io->cb_printf ("f str.%s %u @ 0x%08"PFMT64x"\n"
94 "Cs %u @ 0x%08"PFMT64x"\n",
95 f_name, string->size, addr,
96 string->size, addr);
97 }
98 free (f_name);
99 break;
100 }
101 case R_MODE_PRINT:
102 io->cb_printf ("%03u 0x%08" PFMT64x " 0x%08" PFMT64x " %3u %3u "
103 "(%s) %5s %s\n",
104 string->ordinal, string->paddr, vaddr,
105 string->length, string->size,
106 section_name, type_string, string->string);
107 break;
108 }
109 }
110
string_scan_range(RList * list,RBinFile * bf,int min,const ut64 from,const ut64 to,int type,int raw,RBinSection * section)111 static int string_scan_range(RList *list, RBinFile *bf, int min,
112 const ut64 from, const ut64 to, int type, int raw, RBinSection *section) {
113 RBin *bin = bf->rbin;
114 ut8 tmp[R_STRING_SCAN_BUFFER_SIZE];
115 ut64 str_start, needle = from;
116 int count = 0, i, rc, runes;
117 int str_type = R_STRING_TYPE_DETECT;
118
119 // if list is null it means its gonna dump
120 r_return_val_if_fail (bf, -1);
121
122 if (type == -1) {
123 type = R_STRING_TYPE_DETECT;
124 }
125 if (from == to) {
126 return 0;
127 }
128 if (from > to) {
129 eprintf ("Invalid range to find strings 0x%"PFMT64x" .. 0x%"PFMT64x"\n", from, to);
130 return -1;
131 }
132 int len = to - from;
133 ut8 *buf = calloc (len, 1);
134 if (!buf || !min) {
135 free (buf);
136 return -1;
137 }
138 st64 vdelta = 0, pdelta = 0;
139 RBinSection *s = NULL;
140 bool ascii_only = false;
141 PJ *pj = NULL;
142 if (bf->strmode == R_MODE_JSON && !list) {
143 pj = pj_new ();
144 if (pj) {
145 pj_a (pj);
146 }
147 }
148 r_buf_read_at (bf->buf, from, buf, len);
149 // may oobread
150 while (needle < to) {
151 if (bin && bin->consb.is_breaked) {
152 if (bin->consb.is_breaked ()) {
153 break;
154 }
155 }
156 rc = r_utf8_decode (buf + needle - from, to - needle, NULL);
157 if (!rc) {
158 needle++;
159 continue;
160 }
161 if (type == R_STRING_TYPE_DETECT) {
162 char *w = (char *)buf + needle + rc - from;
163 if ((to - needle) > 5 + rc) {
164 bool is_wide32 = (needle + rc + 2 < to) && (!w[0] && !w[1] && !w[2] && w[3] && !w[4]);
165 if (is_wide32) {
166 str_type = R_STRING_TYPE_WIDE32;
167 } else {
168 bool is_wide = needle + rc + 4 < to && !w[0] && w[1] && !w[2] && w[3] && !w[4];
169 str_type = is_wide? R_STRING_TYPE_WIDE: R_STRING_TYPE_ASCII;
170 }
171 } else {
172 str_type = R_STRING_TYPE_ASCII;
173 }
174 } else if (type == R_STRING_TYPE_UTF8) {
175 str_type = R_STRING_TYPE_ASCII; // initial assumption
176 } else {
177 str_type = type;
178 }
179 runes = 0;
180 str_start = needle;
181
182 /* Eat a whole C string */
183 for (i = 0; i < sizeof (tmp) - 4 && needle < to; i += rc) {
184 RRune r = {0};
185
186 if (str_type == R_STRING_TYPE_WIDE32) {
187 rc = r_utf32le_decode (buf + needle - from, to - needle, &r);
188 if (rc) {
189 rc = 4;
190 }
191 } else if (str_type == R_STRING_TYPE_WIDE) {
192 rc = r_utf16le_decode (buf + needle - from, to - needle, &r);
193 if (rc == 1) {
194 rc = 2;
195 }
196 } else {
197 rc = r_utf8_decode (buf + needle - from, to - needle, &r);
198 if (rc > 1) {
199 str_type = R_STRING_TYPE_UTF8;
200 }
201 }
202
203 /* Invalid sequence detected */
204 if (!rc || (ascii_only && r > 0x7f)) {
205 needle++;
206 break;
207 }
208
209 needle += rc;
210
211 if (r_isprint (r) && r != '\\') {
212 if (str_type == R_STRING_TYPE_WIDE32) {
213 if (r == 0xff) {
214 r = 0;
215 }
216 }
217 rc = r_utf8_encode (tmp + i, r);
218 runes++;
219 /* Print the escape code */
220 } else if (r && r < 0x100 && strchr ("\b\v\f\n\r\t\a\033\\", (char)r)) {
221 if ((i + 32) < sizeof (tmp) && r < 93) {
222 tmp[i + 0] = '\\';
223 tmp[i + 1] = " abtnvfr e "
224 " "
225 " "
226 " \\"[r];
227 } else {
228 // string too long
229 break;
230 }
231 rc = 2;
232 runes++;
233 } else {
234 /* \0 marks the end of C-strings */
235 break;
236 }
237 }
238
239 tmp[i++] = '\0';
240
241 if (runes < min && runes >= 2 && str_type == R_STRING_TYPE_ASCII && needle < to) {
242 // back up past the \0 to the last char just in case it starts a wide string
243 needle -= 2;
244 }
245 if (runes >= min) {
246 // reduce false positives
247 int j, num_blocks, *block_list;
248 int *freq_list = NULL, expected_ascii, actual_ascii, num_chars;
249 if (str_type == R_STRING_TYPE_ASCII) {
250 for (j = 0; j < i; j++) {
251 char ch = tmp[j];
252 if (ch != '\n' && ch != '\r' && ch != '\t') {
253 if (!IS_PRINTABLE (tmp[j])) {
254 continue;
255 }
256 }
257 }
258 }
259 switch (str_type) {
260 case R_STRING_TYPE_UTF8:
261 case R_STRING_TYPE_WIDE:
262 case R_STRING_TYPE_WIDE32:
263 num_blocks = 0;
264 block_list = r_utf_block_list ((const ut8*)tmp, i - 1,
265 str_type == R_STRING_TYPE_WIDE ? &freq_list : NULL);
266 if (block_list) {
267 for (j = 0; block_list[j] != -1; j++) {
268 num_blocks++;
269 }
270 }
271 if (freq_list) {
272 num_chars = 0;
273 actual_ascii = 0;
274 for (j = 0; freq_list[j] != -1; j++) {
275 num_chars += freq_list[j];
276 if (!block_list[j]) { // ASCII
277 actual_ascii = freq_list[j];
278 }
279 }
280 free (freq_list);
281 expected_ascii = num_blocks ? num_chars / num_blocks : 0;
282 if (actual_ascii > expected_ascii) {
283 ascii_only = true;
284 needle = str_start;
285 free (block_list);
286 continue;
287 }
288 }
289 free (block_list);
290 if (num_blocks > R_STRING_MAX_UNI_BLOCKS) {
291 continue;
292 }
293 }
294 RBinString *bs = R_NEW0 (RBinString);
295 if (!bs) {
296 break;
297 }
298 bs->type = str_type;
299 bs->length = runes;
300 bs->size = needle - str_start;
301 bs->ordinal = count++;
302 // TODO: move into adjust_offset
303 switch (str_type) {
304 case R_STRING_TYPE_WIDE:
305 if (str_start - from > 1) {
306 const ut8 *p = buf + str_start - 2 - from;
307 if (p[0] == 0xff && p[1] == 0xfe) {
308 str_start -= 2; // \xff\xfe
309 }
310 }
311 break;
312 case R_STRING_TYPE_WIDE32:
313 if (str_start - from > 3) {
314 const ut8 *p = buf + str_start - 4 - from;
315 if (p[0] == 0xff && p[1] == 0xfe) {
316 str_start -= 4; // \xff\xfe\x00\x00
317 }
318 }
319 break;
320 }
321 if (!s) {
322 if (section) {
323 s = section;
324 } else if (bf->o) {
325 s = r_bin_get_section_at (bf->o, str_start, false);
326 }
327 if (s) {
328 vdelta = s->vaddr;
329 pdelta = s->paddr;
330 }
331 }
332 bs->paddr = str_start;
333 bs->vaddr = str_start - pdelta + vdelta;
334 bs->string = r_str_ndup ((const char *)tmp, i);
335 if (list) {
336 r_list_append (list, bs);
337 if (bf->o) {
338 ht_up_insert (bf->o->strings_db, bs->vaddr, bs);
339 }
340 } else {
341 print_string (bf, bs, raw, pj);
342 r_bin_string_free (bs);
343 }
344 if (from == 0 && to == bf->size) {
345 /* force lookup section at the next one */
346 s = NULL;
347 }
348 }
349 ascii_only = false;
350 }
351 free (buf);
352 if (pj) {
353 pj_end (pj);
354 if (bin) {
355 RIO *io = bin->iob.io;
356 if (io) {
357 io->cb_printf ("%s", pj_string (pj));
358 }
359 }
360 pj_free (pj);
361 }
362 return count;
363 }
364
__isDataSection(RBinFile * a,RBinSection * s)365 static bool __isDataSection(RBinFile *a, RBinSection *s) {
366 if (s->has_strings || s->is_data) {
367 return true;
368 }
369 // Rust
370 return strstr (s->name, "_const") != NULL;
371 }
372
get_strings_range(RBinFile * bf,RList * list,int min,int raw,ut64 from,ut64 to,RBinSection * section)373 static void get_strings_range(RBinFile *bf, RList *list, int min, int raw, ut64 from, ut64 to, RBinSection * section) {
374 r_return_if_fail (bf && bf->buf);
375
376 RBinPlugin *plugin = r_bin_file_cur_plugin (bf);
377
378 if (!raw && (!plugin || !plugin->info)) {
379 return;
380 }
381 if (!min) {
382 min = plugin? plugin->minstrlen: 4;
383 }
384 /* Some plugins return zero, fix it up */
385 if (!min) {
386 min = 4;
387 }
388 if (min < 0) {
389 return;
390 }
391 {
392 RIO *io = bf->rbin->iob.io;
393 RCoreBind *cb = &io->corebind;
394 if (cb && cb->cfgGet) {
395 const bool cfg_debug = cb->cfgGet (cb->core, "cfg.debug");
396 if (!cfg_debug) {
397 if (!to || to > r_buf_size (bf->buf)) {
398 to = r_buf_size (bf->buf);
399 }
400 if (!to) {
401 return;
402 }
403 }
404 }
405 }
406 if (raw != 2) {
407 ut64 size = to - from;
408 // in case of dump ignore here
409 if (bf->rbin->maxstrbuf && size && size > bf->rbin->maxstrbuf) {
410 if (bf->rbin->verbose) {
411 eprintf ("WARNING: bin_strings buffer is too big (0x%08" PFMT64x "). Use -zzz or set bin.maxstrbuf (RABIN2_MAXSTRBUF) in r2 (rabin2)\n",
412 size);
413 }
414 return;
415 }
416 }
417 int type;
418 const char *enc = bf->rbin->strenc;
419 if (!enc) {
420 type = R_STRING_TYPE_DETECT;
421 } else if (!strcmp (enc, "latin1")) {
422 type = R_STRING_TYPE_ASCII;
423 } else if (!strcmp (enc, "utf8")) {
424 type = R_STRING_TYPE_UTF8;
425 } else if (!strcmp (enc, "utf16le")) {
426 type = R_STRING_TYPE_WIDE;
427 } else if (!strcmp (enc, "utf32le")) {
428 type = R_STRING_TYPE_WIDE32;
429 } else { // TODO utf16be, utf32be
430 eprintf ("ERROR: encoding %s not supported\n", enc);
431 return;
432 }
433 string_scan_range (list, bf, min, from, to, type, raw, section);
434 }
435
r_bin_file_new(RBin * bin,const char * file,ut64 file_sz,int rawstr,int fd,const char * xtrname,Sdb * sdb,bool steal_ptr)436 R_IPI RBinFile *r_bin_file_new(RBin *bin, const char *file, ut64 file_sz, int rawstr, int fd, const char *xtrname, Sdb *sdb, bool steal_ptr) {
437 ut32 bf_id;
438 if (!r_id_pool_grab_id (bin->ids->pool, &bf_id)) {
439 return NULL;
440 }
441 RBinFile *bf = R_NEW0 (RBinFile);
442 if (bf) {
443 bf->id = bf_id;
444 bf->rbin = bin;
445 bf->file = file ? strdup (file) : NULL;
446 bf->rawstr = rawstr;
447 bf->fd = fd;
448 bf->curxtr = xtrname ? r_bin_get_xtrplugin_by_name (bin, xtrname) : NULL;
449 bf->sdb = sdb;
450 bf->size = file_sz;
451 bf->xtr_data = r_list_newf ((RListFree)r_bin_xtrdata_free);
452 bf->xtr_obj = NULL;
453 bf->sdb = sdb_new0 ();
454 bf->sdb_addrinfo = sdb_new0 (); //ns (bf->sdb, "addrinfo", 1);
455 // bf->sdb_addrinfo->refs++;
456 }
457 return bf;
458 }
459
get_plugin_from_buffer(RBin * bin,const char * pluginname,RBuffer * buf)460 static RBinPlugin *get_plugin_from_buffer(RBin *bin, const char *pluginname, RBuffer *buf) {
461 RBinPlugin *plugin = bin->force? r_bin_get_binplugin_by_name (bin, bin->force): NULL;
462 if (plugin) {
463 return plugin;
464 }
465 plugin = pluginname? r_bin_get_binplugin_by_name (bin, pluginname): NULL;
466 if (plugin) {
467 return plugin;
468 }
469 plugin = r_bin_get_binplugin_by_buffer (bin, buf);
470 if (plugin) {
471 return plugin;
472 }
473 return r_bin_get_binplugin_by_name (bin, "any");
474 }
475
r_bin_file_object_new_from_xtr_data(RBin * bin,RBinFile * bf,ut64 baseaddr,ut64 loadaddr,RBinXtrData * data)476 R_API bool r_bin_file_object_new_from_xtr_data(RBin *bin, RBinFile *bf, ut64 baseaddr, ut64 loadaddr, RBinXtrData *data) {
477 r_return_val_if_fail (bin && bf && data, false);
478
479 ut64 offset = data->offset;
480 ut64 sz = data->size;
481
482 RBinPlugin *plugin = get_plugin_from_buffer (bin, NULL, data->buf);
483 bf->buf = r_buf_ref (data->buf);
484
485 RBinObject *o = r_bin_object_new (bf, plugin, baseaddr, loadaddr, offset, sz);
486 if (!o) {
487 return false;
488 }
489 // size is set here because the reported size of the object depends on
490 // if loaded from xtr plugin or partially read
491 if (!o->size) {
492 o->size = sz;
493 }
494 bf->narch = data->file_count;
495 if (!o->info) {
496 o->info = R_NEW0 (RBinInfo);
497 }
498 free (o->info->file);
499 free (o->info->arch);
500 free (o->info->machine);
501 free (o->info->type);
502 o->info->file = strdup (bf->file);
503 o->info->arch = strdup (data->metadata->arch);
504 o->info->machine = strdup (data->metadata->machine);
505 o->info->type = strdup (data->metadata->type);
506 o->info->bits = data->metadata->bits;
507 o->info->has_crypto = bf->o->info->has_crypto;
508 data->loaded = true;
509 return true;
510 }
511
xtr_metadata_match(RBinXtrData * xtr_data,const char * arch,int bits)512 static bool xtr_metadata_match(RBinXtrData *xtr_data, const char *arch, int bits) {
513 if (!xtr_data->metadata || !xtr_data->metadata->arch) {
514 return false;
515 }
516 const char *iter_arch = xtr_data->metadata->arch;
517 int iter_bits = xtr_data->metadata->bits;
518 return bits == iter_bits && !strcmp (iter_arch, arch) && !xtr_data->loaded;
519 }
520
r_bin_file_new_from_buffer(RBin * bin,const char * file,RBuffer * buf,int rawstr,ut64 baseaddr,ut64 loadaddr,int fd,const char * pluginname)521 R_IPI RBinFile *r_bin_file_new_from_buffer(RBin *bin, const char *file, RBuffer *buf, int rawstr, ut64 baseaddr, ut64 loadaddr, int fd, const char *pluginname) {
522 r_return_val_if_fail (bin && file && buf, NULL);
523
524 RBinFile *bf = r_bin_file_new (bin, file, r_buf_size (buf), rawstr, fd, pluginname, NULL, false);
525 if (bf) {
526 RListIter *item = r_list_append (bin->binfiles, bf);
527 bf->buf = r_buf_ref (buf);
528 RBinPlugin *plugin = get_plugin_from_buffer (bin, pluginname, bf->buf);
529 RBinObject *o = r_bin_object_new (bf, plugin, baseaddr, loadaddr, 0, r_buf_size (bf->buf));
530 if (!o) {
531 r_list_delete (bin->binfiles, item);
532 return NULL;
533 }
534 // size is set here because the reported size of the object depends on
535 // if loaded from xtr plugin or partially read
536 if (!o->size) {
537 o->size = r_buf_size (buf);
538 }
539 }
540 return bf;
541 }
542
r_bin_file_find_by_arch_bits(RBin * bin,const char * arch,int bits)543 R_API RBinFile *r_bin_file_find_by_arch_bits(RBin *bin, const char *arch, int bits) {
544 RListIter *iter;
545 RBinFile *binfile = NULL;
546 RBinXtrData *xtr_data;
547
548 r_return_val_if_fail (bin && arch, NULL);
549
550 r_list_foreach (bin->binfiles, iter, binfile) {
551 RListIter *iter_xtr;
552 if (!binfile->xtr_data) {
553 continue;
554 }
555 // look for sub-bins in Xtr Data and Load if we need to
556 r_list_foreach (binfile->xtr_data, iter_xtr, xtr_data) {
557 if (xtr_metadata_match (xtr_data, arch, bits)) {
558 if (!r_bin_file_object_new_from_xtr_data (bin, binfile, xtr_data->baddr,
559 xtr_data->laddr, xtr_data)) {
560 return NULL;
561 }
562 return binfile;
563 }
564 }
565 }
566 return binfile;
567 }
568
r_bin_file_find_by_id(RBin * bin,ut32 bf_id)569 R_IPI RBinFile *r_bin_file_find_by_id(RBin *bin, ut32 bf_id) {
570 RBinFile *bf;
571 RListIter *iter;
572 r_list_foreach (bin->binfiles, iter, bf) {
573 if (bf->id == bf_id) {
574 return bf;
575 }
576 }
577 return NULL;
578 }
579
r_bin_file_delete_all(RBin * bin)580 R_API ut64 r_bin_file_delete_all(RBin *bin) {
581 if (bin) {
582 ut64 counter = r_list_length (bin->binfiles);
583 r_list_purge (bin->binfiles);
584 bin->cur = NULL;
585 return counter;
586 }
587 return 0;
588 }
589
r_bin_file_delete(RBin * bin,ut32 bin_id)590 R_API bool r_bin_file_delete(RBin *bin, ut32 bin_id) {
591 r_return_val_if_fail (bin, false);
592
593 RListIter *iter;
594 RBinFile *bf, *cur = r_bin_cur (bin);
595
596 r_list_foreach (bin->binfiles, iter, bf) {
597 if (bf && bf->id == bin_id) {
598 if (cur && cur->id == bin_id) {
599 // avoiding UaF due to dead reference
600 bin->cur = NULL;
601 }
602 r_list_delete (bin->binfiles, iter);
603 return true;
604 }
605 }
606 return false;
607 }
608
r_bin_file_find_by_fd(RBin * bin,ut32 bin_fd)609 R_API RBinFile *r_bin_file_find_by_fd(RBin *bin, ut32 bin_fd) {
610 RListIter *iter;
611 RBinFile *bf;
612
613 r_return_val_if_fail (bin, NULL);
614
615 r_list_foreach (bin->binfiles, iter, bf) {
616 if (bf->fd == bin_fd) {
617 return bf;
618 }
619 }
620 return NULL;
621 }
622
r_bin_file_find_by_name(RBin * bin,const char * name)623 R_API RBinFile *r_bin_file_find_by_name(RBin *bin, const char *name) {
624 RListIter *iter;
625 RBinFile *bf;
626
627 r_return_val_if_fail (bin && name, NULL);
628
629 r_list_foreach (bin->binfiles, iter, bf) {
630 if (bf->file && !strcmp (bf->file, name)) {
631 return bf;
632 }
633 }
634 return NULL;
635 }
636
r_bin_file_set_cur_by_id(RBin * bin,ut32 bin_id)637 R_API bool r_bin_file_set_cur_by_id(RBin *bin, ut32 bin_id) {
638 RBinFile *bf = r_bin_file_find_by_id (bin, bin_id);
639 return bf? r_bin_file_set_cur_binfile (bin, bf): false;
640 }
641
r_bin_file_set_cur_by_fd(RBin * bin,ut32 bin_fd)642 R_API bool r_bin_file_set_cur_by_fd(RBin *bin, ut32 bin_fd) {
643 RBinFile *bf = r_bin_file_find_by_fd (bin, bin_fd);
644 return bf? r_bin_file_set_cur_binfile (bin, bf): false;
645 }
646
r_bin_file_set_obj(RBin * bin,RBinFile * bf,RBinObject * obj)647 R_IPI bool r_bin_file_set_obj(RBin *bin, RBinFile *bf, RBinObject *obj) {
648 r_return_val_if_fail (bin && bf, false);
649 bin->file = bf->file;
650 bin->cur = bf;
651 bin->narch = bf->narch;
652 if (obj) {
653 bf->o = obj;
654 } else {
655 obj = bf->o;
656 }
657 RBinPlugin *plugin = r_bin_file_cur_plugin (bf);
658 if (bin->minstrlen < 1) {
659 bin->minstrlen = plugin? plugin->minstrlen: bin->minstrlen;
660 }
661 if (obj) {
662 if (!obj->info) {
663 return false;
664 }
665 if (!obj->info->lang) {
666 obj->info->lang = r_bin_lang_tostring (obj->lang);
667 }
668 }
669 return true;
670 }
671
r_bin_file_set_cur_binfile(RBin * bin,RBinFile * bf)672 R_API bool r_bin_file_set_cur_binfile(RBin *bin, RBinFile *bf) {
673 r_return_val_if_fail (bin && bf, false);
674 return r_bin_file_set_obj (bin, bf, bf->o);
675 }
676
r_bin_file_set_cur_by_name(RBin * bin,const char * name)677 R_API bool r_bin_file_set_cur_by_name(RBin *bin, const char *name) {
678 r_return_val_if_fail (bin && name, false);
679 RBinFile *bf = r_bin_file_find_by_name (bin, name);
680 return r_bin_file_set_cur_binfile (bin, bf);
681 }
682
r_bin_file_deref(RBin * bin,RBinFile * a)683 R_API bool r_bin_file_deref(RBin *bin, RBinFile *a) {
684 r_return_val_if_fail (bin && a, false);
685 if (!r_bin_cur_object (bin)) {
686 return false;
687 }
688 bin->cur = NULL;
689 return true;
690 }
691
r_bin_file_free(void * _bf)692 R_API void r_bin_file_free(void /*RBinFile*/ *_bf) {
693 if (!_bf) {
694 return;
695 }
696 RBinFile *bf = _bf;
697 RBinPlugin *plugin = r_bin_file_cur_plugin (bf);
698 // Binary format objects are connected to the
699 // RBinObject, so the plugin must destroy the
700 // format data first
701 if (plugin && plugin->destroy) {
702 plugin->destroy (bf);
703 }
704 r_buf_free (bf->buf);
705 if (bf->curxtr && bf->curxtr->destroy && bf->xtr_obj) {
706 bf->curxtr->free_xtr ((void *)(bf->xtr_obj));
707 }
708 // TODO: unset related sdb namespaces
709 if (bf->sdb_addrinfo) {
710 sdb_free (bf->sdb_addrinfo);
711 bf->sdb_addrinfo = NULL;
712 }
713 free (bf->file);
714 r_bin_object_free (bf->o);
715 r_list_free (bf->xtr_data);
716 if (bf->id != -1) {
717 // TODO: use r_storage api
718 r_id_pool_kick_id (bf->rbin->ids->pool, bf->id);
719 }
720 (void) r_bin_object_delete (bf->rbin, bf->id);
721 free (bf);
722 }
723
r_bin_file_xtr_load_buffer(RBin * bin,RBinXtrPlugin * xtr,const char * filename,RBuffer * buf,ut64 baseaddr,ut64 loadaddr,int idx,int fd,int rawstr)724 R_IPI RBinFile *r_bin_file_xtr_load_buffer(RBin *bin, RBinXtrPlugin *xtr, const char *filename, RBuffer *buf, ut64 baseaddr, ut64 loadaddr, int idx, int fd, int rawstr) {
725 r_return_val_if_fail (bin && xtr && buf, NULL);
726
727 RBinFile *bf = r_bin_file_find_by_name (bin, filename);
728 if (!bf) {
729 bf = r_bin_file_new (bin, filename, r_buf_size (buf), rawstr, fd, xtr->name, bin->sdb, false);
730 if (!bf) {
731 return NULL;
732 }
733 r_list_append (bin->binfiles, bf);
734 if (!bin->cur) {
735 bin->cur = bf;
736 }
737 }
738 r_list_free (bf->xtr_data);
739 bf->xtr_data = NULL;
740 if (xtr->extractall_from_buffer) {
741 bf->xtr_data = xtr->extractall_from_buffer (bin, buf);
742 } else if (xtr->extractall_from_bytes) {
743 ut64 sz = 0;
744 const ut8 *bytes = r_buf_data (buf, &sz);
745 eprintf ("TODO: Implement extractall_from_buffer in '%s' xtr.bin plugin\n", xtr->name);
746 bf->xtr_data = xtr->extractall_from_bytes (bin, bytes, sz);
747 }
748 if (bf->xtr_data) {
749 RListIter *iter;
750 RBinXtrData *x;
751 //populate xtr_data with baddr and laddr that will be used later on
752 //r_bin_file_object_new_from_xtr_data
753 r_list_foreach (bf->xtr_data, iter, x) {
754 x->baddr = baseaddr? baseaddr : UT64_MAX;
755 x->laddr = loadaddr? loadaddr : UT64_MAX;
756 }
757 }
758 bf->loadaddr = loadaddr;
759 return bf;
760 }
761
762 // XXX deprecate this function imho.. wee can just access bf->buf directly
r_bin_file_set_bytes(RBinFile * bf,const ut8 * bytes,ut64 sz,bool steal_ptr)763 R_IPI bool r_bin_file_set_bytes(RBinFile *bf, const ut8 *bytes, ut64 sz, bool steal_ptr) {
764 r_return_val_if_fail (bf && bytes, false);
765 r_buf_free (bf->buf);
766 if (steal_ptr) {
767 bf->buf = r_buf_new_with_pointers (bytes, sz, true);
768 } else {
769 bf->buf = r_buf_new_with_bytes (bytes, sz);
770 }
771 return bf->buf != NULL;
772 }
773
r_bin_file_cur_plugin(RBinFile * bf)774 R_API RBinPlugin *r_bin_file_cur_plugin(RBinFile *bf) {
775 return (bf && bf->o)? bf->o->plugin: NULL;
776 }
777
778 // TODO: searchStrings() instead
r_bin_file_get_strings(RBinFile * bf,int min,int dump,int raw)779 R_IPI RList *r_bin_file_get_strings(RBinFile *bf, int min, int dump, int raw) {
780 r_return_val_if_fail (bf, NULL);
781 RListIter *iter;
782 RBinSection *section;
783 RList *ret = dump? NULL: r_list_newf (r_bin_string_free);
784
785 if (!raw && bf && bf->o && bf->o->sections && !r_list_empty (bf->o->sections)) {
786 RBinObject *o = bf->o;
787 r_list_foreach (o->sections, iter, section) {
788 if (__isDataSection (bf, section)) {
789 get_strings_range (bf, ret, min, raw, section->paddr,
790 section->paddr + section->size, section);
791 }
792 }
793 r_list_foreach (o->sections, iter, section) {
794 /* load objc/swift strings */
795 const int bits = (bf->o && bf->o->info) ? bf->o->info->bits : 32;
796 const int cfstr_size = (bits == 64) ? 32 : 16;
797 const int cfstr_offs = (bits == 64) ? 16 : 8;
798 if (strstr (section->name, "__cfstring")) {
799 int i;
800 // XXX do not walk if bin.strings == 0
801 ut8 *p;
802 if (section->size > bf->size) {
803 continue;
804 }
805 ut8 *sbuf = malloc (section->size);
806 if (!sbuf) {
807 continue;
808 }
809 r_buf_read_at (bf->buf, section->paddr + cfstr_offs, sbuf, section->size);
810 for (i = 0; i < section->size; i += cfstr_size) {
811 ut8 *buf = sbuf;
812 p = buf + i;
813 if ((i + ((bits == 64)? 8: 4)) >= section->size) {
814 break;
815 }
816 ut64 cfstr_vaddr = section->vaddr + i;
817 ut64 cstr_vaddr = (bits == 64) ? r_read_le64 (p) : r_read_le32 (p);
818 RBinString *s = __stringAt (bf, ret, cstr_vaddr);
819 if (s) {
820 RBinString *bs = R_NEW0 (RBinString);
821 if (bs) {
822 bs->type = s->type;
823 bs->length = s->length;
824 bs->size = s->size;
825 bs->ordinal = s->ordinal;
826 bs->vaddr = cfstr_vaddr;
827 bs->paddr = cfstr_vaddr; // XXX should be paddr instead
828 bs->string = r_str_newf ("cstr.%s", s->string);
829 r_list_append (ret, bs);
830 ht_up_insert (o->strings_db, bs->vaddr, bs);
831 }
832 }
833 }
834 free (sbuf);
835 }
836 }
837 } else {
838 get_strings_range (bf, ret, min, raw, 0, bf->size, NULL);
839 }
840 return ret;
841 }
842
r_bin_file_get_baddr(RBinFile * bf)843 R_API ut64 r_bin_file_get_baddr(RBinFile *bf) {
844 if (bf && bf->o) {
845 return bf->o->baddr;
846 }
847 return UT64_MAX;
848 }
849
r_bin_file_close(RBin * bin,int bd)850 R_API bool r_bin_file_close(RBin *bin, int bd) {
851 r_return_val_if_fail (bin, false);
852 RBinFile *bf = r_id_storage_take (bin->ids, bd);
853 if (bf) {
854 // file_free removes the fd already.. maybe its unnecessary
855 r_id_storage_delete (bin->ids, bd);
856 r_bin_file_free (bf);
857 return true;
858 }
859 return false;
860 }
861
r_bin_file_compute_hashes(RBin * bin,ut64 limit)862 R_API RList *r_bin_file_compute_hashes(RBin *bin, ut64 limit) {
863 r_return_val_if_fail (bin && bin->cur && bin->cur->o, NULL);
864 ut64 buf_len = 0, r = 0;
865 RBinFile *bf = bin->cur;
866 RBinObject *o = bf->o;
867
868 RIODesc *iod = r_io_desc_get (bin->iob.io, bf->fd);
869 if (!iod) {
870 return NULL;
871 }
872
873 buf_len = r_io_desc_size (iod);
874 // By SLURP_LIMIT normally cannot compute ...
875 if (buf_len > limit) {
876 if (bin->verbose) {
877 eprintf ("Warning: r_bin_file_hash: file exceeds bin.hashlimit\n");
878 }
879 return NULL;
880 }
881 const size_t blocksize = 64000;
882 ut8 *buf = malloc (blocksize);
883 if (!buf) {
884 eprintf ("Cannot allocate computation buffer\n");
885 return NULL;
886 }
887
888 char hash[128];
889 RHash *ctx = r_hash_new (false, R_HASH_MD5 | R_HASH_SHA1 | R_HASH_SHA256);
890 while (r + blocksize < buf_len) {
891 r_io_desc_seek (iod, r, R_IO_SEEK_SET);
892 int b = r_io_desc_read (iod, buf, blocksize);
893 (void)r_hash_do_md5 (ctx, buf, blocksize);
894 (void)r_hash_do_sha1 (ctx, buf, blocksize);
895 (void)r_hash_do_sha256 (ctx, buf, blocksize);
896 r += b;
897 }
898 if (r < buf_len) {
899 r_io_desc_seek (iod, r, R_IO_SEEK_SET);
900 const size_t rem_len = buf_len-r;
901 int b = r_io_desc_read (iod, buf, rem_len);
902 if (b < 1) {
903 eprintf ("r_io_desc_read: error\n");
904 } else {
905 (void)r_hash_do_md5 (ctx, buf, b);
906 (void)r_hash_do_sha1 (ctx, buf, b);
907 (void)r_hash_do_sha256 (ctx, buf, b);
908 }
909 }
910 r_hash_do_end (ctx, R_HASH_MD5);
911 r_hex_bin2str (ctx->digest, R_HASH_SIZE_MD5, hash);
912
913 RList *file_hashes = r_list_newf ((RListFree) r_bin_file_hash_free);
914 RBinFileHash *md5h = R_NEW0 (RBinFileHash);
915 if (md5h) {
916 md5h->type = strdup ("md5");
917 md5h->hex = strdup (hash);
918 r_list_push (file_hashes, md5h);
919 }
920 r_hash_do_end (ctx, R_HASH_SHA1);
921 r_hex_bin2str (ctx->digest, R_HASH_SIZE_SHA1, hash);
922
923 RBinFileHash *sha1h = R_NEW0 (RBinFileHash);
924 if (sha1h) {
925 sha1h->type = strdup ("sha1");
926 sha1h->hex = strdup (hash);
927 r_list_push (file_hashes, sha1h);
928 }
929 r_hash_do_end (ctx, R_HASH_SHA256);
930 r_hex_bin2str (ctx->digest, R_HASH_SIZE_SHA256, hash);
931
932 RBinFileHash *sha256h = R_NEW0 (RBinFileHash);
933 if (sha256h) {
934 sha256h->type = strdup ("sha256");
935 sha256h->hex = strdup (hash);
936 r_list_push (file_hashes, sha256h);
937 }
938
939 if (o->plugin && o->plugin->hashes) {
940 RList *plugin_hashes = o->plugin->hashes (bf);
941 r_list_join (file_hashes, plugin_hashes);
942 free (plugin_hashes);
943 }
944 // TODO: add here more rows
945
946 free (buf);
947 r_hash_free (ctx);
948 return file_hashes;
949 }
950
951 // Set new hashes to current RBinInfo, caller should free the returned RList
r_bin_file_set_hashes(RBin * bin,RList * new_hashes)952 R_API RList *r_bin_file_set_hashes(RBin *bin, RList/*<RBinFileHash*/ *new_hashes) {
953 r_return_val_if_fail (bin && bin->cur && bin->cur->o && bin->cur->o->info, NULL);
954 RBinFile *bf = bin->cur;
955 RBinInfo *info = bf->o->info;
956
957 RList *prev_hashes = info->file_hashes;
958 info->file_hashes = new_hashes;
959
960 return prev_hashes;
961 }
962
r_bin_class_new(const char * name,const char * super,int view)963 R_IPI RBinClass *r_bin_class_new(const char *name, const char *super, int view) {
964 r_return_val_if_fail (name, NULL);
965 RBinClass *c = R_NEW0 (RBinClass);
966 if (c) {
967 c->name = strdup (name);
968 c->super = super? strdup (super): NULL;
969 c->methods = r_list_new ();
970 c->fields = r_list_new ();
971 c->visibility = view;
972 }
973 return c;
974 }
975
r_bin_class_free(RBinClass * k)976 R_IPI void r_bin_class_free(RBinClass *k) {
977 if (k && k->name) {
978 free (k->name);
979 free (k->super);
980 r_list_free (k->methods);
981 r_list_free (k->fields);
982 free (k);
983 }
984 }
985
r_bin_file_add_class(RBinFile * bf,const char * name,const char * super,int view)986 R_API RBinClass *r_bin_file_add_class(RBinFile *bf, const char *name, const char *super, int view) {
987 r_return_val_if_fail (name && bf && bf->o, NULL);
988 RBinClass *c = __getClass (bf, name);
989 if (c) {
990 if (super) {
991 free (c->super);
992 c->super = strdup (super);
993 }
994 return c;
995 }
996 c = r_bin_class_new (name, super, view);
997 if (c) {
998 // XXX. no need for a list, the ht is iterable too
999 c->index = r_list_length (bf->o->classes);
1000 r_list_append (bf->o->classes, c);
1001 ht_pp_insert (bf->o->classes_ht, name, c);
1002 }
1003 return c;
1004 }
1005
r_bin_file_add_method(RBinFile * bf,const char * klass,const char * method,int nargs)1006 R_API RBinSymbol *r_bin_file_add_method(RBinFile *bf, const char *klass, const char *method, int nargs) {
1007 r_return_val_if_fail (bf, NULL);
1008
1009 RBinClass *c = r_bin_file_add_class (bf, klass, NULL, 0);
1010 if (!c) {
1011 eprintf ("Cannot allocate class %s\n", klass);
1012 return NULL;
1013 }
1014 RBinSymbol *sym = __getMethod (bf, klass, method);
1015 if (!sym) {
1016 sym = R_NEW0 (RBinSymbol);
1017 if (sym) {
1018 sym->name = strdup (method);
1019 r_list_append (c->methods, sym);
1020 const char *name = sdb_fmt ("%s::%s", klass, method);
1021 ht_pp_insert (bf->o->methods_ht, name, sym);
1022 }
1023 }
1024 return sym;
1025 }
1026
r_bin_file_add_field(RBinFile * binfile,const char * classname,const char * name)1027 R_API RBinField *r_bin_file_add_field(RBinFile *binfile, const char *classname, const char *name) {
1028 //TODO: add_field into class
1029 //eprintf ("TODO add field: %s \n", name);
1030 return NULL;
1031 }
1032
1033 // XXX this api name makes no sense
1034 /* returns vaddr, rebased with the baseaddr of binfile, if va is enabled for
1035 * bin, paddr otherwise */
r_bin_file_get_vaddr(RBinFile * bf,ut64 paddr,ut64 vaddr)1036 R_API ut64 r_bin_file_get_vaddr(RBinFile *bf, ut64 paddr, ut64 vaddr) {
1037 r_return_val_if_fail (bf && bf->o, paddr);
1038 if (bf->o->info && bf->o->info->has_va) {
1039 return binobj_a2b (bf->o, vaddr);
1040 }
1041 return paddr;
1042 }
1043
r_bin_file_get_trycatch(RBinFile * bf)1044 R_API RList *r_bin_file_get_trycatch(RBinFile *bf) {
1045 r_return_val_if_fail (bf && bf->o && bf->o->plugin, NULL);
1046 if (bf->o->plugin->trycatch) {
1047 return bf->o->plugin->trycatch (bf);
1048 }
1049 return NULL;
1050 }
1051
r_bin_file_get_symbols(RBinFile * bf)1052 R_API RList *r_bin_file_get_symbols(RBinFile *bf) {
1053 r_return_val_if_fail (bf, NULL);
1054 RBinObject *o = bf->o;
1055 return o? o->symbols: NULL;
1056 }
1057