2016-09-02 18:00:16 +00:00
|
|
|
#define VTABLE_BUFF_SIZE 10
|
|
|
|
|
|
|
|
typedef struct vtable_info_t {
|
|
|
|
ut64 saddr; //starting address
|
|
|
|
int methods;
|
|
|
|
RList* funtions;
|
|
|
|
} vtable_info;
|
|
|
|
|
|
|
|
static RList* getVtableMethods(RCore *core, vtable_info *table) {
|
|
|
|
RList* vtableMethods = r_list_new ();
|
|
|
|
if (table && core && vtableMethods) {
|
|
|
|
int curMethod = 0;
|
|
|
|
int totalMethods = table->methods;
|
|
|
|
ut64 startAddress = table->saddr;
|
|
|
|
int bits = r_config_get_i (core->config, "asm.bits");
|
|
|
|
int wordSize = bits / 8;
|
|
|
|
while (curMethod < totalMethods) {
|
2017-08-22 07:42:16 +00:00
|
|
|
ut64 curAddressValue;
|
|
|
|
r_io_read_i (core->io, startAddress, &curAddressValue, 8, false); //XXX
|
2016-09-02 18:00:16 +00:00
|
|
|
RAnalFunction *curFuntion = r_anal_get_fcn_in (core->anal, curAddressValue, 0);
|
|
|
|
r_list_append (vtableMethods, curFuntion);
|
|
|
|
startAddress += wordSize;
|
|
|
|
curMethod++;
|
|
|
|
}
|
|
|
|
table->funtions = vtableMethods;
|
|
|
|
return vtableMethods;
|
|
|
|
}
|
2016-09-03 15:26:46 +00:00
|
|
|
r_list_free (vtableMethods);
|
2016-09-02 18:00:16 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int inTextSection(RCore *core, ut64 curAddress) {
|
|
|
|
//section of the curAddress
|
|
|
|
RBinSection* value = r_bin_get_section_at (core->bin->cur->o, curAddress, true);
|
|
|
|
//If the pointed value lies in .text section
|
|
|
|
return value && !strcmp (value->name, ".text");
|
|
|
|
}
|
|
|
|
|
|
|
|
static int valueInTextSection(RCore *core, ut64 curAddress) {
|
|
|
|
//value at the current address
|
2017-08-22 07:42:16 +00:00
|
|
|
ut64 curAddressValue;
|
|
|
|
r_io_read_i (core->io, curAddress, &curAddressValue, 8, false); //XXX
|
2016-09-02 18:00:16 +00:00
|
|
|
//if the value is in text section
|
|
|
|
return inTextSection (core, curAddressValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int isVtableStart(RCore *core, ut64 curAddress) {
|
2017-03-25 01:30:00 +00:00
|
|
|
RAsmOp asmop = R_EMPTY;
|
2016-09-02 18:00:16 +00:00
|
|
|
RAnalRef *xref;
|
|
|
|
RListIter *xrefIter;
|
|
|
|
ut8 buf[VTABLE_BUFF_SIZE];
|
|
|
|
if (!curAddress || curAddress == UT64_MAX) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (valueInTextSection (core, curAddress)) {
|
|
|
|
// total xref's to curAddress
|
|
|
|
RList *xrefs = r_anal_xrefs_get (core->anal, curAddress);
|
|
|
|
if (!r_list_empty (xrefs)) {
|
|
|
|
r_list_foreach (xrefs, xrefIter, xref) {
|
|
|
|
// section in which currenct xref lies
|
|
|
|
if (inTextSection (core, xref->addr)) {
|
|
|
|
r_io_read_at (core->io, xref->addr, buf, VTABLE_BUFF_SIZE);
|
|
|
|
if (r_asm_disassemble (core->assembler, &asmop, buf, VTABLE_BUFF_SIZE) > 0) {
|
|
|
|
if ((!strncmp (asmop.buf_asm, "mov", 3)) ||
|
|
|
|
(!strncmp (asmop.buf_asm, "lea", 3))) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
RList* search_virtual_tables(RCore *core){
|
|
|
|
if (!core) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
ut64 startAddress;
|
|
|
|
ut64 endAddress;
|
2017-08-27 00:50:36 +00:00
|
|
|
RListIter * iter;
|
|
|
|
RBinSection *section;
|
2016-12-18 16:14:30 +00:00
|
|
|
RList *vtables = r_list_newf ((RListFree)free);
|
2017-08-29 10:39:04 +00:00
|
|
|
if (!vtables) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
RList *sections = r_bin_get_sections (core->bin);
|
|
|
|
if (!sections) {
|
|
|
|
r_list_free (vtables);
|
2016-09-02 18:00:16 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2016-12-18 16:14:30 +00:00
|
|
|
ut64 bits = r_config_get_i (core->config, "asm.bits");
|
|
|
|
int wordSize = bits / 8;
|
2017-08-27 00:50:36 +00:00
|
|
|
r_list_foreach (sections, iter, section) {
|
2016-09-02 18:00:16 +00:00
|
|
|
if (!strcmp (section->name, ".rodata")) {
|
|
|
|
ut8 *segBuff = calloc (1, section->size);
|
2017-08-23 20:28:49 +00:00
|
|
|
r_io_read_at (core->io, section->vaddr, segBuff, section->vsize);
|
2016-09-02 18:00:16 +00:00
|
|
|
startAddress = section->vaddr;
|
2017-08-23 20:28:49 +00:00
|
|
|
endAddress = startAddress + (section->vsize) - (bits/8);
|
2016-09-02 18:00:16 +00:00
|
|
|
while (startAddress <= endAddress) {
|
|
|
|
if (isVtableStart (core, startAddress)) {
|
|
|
|
vtable_info *vtable = calloc (1, sizeof(vtable_info));
|
|
|
|
vtable->saddr = startAddress;
|
|
|
|
int noOfMethods = 0;
|
|
|
|
while (valueInTextSection (core, startAddress)) {
|
|
|
|
noOfMethods++;
|
|
|
|
startAddress += wordSize;
|
|
|
|
}
|
|
|
|
vtable->methods = noOfMethods;
|
|
|
|
r_list_append (vtables, vtable);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
startAddress += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (r_list_empty (vtables)) {
|
|
|
|
// stripped binary?
|
|
|
|
eprintf ("No virtual tables found\n");
|
|
|
|
r_list_free (vtables);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return vtables;
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API void r_core_anal_list_vtables(void *core, bool printJson) {
|
|
|
|
ut64 bits = r_config_get_i (((RCore *)core)->config, "asm.bits");
|
|
|
|
RList* vtables = search_virtual_tables ((RCore *)core);
|
|
|
|
const char *noMethodName = "No Name found";
|
|
|
|
RListIter* vtableMethodNameIter;
|
|
|
|
RAnalFunction *curMethod;
|
|
|
|
int wordSize = bits / 8;
|
|
|
|
RListIter* vtableIter;
|
|
|
|
vtable_info* table;
|
|
|
|
|
2016-12-18 16:14:30 +00:00
|
|
|
if (!vtables) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (printJson) {
|
|
|
|
bool isFirstElement = true;
|
|
|
|
r_cons_print ("[");
|
|
|
|
r_list_foreach (vtables, vtableIter, table) {
|
|
|
|
if (!isFirstElement) {
|
|
|
|
r_cons_print (",");
|
2016-09-02 18:00:16 +00:00
|
|
|
}
|
2016-12-18 16:14:30 +00:00
|
|
|
r_cons_printf ("{\"offset\":%"PFMT64d",\"methods\":%d}",
|
|
|
|
table->saddr, table->methods);
|
|
|
|
isFirstElement = false;
|
|
|
|
}
|
|
|
|
r_cons_println ("]");
|
|
|
|
} else {
|
|
|
|
r_list_foreach (vtables, vtableIter, table) {
|
|
|
|
ut64 vtableStartAddress = table->saddr;
|
|
|
|
RList *vtableMethods = getVtableMethods ((RCore *)core, table);
|
|
|
|
if (vtableMethods) {
|
|
|
|
r_cons_printf ("\nVtable Found at 0x%08"PFMT64x"\n",
|
|
|
|
vtableStartAddress);
|
|
|
|
r_list_foreach (vtableMethods, vtableMethodNameIter, curMethod) {
|
|
|
|
if (curMethod->name) {
|
|
|
|
r_cons_printf ("0x%08"PFMT64x" : %s\n",
|
|
|
|
vtableStartAddress, curMethod->name);
|
|
|
|
} else {
|
|
|
|
r_cons_printf ("0x%08"PFMT64x" : %s\n",
|
|
|
|
vtableStartAddress, noMethodName);
|
2016-09-02 18:00:16 +00:00
|
|
|
}
|
2016-12-18 16:14:30 +00:00
|
|
|
vtableStartAddress += wordSize;
|
2016-09-02 18:00:16 +00:00
|
|
|
}
|
2016-12-18 16:14:30 +00:00
|
|
|
r_cons_newline ();
|
2016-09-02 18:00:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-12-18 16:14:30 +00:00
|
|
|
r_list_free (vtables);
|
2016-09-02 18:00:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void r_core_anal_list_vtables_all(void *core) {
|
|
|
|
RList* vtables = search_virtual_tables ((RCore *)core);
|
|
|
|
RListIter* vtableIter;
|
|
|
|
RListIter* vtableMethodNameIter;
|
|
|
|
RAnalFunction* function;
|
|
|
|
vtable_info* table;
|
|
|
|
|
|
|
|
r_list_foreach (vtables, vtableIter, table) {
|
|
|
|
RList *vtableMethods = getVtableMethods ((RCore *)core, table);
|
|
|
|
r_list_foreach (vtableMethods, vtableMethodNameIter, function) {
|
|
|
|
// char *ret = r_str_newf ("vtable.%s", table->funtio);
|
|
|
|
r_cons_printf ("f %s=0x%08"PFMT64x"\n", function->name, function->addr);
|
|
|
|
}
|
|
|
|
}
|
2016-09-03 15:26:46 +00:00
|
|
|
r_list_free (vtables);
|
2016-09-02 18:00:16 +00:00
|
|
|
}
|
|
|
|
|
2017-03-09 22:50:50 +00:00
|
|
|
static rtti_struct* get_rtti_data (RCore *core, ut64 atAddress) {
|
|
|
|
ut64 bits = r_config_get_i (core->config, "asm.bits");
|
|
|
|
int wordSize = bits / 8;
|
2017-08-22 07:42:16 +00:00
|
|
|
ut64 BaseLocatorAddr;
|
|
|
|
r_io_read_i (core->io, atAddress - wordSize, &BaseLocatorAddr, wordSize, false); //XXX
|
2017-03-09 22:50:50 +00:00
|
|
|
eprintf ("Trying to parse rtti at 0x%08"PFMT64x"\n", BaseLocatorAddr);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
RList* r_core_anal_parse_rtti (void *core, bool printJson) {
|
|
|
|
RList* vtables = search_virtual_tables ((RCore *)core);
|
|
|
|
RListIter* vtableIter;
|
|
|
|
RList* rtti_structures = r_list_new ();
|
|
|
|
vtable_info* table;
|
|
|
|
|
|
|
|
if (vtables) {
|
|
|
|
r_list_foreach (vtables, vtableIter, table) {
|
|
|
|
rtti_struct* current_rtti = get_rtti_data ((RCore *)core, table->saddr);
|
|
|
|
if (current_rtti) {
|
|
|
|
current_rtti->vtable_start_addr = table->saddr;
|
|
|
|
r_list_append (rtti_structures, current_rtti);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
r_list_free (vtables);
|
|
|
|
return rtti_structures;
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API void r_core_anal_print_rtti (void *core) {
|
|
|
|
eprintf ("Work in progress\n");
|
|
|
|
}
|