1 /* radare - LGPL - Copyright 2009-2018 - pancake, maijin, thestr4ng3r */
2 
3 #include "r_anal.h"
4 
5 #define NAME_BUF_SIZE    64
6 #define BASE_CLASSES_MAX 32
7 
8 
9 typedef struct rtti_complete_object_locator_t {
10 	ut32 signature;
11 	ut32 vtable_offset;         // offset of the vtable within class
12 	ut32 cd_offset;             // constructor displacement offset
13 	ut32 type_descriptor_addr;  // only a relative offset for 64bit
14 	ut32 class_descriptor_addr; // only a relative offset for 64bit
15 	ut32 object_base;           // only for 64bit, see rtti_msvc_read_complete_object_locator()
16 } rtti_complete_object_locator;
17 
18 
19 typedef struct rtti_class_hierarchy_descriptor_t {
20 	ut32 signature;
21 	ut32 attributes;            // bit 0 set = multiple inheritance, bit 1 set = virtual inheritance
22 	ut32 num_base_classes;
23 	ut32 base_class_array_addr; // only a relative offset for 64bit
24 } rtti_class_hierarchy_descriptor;
25 
26 typedef struct rtti_base_class_descriptor_t {
27 	ut32 type_descriptor_addr;  // only a relative offset for 64bit
28 	ut32 num_contained_bases;
29 	struct {
30 		st32 mdisp;             // member displacement
31 		st32 pdisp;             // vbtable displacement
32 		st32 vdisp;             // displacement inside vbtable
33 	} where;
34 	ut32 attributes;
35 } rtti_base_class_descriptor;
36 
37 typedef struct rtti_type_descriptor_t {
38 	ut64 vtable_addr;
39 	ut64 spare;
40 	char *name;
41 } rtti_type_descriptor;
42 
rtti_type_descriptor_fini(rtti_type_descriptor * td)43 static void rtti_type_descriptor_fini(rtti_type_descriptor *td) {
44 	free (td->name);
45 	td->name = NULL;
46 }
47 
rtti_msvc_addr(RVTableContext * context,ut64 col_addr,ut64 col_base,ut32 addr)48 static inline ut64 rtti_msvc_addr(RVTableContext *context, ut64 col_addr, ut64 col_base, ut32 addr) {
49 	if (context->word_size != 8) {
50 		return addr;
51 	}
52 	return addr + (col_addr - col_base);
53 }
54 
rtti_msvc_read_complete_object_locator(RVTableContext * context,ut64 addr,rtti_complete_object_locator * col)55 static bool rtti_msvc_read_complete_object_locator(RVTableContext *context, ut64 addr, rtti_complete_object_locator *col) {
56 	if (addr == UT64_MAX) {
57 		return false;
58 	}
59 
60 	ut8 buf[6 * sizeof (ut32)];
61 	int colSize = 5 * sizeof (ut32);
62 	if (context->word_size == 8) {
63 		colSize += sizeof(ut32);
64 	}
65 	if (colSize > sizeof (buf)) {
66 		return false;
67 	}
68 
69 	if (!context->anal->iob.read_at (context->anal->iob.io, addr, buf, colSize)) {
70 		return false;
71 	}
72 
73 	ut32 (*read_at_32)(const void *src, size_t offset) = context->anal->big_endian ? r_read_at_be32 : r_read_at_le32;
74 	col->signature = read_at_32 (buf, 0);
75 	col->vtable_offset = read_at_32 (buf, 4);
76 	col->cd_offset = read_at_32 (buf, 8);
77 
78 	int offsetSize = R_MIN (context->word_size, 4);
79 	col->type_descriptor_addr = (ut32) r_read_ble (buf + 12, (bool) context->anal->big_endian, offsetSize * 8);
80 	col->class_descriptor_addr = (ut32) r_read_ble (buf + 12 + offsetSize, (bool) context->anal->big_endian, offsetSize * 8);
81 	if (context->word_size == 8) {
82 		// 64bit is special:
83 		// Type Descriptor and Class Hierarchy Descriptor addresses are computed
84 		// by 32 bit values *(col+12) + *(col+0x14)
85 		// and *(col+16) + *(col+0x14) respectively
86 		col->object_base = read_at_32 (buf, 20);
87 	} else {
88 		col->object_base = 0;
89 	}
90 
91 	return true;
92 }
93 
rtti_msvc_read_class_hierarchy_descriptor(RVTableContext * context,ut64 addr,rtti_class_hierarchy_descriptor * chd)94 static bool rtti_msvc_read_class_hierarchy_descriptor(RVTableContext *context, ut64 addr, rtti_class_hierarchy_descriptor *chd) {
95 	if (addr == UT64_MAX) {
96 		return false;
97 	}
98 
99 	ut8 buf[4 * sizeof (ut32)];
100 	int chdSize = 3 * sizeof (ut32) + R_MIN (4, context->word_size);
101 	if (chdSize > sizeof (buf)) {
102 		return false;
103 	}
104 
105 	if (!context->anal->iob.read_at (context->anal->iob.io, addr, buf, chdSize)) {
106 		return false;
107 	}
108 
109 	ut32 (*read_at_32)(const void *src, size_t offset) = context->anal->big_endian ? r_read_at_be32 : r_read_at_le32;
110 	chd->signature = read_at_32 (buf, 0);
111 	chd->attributes = read_at_32 (buf, 4);
112 	chd->num_base_classes = read_at_32 (buf, 8);
113 	if (context->word_size <= 4) {
114 		chd->base_class_array_addr = (ut32) r_read_ble (buf + 12, (bool) context->anal->big_endian, context->word_size * 8);
115 	} else {
116 		// 64bit is special, like in Complete Object Locator.
117 		// Only the offset from the base from Complete Object Locator
118 		// is contained in Class Hierarchy Descriptor
119 		chd->base_class_array_addr = read_at_32 (buf, 12);
120 	}
121 	return true;
122 }
123 
rtti_msvc_base_class_descriptor_size(RVTableContext * context)124 static ut64 rtti_msvc_base_class_descriptor_size(RVTableContext *context) {
125 	return context->word_size + 5 * sizeof (ut32);
126 }
127 
rtti_msvc_read_base_class_descriptor(RVTableContext * context,ut64 addr,rtti_base_class_descriptor * bcd)128 static bool rtti_msvc_read_base_class_descriptor(RVTableContext *context, ut64 addr, rtti_base_class_descriptor *bcd) {
129 	if (addr == UT64_MAX) {
130 		return false;
131 	}
132 
133 	ut8 buf[sizeof (ut64) + 5 * sizeof (ut32)];
134 	int bcdSize = (int) rtti_msvc_base_class_descriptor_size (context);
135 	if (bcdSize > sizeof (buf)) {
136 		return false;
137 	}
138 
139 	if (!context->anal->iob.read_at (context->anal->iob.io, addr, buf, bcdSize)) {
140 		return false;
141 	}
142 
143 	ut32 (*read_at_32)(const void *src, size_t offset) = context->anal->big_endian ? r_read_at_be32 : r_read_at_le32;
144 	int typeDescriptorAddrSize = R_MIN (context->word_size, 4);
145 	bcd->type_descriptor_addr = (ut32) r_read_ble (buf, (bool) context->anal->big_endian, typeDescriptorAddrSize * 8);
146 	size_t offset = (size_t) typeDescriptorAddrSize;
147 	bcd->num_contained_bases = read_at_32 (buf, offset);
148 	bcd->where.mdisp = read_at_32 (buf, offset + sizeof (ut32));
149 	bcd->where.pdisp = read_at_32 (buf, offset + 2 * sizeof (ut32));
150 	bcd->where.vdisp = read_at_32 (buf, offset + 3 * sizeof (ut32));
151 	bcd->attributes = read_at_32 (buf, offset + 4 * sizeof (ut32));
152 	return true;
153 }
154 
rtti_msvc_read_base_class_array(RVTableContext * context,ut32 num_base_classes,ut64 base,ut32 offset)155 static RList *rtti_msvc_read_base_class_array(RVTableContext *context, ut32 num_base_classes, ut64 base, ut32 offset) {
156 	if (base == UT64_MAX || offset == UT32_MAX || num_base_classes == UT32_MAX) {
157 		return NULL;
158 	}
159 
160 	RList *ret = r_list_newf (free);
161 	if (!ret) {
162 		return NULL;
163 	}
164 
165 	ut64 addr = base + offset;
166 	ut64 stride = R_MIN (context->word_size, 4);
167 
168 	if (num_base_classes > BASE_CLASSES_MAX) {
169 		if (context->anal->verbose) {
170 			eprintf ("WARNING: Length of base class array at 0x%08"PFMT64x" exceeds %d.\n", addr, BASE_CLASSES_MAX);
171 		}
172 		num_base_classes = BASE_CLASSES_MAX;
173 	}
174 
175 	r_cons_break_push (NULL, NULL);
176 	while (num_base_classes > 0) {
177 		if (r_cons_is_breaked ()) {
178 			break;
179 		}
180 
181 		ut64 bcdAddr;
182 		if (context->word_size <= 4) {
183 			if (!context->read_addr (context->anal, addr, &bcdAddr)) {
184 				break;
185 			}
186 			if (bcdAddr == UT32_MAX) {
187 				break;
188 			}
189 		} else {
190 			// special offset calculation for 64bit
191 			ut8 tmp[4] = {0};
192 			if (!context->anal->iob.read_at(context->anal->iob.io, addr, tmp, 4)) {
193 				r_list_free (ret);
194 				return NULL;
195 			}
196 			ut32 (*read_32)(const void *src) = context->anal->big_endian ? r_read_be32 : r_read_le32;
197 			ut32 bcdOffset = read_32 (tmp);
198 			if (bcdOffset == UT32_MAX) {
199 				break;
200 			}
201 			bcdAddr = base + bcdOffset;
202 		}
203 
204 		rtti_base_class_descriptor *bcd = malloc (sizeof (rtti_base_class_descriptor));
205 		if (!bcd) {
206 			break;
207 		}
208 		if (!rtti_msvc_read_base_class_descriptor (context, bcdAddr, bcd)) {
209 			free (bcd);
210 			break;
211 		}
212 		r_list_append (ret, bcd);
213 		addr += stride;
214 		num_base_classes--;
215 	}
216 	r_cons_break_pop ();
217 
218 	if (num_base_classes > 0) {
219 		// there was an error in the loop above
220 		r_list_free (ret);
221 		return NULL;
222 	}
223 
224 	return ret;
225 }
226 
rtti_msvc_read_type_descriptor(RVTableContext * context,ut64 addr,rtti_type_descriptor * td)227 static bool rtti_msvc_read_type_descriptor(RVTableContext *context, ut64 addr, rtti_type_descriptor *td) {
228 	if (addr == UT64_MAX) {
229 		return false;
230 	}
231 
232 	if (!context->read_addr (context->anal, addr, &td->vtable_addr)) {
233 		return false;
234 	}
235 	if (!context->read_addr (context->anal, addr + context->word_size, &td->spare)) {
236 		return false;
237 	}
238 
239 	ut64 nameAddr = addr + 2 * context->word_size;
240 	ut8 buf[NAME_BUF_SIZE];
241 	ut64 bufOffset = 0;
242 	size_t nameLen = 0;
243 	bool endFound = false;
244 	bool endInvalid = false;
245 	while (1) {
246 		context->anal->iob.read_at (context->anal->iob.io, nameAddr + bufOffset, buf, sizeof (buf));
247 		int i;
248 		for (i=0; i<sizeof (buf); i++) {
249 			if (buf[i] == '\0') {
250 				endFound = true;
251 				break;
252 			}
253 			if (buf[i] == 0xff) {
254 				endInvalid = true;
255 				break;
256 			}
257 			nameLen++;
258 		}
259 		if (endFound || endInvalid) {
260 			break;
261 		}
262 		bufOffset += sizeof (buf);
263 	}
264 
265 	if (endInvalid) {
266 		return false;
267 	}
268 
269 	td->name = malloc (nameLen + 1);
270 	if (!td->name) {
271 		return false;
272 	}
273 
274 	if (bufOffset == 0) {
275 		memcpy (td->name, buf, nameLen + 1);
276 	} else {
277 		context->anal->iob.read_at (context->anal->iob.io, nameAddr,
278 									(ut8 *)td->name, (int) (nameLen + 1));
279 	}
280 
281 	return true;
282 }
283 
rtti_msvc_print_complete_object_locator(rtti_complete_object_locator * col,ut64 addr,const char * prefix)284 static void rtti_msvc_print_complete_object_locator(rtti_complete_object_locator *col, ut64 addr, const char *prefix) {
285 	r_cons_printf ("%sComplete Object Locator at 0x%08"PFMT64x":\n"
286 				   "%s\tsignature: %#x\n"
287 				   "%s\tvftableOffset: %#x\n"
288 				   "%s\tcdOffset: %#x\n"
289 				   "%s\ttypeDescriptorAddr: 0x%08"PFMT32x"\n"
290 				   "%s\tclassDescriptorAddr: 0x%08"PFMT32x"\n",
291 				   prefix, addr,
292 				   prefix, col->signature,
293 				   prefix, col->vtable_offset,
294 				   prefix, col->cd_offset,
295 				   prefix, col->type_descriptor_addr,
296 				   prefix, col->class_descriptor_addr);
297 	r_cons_printf ("%s\tobjectBase: 0x%08"PFMT32x"\n\n",
298 				   prefix, col->object_base);
299 }
300 
rtti_msvc_print_complete_object_locator_json(PJ * pj,rtti_complete_object_locator * col)301 static void rtti_msvc_print_complete_object_locator_json(PJ *pj, rtti_complete_object_locator *col) {
302 	pj_o (pj);
303 	pj_kn (pj, "signature", col->signature);
304 	pj_kn (pj, "vftable_offset", col->vtable_offset);
305 	pj_kn (pj, "cd_offset", col->cd_offset);
306 	pj_kn (pj, "type_desc_addr", col->type_descriptor_addr);
307 	pj_kn (pj, "class_desc_addr", col->class_descriptor_addr);
308 	pj_kn (pj, "object_base", col->object_base);
309 	pj_end (pj);
310 }
311 
rtti_msvc_print_type_descriptor(rtti_type_descriptor * td,ut64 addr,const char * prefix)312 static void rtti_msvc_print_type_descriptor(rtti_type_descriptor *td, ut64 addr, const char *prefix) {
313 	r_cons_printf ("%sType Descriptor at 0x%08"PFMT64x":\n"
314 				   "%s\tvtableAddr: 0x%08"PFMT64x"\n"
315 				   "%s\tspare: 0x%08"PFMT64x"\n"
316 				   "%s\tname: %s\n\n",
317 				   prefix, addr,
318 				   prefix, td->vtable_addr,
319 				   prefix, td->spare,
320 				   prefix, td->name);
321 }
322 
rtti_msvc_print_type_descriptor_json(PJ * pj,rtti_type_descriptor * td)323 static void rtti_msvc_print_type_descriptor_json(PJ *pj, rtti_type_descriptor *td) {
324 	pj_o (pj);
325 	pj_kn (pj, "vtable_addr", td->vtable_addr);
326 	pj_kn (pj, "spare", td->spare);
327 	pj_ks (pj, "name", td->name);
328 	pj_end (pj);
329 }
330 
rtti_msvc_print_class_hierarchy_descriptor(rtti_class_hierarchy_descriptor * chd,ut64 addr,const char * prefix)331 static void rtti_msvc_print_class_hierarchy_descriptor(rtti_class_hierarchy_descriptor *chd, ut64 addr, const char *prefix) {
332 	r_cons_printf ("%sClass Hierarchy Descriptor at 0x%08"PFMT64x":\n"
333 				   "%s\tsignature: %#x\n"
334 				   "%s\tattributes: %#x\n"
335 				   "%s\tnumBaseClasses: %#x\n"
336 				   "%s\tbaseClassArrayAddr: 0x%08"PFMT32x"\n\n",
337 				   prefix, addr,
338 				   prefix, chd->signature,
339 				   prefix, chd->attributes,
340 				   prefix, chd->num_base_classes,
341 				   prefix, chd->base_class_array_addr);
342 }
343 
rtti_msvc_print_class_hierarchy_descriptor_json(PJ * pj,rtti_class_hierarchy_descriptor * chd)344 static void rtti_msvc_print_class_hierarchy_descriptor_json(PJ *pj, rtti_class_hierarchy_descriptor *chd) {
345 	pj_o (pj);
346 	pj_kn (pj, "signature", chd->signature);
347 	pj_kn (pj, "attributes", chd->attributes);
348 	pj_kn (pj, "num_base_classes", chd->num_base_classes);
349 	pj_kn (pj, "base_class_array_addr", chd->base_class_array_addr);
350 	pj_end (pj);
351 }
352 
rtti_msvc_print_base_class_descriptor(rtti_base_class_descriptor * bcd,const char * prefix)353 static void rtti_msvc_print_base_class_descriptor(rtti_base_class_descriptor *bcd, const char *prefix) {
354 	r_cons_printf ("%sBase Class Descriptor:\n"
355 				   "%s\ttypeDescriptorAddr: 0x%08"PFMT32x"\n"
356 				   "%s\tnumContainedBases: %#x\n"
357 				   "%s\twhere:\n"
358 				   "%s\t\tmdisp: %d\n"
359 				   "%s\t\tpdisp: %d\n"
360 				   "%s\t\tvdisp: %d\n"
361 				   "%s\tattributes: %#x\n\n",
362 				   prefix,
363 				   prefix, bcd->type_descriptor_addr,
364 				   prefix, bcd->num_contained_bases,
365 				   prefix,
366 				   prefix, bcd->where.mdisp,
367 				   prefix, bcd->where.pdisp,
368 				   prefix, bcd->where.vdisp,
369 				   prefix, bcd->attributes);
370 }
371 
rtti_msvc_print_base_class_descriptor_json(PJ * pj,rtti_base_class_descriptor * bcd)372 static void rtti_msvc_print_base_class_descriptor_json(PJ *pj, rtti_base_class_descriptor *bcd) {
373 	pj_o (pj);
374 	pj_kn (pj, "type_desc_addr", bcd->type_descriptor_addr);
375 	pj_kn (pj, "num_contained_bases", bcd->num_contained_bases);
376 	pj_ko (pj, "where");
377 	pj_ki (pj, "mdisp", bcd->where.mdisp);
378 	pj_ki (pj, "pdisp", bcd->where.pdisp);
379 	pj_ki (pj, "vdisp", bcd->where.vdisp);
380 	pj_end (pj);
381 	pj_kn (pj, "attributes", bcd->attributes);
382 	pj_end (pj);
383 }
384 
385 
386 /**
387  * Demangle a class name as found in MSVC RTTI type descriptors.
388  *
389  * Examples:
390  * .?AVClassA@@
391  * => ClassA
392  * .?AVClassInInnerNamespace@InnerNamespace@OuterNamespace@@
393  * => OuterNamespace::InnerNamespace::AVClassInInnerNamespace
394  */
r_anal_rtti_msvc_demangle_class_name(RVTableContext * context,const char * name)395 R_API char *r_anal_rtti_msvc_demangle_class_name(RVTableContext *context, const char *name) {
396 	if (!name) {
397 		return NULL;
398 	}
399 	size_t original_len = strlen (name);
400 	if (original_len < 7
401 		|| (strncmp (name, ".?AV", 4) != 0 && strncmp (name, ".?AU", 4) != 0)
402 		|| strncmp (name + original_len - 2, "@@", 2) != 0) {
403 		return NULL;
404 	}
405 	char *ret = context->anal->binb.demangle (NULL, "msvc", name, 0, false);
406 	if (ret && *ret) {
407 		char *n = strchr (ret, ' ');
408 		if (n && *(++n)) {
409 			char *tmp = strdup (n);
410 			free (ret);
411 			ret = tmp;
412 		} else {
413 			R_FREE (ret);
414 		}
415 	} else {
416 		R_FREE (ret);
417 	}
418 	return ret;
419 }
420 
r_anal_rtti_msvc_print_complete_object_locator(RVTableContext * context,ut64 addr,int mode)421 R_API void r_anal_rtti_msvc_print_complete_object_locator(RVTableContext *context, ut64 addr, int mode) {
422 	rtti_complete_object_locator col;
423 	if (!rtti_msvc_read_complete_object_locator (context, addr, &col)) {
424 		eprintf ("Failed to parse Complete Object Locator at 0x%08"PFMT64x"\n", addr);
425 		return;
426 	}
427 
428 	if (mode == 'j') {
429 		PJ *pj = pj_new ();
430 		if (!pj) {
431 			return;
432 		}
433 		rtti_msvc_print_complete_object_locator_json (pj, &col);
434 		r_cons_print (pj_string (pj));
435 		pj_free (pj);
436 	} else {
437 		rtti_msvc_print_complete_object_locator (&col, addr, "");
438 	}
439 }
440 
r_anal_rtti_msvc_print_type_descriptor(RVTableContext * context,ut64 addr,int mode)441 R_API void r_anal_rtti_msvc_print_type_descriptor(RVTableContext *context, ut64 addr, int mode) {
442 	rtti_type_descriptor td = { 0 };
443 	if (!rtti_msvc_read_type_descriptor (context, addr, &td)) {
444 		eprintf ("Failed to parse Type Descriptor at 0x%08"PFMT64x"\n", addr);
445 		return;
446 	}
447 
448 	if (mode == 'j') {
449 		PJ *pj = pj_new ();
450 		if (!pj) {
451 			return;
452 		}
453 		rtti_msvc_print_type_descriptor_json (pj, &td);
454 		r_cons_print (pj_string (pj));
455 		pj_free (pj);
456 	} else {
457 		rtti_msvc_print_type_descriptor (&td, addr, "");
458 	}
459 
460 	rtti_type_descriptor_fini (&td);
461 }
462 
r_anal_rtti_msvc_print_class_hierarchy_descriptor(RVTableContext * context,ut64 addr,int mode)463 R_API void r_anal_rtti_msvc_print_class_hierarchy_descriptor(RVTableContext *context, ut64 addr, int mode) {
464 	rtti_class_hierarchy_descriptor chd;
465 	if (!rtti_msvc_read_class_hierarchy_descriptor (context, addr, &chd)) {
466 		eprintf ("Failed to parse Class Hierarchy Descriptor at 0x%08"PFMT64x"\n", addr);
467 		return;
468 	}
469 
470 	if (mode == 'j') {
471 		PJ *pj = pj_new ();
472 		if (!pj) {
473 			return;
474 		}
475 		rtti_msvc_print_class_hierarchy_descriptor_json (pj, &chd);
476 		r_cons_print (pj_string (pj));
477 		pj_free (pj);
478 	} else {
479 		rtti_msvc_print_class_hierarchy_descriptor (&chd, addr, "");
480 	}
481 }
482 
r_anal_rtti_msvc_print_base_class_descriptor(RVTableContext * context,ut64 addr,int mode)483 R_API void r_anal_rtti_msvc_print_base_class_descriptor(RVTableContext *context, ut64 addr, int mode) {
484 	rtti_base_class_descriptor bcd;
485 	if (!rtti_msvc_read_base_class_descriptor (context, addr, &bcd)) {
486 		eprintf ("Failed to parse Base Class Descriptor at 0x%08"PFMT64x"\n", addr);
487 		return;
488 	}
489 
490 	if (mode == 'j') {
491 		PJ *pj = pj_new ();
492 		if (!pj) {
493 			return;
494 		}
495 		rtti_msvc_print_base_class_descriptor_json (pj, &bcd);
496 		r_cons_print (pj_string (pj));
497 		pj_free (pj);
498 	} else {
499 		rtti_msvc_print_base_class_descriptor (&bcd, "");
500 	}
501 }
502 
rtti_msvc_print_complete_object_locator_recurse(RVTableContext * context,ut64 atAddress,int mode,bool strict)503 static bool rtti_msvc_print_complete_object_locator_recurse(RVTableContext *context, ut64 atAddress, int mode, bool strict) {
504 	bool use_json = mode == 'j';
505 	PJ *pj = NULL;
506 
507 	ut64 colRefAddr = atAddress - context->word_size;
508 	ut64 colAddr;
509 	if (!context->read_addr (context->anal, colRefAddr, &colAddr)) {
510 		return false;
511 	}
512 
513 	// complete object locator
514 	rtti_complete_object_locator col;
515 	if (!rtti_msvc_read_complete_object_locator (context, colAddr, &col)) {
516 		if (!strict) {
517 			eprintf ("Failed to parse Complete Object Locator at 0x%08"PFMT64x" (referenced from 0x%08"PFMT64x")\n", colAddr, colRefAddr);
518 		}
519 		return false;
520 	}
521 
522 	// type descriptor
523 	ut64 typeDescriptorAddr = rtti_msvc_addr (context, colAddr, col.object_base, col.type_descriptor_addr);
524 	rtti_type_descriptor td = { 0 };
525 	if (!rtti_msvc_read_type_descriptor (context, typeDescriptorAddr, &td)) {
526 		if (!strict) {
527 			eprintf ("Failed to parse Type Descriptor at 0x%08"PFMT64x"\n", typeDescriptorAddr);
528 		}
529 		return false;
530 	}
531 
532 	// class hierarchy descriptor
533 	ut64 classHierarchyDescriptorAddr = rtti_msvc_addr (context, colAddr, col.object_base, col.class_descriptor_addr);
534 	rtti_class_hierarchy_descriptor chd;
535 	if (!rtti_msvc_read_class_hierarchy_descriptor (context, classHierarchyDescriptorAddr, &chd)) {
536 		if (!strict) {
537 			eprintf ("Failed to parse Class Hierarchy Descriptor at 0x%08"PFMT64x"\n", classHierarchyDescriptorAddr);
538 		}
539 		rtti_type_descriptor_fini (&td);
540 		return false;
541 	}
542 
543 	ut64 base = chd.base_class_array_addr;
544 	ut32 baseClassArrayOffset = 0;
545 	if (context->word_size == 8) {
546 		base = colAddr - col.object_base;
547 		baseClassArrayOffset = chd.base_class_array_addr;
548 	}
549 
550 	RList *baseClassArray = rtti_msvc_read_base_class_array (context, chd.num_base_classes, base, baseClassArrayOffset);
551 	if (!baseClassArray) {
552 		if (!strict) {
553 			eprintf ("Failed to parse Base Class Array starting at 0x%08"PFMT64x"\n", base + baseClassArrayOffset);
554 		}
555 		rtti_type_descriptor_fini (&td);
556 		return false;
557 	}
558 
559 
560 	// print
561 	if (use_json) {
562 		pj = pj_new ();
563 		if (!pj) {
564 			return false;
565 		}
566 		pj_o (pj);
567 		pj_k (pj, "complete_object_locator");
568 		rtti_msvc_print_complete_object_locator_json (pj, &col);
569 		pj_k (pj, "type_desc");
570 		rtti_msvc_print_type_descriptor_json (pj, &td);
571 		pj_k (pj, "class_hierarchy_desc");
572 		rtti_msvc_print_class_hierarchy_descriptor_json (pj, &chd);
573 		pj_ka (pj, "base_classes");
574 	} else {
575 		rtti_msvc_print_complete_object_locator (&col, colAddr, "");
576 		rtti_msvc_print_type_descriptor (&td, typeDescriptorAddr, "\t");
577 		rtti_msvc_print_class_hierarchy_descriptor (&chd, classHierarchyDescriptorAddr, "\t");
578 	}
579 
580 
581 	// base classes
582 	RListIter *bcdIter;
583 	rtti_base_class_descriptor *bcd;
584 	r_list_foreach (baseClassArray, bcdIter, bcd) {
585 		if (use_json) {
586 			pj_o (pj);
587 			pj_k (pj, "desc");
588 			rtti_msvc_print_base_class_descriptor_json (pj, bcd);
589 		} else {
590 			rtti_msvc_print_base_class_descriptor (bcd, "\t\t");
591 		}
592 
593 		ut64 baseTypeDescriptorAddr = rtti_msvc_addr (context, colAddr, col.object_base, bcd->type_descriptor_addr);
594 		rtti_type_descriptor btd = { 0 };
595 		if (rtti_msvc_read_type_descriptor (context, baseTypeDescriptorAddr, &btd)) {
596 			if (use_json) {
597 				pj_k (pj, "type_desc");
598 				rtti_msvc_print_type_descriptor_json (pj, &btd);
599 			} else {
600 				rtti_msvc_print_type_descriptor (&btd, baseTypeDescriptorAddr, "\t\t\t");
601 			}
602 			rtti_type_descriptor_fini (&btd);
603 		} else {
604 			if (!strict) {
605 				eprintf ("Failed to parse Type Descriptor at 0x%08"PFMT64x"\n", baseTypeDescriptorAddr);
606 			}
607 		}
608 
609 		if (use_json) {
610 			pj_end (pj);
611 		}
612 	}
613 	if (use_json) {
614 		pj_end (pj);
615 		pj_end (pj);
616 		r_cons_print (pj_string (pj));
617 		pj_free (pj);
618 	}
619 
620 	rtti_type_descriptor_fini (&td);
621 	return true;
622 }
623 
r_anal_rtti_msvc_print_at_vtable(RVTableContext * context,ut64 addr,int mode,bool strict)624 R_API bool r_anal_rtti_msvc_print_at_vtable(RVTableContext *context, ut64 addr, int mode, bool strict) {
625 	return rtti_msvc_print_complete_object_locator_recurse (context, addr, mode, strict);
626 }
627 
628 typedef struct recovery_type_descriptor_t RecoveryTypeDescriptor;
629 
630 typedef struct recovery_base_descriptor_t {
631 	rtti_base_class_descriptor *bcd;
632 	RecoveryTypeDescriptor *td;
633 } RecoveryBaseDescriptor;
634 
635 typedef struct recovery_complete_object_locator_t {
636 	ut64 addr;
637 	bool valid;
638 	RVTableInfo *vtable;
639 	rtti_complete_object_locator col;
640 	RecoveryTypeDescriptor *td;
641 	rtti_class_hierarchy_descriptor chd;
642 	RList *bcd; // <rtti_base_class_descriptor>
643 	RVector base_td; // <RecoveryBaseDescriptor>
644 } RecoveryCompleteObjectLocator;
645 
recovery_complete_object_locator_new()646 RecoveryCompleteObjectLocator *recovery_complete_object_locator_new() {
647 	RecoveryCompleteObjectLocator *col = R_NEW0 (RecoveryCompleteObjectLocator);
648 	if (!col) {
649 		return NULL;
650 	}
651 	r_vector_init (&col->base_td, sizeof(RecoveryBaseDescriptor), NULL, NULL);
652 	return col;
653 }
654 
recovery_complete_object_locator_free(RecoveryCompleteObjectLocator * col)655 void recovery_complete_object_locator_free(RecoveryCompleteObjectLocator *col) {
656 	if (!col) {
657 		return;
658 	}
659 	r_list_free (col->bcd);
660 	r_vector_clear (&col->base_td);
661 	free (col);
662 }
663 
664 
665 struct recovery_type_descriptor_t {
666 	ut64 addr;
667 	bool valid;
668 	rtti_type_descriptor td;
669 	RecoveryCompleteObjectLocator *col;
670 };
671 
recovery_type_descriptor_new()672 RecoveryTypeDescriptor *recovery_type_descriptor_new() {
673 	RecoveryTypeDescriptor *td = R_NEW (RecoveryTypeDescriptor);
674 	if (!td) {
675 		return NULL;
676 	}
677 
678 	td->addr = 0;
679 	td->valid = false;
680 	memset (&td->td, 0, sizeof (td->td));
681 	td->col = NULL;
682 	//td->vtable = NULL;
683 	return td;
684 }
685 
recovery_type_descriptor_free(RecoveryTypeDescriptor * td)686 void recovery_type_descriptor_free(RecoveryTypeDescriptor *td) {
687 	if (!td) {
688 		return;
689 	}
690 	rtti_type_descriptor_fini (&td->td);
691 	free (td);
692 }
693 
694 
695 typedef struct rtti_msvc_anal_context_t {
696 	RVTableContext *vt_context;
697 	RPVector vtables; // <RVTableInfo>
698 	RPVector complete_object_locators; // <RecoveryCompleteObjectLocator>
699 	HtUP *addr_col; // <ut64, RecoveryCompleteObjectLocator *>
700 	RPVector type_descriptors; // <RecoveryTypeDescriptor>
701 	HtUP *addr_td; // <ut64, RecoveryTypeDescriptor *>
702 	HtUP *col_td_classes; // <ut64, char *> contains already recovered classes for col (or td) addresses
703 } RRTTIMSVCAnalContext;
704 
705 
706 RecoveryTypeDescriptor *recovery_anal_type_descriptor(RRTTIMSVCAnalContext *context, ut64 addr, RecoveryCompleteObjectLocator *col);
707 
recovery_anal_complete_object_locator(RRTTIMSVCAnalContext * context,ut64 addr,RVTableInfo * vtable)708 RecoveryCompleteObjectLocator *recovery_anal_complete_object_locator(RRTTIMSVCAnalContext *context, ut64 addr, RVTableInfo *vtable) {
709 	RecoveryCompleteObjectLocator *col = ht_up_find (context->addr_col, addr, NULL);
710 	if (col) {
711 		return col;
712 	}
713 
714 	col = recovery_complete_object_locator_new ();
715 	if (!col) {
716 		return NULL;
717 	}
718 	r_pvector_push (&context->complete_object_locators, col);
719 	ht_up_insert (context->addr_col, addr, col);
720 	col->addr = addr;
721 	col->valid = rtti_msvc_read_complete_object_locator (context->vt_context, addr, &col->col);
722 	if (!col->valid) {
723 		return col;
724 	}
725 	col->vtable = vtable;
726 
727 
728 	ut64 td_addr = rtti_msvc_addr (context->vt_context, col->addr, col->col.object_base, col->col.type_descriptor_addr);
729 	col->td = recovery_anal_type_descriptor (context, td_addr, col);
730 	if (!col->td->valid) {
731 		col->valid = false;
732 		return col;
733 	}
734 	col->td->col = col;
735 
736 
737 	ut64 chd_addr = rtti_msvc_addr (context->vt_context, col->addr, col->col.object_base, col->col.class_descriptor_addr);
738 	col->valid &= rtti_msvc_read_class_hierarchy_descriptor (context->vt_context, chd_addr, &col->chd);
739 	if (!col->valid) {
740 		return col;
741 	}
742 
743 
744 	ut64 base = col->chd.base_class_array_addr;
745 	ut32 baseClassArrayOffset = 0;
746 	if (context->vt_context->word_size == 8) {
747 		base = col->addr - col->col.object_base;
748 		baseClassArrayOffset = col->chd.base_class_array_addr;
749 	}
750 
751 	col->bcd = rtti_msvc_read_base_class_array (context->vt_context, col->chd.num_base_classes, base, baseClassArrayOffset);
752 	if (!col->bcd) {
753 		col->valid = false;
754 		return col;
755 	}
756 
757 
758 	r_vector_reserve (&col->base_td, (size_t)col->bcd->length);
759 	RListIter *bcdIter;
760 	rtti_base_class_descriptor *bcd;
761 	r_list_foreach (col->bcd, bcdIter, bcd) {
762 		ut64 base_td_addr = rtti_msvc_addr (context->vt_context, col->addr, col->col.object_base, bcd->type_descriptor_addr);
763 		RecoveryTypeDescriptor *td = recovery_anal_type_descriptor (context, base_td_addr, NULL);
764 		if (td == col->td) {
765 			continue;
766 		}
767 		if (!td->valid) {
768 			if (context->vt_context->anal->verbose) {
769 				eprintf ("Warning: type descriptor of base is invalid.\n");
770 			}
771 			continue;
772 		}
773 		RecoveryBaseDescriptor *base_desc = r_vector_push (&col->base_td, NULL);
774 		base_desc->bcd = bcd;
775 		base_desc->td = td;
776 	}
777 
778 	return col;
779 }
780 
recovery_anal_type_descriptor(RRTTIMSVCAnalContext * context,ut64 addr,RecoveryCompleteObjectLocator * col)781 RecoveryTypeDescriptor *recovery_anal_type_descriptor(RRTTIMSVCAnalContext *context, ut64 addr, RecoveryCompleteObjectLocator *col) {
782 	RecoveryTypeDescriptor *td = ht_up_find (context->addr_td, addr, NULL);
783 	if (td) {
784 		if (col != NULL) {
785 			td->col = col;
786 		}
787 		return td;
788 	}
789 
790 	td = recovery_type_descriptor_new ();
791 	if (!td) {
792 		return NULL;
793 	}
794 	r_pvector_push (&context->type_descriptors, td);
795 	ht_up_insert (context->addr_td, addr, td);
796 	td->addr = addr;
797 	td->valid = rtti_msvc_read_type_descriptor (context->vt_context, addr, &td->td);
798 	if (!td->valid) {
799 		return td;
800 	}
801 
802 	td->col = col;
803 
804 	return td;
805 }
806 
unique_class_name(RAnal * anal,const char * original_name)807 static char *unique_class_name(RAnal *anal, const char *original_name) {
808 	if (!r_anal_class_exists (anal, original_name)) {
809 		return strdup (original_name);
810 	}
811 
812 	char *name = NULL;
813 	if (anal->verbose) {
814 		eprintf ("Warning: class name %s already taken!\n", original_name);
815 	}
816 	int i = 1;
817 
818 	do {
819 		free (name);
820 		name = r_str_newf ("%s.%d", original_name, i++);
821 		if (!name) {
822 			return NULL;
823 		}
824 	} while (r_anal_class_exists (anal, name));
825 
826 	return name;
827 }
828 
recovery_apply_vtable(RAnal * anal,const char * class_name,RVTableInfo * vtable_info)829 static void recovery_apply_vtable(RAnal *anal, const char *class_name, RVTableInfo *vtable_info) {
830 	if (!vtable_info) {
831 		return;
832 	}
833 
834 	RAnalVTable vtable = {0};
835 	vtable.addr = vtable_info->saddr;
836 	r_anal_class_vtable_set (anal, class_name, &vtable);
837 	r_anal_class_vtable_fini (&vtable);
838 
839 	RVTableMethodInfo *vmeth;
840 	r_vector_foreach (&vtable_info->methods, vmeth) {
841 		RAnalMethod meth;
842 		meth.addr = vmeth->addr;
843 		meth.vtable_offset = vmeth->vtable_offset;
844 		meth.name = r_str_newf ("virtual_%" PFMT64d, meth.vtable_offset);
845 		r_anal_class_method_set (anal, class_name, &meth);
846 		r_anal_class_method_fini (&meth);
847 	}
848 }
849 
850 static const char *recovery_apply_complete_object_locator(RRTTIMSVCAnalContext *context, RecoveryCompleteObjectLocator *col);
851 static const char *recovery_apply_type_descriptor(RRTTIMSVCAnalContext *context, RecoveryTypeDescriptor *td);
852 
recovery_apply_bases(RRTTIMSVCAnalContext * context,const char * class_name,RVector * base_descs)853 static void recovery_apply_bases(RRTTIMSVCAnalContext *context, const char *class_name, RVector *base_descs) {
854 	RecoveryBaseDescriptor *base_desc;
855 	r_vector_foreach (base_descs, base_desc) {
856 		RecoveryTypeDescriptor *base_td = base_desc->td;
857 		if (!base_td->valid) {
858 			eprintf ("Warning Base td is invalid!\n");
859 			continue;
860 		}
861 
862 		const char *base_class_name;
863 		if (!base_td->col) {
864 			if (context->vt_context->anal->verbose) {
865 				eprintf ("Warning: Base td %s has no col. Falling back to recovery from td only.\n", base_td->td.name);
866 			}
867 			base_class_name = recovery_apply_type_descriptor (context, base_td);
868 		} else {
869 			base_class_name = recovery_apply_complete_object_locator (context, base_td->col);
870 		}
871 
872 		if (!base_class_name) {
873 			if (context->vt_context->anal->verbose) {
874 				eprintf ("Failed to convert !base td->col or td to a class\n");
875 			}
876 			continue;
877 		}
878 
879 		RAnalBaseClass base;
880 		base.id = NULL;
881 		base.offset = (ut64)base_desc->bcd->where.mdisp;
882 		base.class_name = strdup (base_class_name);
883 		r_anal_class_base_set (context->vt_context->anal, class_name, &base);
884 		r_anal_class_base_fini (&base);
885 	}
886 }
887 
888 
recovery_apply_complete_object_locator(RRTTIMSVCAnalContext * context,RecoveryCompleteObjectLocator * col)889 static const char *recovery_apply_complete_object_locator(RRTTIMSVCAnalContext *context, RecoveryCompleteObjectLocator *col) {
890 	if (!col->valid) {
891 		return NULL;
892 	}
893 
894 	if (!col->td) {
895 		if (context->vt_context->anal->verbose) {
896 			eprintf ("Warning: no td for col at 0x%"PFMT64x"\n", col->addr);
897 		}
898 		return NULL;
899 	}
900 
901 	RAnal *anal = context->vt_context->anal;
902 
903 	const char *existing = ht_up_find (context->col_td_classes, col->addr, NULL);
904 	if (existing != NULL) {
905 		return existing;
906 	}
907 
908 	char *name = r_anal_rtti_msvc_demangle_class_name (context->vt_context, col->td->td.name);
909 	if (!name) {
910 		if (context->vt_context->anal->verbose) {
911 			eprintf ("Failed to demangle a class name: \"%s\"\n", col->td->td.name);
912 		}
913 		name = strdup (col->td->td.name);
914 		if (!name) {
915 			return NULL;
916 		}
917 	}
918 
919 	char *tmp = name;
920 	name = unique_class_name (anal, name);
921 	free (tmp);
922 	if (!name) {
923 		return NULL;
924 	}
925 
926 	r_anal_class_create (anal, name);
927 	ht_up_insert (context->col_td_classes, col->addr, name);
928 
929 	recovery_apply_vtable (anal, name, col->vtable);
930 	recovery_apply_bases (context, name, &col->base_td);
931 
932 	return name;
933 }
934 
935 
936 
recovery_apply_type_descriptor(RRTTIMSVCAnalContext * context,RecoveryTypeDescriptor * td)937 static const char *recovery_apply_type_descriptor(RRTTIMSVCAnalContext *context, RecoveryTypeDescriptor *td) {
938 	if (!td->valid) {
939 		return NULL;
940 	}
941 
942 	RAnal *anal = context->vt_context->anal;
943 
944 	const char *existing = ht_up_find (context->col_td_classes, td->addr, NULL);
945 	if (existing != NULL) {
946 		return existing;
947 	}
948 
949 	char *name = r_anal_rtti_msvc_demangle_class_name (context->vt_context, td->td.name);
950 	if (!name) {
951 		if (context->vt_context->anal->verbose) {
952 			eprintf("Failed to demangle a class name: \"%s\"\n", td->td.name);
953 		}
954 		name = strdup (td->td.name);
955 		if (!name) {
956 			return NULL;
957 		}
958 	}
959 
960 	r_anal_class_create (anal, name);
961 	ht_up_insert (context->col_td_classes, td->addr, name);
962 
963 	if (!td->col || !td->col->valid) {
964 		return name;
965 	}
966 
967 	recovery_apply_vtable (anal, name, td->col->vtable);
968 	recovery_apply_bases (context, name, &td->col->base_td);
969 
970 	return name;
971 }
972 
str_value_free(HtUPKv * kv)973 void str_value_free(HtUPKv *kv) {
974 	free (kv->value);
975 }
976 
r_anal_rtti_msvc_recover_all(RVTableContext * vt_context,RList * vtables)977 R_API void r_anal_rtti_msvc_recover_all(RVTableContext *vt_context, RList *vtables) {
978 	RRTTIMSVCAnalContext context;
979 	context.vt_context = vt_context;
980 	r_pvector_init (&context.vtables, (RPVectorFree)r_anal_vtable_info_free);
981 
982 	r_pvector_init (&context.complete_object_locators, (RPVectorFree) recovery_complete_object_locator_free);
983 	context.addr_col = ht_up_new0 ();
984 	r_pvector_init (&context.type_descriptors, (RPVectorFree) recovery_type_descriptor_free);
985 	context.addr_td = ht_up_new0 ();
986 
987 	context.col_td_classes = ht_up_new (NULL, (HtUPKvFreeFunc)str_value_free, (HtUPCalcSizeV)strlen);
988 
989 	RListIter *vtableIter;
990 	RVTableInfo *table;
991 	r_list_foreach (vtables, vtableIter, table) {
992 		ut64 colRefAddr = table->saddr - vt_context->word_size;
993 		ut64 colAddr;
994 		if (!vt_context->read_addr (vt_context->anal, colRefAddr, &colAddr)) {
995 			continue;
996 		}
997 		recovery_anal_complete_object_locator (&context, colAddr, table);
998 	}
999 
1000 	void **it;
1001 #if USE_TD_RECOVERY
1002 	r_pvector_foreach (&context.type_descriptors, it) {
1003 		RecoveryTypeDescriptor *td = *it;
1004 		if (!td->valid) {
1005 			continue;
1006 		}
1007 		recovery_apply_type_descriptor (&context, td);
1008 	}
1009 #else
1010 	r_pvector_foreach (&context.complete_object_locators, it) {
1011 		RecoveryCompleteObjectLocator *col = *it;
1012 		if (!col->valid) {
1013 			continue;
1014 		}
1015 		recovery_apply_complete_object_locator (&context, col);
1016 	}
1017 #endif
1018 
1019 	r_pvector_clear (&context.vtables);
1020 	r_pvector_clear (&context.complete_object_locators);
1021 	ht_up_free (context.addr_col);
1022 	r_pvector_clear (&context.type_descriptors);
1023 	ht_up_free (context.addr_td);
1024 	ht_up_free (context.col_td_classes);
1025 }
1026 
1027