diff --git a/ClassDataStructureDetection/Constructors/DetectConstructor.py b/ClassDataStructureDetection/Constructors/DetectConstructor.py index cca56a7..1f66c51 100644 --- a/ClassDataStructureDetection/Constructors/DetectConstructor.py +++ b/ClassDataStructureDetection/Constructors/DetectConstructor.py @@ -1,33 +1,92 @@ import binaryninja as bn -from typing import List +from typing import * from ... import Config -from ...RttiInfomation.VirtualTableInference import VirtualFunctionTable -import pysnooper - - -def GetVirtualTableAssignmentInstruction(func: bn.function.Function): - current_candidate_instr = None - for instr in func.hlil.instructions: - # - if instr.operation == 17: - # Check if Arg1 is being assigned to. - func_params = func.hlil.source_function.parameter_vars.vars - if func_params and instr.vars: - if func_params[0] == instr.vars[0]: - # , - if instr.operands[1].operation == 27 or instr.operands[1].operation == 26: - # - # - # De-referencing the pointer, meaning if this - # pointer is to a struct, this is de-referencing offset 0x0. - if instr.operands[0].operation == 23 or instr.operands[0].operation == 24: - if type(instr.operands[0].operands[0]) == bn.highlevelil.HighLevelILVar: - current_candidate_instr = instr +from ...RttiInformation.VirtualTableInference import VirtualFunctionTable +from ...Common import Utils + +global_constructor_destructor_list: List = list() + + +def GetAllAssignmentInstructions(func: bn.function.Function) -> Dict: + """ + Search the given function for all data references assigned to an offset into the pointer given + in Arg1 of the function (the "This" pointer). + :return {offset_into_Arg1: [DataVar address]} + """ + candidate_instructions: Dict = dict() + + try: + for instr in func.hlil.instructions: + # + if instr.operation.name == "HLIL_ASSIGN": + # Check if Arg1 is being assigned to. + func_params = func.hlil.source_function.parameter_vars.vars + if func_params and instr.vars: + if func_params[0] == instr.vars[0]: + if instr.operands[1].operation.name == "HLIL_CONST_PTR" or \ + instr.operands[1].operation.name == "HLIL_CONST": + # A pointer or a constant is being assigned into an offset within Arg1 + # Example: + # + if instr.operands[0].operation.name == "HLIL_DEREF" or \ + instr.operands[0].operation.name == "HLIL_DEREF_FIELD": + if type(instr.operands[0].operands[0]) == bn.highlevelil.HighLevelILVar: + if instr.operands[0].operation.name == "HLIL_ARRAY_INDEX": + # Arg1 is treated as an array and the assignment is being done into + # an offset within the array. + # Example: + # , + offset_into_class = instr.operands[0].operands[1].operands[0] + else: + # Directly De-referencing the pointer, meaning if this pointer is to a + # struct, this is de-referencing offset 0x0. + offset_into_class = 0 + + if candidate_instructions.get(offset_into_class): + candidate_instructions[offset_into_class].append( + instr.operands[1].value.value + ) + else: + candidate_instructions.update({0: [instr.operands[1].value.value]}) + + elif type(instr.operands[0].operands[0]) == bn.highlevelil.HighLevelILAdd: + # Referencing an offset within the pointer. + # example: + # [, ] + if instr.operands[0].operands[0].operands[1].operation.name == "HLIL_CONST": + offset_into_class = instr.operands[0].operands[0].operands[1].value.value + if candidate_instructions.get(offset_into_class): + candidate_instructions[offset_into_class].append( + instr.operands[1].value.value + ) + else: + candidate_instructions.update( + { + offset_into_class: [ + instr.operands[1].value.value + ] + } + ) + else: + Utils.LogToFile(f"GetAllAssignmentInstructions: UNKNOWN assignment type at HLIL " + f"Address {hex(instr.address)} ! please report this. " + f"\nInstruction: {instr}") + except Exception as e: + print(f"GetAllAssignmentInstructions {hex(func.start)}, Exception: {e}") + # We are only interested in the last assignment of a vfTable in a function, since the ones before it are + # base classes. + return candidate_instructions + + +def GetThisClassVirtualTableAssignmentInstruction(func: bn.function.Function) -> Optional[int]: + candidate_instructions = GetAllAssignmentInstructions(func) # We are only interested in the last assignment of a vfTable in a function, since the ones before it are # base classes. - # [ - return current_candidate_instr + if candidate_instructions.get(0): + return candidate_instructions[0][-1] + else: + return None def GetPotentialConstructors(bv: bn.binaryview, vfTable_addr: int) -> \ @@ -45,14 +104,14 @@ def GetPotentialConstructors(bv: bn.binaryview, vfTable_addr: int) -> \ return potential_constructors -def DetectConstructorForVTable(bv: bn.binaryview, vfTable_addr: int, vfTable_contained_functions: List[int]) -> bool: - found_constructors = 0 - potential_constructors: List[bn.function.Function] = GetPotentialConstructors(bv, vfTable_addr) - for potential_constructor in potential_constructors: - if VerifyConstructor(bv, potential_constructor, found_constructors): - print(f'ClassyPP: Found constructor - {potential_constructor.name}') - found_constructors += 1 - return found_constructors != 0 +def DetectConstructorForVTable(bv: bn.binaryview, vfTable_addr: int) -> list[bn.function.Function]: + potential_constructors: List[bn.function.Function] = list() + for potential_constructor in GetPotentialConstructors(bv, vfTable_addr): + if VerifyConstructor(bv, potential_constructor): + potential_constructors.append(potential_constructor) + print(f'Found constructor - {potential_constructor.name}') + global_constructor_destructor_list.append(potential_constructor.start) + return potential_constructors def IsDestructor(bv: bn.binaryview, potential_destructor: bn.function.Function) -> bool: @@ -67,36 +126,50 @@ def IsDestructor(bv: bn.binaryview, potential_destructor: bn.function.Function) return False -def VerifyConstructor(bv: bn.binaryview, potential_constructor: bn.function.Function, found_constructors: int) -> bool: +def DefineConstructor(bv: bn.binaryview, potential_constructors: list[bn.function.Function], + vtable_addr: int, class_name=None) -> bool: + # Since several constructors with the same name (but different signature) may exist, we + # will attach a postfix index to each of the names. + constructor_index = 0 + if not class_name: + class_name: str = bv.get_data_var_at(vtable_addr).name + if class_name: + if class_name.endswith("_vfTable"): + # Remove the _vfTable tag from the name + class_name = class_name[:-8] + for constructor in potential_constructors: + func_type = "Constructor" + if IsDestructor(bv, constructor): + func_type = "Destructor" + if Config.CONSTRUCTOR_FUNCTION_HANDLING == 0: + AddComment(bv, constructor.start, vtable_addr, + class_name, func_type) + elif Config.CONSTRUCTOR_FUNCTION_HANDLING == 1: + ChangeFuncName(bv, constructor.start, constructor_index, + class_name, func_type) + else: + # invalid choice + return False + constructor_index += 1 + return True + else: + print(f"DefineConstructor: Cannot get class name for vtable at {hex(vtable_addr)}") + + +def VerifyConstructor(bv: bn.binaryview, potential_constructor: bn.function.Function) -> bool: # The heuristics used here will locate both the constructors and destructors. # It is not easy to automatically distinguish between the two. - func_type = "Constructor" + try: - if instr := GetVirtualTableAssignmentInstruction(potential_constructor): - pointer: int = instr.operands[1].operands[0] + if pointer := GetThisClassVirtualTableAssignmentInstruction(potential_constructor): data_refs = list(bv.get_data_refs_from(pointer)) if data_refs: if len(data_refs) != 1: # print(f'Error, too many data refs for {pointer}') - pass + return False else: # Check if this is a function pointer - if bv.get_function_at(data_refs[0]): - class_name: str = bv.get_data_var_at(pointer).name - if class_name.endswith("_vfTable"): - # Remove the _vfTable tag from the name - class_name = class_name[:-8] - if IsDestructor(bv, potential_constructor): - func_type = "Destructor" - if Config.CONSTRUCTOR_FUNCTION_HANDLING == 0: - AddComment(bv, potential_constructor.start, pointer, - class_name, func_type) - elif Config.CONSTRUCTOR_FUNCTION_HANDLING == 1: - ChangeFuncName(bv, potential_constructor.start, found_constructors, - class_name, func_type) - else: - # invalid choice - return False + if bv.get_function_at(data_refs[0]) is not None: return True else: # print(f'Error in instruction {instr}') diff --git a/ClassObjectRepresentation/CppClass.py b/ClassObjectRepresentation/CppClass.py index 9f7c383..3105d63 100644 --- a/ClassObjectRepresentation/CppClass.py +++ b/ClassObjectRepresentation/CppClass.py @@ -1,13 +1,30 @@ +from dataclasses import dataclass, field +# {ClassName: ClassyClass} +global_classes: dict = dict() + + +def GenerateClassNameFromVtableAddr(vTable_addr: int) -> str: + return f"class_{hex(vTable_addr)}_vfTable" + + +@dataclass class ClassyClass: - def __init__(self): - self.name: str = '' - self.size: int = 0 + def __init__(self, name: str, vfTable_addr: int, constructors: list[int] = None, + inherited_classes: list = None, vfTable_functions: list[int] = None, size: int = 0, + namespace="", fields=None): + + self.name: str = name + self.vfTable_addr: int = vfTable_addr + self.constructors: list[int] = constructors if constructors else list() + self.namespace: str = namespace + self.size: int = size # fields - {offset: (, , Optional(Address in executable pointed to))} - self.fields: dict = dict() + self.fields: dict = fields if fields else dict() + # list[ClassyClass] + self.inherited_classes: list = inherited_classes if inherited_classes else list() # vfTable - A list of all function addresses in the table - self.vfTable: list[int] = list() - self.constructors: list[int] = list() - self.inherited_classes: list[ClassyClass] = list() - self.namespace: str = '' \ No newline at end of file + self.vfTable_functions: list[int] = vfTable_functions if vfTable_functions else list() + + global_classes.update({self.name: self}) diff --git a/RttiInfomation/BaseClass.py b/RttiInformation/BaseClass.py similarity index 100% rename from RttiInfomation/BaseClass.py rename to RttiInformation/BaseClass.py diff --git a/RttiInfomation/BaseClassArray.py b/RttiInformation/BaseClassArray.py similarity index 100% rename from RttiInfomation/BaseClassArray.py rename to RttiInformation/BaseClassArray.py diff --git a/RttiInfomation/BaseClassDescriptor.py b/RttiInformation/BaseClassDescriptor.py similarity index 100% rename from RttiInfomation/BaseClassDescriptor.py rename to RttiInformation/BaseClassDescriptor.py diff --git a/RttiInfomation/ClassContext.py b/RttiInformation/ClassContext.py similarity index 97% rename from RttiInfomation/ClassContext.py rename to RttiInformation/ClassContext.py index 278380f..6b64e02 100644 --- a/RttiInfomation/ClassContext.py +++ b/RttiInformation/ClassContext.py @@ -6,7 +6,7 @@ from ..Common import Utils from .. import Config from .ClassMemoryLayout import ClassStructCreation -import pysnooper + ############################################################################################### # GLOBAL STRUCTS @@ -106,13 +106,13 @@ def DebugPrintCol(self, Col: CompleteObjectLocator, current_address): def DeduceClassHierarchies(self): ClassHierarchyDeduction.DefineClassHierarchy(self.bv) - def DefineRTTI(self) -> bool: + def DetectAndDefineAllInformation(self) -> bool: for sect in self.bv.sections.values(): if IsSectionCompatibleToRTTI(sect): current_address = sect.start while current_address < sect.end - self.rtti_complete_object_locator_size: if Col := self.GetCompleteObjectLocator(current_address): - Utils.LogToFile(f'DefineRTTI: Defined {Col.__repr__()} \n') + Utils.LogToFile(f'Defined {Col.__repr__()} \n') print(f"Defined Class: {Utils.DemangleName(Col.mangled_class_name)}") if Config.ENABLE_DEBUG_LOGGING: self.DebugPrintCol(Col, current_address) diff --git a/RttiInfomation/ClassHierarchyDescriptor.py b/RttiInformation/ClassHierarchyDescriptor.py similarity index 100% rename from RttiInfomation/ClassHierarchyDescriptor.py rename to RttiInformation/ClassHierarchyDescriptor.py diff --git a/RttiInfomation/ClassHierarchyInference/ClassHierarchyDeduction.py b/RttiInformation/ClassHierarchyInference/ClassHierarchyDeduction.py similarity index 96% rename from RttiInfomation/ClassHierarchyInference/ClassHierarchyDeduction.py rename to RttiInformation/ClassHierarchyInference/ClassHierarchyDeduction.py index 72097d6..532d2f8 100644 --- a/RttiInfomation/ClassHierarchyInference/ClassHierarchyDeduction.py +++ b/RttiInformation/ClassHierarchyInference/ClassHierarchyDeduction.py @@ -2,7 +2,7 @@ import networkx as nx from networkx import DiGraph -from ...RttiInfomation import ClassContext +from ...RttiInformation import ClassContext from ...Common import Utils from ... import Config import binaryninja as bn @@ -76,7 +76,8 @@ def RenameFunction(bv: bn.binaryview, vtable_function: int, lca: int, function_i else: func.set_comment_at(func.start, f'{class_name}_method{function_index}') return True - except: + except Exception as e: + print(f"Unable to rename function {hex(vtable_function)}, got Exception: \n{e}") return False @@ -136,17 +137,17 @@ def CreateBcdHierarchyRecursively(base_class_array: List[int], def WriteGraphToFile(graph: DiGraph, gexf=True, graphml=False): if gexf: # To read the following stored graph: read_gexf(Config.GRAPH_FILE_FULL_PATH) - nx.write_gexf(graph, Config.GRAPH_FILE_FULL_PATH + 'RttiInfomation.gexf') + nx.write_gexf(graph, Config.GRAPH_FILE_FULL_PATH + 'RttiInformation.gexf') if graphml: # Write the graph in graphml form in order to be able to upload it to other databases (such as neo4j) # In neo4j: - # CALL apoc.import.graphml('RttiInfomation.graphml', {storeNodeIds: true}) + # CALL apoc.import.graphml('RttiInformation.graphml', {storeNodeIds: true}) # MATCH (n) # CALL apoc.create.addLabels([id(n)], [n.id]) # yield node # return node - nx.write_graphml(graph, Config.GRAPH_FILE_FULL_PATH + 'RttiInfomation.graphml') + nx.write_graphml(graph, Config.GRAPH_FILE_FULL_PATH + 'RttiInformation.graphml') def CreateHierarchyGraph() -> nx.DiGraph: diff --git a/RttiInfomation/ClassHierarchyInference/__init__.py b/RttiInformation/ClassHierarchyInference/__init__.py similarity index 100% rename from RttiInfomation/ClassHierarchyInference/__init__.py rename to RttiInformation/ClassHierarchyInference/__init__.py diff --git a/RttiInfomation/ClassMemoryLayout/ClassStructCreation.py b/RttiInformation/ClassMemoryLayout/ClassStructCreation.py similarity index 100% rename from RttiInfomation/ClassMemoryLayout/ClassStructCreation.py rename to RttiInformation/ClassMemoryLayout/ClassStructCreation.py diff --git a/RttiInfomation/ClassMemoryLayout/LayoutLoader.py b/RttiInformation/ClassMemoryLayout/LayoutLoader.py similarity index 100% rename from RttiInfomation/ClassMemoryLayout/LayoutLoader.py rename to RttiInformation/ClassMemoryLayout/LayoutLoader.py diff --git a/RttiInfomation/ClassMemoryLayout/LayoutParser.py b/RttiInformation/ClassMemoryLayout/LayoutParser.py similarity index 100% rename from RttiInfomation/ClassMemoryLayout/LayoutParser.py rename to RttiInformation/ClassMemoryLayout/LayoutParser.py diff --git a/RttiInfomation/ClassMemoryLayout/__init__.py b/RttiInformation/ClassMemoryLayout/__init__.py similarity index 100% rename from RttiInfomation/ClassMemoryLayout/__init__.py rename to RttiInformation/ClassMemoryLayout/__init__.py diff --git a/RttiInfomation/ClassMemoryLayout/class_layouts.layout b/RttiInformation/ClassMemoryLayout/class_layouts.layout similarity index 100% rename from RttiInfomation/ClassMemoryLayout/class_layouts.layout rename to RttiInformation/ClassMemoryLayout/class_layouts.layout diff --git a/RttiInfomation/CompleteObjectLocator.py b/RttiInformation/CompleteObjectLocator.py similarity index 100% rename from RttiInfomation/CompleteObjectLocator.py rename to RttiInformation/CompleteObjectLocator.py diff --git a/RttiInfomation/TypeCreation.py b/RttiInformation/TypeCreation.py similarity index 100% rename from RttiInfomation/TypeCreation.py rename to RttiInformation/TypeCreation.py diff --git a/RttiInfomation/TypeDescriptor.py b/RttiInformation/TypeDescriptor.py similarity index 100% rename from RttiInfomation/TypeDescriptor.py rename to RttiInformation/TypeDescriptor.py diff --git a/RttiInfomation/VirtualTableInference/VirtualFunctionTable.py b/RttiInformation/VirtualTableInference/VirtualFunctionTable.py similarity index 55% rename from RttiInfomation/VirtualTableInference/VirtualFunctionTable.py rename to RttiInformation/VirtualTableInference/VirtualFunctionTable.py index 4fcad3c..f354183 100644 --- a/RttiInfomation/VirtualTableInference/VirtualFunctionTable.py +++ b/RttiInformation/VirtualTableInference/VirtualFunctionTable.py @@ -1,5 +1,6 @@ import binaryninja as bn - +from ...ClassDataStructureDetection.Constructors import DetectConstructor +from ...ClassObjectRepresentation import CppClass from ...Common import Utils from typing import * @@ -8,6 +9,60 @@ global_functions_contained_in_all_vfTables: List[int] = list() +def VerifyNonRttiVtable(bv: bn.binaryview, potential_vtable_addr: int) -> bool: + if potential_vtable_addr in global_vfTables.keys(): + return True + else: + verified_vtable = VFTABLE(bv, + potential_vtable_addr, + f"vtable_{hex(potential_vtable_addr)}_nonRtti") + if verified_vtable.verified: + return True + return False + + +def DetectVTables(bv: bn.binaryview): + """ + The general algorithm of this function is this: + 1. Go over all recognized functions in the binaryView. + 1.1 If the function is already defined as a constructor / destructor by the RTTI information then skip it. + 1.2 If the function is verified as a possible constructor / destructor detection algorithm (but was not mentioned + by the RTTI information) then check all possible vtable assignments in the function. + 2. First, if we have an assignment of a vTable to offset 0 of Arg1 then we assume this is indeed + a constructor / destructor - vTable is defined as vtable_vTableAddress_nonRtti, and class is defined + as class_vTableAddress. + 3. Once we found a constructor / destructor then we add all non 0 offsets of Arg1 assignments found in the + function for further inspection (This is he deffered_vtable_addr list). + The logic here is that the class may contain vTable assignments of its base or multiple inherited classes, + and those vTables should also have their own constructors / destructors somewhere else in the file. + 4. Once we searched all functions in the bv, we now iterate the deffered_vtable_addr list to detect which + of these addresses was later confirmed as a vtable, and accordingly we can add this information to the + correct class. + """ + print("Searching for vTables...") + # First, we go over the known vfTables (As inferred from RTTI info) and locate their constructors. + for vtable_addr, contained_functions in global_vfTables.items(): + if potential_constructors := DetectConstructor.DetectConstructorForVTable(bv, vtable_addr): + DetectConstructor.DefineConstructor(bv, potential_constructors, vtable_addr) + for func in bv.functions: + if func.start not in DetectConstructor.global_constructor_destructor_list and \ + func.start not in global_functions_contained_in_all_vfTables: + if DetectConstructor.VerifyConstructor(bv, func): + # VerifyConstructor will check that there is a pointer assignment into offset 0x0 + # in the "This" pointer (Arg1). Now we need to check if this pointer is a vTable. + assignment_instructions = DetectConstructor.GetAllAssignmentInstructions(func) + # Check if the last assignment into offset 0 of Arg1 in the constructor func is a vTable. + suspected_vtable: int = assignment_instructions[0][-1] + print(f"Found non RTTI vtable at {hex(suspected_vtable)}") + if potential_constructors := DetectConstructor.DetectConstructorForVTable(bv, suspected_vtable): + class_name: str = CppClass.GenerateClassNameFromVtableAddr(suspected_vtable) + vtable = VFTABLE(bv, suspected_vtable, class_name) + if vtable.verified: + DetectConstructor.DefineConstructor(bv, potential_constructors, suspected_vtable, class_name) + + # TODO : add information of base classes according to non 0x0 offset assignments. + + class VFTABLE: def __init__(self, bv: bn.binaryview, base_addr: int, demangled_name: str): @@ -28,15 +83,20 @@ def VerifyVFT(self) -> bool: # class) then it is safe to change its type to 'void *' in order to "fix" the binja bug and allow it to # recognize data refs. vTable_data_var = self.bv.get_data_var_at(self.base_addr) - vTable_data_var.type = self.bv.parse_type_string("void*")[0] - # Now we should see data refs from this address - data_refs_from_base_addr = list(self.bv.get_data_refs_from(self.base_addr)) + if vTable_data_var is not None: + vTable_data_var.type = self.bv.parse_type_string("void*")[0] + # Now we should see data refs from this address + data_refs_from_base_addr = list(self.bv.get_data_refs_from(self.base_addr)) + else: + print(f"VerifyVFT: unable to get information on data variable at addr {self.base_addr}.") + return False if len(data_refs_from_base_addr) > 0: if self.bv.get_function_at(data_refs_from_base_addr[0]): if self.DefineVFT(): # Update this vfTable in the global table, this will be used later for locating constructor funcs global_vfTables.update({self.base_addr: self.contained_functions}) + global_functions_contained_in_all_vfTables.extend(self.contained_functions) Utils.LogToFile(f'VFTABLE: verified table at address {hex(self.base_addr)}') return True return False diff --git a/RttiInfomation/VirtualTableInference/__init__.py b/RttiInformation/VirtualTableInference/__init__.py similarity index 100% rename from RttiInfomation/VirtualTableInference/__init__.py rename to RttiInformation/VirtualTableInference/__init__.py diff --git a/RttiInfomation/__init__.py b/RttiInformation/__init__.py similarity index 100% rename from RttiInfomation/__init__.py rename to RttiInformation/__init__.py diff --git a/RttiInfomation/example flow.drawio b/RttiInformation/example flow.drawio similarity index 100% rename from RttiInfomation/example flow.drawio rename to RttiInformation/example flow.drawio diff --git a/RttiInfomation/rtti-layout-better.png b/RttiInformation/rtti-layout-better.png similarity index 100% rename from RttiInfomation/rtti-layout-better.png rename to RttiInformation/rtti-layout-better.png diff --git a/RttiInfomation/rtti-layout.png b/RttiInformation/rtti-layout.png similarity index 100% rename from RttiInfomation/rtti-layout.png rename to RttiInformation/rtti-layout.png diff --git a/StartInspection.py b/StartInspection.py index e205a4b..0dbc1c4 100644 --- a/StartInspection.py +++ b/StartInspection.py @@ -1,17 +1,11 @@ -""" -import ClassyPP -import importlib -importlib.reload(ClassyPP); -ClassyPP.StartInspection.inspect(bv) -""" - +import pprint import binaryninja as bn -from .RttiInfomation.ClassContext import GlobalClassContextManager +from .RttiInformation.ClassContext import GlobalClassContextManager from .Common import Utils from . import Config -from .RttiInfomation import TypeCreation +from .RttiInformation import TypeCreation from .ClassDataStructureDetection.Constructors import DetectConstructor -from .RttiInfomation.VirtualTableInference import VirtualFunctionTable +from .RttiInformation.VirtualTableInference import VirtualFunctionTable def is_bv_valid_for_plugin(bv: bn.binaryview) -> bool: @@ -55,15 +49,14 @@ def DetectAndVerifyConstructor(self): if Config.CONSTRUCTOR_FUNCTION_HANDLING != 2: # Iterate over all found vfTables and detect their constructors print(f'ClassyPP: Constructor Detection process started...') - for base_addr, contained_functions in VirtualFunctionTable.global_vfTables.items(): - if DetectConstructor.DetectConstructorForVTable(self.bv, base_addr, contained_functions): - pass + Utils.LogToFile(str(VirtualFunctionTable.global_vfTables)) + VirtualFunctionTable.DetectVTables(self.bv) def RTTI_inspection(self) -> bool: Utils.LogToFile(f'inspect: Starting Scan.') if TypeCreation.CreateTypes(self.bv): GCM: GlobalClassContextManager = GlobalClassContextManager(self.bv) - if GCM.DefineRTTI(): + if GCM.DetectAndDefineAllInformation(): Utils.LogToFile(f'ClassyPP: Successfully created types.') print(f'ClassyPP: Successfully defined RTTI Information.') return True diff --git a/__init__.py b/__init__.py index c32c1a9..aa356e7 100644 --- a/__init__.py +++ b/__init__.py @@ -1,30 +1,3 @@ -""" -from .RttiInfomation import TypeCreation -from .RttiInfomation import BaseClassDescriptor, ClassContext, \ - ClassHierarchyDescriptor, CompleteObjectLocator, TypeDescriptor, \ - BaseClassArray, VirtualFunctionTable, ClassHierarchyDeduction -from .Common import Utils -from . import Config -from .RttiInfomation.ClassMemoryLayout import ClassStructCreation, LayoutParser, LayoutLoader -import importlib - -importlib.reload(StartInspection) -importlib.reload(BaseClassDescriptor) -importlib.reload(BaseClassArray) -importlib.reload(ClassContext) -importlib.reload(ClassHierarchyDescriptor) -importlib.reload(CompleteObjectLocator) -importlib.reload(TypeDescriptor) -importlib.reload(TypeCreation) -importlib.reload(VirtualFunctionTable) -importlib.reload(Utils) -importlib.reload(Config) -importlib.reload(ClassHierarchyDeduction) -importlib.reload(LayoutLoader) -importlib.reload(LayoutParser) -importlib.reload(ClassStructCreation) -""" - import binaryninja as bn from . import StartInspection diff --git a/plugin.json b/plugin.json index 0436ab5..251dfbe 100644 --- a/plugin.json +++ b/plugin.json @@ -31,7 +31,7 @@ "ClassyPP uses an external C++ demangler - Demumble - https://github.com/nico/demumble/releases." ] }, - "version": "1.4.0", + "version": "1.5.0", "author": "CyShell", "minimumbinaryninjaversion": 3233 }