radare2/libr/core/anal_vt.c

216 lines
6.2 KiB
C

#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) {
ut64 curAddressValue = r_io_read_i (core->io, startAddress, 8);
RAnalFunction *curFuntion = r_anal_get_fcn_in (core->anal, curAddressValue, 0);
r_list_append (vtableMethods, curFuntion);
startAddress += wordSize;
curMethod++;
}
table->funtions = vtableMethods;
return vtableMethods;
}
r_list_free (vtableMethods);
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
ut64 curAddressValue = r_io_read_i (core->io, curAddress, 8);
//if the value is in text section
return inTextSection (core, curAddressValue);
}
static int isVtableStart(RCore *core, ut64 curAddress) {
RAsmOp asmop = {0};
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;
RListIter * iter;
RIOSection *section;
RList *vtables = r_list_newf ((RListFree)free);
if (!vtables) {
return NULL;
}
ut64 bits = r_config_get_i (core->config, "asm.bits");
int wordSize = bits / 8;
r_list_foreach (core->io->sections, iter, section) {
if (!strcmp (section->name, ".rodata")) {
ut8 *segBuff = calloc (1, section->size);
r_io_read_at (core->io, section->paddr, segBuff, section->size);
startAddress = section->vaddr;
endAddress = startAddress + (section->size) - (bits/8);
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;
if (!vtables) {
return;
}
if (printJson) {
bool isFirstElement = true;
r_cons_print ("[");
r_list_foreach (vtables, vtableIter, table) {
if (!isFirstElement) {
r_cons_print (",");
}
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);
}
vtableStartAddress += wordSize;
}
r_cons_newline ();
}
}
}
r_list_free (vtables);
}
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);
}
}
r_list_free (vtables);
}
static rtti_struct* get_rtti_data (RCore *core, ut64 atAddress) {
ut64 bits = r_config_get_i (core->config, "asm.bits");
int wordSize = bits / 8;
ut64 BaseLocatorAddr = r_io_read_i (core->io, atAddress - wordSize, wordSize);
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");
}