Skip to content

Commit 5fcb488

Browse files
nullableVoidPtremesare
authored andcommitted
MSVC RTTI: Recursively define ClassHierarchyDescriptors
This will better define base classes without a CompleteObjectLocator associated with it
1 parent abaa6d1 commit 5fcb488

File tree

2 files changed

+72
-33
lines changed

2 files changed

+72
-33
lines changed

plugins/msvc_rtti/rtti.cpp

Lines changed: 70 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,64 @@ std::optional<ClassInfo> MicrosoftRTTIProcessor::ProcessRTTI(uint64_t coLocatorA
452452

453453
auto ptrBaseTy = coLocator->signature ? RelativeToBinaryStartPointerBaseType : AbsolutePointerBaseType;
454454

455+
auto defineClassHierarchyDesc = [&](const uint64_t classHierarchyDescAddr, ClassInfo& classInfo, std::optional<CompleteObjectLocator> coLocator) {
456+
auto classHierarchyDesc = ClassHierarchyDescriptor(m_view, classHierarchyDescAddr);
457+
auto classHierarchyDescName = fmt::format("{}::`RTTI Class Hierarchy Descriptor'", classInfo.className);
458+
m_view->DefineAutoSymbol(new Symbol{DataSymbol, classHierarchyDescName, classHierarchyDescAddr});
459+
m_view->DefineDataVariable(classHierarchyDescAddr,
460+
Confidence(ClassHierarchyDescriptorType(m_view, ptrBaseTy), RTTI_CONFIDENCE));
461+
462+
auto baseClassArrayAddr = resolveAddr(classHierarchyDesc.pBaseClassArray);
463+
auto baseClassArray = BaseClassArray(m_view, baseClassArrayAddr, classHierarchyDesc.numBaseClasses);
464+
auto baseClassArrayName = fmt::format("{}::`RTTI Base Class Array'", classInfo.className);
465+
m_view->DefineAutoSymbol(new Symbol{DataSymbol, baseClassArrayName, baseClassArrayAddr});
466+
m_view->DefineDataVariable(baseClassArrayAddr,
467+
Confidence(BaseClassArrayType(m_view, baseClassArray.length, ptrBaseTy),
468+
RTTI_CONFIDENCE));
469+
470+
std::map<uint64_t, ClassInfo> baseClasses = {};
471+
for (auto pBaseClassDescAddr: baseClassArray.descriptors)
472+
{
473+
auto baseClassDescAddr = resolveAddr(pBaseClassDescAddr);
474+
auto baseClassDesc = BaseClassDescriptor(m_view, baseClassDescAddr);
475+
476+
auto baseClassTypeDescAddr = resolveAddr(baseClassDesc.pTypeDescriptor);
477+
auto baseClassTypeDesc = TypeDescriptor(m_view, baseClassTypeDescAddr);
478+
auto baseClassName = DemangleName(baseClassTypeDesc.name);
479+
if (!baseClassName.has_value())
480+
{
481+
m_logger->LogWarn("Skipping BaseClassDescriptor with mangled name %llx", baseClassTypeDescAddr);
482+
continue;
483+
}
484+
485+
// TODO: we probably want to maintain this state
486+
auto baseClassInfo = ClassInfo{baseClassName.value()};
487+
488+
if (coLocator.has_value())
489+
{
490+
if (baseClassDesc.where_mdisp == coLocator->offset && !classInfo.baseClassName.has_value() && classInfo.className != baseClassInfo.className)
491+
classInfo.baseClassName = baseClassInfo.className;
492+
}
493+
494+
auto baseClassDescName = fmt::format("{}::`RTTI Base Class Descriptor at ({},{},{},{})", baseClassInfo.className,
495+
baseClassDesc.where_mdisp, baseClassDesc.where_pdisp,
496+
baseClassDesc.where_vdisp, baseClassDesc.attributes);
497+
m_view->DefineAutoSymbol(new Symbol{DataSymbol, baseClassDescName, baseClassDescAddr});
498+
m_view->DefineDataVariable(baseClassDescAddr,
499+
Confidence(BaseClassDescriptorType(m_view, ptrBaseTy), RTTI_CONFIDENCE));
500+
501+
auto baseClassTypeDescSymName = fmt::format("class {} `RTTI Type Descriptor'", baseClassInfo.className);
502+
m_view->DefineAutoSymbol(new Symbol{DataSymbol, baseClassTypeDescSymName, baseClassTypeDescAddr});
503+
m_view->DefineDataVariable(baseClassTypeDescAddr,
504+
Confidence(TypeDescriptorType(m_view, baseClassTypeDesc.name.length()), RTTI_CONFIDENCE));
505+
506+
auto classHierarchyDescAddr = resolveAddr(baseClassDesc.pClassHierarchyDescriptor);
507+
baseClasses[classHierarchyDescAddr] = baseClassInfo;
508+
}
509+
510+
return baseClasses;
511+
};
512+
455513
// Get type descriptor then check to see if the class name was demangled.
456514
auto typeDescAddr = resolveAddr(coLocator->pTypeDescriptor);
457515
auto typeDesc = TypeDescriptor(m_view, typeDescAddr);
@@ -480,43 +538,21 @@ std::optional<ClassInfo> MicrosoftRTTIProcessor::ProcessRTTI(uint64_t coLocatorA
480538
Confidence(TypeDescriptorType(m_view, typeDesc.name.length()), RTTI_CONFIDENCE));
481539

482540
auto classHierarchyDescAddr = resolveAddr(coLocator->pClassHierarchyDescriptor);
483-
auto classHierarchyDesc = ClassHierarchyDescriptor(m_view, classHierarchyDescAddr);
484-
auto classHierarchyDescName = fmt::format("{}::`RTTI Class Hierarchy Descriptor'", classInfo.className);
485-
m_view->DefineAutoSymbol(new Symbol{DataSymbol, classHierarchyDescName, classHierarchyDescAddr});
486-
m_view->DefineDataVariable(classHierarchyDescAddr,
487-
Confidence(ClassHierarchyDescriptorType(m_view, ptrBaseTy), RTTI_CONFIDENCE));
488-
489-
auto baseClassArrayAddr = resolveAddr(classHierarchyDesc.pBaseClassArray);
490-
auto baseClassArray = BaseClassArray(m_view, baseClassArrayAddr, classHierarchyDesc.numBaseClasses);
491-
auto baseClassArrayName = fmt::format("{}::`RTTI Base Class Array'", classInfo.className);
492-
m_view->DefineAutoSymbol(new Symbol{DataSymbol, baseClassArrayName, baseClassArrayAddr});
493-
m_view->DefineDataVariable(baseClassArrayAddr,
494-
Confidence(BaseClassArrayType(m_view, baseClassArray.length, ptrBaseTy),
495-
RTTI_CONFIDENCE));
496-
497-
for (auto pBaseClassDescAddr: baseClassArray.descriptors)
541+
auto baseClasses = defineClassHierarchyDesc(classHierarchyDescAddr, classInfo, coLocator);
542+
m_visitedClassHierarchyDescAddrs.insert(classHierarchyDescAddr);
543+
while (baseClasses.size() > 0)
498544
{
499-
auto baseClassDescAddr = resolveAddr(pBaseClassDescAddr);
500-
auto baseClassDesc = BaseClassDescriptor(m_view, baseClassDescAddr);
501-
502-
auto baseClassTypeDescAddr = resolveAddr(baseClassDesc.pTypeDescriptor);
503-
auto baseClassTypeDesc = TypeDescriptor(m_view, baseClassTypeDescAddr);
504-
auto baseClassName = DemangleName(baseClassTypeDesc.name);
505-
if (!baseClassName.has_value())
545+
std::map<uint64_t, ClassInfo> newBaseClasses = {};
546+
for (auto& [baseClassHierarchyDescAddr, baseClassInfo] : baseClasses)
506547
{
507-
m_logger->LogWarn("Skipping BaseClassDescriptor with mangled name %llx", baseClassTypeDescAddr);
508-
continue;
509-
}
548+
if (m_visitedClassHierarchyDescAddrs.find(baseClassHierarchyDescAddr) != m_visitedClassHierarchyDescAddrs.end())
549+
continue;
510550

511-
if (baseClassDesc.where_mdisp == coLocator->offset && classInfo.className != baseClassName.value())
512-
classInfo.baseClassName = baseClassName;
551+
newBaseClasses.merge(defineClassHierarchyDesc(baseClassHierarchyDescAddr, baseClassInfo, std::nullopt));
552+
m_visitedClassHierarchyDescAddrs.insert(baseClassHierarchyDescAddr);
553+
}
513554

514-
auto baseClassDescName = fmt::format("{}::`RTTI Base Class Descriptor at ({},{},{},{})", baseClassName.value(),
515-
baseClassDesc.where_mdisp, baseClassDesc.where_pdisp,
516-
baseClassDesc.where_vdisp, baseClassDesc.attributes);
517-
m_view->DefineAutoSymbol(new Symbol{DataSymbol, baseClassDescName, baseClassDescAddr});
518-
m_view->DefineDataVariable(baseClassDescAddr,
519-
Confidence(BaseClassDescriptorType(m_view, ptrBaseTy), RTTI_CONFIDENCE));
555+
baseClasses = newBaseClasses;
520556
}
521557

522558
auto coLocatorName = fmt::format("{}::`RTTI Complete Object Locator'", className.value());
@@ -661,6 +697,7 @@ MicrosoftRTTIProcessor::MicrosoftRTTIProcessor(const Ref<BinaryView> &view, bool
661697
allowAnonymousClassNames = allowAnonymous;
662698
checkWritableRData = checkRData;
663699
m_classInfo = {};
700+
m_visitedClassHierarchyDescAddrs = {};
664701
virtualFunctionTableSweep = vftSweep;
665702
auto metadata = view->QueryMetadata(VIEW_METADATA_MSVC);
666703
if (metadata != nullptr)

plugins/msvc_rtti/rtti.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ namespace BinaryNinja {
101101

102102
std::map<uint64_t, ClassInfo> m_classInfo;
103103

104+
std::set<uint64_t> m_visitedClassHierarchyDescAddrs;
105+
104106
void DeserializedMetadata(const Ref<Metadata> &metadata);
105107

106108
std::optional<std::string> DemangleName(const std::string &mangledName);

0 commit comments

Comments
 (0)