[docs]classVtableFinder(Analysis):""" This analysis locates Vtables in a binary based on heuristics taken from - "Reconstruction of Class Hierarchies for Decompilation of C++ Programs" """
[docs]def__init__(self):if"CFGFast"notinself.project.kb.cfgs:# populate knowledge baseself.project.analyses[CFGFast].prep()(cross_references=True)skip_analysis=True# check if the sections existforsecinself.project.loader.main_object.sections:ifsec.namein[".data.rel.ro",".rodata",".data.rel.ro.local"]:skip_analysis=Falseifnotskip_analysis:self.vtables_list=self.analyze()else:l.warning("VtableFinder analysis is skipped")
[docs]defanalyze(self):# finding candidate starting vtable addresses# "current location is referenced from a code segment and its value is a pointer to a function,# then it is marked as a start of vtable"# taken from - Reconstruction of Class Hierarchies for Decompilation of C++ Programslist_vtables=[]forsecinself.project.loader.main_object.sections:ifsec.namein[".data.rel.ro",".rodata",".data.rel.ro.local"]:foroffsetinrange(0,sec.memsize,self.project.arch.bytes):cur_addr=sec.vaddr+offsetpossible_func_addr=self.project.loader.memory.unpack_word(cur_addr)# check if this address is referenced in the code segmentifself.is_cross_referenced(cur_addr):# check if it is also a function, if so then it is possibly a vtable startifself.is_function(possible_func_addr):new_vtable=self.create_extract_vtable(cur_addr,sec.memsize)ifnew_vtableisnotNone:list_vtables.append(new_vtable)returnlist_vtables
[docs]defcreate_extract_vtable(self,start_addr,sec_size):# using the starting address extracting the vtable# "Other elements of vtable must be unreferenced pointers to function"# "Vtable ends with the first location that is either referenced from the program code,# or is not a pointer to a function"# taken from - Reconstruction of Class Hierarchies for Decompilation of C++ Programsfirst_func_addr=self.project.loader.memory.unpack_word(start_addr)cur_vtable=Vtable(start_addr,self.project.arch.bytes,[first_func_addr])forcur_addrinrange(start_addr+self.project.arch.bytes,start_addr+sec_size,self.project.arch.bytes,):possible_func_addr=self.project.loader.memory.unpack_word(cur_addr)ifself.is_function(possible_func_addr)andnotself.is_cross_referenced(cur_addr):cur_vtable.func_addrs.append(possible_func_addr)cur_vtable.size+=self.project.arch.byteselifnotself.is_function(possible_func_addr)orself.is_cross_referenced(cur_addr):returncur_vtablereturnNone