diff --git a/.clang-format b/.clang-format deleted file mode 100644 index 2a81fb8..0000000 --- a/.clang-format +++ /dev/null @@ -1,86 +0,0 @@ ---- -AccessModifierOffset: -4 -AlignAfterOpenBracket: DontAlign -AlignConsecutiveMacros: Consecutive -AlignConsecutiveAssignments: None -AlignConsecutiveDeclarations: None -AlignEscapedNewlines: DontAlign -AlignOperands: false -AlignTrailingComments: true -AllowAllArgumentsOnNextLine: true -AllowAllConstructorInitializersOnNextLine: false -AllowAllParametersOfDeclarationOnNextLine: false -AllowShortBlocksOnASingleLine: Never -AllowShortCaseLabelsOnASingleLine: false -AllowShortFunctionsOnASingleLine: Inline -AllowShortIfStatementsOnASingleLine: Never -AllowShortLambdasOnASingleLine: Inline -AllowShortLoopsOnASingleLine: false -AlwaysBreakAfterDefinitionReturnType: None -AlwaysBreakAfterReturnType: None -AlwaysBreakBeforeMultilineStrings: true -AlwaysBreakTemplateDeclarations: 'Yes' -BinPackArguments: true -BinPackParameters: true -BreakBeforeBraces: Custom -BraceWrapping: - AfterCaseLabel: true - AfterClass: true - AfterControlStatement: 'true' - AfterEnum: true - AfterFunction: true - AfterNamespace: false - AfterObjCDeclaration: true - AfterStruct: true - AfterUnion: true - AfterExternBlock: true - BeforeCatch: true - BeforeElse: true - IndentBraces: false - SplitEmptyFunction: false - SplitEmptyRecord: false - SplitEmptyNamespace: false -BreakBeforeBinaryOperators: NonAssignment -BreakBeforeTernaryOperators: false -BreakConstructorInitializers: AfterColon -BreakInheritanceList: AfterColon -ColumnLimit: 120 -CompactNamespaces: true -ConstructorInitializerAllOnOneLineOrOnePerLine: false -Cpp11BracedListStyle: true -DerivePointerAlignment: false -DisableFormat: false -EmptyLineBeforeAccessModifier: Always -FixNamespaceComments: true -IncludeBlocks: Preserve -IndentCaseLabels: false -IndentPPDirectives: BeforeHash -IndentWrappedFunctionNames: true -KeepEmptyLinesAtTheStartOfBlocks: false -MaxEmptyLinesToKeep: 2 -NamespaceIndentation: All -PenaltyIndentedWhitespace: 100 -PointerAlignment: Left -SortIncludes: Never -SortUsingDeclarations: true -SpaceAfterCStyleCast: false -SpaceAfterLogicalNot: false -SpaceAfterTemplateKeyword: true -SpaceBeforeAssignmentOperators: true -SpaceBeforeCpp11BracedList: true -SpaceBeforeCtorInitializerColon: true -SpaceBeforeInheritanceColon: true -SpaceBeforeParens: ControlStatements -SpaceBeforeRangeBasedForLoopColon: true -SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 2 -SpacesInAngles: false -SpacesInCStyleCastParentheses: false -SpacesInContainerLiterals: false -SpacesInParentheses: false -SpacesInSquareBrackets: false -IndentWidth: 4 -TabWidth: 4 -UseTab: AlignWithSpaces - -... \ No newline at end of file diff --git a/include/rtti.h b/include/rtti.h index bfdcd56..9a0ebb9 100644 --- a/include/rtti.h +++ b/include/rtti.h @@ -2,107 +2,117 @@ #include "binaryninjaapi.h" -constexpr const char* VIEW_METADATA_MSVC = "msvc"; +constexpr const char *VIEW_METADATA_MSVC = "msvc"; namespace BinaryNinja { - struct BaseClassArray - { - uint32_t length; - std::vector descriptors; - - BaseClassArray(BinaryView* view, uint64_t address, uint32_t length); - }; - - struct ClassHierarchyDescriptor - { - uint32_t signature; - uint32_t attributes; - uint32_t numBaseClasses; - int32_t pBaseClassArray; - - ClassHierarchyDescriptor(BinaryView* view, uint64_t address); - }; - - struct BaseClassDescriptor - { - int32_t pTypeDescriptor; - uint32_t numContainedBases; - int32_t where_mdisp; - int32_t where_pdisp; - int32_t where_vdisp; - uint32_t attributes; - int32_t pClassHierarchyDescriptor; - - BaseClassDescriptor(BinaryView* view, uint64_t address); - }; - - struct TypeDescriptor - { - uint64_t pVFTable; - uint64_t spare; - std::string name; - - TypeDescriptor(BinaryView* view, uint64_t address); - }; - - struct CompleteObjectLocator - { - uint32_t signature; - uint32_t offset; - uint32_t cdOffset; - int32_t pTypeDescriptor; - int32_t pClassHeirarchyDescriptor; - // Only on 64 bit - int32_t pSelf; - - CompleteObjectLocator(BinaryView *view, uint64_t address); - }; + struct BaseClassArray + { + uint32_t length; + std::vector descriptors; + + BaseClassArray(BinaryView *view, uint64_t address, uint32_t length); + }; + + struct ClassHierarchyDescriptor + { + uint32_t signature; + uint32_t attributes; + uint32_t numBaseClasses; + int32_t pBaseClassArray; + + ClassHierarchyDescriptor(BinaryView *view, uint64_t address); + }; + + struct BaseClassDescriptor + { + int32_t pTypeDescriptor; + uint32_t numContainedBases; + int32_t where_mdisp; + int32_t where_pdisp; + int32_t where_vdisp; + uint32_t attributes; + int32_t pClassHierarchyDescriptor; + + BaseClassDescriptor(BinaryView *view, uint64_t address); + }; + + struct TypeDescriptor + { + uint64_t pVFTable; + uint64_t spare; + std::string name; + + TypeDescriptor(BinaryView *view, uint64_t address); + }; + + struct CompleteObjectLocator + { + uint32_t signature; + uint32_t offset; + uint32_t cdOffset; + int32_t pTypeDescriptor; + int32_t pClassHeirarchyDescriptor; + // Only on 64 bit + int32_t pSelf; + + CompleteObjectLocator(BinaryView *view, uint64_t address); + }; struct VirtualFunctionInfo { uint64_t funcAddr; Ref SerializedMetadata(); - static VirtualFunctionInfo DeserializedMetadata(const Ref& metadata); + + static VirtualFunctionInfo DeserializedMetadata(const Ref &metadata); }; struct VirtualFunctionTableInfo { uint64_t address; - std::vector virtualFunctions; + std::vector virtualFunctions; Ref SerializedMetadata(); - static VirtualFunctionTableInfo DeserializedMetadata(const Ref& metadata); + + static VirtualFunctionTableInfo DeserializedMetadata(const Ref &metadata); }; - struct ClassInfo - { - std::string className; - std::optional baseClassName; - std::optional classOffset; - std::optional vft; - - Ref SerializedMetadata(); - static ClassInfo DeserializedMetadata(const Ref& metadata); - }; - - class MicrosoftRTTIProcessor - { - Ref m_view; - Ref m_logger; - bool allowMangledClassNames; - bool checkWritableRData; - - std::map m_classInfo; - - void DeserializedMetadata(const Ref& metadata); - std::optional DemangleName(const std::string& mangledName); - std::optional ProcessRTTI(uint64_t coLocatorAddr); - std::optional ProcessVFT(uint64_t vftAddr, const ClassInfo& classInfo); - public: - MicrosoftRTTIProcessor(const Ref& view, bool useMangled = true, bool checkRData = true); - Ref SerializedMetadata(); - void ProcessRTTI(); - void ProcessVFT(); - }; -} \ No newline at end of file + struct ClassInfo + { + std::string className; + std::optional baseClassName; + std::optional classOffset; + std::optional vft; + + Ref SerializedMetadata(); + + static ClassInfo DeserializedMetadata(const Ref &metadata); + }; + + class MicrosoftRTTIProcessor + { + Ref m_view; + Ref m_logger; + bool allowMangledClassNames; + bool checkWritableRData; + + std::map m_classInfo; + + void DeserializedMetadata(const Ref &metadata); + + std::optional DemangleName(const std::string &mangledName); + + std::optional ProcessRTTI(uint64_t coLocatorAddr); + + std::optional ProcessVFT(uint64_t vftAddr, const ClassInfo &classInfo); + + public: + MicrosoftRTTIProcessor(const Ref &view, bool useMangled = true, bool checkRData = true); + + Ref SerializedMetadata(); + + void ProcessRTTI(); + + void ProcessVFT(); + }; +} diff --git a/scripts/class_dump.py b/scripts/class_dump.py index 0cd83e4..e90bcb0 100644 --- a/scripts/class_dump.py +++ b/scripts/class_dump.py @@ -8,14 +8,11 @@ # '5368823856': {'className': 'type_info'} # } # } +import sys from time import sleep -from typing import List -from binaryninja.types import BaseStructure -from binaryninja import BinaryView, BaseStructure, NamedTypeReferenceClass, StructureVariant, NamedTypeReferenceType, \ - StructureBuilder, PointerType, PluginCommandContext, PluginCommand +from binaryninja import BinaryView, PluginCommandContext, PluginCommand -import sys if len(sys.argv) != 2: print("Usage: python class_dump.py ") sys.exit(1) @@ -36,10 +33,12 @@ sleep(1) data = view.query_metadata("msvc") + class ClassInfo: def __init__(self, class_name: str, base_classes: dict[int, str]): self.class_name = class_name self.base_classes = base_classes + def __repr__(self): return f"ClassInfo(class_name={self.class_name}, base_classes={self.base_classes})" diff --git a/scripts/class_graph.py b/scripts/class_graph.py index 6c5ecb3..a3ce26b 100644 --- a/scripts/class_graph.py +++ b/scripts/class_graph.py @@ -10,11 +10,9 @@ # } -from PySide6.QtWidgets import QApplication, QDialog, QVBoxLayout -from PySide6.QtGui import QFont -from PySide6.QtCore import QSize # FYI we do not have this in binja from PySide6.QtCharts import QChart, QChartView, QLineSeries +from PySide6.QtWidgets import QDialog, QVBoxLayout data = { 'classes': { @@ -26,6 +24,7 @@ } } + class GraphDialog(QDialog): def __init__(self): super().__init__() @@ -70,9 +69,10 @@ def add_data_to_series(self): y += 10 + def create_window(): dialog = GraphDialog() dialog.exec_() -execute_on_main_thread(create_window) \ No newline at end of file +execute_on_main_thread(create_window) diff --git a/scripts/class_graphviz.py b/scripts/class_graphviz.py index f468ecb..497e6a5 100644 --- a/scripts/class_graphviz.py +++ b/scripts/class_graphviz.py @@ -1,6 +1,7 @@ +import sys from time import sleep + import graphviz -import sys from binaryninja import BinaryView, PluginCommandContext, PluginCommand # Whether to open the png after it is created. @@ -29,6 +30,7 @@ print("Creating graph...") data = view.query_metadata("msvc") + def create_graph(data): dot = graphviz.Digraph() classes = data.get('classes', {}) @@ -40,6 +42,7 @@ def create_graph(data): dot.edge(base_class_name, class_name) return dot + # data = { # 'classes': { # '5368823328': {'className': 'Animal'}, diff --git a/scripts/class_types.py b/scripts/class_types.py index c9142d8..aab7a37 100644 --- a/scripts/class_types.py +++ b/scripts/class_types.py @@ -10,7 +10,6 @@ # } from typing import List -from binaryninja.types import BaseStructure from binaryninja import BinaryView, BaseStructure, NamedTypeReferenceClass, StructureVariant, NamedTypeReferenceType, \ StructureBuilder, PointerType diff --git a/src/plugin.cpp b/src/plugin.cpp index 71dcfbf..4e2dbd2 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -37,35 +37,34 @@ bool MetadataExists(Ref view) } -extern "C" +extern "C" { +BN_DECLARE_CORE_ABI_VERSION + +BINARYNINJAPLUGIN bool CorePluginInit() { - BN_DECLARE_CORE_ABI_VERSION + // TODO: In the future we will have a module level workflow which: + // TODO: 1. Symbolizes RTTI information + // TODO: 2. Creates Virtual Function Tables + // TODO: 3. Populates MSVC metadata entry + // TODO: And a function level workflow which: + // TODO: 1. Uses MSVC metadata to identify if a function is apart of a VFT + // TODO: 2. Identify if the function is unique to a class, renaming and retyping if true + // TODO: 3. Identify functions which address a VFT and are probably a constructor (alloc use), retyping if true + // TODO: 4. Identify functions which address a VFT and are probably a deconstructor (free use), retyping if true - BINARYNINJAPLUGIN bool CorePluginInit() - { - // TODO: In the future we will have a module level workflow which: - // TODO: 1. Symbolizes RTTI information - // TODO: 2. Creates Virtual Function Tables - // TODO: 3. Populates MSVC metadata entry - // TODO: And a function level workflow which: - // TODO: 1. Uses MSVC metadata to identify if a function is apart of a VFT - // TODO: 2. Identify if the function is unique to a class, renaming and retyping if true - // TODO: 3. Identify functions which address a VFT and are probably a constructor (alloc use), retyping if true - // TODO: 4. Identify functions which address a VFT and are probably a deconstructor (free use), retyping if true + // Ref msvcWorkflow = Workflow::Instance("core.function.defaultAnalysis")->Clone("MSVCWorkflow"); + // msvcWorkflow->RegisterActivity(new Activity("extension.msvc.rttiAnalysis", &RTTIAnalysis)); + // msvcWorkflow->Insert("core.module.defaultAnalysis", "extension.msvc.rttiAnalysis"); + // Workflow::RegisterWorkflow(msvcWorkflow, + // R"#({ + // "title" : "MSVC Workflow", + // "description" : "Analyze MSVC RTTI", + // "capabilities" : [] + // })#"); - // Ref msvcWorkflow = Workflow::Instance("core.function.defaultAnalysis")->Clone("MSVCWorkflow"); - // msvcWorkflow->RegisterActivity(new Activity("extension.msvc.rttiAnalysis", &RTTIAnalysis)); - // msvcWorkflow->Insert("core.module.defaultAnalysis", "extension.msvc.rttiAnalysis"); - // Workflow::RegisterWorkflow(msvcWorkflow, - // R"#({ - // "title" : "MSVC Workflow", - // "description" : "Analyze MSVC RTTI", - // "capabilities" : [] - // })#"); - - PluginCommand::Register("MSVC\\Find RTTI", "Scans for all RTTI in view.", ScanRTTI); - PluginCommand::Register("MSVC\\Find VFTs", "Scans for all VFTs in the view.", ScanVFT, MetadataExists); + PluginCommand::Register("MSVC\\Find RTTI", "Scans for all RTTI in view.", ScanRTTI); + PluginCommand::Register("MSVC\\Find VFTs", "Scans for all VFTs in the view.", ScanVFT, MetadataExists); - return true; - } -} \ No newline at end of file + return true; +} +} diff --git a/src/rtti.cpp b/src/rtti.cpp index 781c55e..640bc44 100644 --- a/src/rtti.cpp +++ b/src/rtti.cpp @@ -64,8 +64,7 @@ CompleteObjectLocator::CompleteObjectLocator(BinaryView *view, uint64_t address) if (signature == COL_SIG_REV1) { pSelf = static_cast(reader.Read32()); - } - else + } else { pSelf = 0; } @@ -92,8 +91,7 @@ std::optional ReadCompleteObjectorLocator(BinaryView *vie if (coLocator.pClassHeirarchyDescriptor + startAddr > endAddr) return std::nullopt; - } - else + } else { // Absolute addrs if (coLocator.pTypeDescriptor < startAddr || coLocator.pTypeDescriptor > endAddr) @@ -107,7 +105,7 @@ std::optional ReadCompleteObjectorLocator(BinaryView *vie } -Ref GetPMDType(BinaryView* view) +Ref GetPMDType(BinaryView *view) { auto typeId = Type::GenerateAutoTypeId("msvc_rtti", QualifiedName("PMD")); Ref typeCache = view->GetTypeById(typeId); @@ -129,8 +127,9 @@ Ref GetPMDType(BinaryView* view) } -Ref ClassHierarchyDescriptorType(BinaryView* view, BNPointerBaseType ptrBaseTy); -Ref BaseClassDescriptorType(BinaryView* view, BNPointerBaseType ptrBaseTy) +Ref ClassHierarchyDescriptorType(BinaryView *view, BNPointerBaseType ptrBaseTy); + +Ref BaseClassDescriptorType(BinaryView *view, BNPointerBaseType ptrBaseTy) { auto typeId = Type::GenerateAutoTypeId("msvc_rtti", QualifiedName("RTTIBaseClassDescriptor")); Ref typeCache = view->GetTypeById(typeId); @@ -142,19 +141,19 @@ Ref BaseClassDescriptorType(BinaryView* view, BNPointerBaseType ptrBaseTy) StructureBuilder baseClassDescriptorBuilder; // Would require creating a new type for every type descriptor length. Instead just use void* Ref pTypeDescType = TypeBuilder::PointerType(4, Type::VoidType()) - .SetPointerBase(ptrBaseTy, 0) - .Finalize(); + .SetPointerBase(ptrBaseTy, 0) + .Finalize(); baseClassDescriptorBuilder.AddMember(pTypeDescType, "pTypeDescriptor"); baseClassDescriptorBuilder.AddMember(uintType, "numContainedBases"); baseClassDescriptorBuilder.AddMember(GetPMDType(view), "where"); baseClassDescriptorBuilder.AddMember(uintType, "attributes"); Ref pClassDescType = TypeBuilder::PointerType(4, ClassHierarchyDescriptorType(view, ptrBaseTy)) - .SetPointerBase(ptrBaseTy, 0) - .Finalize(); + .SetPointerBase(ptrBaseTy, 0) + .Finalize(); baseClassDescriptorBuilder.AddMember(pClassDescType, "pClassDescriptor"); view->DefineType(typeId, QualifiedName("_RTTIBaseClassDescriptor"), - TypeBuilder::StructureType(&baseClassDescriptorBuilder).Finalize()); + TypeBuilder::StructureType(&baseClassDescriptorBuilder).Finalize()); typeCache = view->GetTypeById(typeId); } @@ -162,19 +161,19 @@ Ref BaseClassDescriptorType(BinaryView* view, BNPointerBaseType ptrBaseTy) } -Ref BaseClassArrayType(BinaryView* view, const uint64_t length, BNPointerBaseType ptrBaseTy) +Ref BaseClassArrayType(BinaryView *view, const uint64_t length, BNPointerBaseType ptrBaseTy) { StructureBuilder baseClassArrayBuilder; Ref pBaseClassDescType = TypeBuilder::PointerType(4, BaseClassDescriptorType(view, ptrBaseTy)) - .SetPointerBase(ptrBaseTy, 0) - .Finalize(); + .SetPointerBase(ptrBaseTy, 0) + .Finalize(); baseClassArrayBuilder.AddMember( Type::ArrayType(pBaseClassDescType, length), "arrayOfBaseClassDescriptors"); return TypeBuilder::StructureType(&baseClassArrayBuilder).Finalize(); } -Ref ClassHierarchyDescriptorType(BinaryView* view, BNPointerBaseType ptrBaseTy) +Ref ClassHierarchyDescriptorType(BinaryView *view, BNPointerBaseType ptrBaseTy) { auto typeId = Type::GenerateAutoTypeId("msvc_rtti", QualifiedName("RTTIClassHierarchyDescriptor")); Ref typeCache = view->GetTypeById(typeId); @@ -188,12 +187,12 @@ Ref ClassHierarchyDescriptorType(BinaryView* view, BNPointerBaseType ptrBa classHierarchyDescriptorBuilder.AddMember(uintType, "attributes"); classHierarchyDescriptorBuilder.AddMember(uintType, "numBaseClasses"); Ref pBaseClassArrayType = TypeBuilder::PointerType(4, Type::VoidType()) - .SetPointerBase(ptrBaseTy, 0) - .Finalize(); + .SetPointerBase(ptrBaseTy, 0) + .Finalize(); classHierarchyDescriptorBuilder.AddMember(pBaseClassArrayType, "pBaseClassArray"); view->DefineType(typeId, QualifiedName("_RTTIClassHierarchyDescriptor"), - TypeBuilder::StructureType(&classHierarchyDescriptorBuilder).Finalize()); + TypeBuilder::StructureType(&classHierarchyDescriptorBuilder).Finalize()); typeCache = view->GetTypeById(typeId); } @@ -282,7 +281,7 @@ Ref CompleteObjectLocator32Type(BinaryView *view) } -Ref TypeDescriptorType(BinaryView* view, uint64_t length) +Ref TypeDescriptorType(BinaryView *view, uint64_t length) { size_t addrSize = view->GetAddressSize(); StructureBuilder typeDescriptorBuilder; @@ -296,96 +295,96 @@ Ref TypeDescriptorType(BinaryView* view, uint64_t length) Ref ClassInfo::SerializedMetadata() { - std::map> classInfoMeta; - classInfoMeta["className"] = new Metadata(className); - if (baseClassName.has_value()) - classInfoMeta["baseClassName"] = new Metadata(baseClassName.value()); - if (classOffset.has_value()) - classInfoMeta["classOffset"] = new Metadata(classOffset.value()); - if (vft.has_value()) - classInfoMeta["vft"] = vft->SerializedMetadata(); - return new Metadata(classInfoMeta); + std::map > classInfoMeta; + classInfoMeta["className"] = new Metadata(className); + if (baseClassName.has_value()) + classInfoMeta["baseClassName"] = new Metadata(baseClassName.value()); + if (classOffset.has_value()) + classInfoMeta["classOffset"] = new Metadata(classOffset.value()); + if (vft.has_value()) + classInfoMeta["vft"] = vft->SerializedMetadata(); + return new Metadata(classInfoMeta); } -ClassInfo ClassInfo::DeserializedMetadata(const Ref& metadata) +ClassInfo ClassInfo::DeserializedMetadata(const Ref &metadata) { - std::map> classInfoMeta = metadata->GetKeyValueStore(); - ClassInfo info = { classInfoMeta["className"]->GetString() }; - if (classInfoMeta.find("baseClassName") != classInfoMeta.end()) - info.baseClassName = classInfoMeta["baseClassName"]->GetString(); - if (classInfoMeta.find("classOffset") != classInfoMeta.end()) - info.classOffset = classInfoMeta["classOffset"]->GetUnsignedInteger(); - if (classInfoMeta.find("vft") != classInfoMeta.end()) - info.vft = VirtualFunctionTableInfo::DeserializedMetadata(classInfoMeta["vft"]); - return info; + std::map > classInfoMeta = metadata->GetKeyValueStore(); + ClassInfo info = {classInfoMeta["className"]->GetString()}; + if (classInfoMeta.find("baseClassName") != classInfoMeta.end()) + info.baseClassName = classInfoMeta["baseClassName"]->GetString(); + if (classInfoMeta.find("classOffset") != classInfoMeta.end()) + info.classOffset = classInfoMeta["classOffset"]->GetUnsignedInteger(); + if (classInfoMeta.find("vft") != classInfoMeta.end()) + info.vft = VirtualFunctionTableInfo::DeserializedMetadata(classInfoMeta["vft"]); + return info; } Ref VirtualFunctionTableInfo::SerializedMetadata() { - std::vector> funcsMeta; - funcsMeta.reserve(virtualFunctions.size()); - for (auto& vFunc : virtualFunctions) - funcsMeta.emplace_back(vFunc.SerializedMetadata()); - std::map> vftMeta; - vftMeta["address"] = new Metadata(address); - vftMeta["functions"] = new Metadata(funcsMeta); - return new Metadata(vftMeta); + std::vector > funcsMeta; + funcsMeta.reserve(virtualFunctions.size()); + for (auto &vFunc: virtualFunctions) + funcsMeta.emplace_back(vFunc.SerializedMetadata()); + std::map > vftMeta; + vftMeta["address"] = new Metadata(address); + vftMeta["functions"] = new Metadata(funcsMeta); + return new Metadata(vftMeta); } -VirtualFunctionTableInfo VirtualFunctionTableInfo::DeserializedMetadata(const Ref& metadata) +VirtualFunctionTableInfo VirtualFunctionTableInfo::DeserializedMetadata(const Ref &metadata) { - std::map> vftMeta = metadata->GetKeyValueStore(); - VirtualFunctionTableInfo vftInfo = { vftMeta["address"]->GetUnsignedInteger() }; - if (vftMeta.find("functions") != vftMeta.end()) - { - for (auto& entry : vftMeta["functions"]->GetArray()) - vftInfo.virtualFunctions.emplace_back(VirtualFunctionInfo::DeserializedMetadata(entry)); - } - return vftInfo; + std::map > vftMeta = metadata->GetKeyValueStore(); + VirtualFunctionTableInfo vftInfo = {vftMeta["address"]->GetUnsignedInteger()}; + if (vftMeta.find("functions") != vftMeta.end()) + { + for (auto &entry: vftMeta["functions"]->GetArray()) + vftInfo.virtualFunctions.emplace_back(VirtualFunctionInfo::DeserializedMetadata(entry)); + } + return vftInfo; } Ref VirtualFunctionInfo::SerializedMetadata() { - std::map> vFuncMeta; - vFuncMeta["address"] = new Metadata(funcAddr); - return new Metadata(vFuncMeta); + std::map > vFuncMeta; + vFuncMeta["address"] = new Metadata(funcAddr); + return new Metadata(vFuncMeta); } -VirtualFunctionInfo VirtualFunctionInfo::DeserializedMetadata(const Ref& metadata) +VirtualFunctionInfo VirtualFunctionInfo::DeserializedMetadata(const Ref &metadata) { - std::map> vFuncMeta = metadata->GetKeyValueStore(); - VirtualFunctionInfo vFuncInfo = { vFuncMeta["address"]->GetUnsignedInteger() }; - return vFuncInfo; + std::map > vFuncMeta = metadata->GetKeyValueStore(); + VirtualFunctionInfo vFuncInfo = {vFuncMeta["address"]->GetUnsignedInteger()}; + return vFuncInfo; } Ref MicrosoftRTTIProcessor::SerializedMetadata() { - std::map> classesMeta; - for (auto& [coLocatorAddr, classInfo] : m_classInfo) - { - auto addrStr = std::to_string(coLocatorAddr); - classesMeta[addrStr] = classInfo.SerializedMetadata(); - } - - std::map> msvcMeta; - msvcMeta["classes"] = new Metadata(classesMeta); - return new Metadata(msvcMeta); + std::map > classesMeta; + for (auto &[coLocatorAddr, classInfo]: m_classInfo) + { + auto addrStr = std::to_string(coLocatorAddr); + classesMeta[addrStr] = classInfo.SerializedMetadata(); + } + + std::map > msvcMeta; + msvcMeta["classes"] = new Metadata(classesMeta); + return new Metadata(msvcMeta); } -void MicrosoftRTTIProcessor::DeserializedMetadata(const Ref& metadata) +void MicrosoftRTTIProcessor::DeserializedMetadata(const Ref &metadata) { - std::map> msvcMeta = metadata->GetKeyValueStore(); - if (msvcMeta.find("classes") != msvcMeta.end()) - { - for (auto& [coLocatorAddrStr, classInfoMeta] : msvcMeta["classes"]->GetKeyValueStore()) - { - uint64_t coLocatorAddr = std::stoull(coLocatorAddrStr); - m_classInfo[coLocatorAddr] = ClassInfo::DeserializedMetadata(classInfoMeta); - } - } + std::map > msvcMeta = metadata->GetKeyValueStore(); + if (msvcMeta.find("classes") != msvcMeta.end()) + { + for (auto &[coLocatorAddrStr, classInfoMeta]: msvcMeta["classes"]->GetKeyValueStore()) + { + uint64_t coLocatorAddr = std::stoull(coLocatorAddrStr); + m_classInfo[coLocatorAddr] = ClassInfo::DeserializedMetadata(classInfoMeta); + } + } } -std::optional MicrosoftRTTIProcessor::DemangleName(const std::string& mangledName) +std::optional MicrosoftRTTIProcessor::DemangleName(const std::string &mangledName) { QualifiedName demangledName = {}; Ref outType = {}; @@ -428,27 +427,31 @@ std::optional MicrosoftRTTIProcessor::ProcessRTTI(uint64_t coLocatorA if (!className.has_value()) return std::nullopt; - auto classInfo = ClassInfo { className.value() }; - if (coLocator->offset > 0) - classInfo.classOffset = coLocator->offset; + auto classInfo = ClassInfo{className.value()}; + if (coLocator->offset > 0) + classInfo.classOffset = coLocator->offset; auto typeDescSymName = fmt::format("class {} `RTTI Type Descriptor'", classInfo.className); - m_view->DefineAutoSymbol(new Symbol {DataSymbol, typeDescSymName, typeDescAddr}); - m_view->DefineDataVariable(typeDescAddr, Confidence(TypeDescriptorType(m_view, typeDesc.name.length()), RTTI_CONFIDENCE)); + m_view->DefineAutoSymbol(new Symbol{DataSymbol, typeDescSymName, typeDescAddr}); + m_view->DefineDataVariable(typeDescAddr, + Confidence(TypeDescriptorType(m_view, typeDesc.name.length()), RTTI_CONFIDENCE)); auto classHierarchyDescAddr = resolveAddr(coLocator->pClassHeirarchyDescriptor); auto classHierarchyDesc = ClassHierarchyDescriptor(m_view, classHierarchyDescAddr); auto classHierarchyDescName = fmt::format("{}::`RTTI Class Hierarchy Descriptor'", classInfo.className); - m_view->DefineAutoSymbol(new Symbol {DataSymbol, classHierarchyDescName, classHierarchyDescAddr}); - m_view->DefineDataVariable(classHierarchyDescAddr, Confidence(ClassHierarchyDescriptorType(m_view, ptrBaseTy), RTTI_CONFIDENCE)); + m_view->DefineAutoSymbol(new Symbol{DataSymbol, classHierarchyDescName, classHierarchyDescAddr}); + m_view->DefineDataVariable(classHierarchyDescAddr, + Confidence(ClassHierarchyDescriptorType(m_view, ptrBaseTy), RTTI_CONFIDENCE)); auto baseClassArrayAddr = resolveAddr(classHierarchyDesc.pBaseClassArray); auto baseClassArray = BaseClassArray(m_view, baseClassArrayAddr, classHierarchyDesc.numBaseClasses); auto baseClassArrayName = fmt::format("{}::`RTTI Base Class Array'", classInfo.className); - m_view->DefineAutoSymbol(new Symbol {DataSymbol, baseClassArrayName, baseClassArrayAddr}); - m_view->DefineDataVariable(baseClassArrayAddr, Confidence(BaseClassArrayType(m_view, baseClassArray.length, ptrBaseTy), RTTI_CONFIDENCE)); + m_view->DefineAutoSymbol(new Symbol{DataSymbol, baseClassArrayName, baseClassArrayAddr}); + m_view->DefineDataVariable(baseClassArrayAddr, + Confidence(BaseClassArrayType(m_view, baseClassArray.length, ptrBaseTy), + RTTI_CONFIDENCE)); - for (auto pBaseClassDescAddr : baseClassArray.descriptors) + for (auto pBaseClassDescAddr: baseClassArray.descriptors) { auto baseClassDescAddr = resolveAddr(pBaseClassDescAddr); auto baseClassDesc = BaseClassDescriptor(m_view, baseClassDescAddr); @@ -468,14 +471,15 @@ std::optional MicrosoftRTTIProcessor::ProcessRTTI(uint64_t coLocatorA auto baseClassDescName = fmt::format("{}::`RTTI Base Class Descriptor at ({},{},{},{})", baseClassName.value(), baseClassDesc.where_mdisp, baseClassDesc.where_pdisp, baseClassDesc.where_vdisp, baseClassDesc.attributes); - m_view->DefineAutoSymbol(new Symbol {DataSymbol, baseClassDescName, baseClassDescAddr}); - m_view->DefineDataVariable(baseClassDescAddr, Confidence(BaseClassDescriptorType(m_view, ptrBaseTy), RTTI_CONFIDENCE)); + m_view->DefineAutoSymbol(new Symbol{DataSymbol, baseClassDescName, baseClassDescAddr}); + m_view->DefineDataVariable(baseClassDescAddr, + Confidence(BaseClassDescriptorType(m_view, ptrBaseTy), RTTI_CONFIDENCE)); } auto coLocatorName = fmt::format("{}::`RTTI Complete Object Locator'", className.value()); if (classInfo.baseClassName.has_value()) coLocatorName += fmt::format("{{for `{}'}}", classInfo.baseClassName.value()); - m_view->DefineAutoSymbol(new Symbol {DataSymbol, coLocatorName, coLocatorAddr}); + m_view->DefineAutoSymbol(new Symbol{DataSymbol, coLocatorName, coLocatorAddr}); if (coLocator->signature == COL_SIG_REV1) m_view->DefineDataVariable(coLocatorAddr, Confidence(CompleteObjectLocator64Type(m_view), RTTI_CONFIDENCE)); else @@ -485,13 +489,13 @@ std::optional MicrosoftRTTIProcessor::ProcessRTTI(uint64_t coLocatorA } -std::optional MicrosoftRTTIProcessor::ProcessVFT(uint64_t vftAddr, const ClassInfo& classInfo) +std::optional MicrosoftRTTIProcessor::ProcessVFT(uint64_t vftAddr, const ClassInfo &classInfo) { - VirtualFunctionTableInfo vftInfo = { vftAddr }; + VirtualFunctionTableInfo vftInfo = {vftAddr}; // Gather all virtual functions BinaryReader reader = BinaryReader(m_view); reader.Seek(vftAddr); - std::vector> virtualFunctions = {}; + std::vector > virtualFunctions = {}; while (true) { uint64_t vFuncAddr = reader.ReadPointer(); @@ -504,36 +508,37 @@ std::optional MicrosoftRTTIProcessor::ProcessVFT(uint6 // Last CompleteObjectLocator or hit the next CompleteObjectLocator break; } - // TODO: Is likely a function check here? + // TODO: Is likely a function check here? m_logger->LogDebug("Discovered function from virtual function table... %llx", vFuncAddr); auto vFunc = m_view->AddFunctionForAnalysis(m_view->GetDefaultPlatform(), vFuncAddr, true); funcs.emplace_back(vFunc); } - // Only ever add one function. + // Only ever add one function. virtualFunctions.emplace_back(funcs.front()); } - if (virtualFunctions.empty()) - { - m_logger->LogDebug("Skipping empty virtual function table... %llx", vftAddr); - return std::nullopt; - } + if (virtualFunctions.empty()) + { + m_logger->LogDebug("Skipping empty virtual function table... %llx", vftAddr); + return std::nullopt; + } - for (auto& func : virtualFunctions) - vftInfo.virtualFunctions.emplace_back(VirtualFunctionInfo { func->GetStart() }); + for (auto &func: virtualFunctions) + vftInfo.virtualFunctions.emplace_back(VirtualFunctionInfo{func->GetStart()}); // Create virtual function table type auto vftTypeName = fmt::format("{}::VTable", classInfo.className); - if (classInfo.baseClassName.has_value()) - { - vftTypeName = fmt::format("{}::{}", classInfo.baseClassName.value(), vftTypeName); // TODO: What is the correct form for the name? - } + if (classInfo.baseClassName.has_value()) + { + vftTypeName = fmt::format("{}::{}", classInfo.baseClassName.value(), vftTypeName); + // TODO: What is the correct form for the name? + } // TODO: Hack the debug type id is used here to allow the PDB type (debug info) to overwrite the RTTI vtable type. auto typeId = Type::GenerateAutoDebugTypeId(vftTypeName); Ref vftType = m_view->GetTypeById(typeId); - // TODO we need to inherit vtables in cases where the backing functions are coupled to a no member field vtable. - // TOOD: Inheriting vtables is a terrible idea usually btw. + // TODO we need to inherit vtables in cases where the backing functions are coupled to a no member field vtable. + // TOOD: Inheriting vtables is a terrible idea usually btw. if (vftType == nullptr) { @@ -541,46 +546,48 @@ std::optional MicrosoftRTTIProcessor::ProcessVFT(uint6 StructureBuilder vftBuilder = {}; vftBuilder.SetPropagateDataVariableReferences(true); size_t vFuncIdx = 0; - for (auto&& vFunc : virtualFunctions) + for (auto &&vFunc: virtualFunctions) { - // TODO: Identify when the functions name can be used instead of the vFunc_* placeholder. + // TODO: Identify when the functions name can be used instead of the vFunc_* placeholder. auto vFuncName = fmt::format("vFunc_{}", vFuncIdx); // NOTE: The analyzed function type might not be available here. vftBuilder.AddMember( Type::PointerType(addrSize, vFunc->GetType(), true), vFuncName); vFuncIdx++; } - m_view->DefineType(typeId, vftTypeName, Confidence(TypeBuilder::StructureType(&vftBuilder).Finalize(), RTTI_CONFIDENCE)); + m_view->DefineType(typeId, vftTypeName, + Confidence(TypeBuilder::StructureType(&vftBuilder).Finalize(), RTTI_CONFIDENCE)); vftType = m_view->GetTypeById(typeId); } auto vftName = fmt::format("{}::`vftable'", classInfo.className); if (classInfo.baseClassName.has_value()) vftName += fmt::format("{{for `{}'}}", classInfo.baseClassName.value()); - m_view->DefineAutoSymbol(new Symbol {DataSymbol, vftName, vftAddr}); + m_view->DefineAutoSymbol(new Symbol{DataSymbol, vftName, vftAddr}); m_view->DefineDataVariable(vftAddr, Confidence(vftType, RTTI_CONFIDENCE)); - return vftInfo; + return vftInfo; } -MicrosoftRTTIProcessor::MicrosoftRTTIProcessor(const Ref& view, bool useMangled, bool checkRData) : m_view(view) +MicrosoftRTTIProcessor::MicrosoftRTTIProcessor(const Ref &view, bool useMangled, bool checkRData) : m_view( + view) { m_logger = new Logger("Microsoft RTTI"); allowMangledClassNames = useMangled; checkWritableRData = checkRData; - m_classInfo = {}; - auto metadata = view->QueryMetadata(VIEW_METADATA_MSVC); - if (metadata != nullptr) - { - // Load in metadata to the processor. - DeserializedMetadata(metadata); - } + m_classInfo = {}; + auto metadata = view->QueryMetadata(VIEW_METADATA_MSVC); + if (metadata != nullptr) + { + // Load in metadata to the processor. + DeserializedMetadata(metadata); + } } void MicrosoftRTTIProcessor::ProcessRTTI() { - auto start_time = std::chrono::high_resolution_clock::now(); + auto start_time = std::chrono::high_resolution_clock::now(); uint64_t startAddr = m_view->GetStart(); uint64_t endAddr = m_view->GetEnd(); BinaryReader optReader = BinaryReader(m_view); @@ -601,8 +608,7 @@ void MicrosoftRTTIProcessor::ProcessRTTI() if (auto classInfo = ProcessRTTI(coLocatorAddr)) m_classInfo[coLocatorAddr] = classInfo.value(); } - } - else if (sigVal == COL_SIG_REV0) + } else if (sigVal == COL_SIG_REV0) { // Check ?AV optReader.SeekRelative(8); @@ -618,7 +624,7 @@ void MicrosoftRTTIProcessor::ProcessRTTI() if (typeDescNameStart == ".?AV" || typeDescNameStart == ".?AU" || typeDescNameStart == ".?AW") { if (auto classInfo = ProcessRTTI(coLocatorAddr)) - m_classInfo[coLocatorAddr] = classInfo.value(); + m_classInfo[coLocatorAddr] = classInfo.value(); } } } @@ -628,7 +634,7 @@ void MicrosoftRTTIProcessor::ProcessRTTI() // Scan data sections for colocators. auto rdataSection = m_view->GetSectionByName(".rdata"); - for (const Ref& segment : m_view->GetSegments()) + for (const Ref &segment: m_view->GetSegments()) { if (segment->GetFlags() == (SegmentReadable | SegmentContainsData)) { @@ -636,30 +642,31 @@ void MicrosoftRTTIProcessor::ProcessRTTI() scan(segment); } else if (checkWritableRData && rdataSection && rdataSection->GetStart() == segment->GetStart()) { - m_logger->LogDebug("Attempting to find VirtualFunctionTables in writable rdata segment %llx", segment->GetStart()); + m_logger->LogDebug("Attempting to find VirtualFunctionTables in writable rdata segment %llx", + segment->GetStart()); scan(segment); } } - auto end_time = std::chrono::high_resolution_clock::now(); - std::chrono::duration elapsed_time = end_time - start_time; - m_logger->LogInfo("ProcessRTTI took %f seconds", elapsed_time.count()); + auto end_time = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed_time = end_time - start_time; + m_logger->LogInfo("ProcessRTTI took %f seconds", elapsed_time.count()); } void MicrosoftRTTIProcessor::ProcessVFT() { - auto start_time = std::chrono::high_resolution_clock::now(); - for (auto& [coLocatorAddr, classInfo] : m_classInfo) - { - for (auto& ref : m_view->GetDataReferences(coLocatorAddr)) - { - auto vftAddr = ref + m_view->GetAddressSize(); - if (auto vftInfo = ProcessVFT(vftAddr, classInfo)) - m_classInfo[coLocatorAddr].vft = vftInfo.value(); - } - } - - auto end_time = std::chrono::high_resolution_clock::now(); - std::chrono::duration elapsed_time = end_time - start_time; - m_logger->LogInfo("ProcessVFT took %f seconds", elapsed_time.count()); -} \ No newline at end of file + auto start_time = std::chrono::high_resolution_clock::now(); + for (auto &[coLocatorAddr, classInfo]: m_classInfo) + { + for (auto &ref: m_view->GetDataReferences(coLocatorAddr)) + { + auto vftAddr = ref + m_view->GetAddressSize(); + if (auto vftInfo = ProcessVFT(vftAddr, classInfo)) + m_classInfo[coLocatorAddr].vft = vftInfo.value(); + } + } + + auto end_time = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed_time = end_time - start_time; + m_logger->LogInfo("ProcessVFT took %f seconds", elapsed_time.count()); +}