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