From b8092fa9ca49b6ed5f1776e7ccc917e257f977e7 Mon Sep 17 00:00:00 2001 From: nullableVoidPtr <30564701+nullableVoidPtr@users.noreply.github.com> Date: Mon, 20 Jan 2025 16:48:44 +1100 Subject: [PATCH 1/4] [MSVC RTTI] Define attribute enumerations for Base Class Descriptors and Class Hierarchy Descriptors --- plugins/msvc_rtti/rtti.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/plugins/msvc_rtti/rtti.cpp b/plugins/msvc_rtti/rtti.cpp index 7dfa6130aa..1ec8539307 100644 --- a/plugins/msvc_rtti/rtti.cpp +++ b/plugins/msvc_rtti/rtti.cpp @@ -141,6 +141,7 @@ Ref BaseClassDescriptorType(BinaryView *view, BNPointerBaseType ptrBaseTy) if (typeCache == nullptr) { + Ref arch = view->GetDefaultArchitecture(); Ref uintType = Type::IntegerType(4, false); StructureBuilder baseClassDescriptorBuilder; @@ -151,7 +152,17 @@ Ref BaseClassDescriptorType(BinaryView *view, BNPointerBaseType ptrBaseTy) baseClassDescriptorBuilder.AddMember(pTypeDescType, "pTypeDescriptor"); baseClassDescriptorBuilder.AddMember(uintType, "numContainedBases"); baseClassDescriptorBuilder.AddMember(GetPMDType(view), "where"); - baseClassDescriptorBuilder.AddMember(uintType, "attributes"); + Ref attrEnum = EnumerationBuilder() + .AddMemberWithValue("BCD_NOT_VISIBLE", 0x01) + .AddMemberWithValue("BCD_AMBIGUOUS", 0x02) + .AddMemberWithValue("BCD_PRIVORPROTBASE", 0x04) + .AddMemberWithValue("BCD_PRIVORPROTINCOMPOBJ", 0x08) + .AddMemberWithValue("BCD_VBOFCONTOBJ", 0x10) + .AddMemberWithValue("BCD_NONPOLYMORPHIC", 0x20) + .AddMemberWithValue("BCD_HASPCHD", 0x40) + .Finalize(); + Ref attrType = Type::EnumerationType(arch, attrEnum, 4); + baseClassDescriptorBuilder.AddMember(attrType, "attributes"); Ref pClassDescType = TypeBuilder::PointerType(4, ClassHierarchyDescriptorType(view, ptrBaseTy)) .SetPointerBase(ptrBaseTy, 0) .Finalize(); @@ -185,11 +196,18 @@ Ref ClassHierarchyDescriptorType(BinaryView *view, BNPointerBaseType ptrBa if (typeCache == nullptr) { + Ref arch = view->GetDefaultArchitecture(); Ref uintType = Type::IntegerType(4, false); StructureBuilder classHierarchyDescriptorBuilder; classHierarchyDescriptorBuilder.AddMember(uintType, "signature"); - classHierarchyDescriptorBuilder.AddMember(uintType, "attributes"); + Ref attrEnum = EnumerationBuilder() + .AddMemberWithValue("CHD_MULTINH", 0x01) + .AddMemberWithValue("CHD_VIRTINH", 0x02) + .AddMemberWithValue("CHD_AMBIGUOUS", 0x04) + .Finalize(); + Ref attrType = Type::EnumerationType(arch, attrEnum, 4); + classHierarchyDescriptorBuilder.AddMember(attrType, "attributes"); classHierarchyDescriptorBuilder.AddMember(uintType, "numBaseClasses"); Ref pBaseClassArrayType = TypeBuilder::PointerType(4, Type::VoidType()) .SetPointerBase(ptrBaseTy, 0) From ed35d786cf26262cfc588504d1d71a7be876b2cf Mon Sep 17 00:00:00 2001 From: nullableVoidPtr <30564701+nullableVoidPtr@users.noreply.github.com> Date: Mon, 20 Jan 2025 17:43:24 +1100 Subject: [PATCH 2/4] fix: typo on pClassHierarchyDescriptor --- plugins/msvc_rtti/rtti.cpp | 8 ++++---- plugins/msvc_rtti/rtti.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/msvc_rtti/rtti.cpp b/plugins/msvc_rtti/rtti.cpp index 1ec8539307..afaa8424e8 100644 --- a/plugins/msvc_rtti/rtti.cpp +++ b/plugins/msvc_rtti/rtti.cpp @@ -60,7 +60,7 @@ CompleteObjectLocator::CompleteObjectLocator(BinaryView *view, uint64_t address) offset = reader.Read32(); cdOffset = reader.Read32(); pTypeDescriptor = static_cast(reader.Read32()); - pClassHeirarchyDescriptor = static_cast(reader.Read32()); + pClassHierarchyDescriptor = static_cast(reader.Read32()); if (signature == COL_SIG_REV1) { pSelf = static_cast(reader.Read32()); @@ -93,7 +93,7 @@ std::optional ReadCompleteObjectorLocator(BinaryView *vie if (outsideSection(coLocator.pTypeDescriptor + startAddr)) return std::nullopt; - if (outsideSection(coLocator.pClassHeirarchyDescriptor + startAddr)) + if (outsideSection(coLocator.pClassHierarchyDescriptor + startAddr)) return std::nullopt; } else @@ -102,7 +102,7 @@ std::optional ReadCompleteObjectorLocator(BinaryView *vie if (outsideSection(coLocator.pTypeDescriptor)) return std::nullopt; - if (outsideSection(coLocator.pClassHeirarchyDescriptor)) + if (outsideSection(coLocator.pClassHierarchyDescriptor)) return std::nullopt; } @@ -479,7 +479,7 @@ std::optional MicrosoftRTTIProcessor::ProcessRTTI(uint64_t coLocatorA m_view->DefineDataVariable(typeDescAddr, Confidence(TypeDescriptorType(m_view, typeDesc.name.length()), RTTI_CONFIDENCE)); - auto classHierarchyDescAddr = resolveAddr(coLocator->pClassHeirarchyDescriptor); + auto classHierarchyDescAddr = resolveAddr(coLocator->pClassHierarchyDescriptor); auto classHierarchyDesc = ClassHierarchyDescriptor(m_view, classHierarchyDescAddr); auto classHierarchyDescName = fmt::format("{}::`RTTI Class Hierarchy Descriptor'", classInfo.className); m_view->DefineAutoSymbol(new Symbol{DataSymbol, classHierarchyDescName, classHierarchyDescAddr}); diff --git a/plugins/msvc_rtti/rtti.h b/plugins/msvc_rtti/rtti.h index 062c7b78fc..ab964ba941 100644 --- a/plugins/msvc_rtti/rtti.h +++ b/plugins/msvc_rtti/rtti.h @@ -51,7 +51,7 @@ namespace BinaryNinja { uint32_t offset; uint32_t cdOffset; int32_t pTypeDescriptor; - int32_t pClassHeirarchyDescriptor; + int32_t pClassHierarchyDescriptor; // Only on 64 bit int32_t pSelf; From 7a74f802772216dfa3704e26e4aa986d908c97e1 Mon Sep 17 00:00:00 2001 From: nullableVoidPtr <30564701+nullableVoidPtr@users.noreply.github.com> Date: Mon, 20 Jan 2025 19:39:07 +1100 Subject: [PATCH 3/4] [MSVC RTTI] recursively define ClassHierarchyDescriptors This will better define base classes without a CompleteObjectLocator associated with it --- plugins/msvc_rtti/rtti.cpp | 103 +++++++++++++++++++++++++------------ plugins/msvc_rtti/rtti.h | 2 + 2 files changed, 72 insertions(+), 33 deletions(-) diff --git a/plugins/msvc_rtti/rtti.cpp b/plugins/msvc_rtti/rtti.cpp index afaa8424e8..f1d172a1a9 100644 --- a/plugins/msvc_rtti/rtti.cpp +++ b/plugins/msvc_rtti/rtti.cpp @@ -452,6 +452,64 @@ std::optional MicrosoftRTTIProcessor::ProcessRTTI(uint64_t coLocatorA auto ptrBaseTy = coLocator->signature ? RelativeToBinaryStartPointerBaseType : AbsolutePointerBaseType; + auto defineClassHierarchyDesc = [&](const uint64_t classHierarchyDescAddr, ClassInfo& classInfo, std::optional coLocator) { + 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)); + + 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)); + + std::map baseClasses = {}; + for (auto pBaseClassDescAddr: baseClassArray.descriptors) + { + auto baseClassDescAddr = resolveAddr(pBaseClassDescAddr); + auto baseClassDesc = BaseClassDescriptor(m_view, baseClassDescAddr); + + auto baseClassTypeDescAddr = resolveAddr(baseClassDesc.pTypeDescriptor); + auto baseClassTypeDesc = TypeDescriptor(m_view, baseClassTypeDescAddr); + auto baseClassName = DemangleName(baseClassTypeDesc.name); + if (!baseClassName.has_value()) + { + m_logger->LogWarn("Skipping BaseClassDescriptor with mangled name %llx", baseClassTypeDescAddr); + continue; + } + + // TODO: we probably want to maintain this state + auto baseClassInfo = ClassInfo{baseClassName.value()}; + + if (coLocator.has_value()) + { + if (baseClassDesc.where_mdisp == coLocator->offset && !classInfo.baseClassName.has_value() && classInfo.className != baseClassInfo.className) + classInfo.baseClassName = baseClassInfo.className; + } + + auto baseClassDescName = fmt::format("{}::`RTTI Base Class Descriptor at ({},{},{},{})", baseClassInfo.className, + 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)); + + auto baseClassTypeDescSymName = fmt::format("class {} `RTTI Type Descriptor'", baseClassInfo.className); + m_view->DefineAutoSymbol(new Symbol{DataSymbol, baseClassTypeDescSymName, baseClassTypeDescAddr}); + m_view->DefineDataVariable(baseClassTypeDescAddr, + Confidence(TypeDescriptorType(m_view, baseClassTypeDesc.name.length()), RTTI_CONFIDENCE)); + + auto classHierarchyDescAddr = resolveAddr(baseClassDesc.pClassHierarchyDescriptor); + baseClasses[classHierarchyDescAddr] = baseClassInfo; + } + + return baseClasses; + }; + // Get type descriptor then check to see if the class name was demangled. auto typeDescAddr = resolveAddr(coLocator->pTypeDescriptor); auto typeDesc = TypeDescriptor(m_view, typeDescAddr); @@ -480,43 +538,21 @@ std::optional MicrosoftRTTIProcessor::ProcessRTTI(uint64_t coLocatorA Confidence(TypeDescriptorType(m_view, typeDesc.name.length()), RTTI_CONFIDENCE)); auto classHierarchyDescAddr = resolveAddr(coLocator->pClassHierarchyDescriptor); - 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)); - - 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)); - - for (auto pBaseClassDescAddr: baseClassArray.descriptors) + auto baseClasses = defineClassHierarchyDesc(classHierarchyDescAddr, classInfo, coLocator); + m_visitedClassHierarchyDescAddrs.insert(classHierarchyDescAddr); + while (baseClasses.size() > 0) { - auto baseClassDescAddr = resolveAddr(pBaseClassDescAddr); - auto baseClassDesc = BaseClassDescriptor(m_view, baseClassDescAddr); - - auto baseClassTypeDescAddr = resolveAddr(baseClassDesc.pTypeDescriptor); - auto baseClassTypeDesc = TypeDescriptor(m_view, baseClassTypeDescAddr); - auto baseClassName = DemangleName(baseClassTypeDesc.name); - if (!baseClassName.has_value()) + std::map newBaseClasses = {}; + for (auto& [baseClassHierarchyDescAddr, baseClassInfo] : baseClasses) { - m_logger->LogWarn("Skipping BaseClassDescriptor with mangled name %llx", baseClassTypeDescAddr); - continue; - } + if (m_visitedClassHierarchyDescAddrs.find(baseClassHierarchyDescAddr) != m_visitedClassHierarchyDescAddrs.end()) + continue; - if (baseClassDesc.where_mdisp == coLocator->offset && classInfo.className != baseClassName.value()) - classInfo.baseClassName = baseClassName; + newBaseClasses.merge(defineClassHierarchyDesc(baseClassHierarchyDescAddr, baseClassInfo, std::nullopt)); + m_visitedClassHierarchyDescAddrs.insert(baseClassHierarchyDescAddr); + } - 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)); + baseClasses = newBaseClasses; } auto coLocatorName = fmt::format("{}::`RTTI Complete Object Locator'", className.value()); @@ -661,6 +697,7 @@ MicrosoftRTTIProcessor::MicrosoftRTTIProcessor(const Ref &view, bool allowAnonymousClassNames = allowAnonymous; checkWritableRData = checkRData; m_classInfo = {}; + m_visitedClassHierarchyDescAddrs = {}; virtualFunctionTableSweep = vftSweep; auto metadata = view->QueryMetadata(VIEW_METADATA_MSVC); if (metadata != nullptr) diff --git a/plugins/msvc_rtti/rtti.h b/plugins/msvc_rtti/rtti.h index ab964ba941..0bb3a73352 100644 --- a/plugins/msvc_rtti/rtti.h +++ b/plugins/msvc_rtti/rtti.h @@ -101,6 +101,8 @@ namespace BinaryNinja { std::map m_classInfo; + std::set m_visitedClassHierarchyDescAddrs; + void DeserializedMetadata(const Ref &metadata); std::optional DemangleName(const std::string &mangledName); From 5553d1671a82ba868413c7eb9e39d4cb0120b630 Mon Sep 17 00:00:00 2001 From: nullableVoidPtr <30564701+nullableVoidPtr@users.noreply.github.com> Date: Mon, 20 Jan 2025 19:58:33 +1100 Subject: [PATCH 4/4] [MSVC RTTI] narrow when pClassHierarchyDescriptor is recursed into --- plugins/msvc_rtti/rtti.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/msvc_rtti/rtti.cpp b/plugins/msvc_rtti/rtti.cpp index f1d172a1a9..07a33d61d5 100644 --- a/plugins/msvc_rtti/rtti.cpp +++ b/plugins/msvc_rtti/rtti.cpp @@ -6,6 +6,7 @@ constexpr int COL_SIG_REV0 = 0; constexpr int COL_SIG_REV1 = 1; constexpr int RTTI_CONFIDENCE = 100; +constexpr int BCD_HASPCHD = 0x40; ClassHierarchyDescriptor::ClassHierarchyDescriptor(BinaryView *view, uint64_t address) { @@ -503,8 +504,10 @@ std::optional MicrosoftRTTIProcessor::ProcessRTTI(uint64_t coLocatorA m_view->DefineDataVariable(baseClassTypeDescAddr, Confidence(TypeDescriptorType(m_view, baseClassTypeDesc.name.length()), RTTI_CONFIDENCE)); - auto classHierarchyDescAddr = resolveAddr(baseClassDesc.pClassHierarchyDescriptor); - baseClasses[classHierarchyDescAddr] = baseClassInfo; + if (baseClassDesc.attributes & BCD_HASPCHD) { + auto classHierarchyDescAddr = resolveAddr(baseClassDesc.pClassHierarchyDescriptor); + baseClasses[classHierarchyDescAddr] = baseClassInfo; + } } return baseClasses;