Skip to content

Commit e95dc2c

Browse files
committed
MSVC RTTI: Fix crash due to function creation on invalid virtual function entry
Also fix type clobbering on anonymous class names
1 parent 49bafa9 commit e95dc2c

File tree

2 files changed

+40
-18
lines changed

2 files changed

+40
-18
lines changed

plugins/msvc_rtti/rtti.cpp

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,17 @@ std::optional<ClassInfo> MicrosoftRTTIProcessor::ProcessRTTI(uint64_t coLocatorA
441441
if (!className.has_value())
442442
return std::nullopt;
443443

444+
// If the className is empty we will change it to the address, this is to fix type clobbering.
445+
if (className->empty())
446+
{
447+
if (!allowAnonymousClassNames)
448+
{
449+
m_logger->LogDebug("Skipping CompleteObjectorLocator with anonymous name %llx", coLocatorAddr);
450+
return std::nullopt;
451+
}
452+
className = fmt::format("ANONYMOUS_{:#x}", coLocatorAddr);
453+
}
454+
444455
auto classInfo = ClassInfo{className.value()};
445456
if (coLocator->offset > 0)
446457
classInfo.classOffset = coLocator->offset;
@@ -509,7 +520,8 @@ std::optional<VirtualFunctionTableInfo> MicrosoftRTTIProcessor::ProcessVFT(uint6
509520
// Gather all virtual functions
510521
BinaryReader reader = BinaryReader(m_view);
511522
reader.Seek(vftAddr);
512-
std::vector<Ref<Function> > virtualFunctions = {};
523+
// Virtual functions and the analysis object of it, if it exists.
524+
std::vector<std::pair<uint64_t, std::optional<Ref<Function>>>> virtualFunctions = {};
513525
while (true)
514526
{
515527
uint64_t vFuncAddr = reader.ReadPointer();
@@ -525,10 +537,13 @@ std::optional<VirtualFunctionTableInfo> MicrosoftRTTIProcessor::ProcessVFT(uint6
525537
// TODO: Is likely a function check here?
526538
m_logger->LogDebug("Discovered function from virtual function table... %llx", vFuncAddr);
527539
auto vFunc = m_view->AddFunctionForAnalysis(m_view->GetDefaultPlatform(), vFuncAddr, true);
528-
funcs.emplace_back(vFunc);
540+
virtualFunctions.emplace_back(vFuncAddr, vFunc ? std::optional(vFunc) : std::nullopt);
541+
}
542+
else
543+
{
544+
// Only ever add one function.
545+
virtualFunctions.emplace_back(vFuncAddr, funcs.front());
529546
}
530-
// Only ever add one function.
531-
virtualFunctions.emplace_back(funcs.front());
532547
}
533548

534549
if (virtualFunctions.empty())
@@ -537,8 +552,8 @@ std::optional<VirtualFunctionTableInfo> MicrosoftRTTIProcessor::ProcessVFT(uint6
537552
return std::nullopt;
538553
}
539554

540-
for (auto &func: virtualFunctions)
541-
vftInfo.virtualFunctions.emplace_back(VirtualFunctionInfo{func->GetStart()});
555+
for (auto &[vFuncAddr, _]: virtualFunctions)
556+
vftInfo.virtualFunctions.emplace_back(VirtualFunctionInfo{vFuncAddr});
542557

543558
// Create virtual function table type
544559
auto vftTypeName = fmt::format("{}::VTable", classInfo.className);
@@ -585,22 +600,27 @@ std::optional<VirtualFunctionTableInfo> MicrosoftRTTIProcessor::ProcessVFT(uint6
585600
}
586601
}
587602

588-
for (auto &&vFunc: virtualFunctions)
603+
for (auto &&[_, vFunc]: virtualFunctions)
589604
{
590605
auto vFuncName = fmt::format("vFunc_{}", vFuncIdx);
591-
// If we have a better name, use it.
592-
auto vFuncSymName = vFunc->GetSymbol()->GetShortName();
593-
if (vFuncSymName.compare(0, 4, "sub_") != 0)
594-
vFuncName = vFunc->GetSymbol()->GetShortName();
595-
// MyClass::func -> func
596-
std::size_t pos = vFuncName.rfind("::");
597-
if (pos != std::string::npos)
598-
vFuncName = vFuncName.substr(pos + 2);
606+
if (vFunc.has_value())
607+
{
608+
// If we have a better name, use it.
609+
auto vFuncObj = vFunc.value();
610+
auto vFuncSymName = vFuncObj->GetSymbol()->GetShortName();
611+
if (vFuncSymName.compare(0, 4, "sub_") != 0)
612+
vFuncName = vFuncObj->GetSymbol()->GetShortName();
613+
// MyClass::func -> func
614+
std::size_t pos = vFuncName.rfind("::");
615+
if (pos != std::string::npos)
616+
vFuncName = vFuncName.substr(pos + 2);
617+
}
599618

600619
// NOTE: The analyzed function type might not be available here.
601620
auto vFuncOffset = vFuncIdx * addrSize;
621+
// We have access to a backing function type, use it, otherwise void!
602622
vftBuilder.AddMemberAtOffset(
603-
Type::PointerType(addrSize, vFunc->GetType(), true), vFuncName, vFuncOffset);
623+
Type::PointerType(addrSize, vFunc.has_value() ? vFunc.value()->GetType() : Type::VoidType(), true), vFuncName, vFuncOffset);
604624
vFuncIdx++;
605625
}
606626
m_view->DefineType(typeId, vftTypeName,
@@ -616,10 +636,11 @@ std::optional<VirtualFunctionTableInfo> MicrosoftRTTIProcessor::ProcessVFT(uint6
616636
}
617637

618638

619-
MicrosoftRTTIProcessor::MicrosoftRTTIProcessor(const Ref<BinaryView> &view, bool useMangled, bool checkRData, bool vftSweep) : m_view(view)
639+
MicrosoftRTTIProcessor::MicrosoftRTTIProcessor(const Ref<BinaryView> &view, bool useMangled, bool checkRData, bool vftSweep, bool allowAnonymous) : m_view(view)
620640
{
621641
m_logger = new Logger("Microsoft RTTI");
622642
allowMangledClassNames = useMangled;
643+
allowAnonymousClassNames = allowAnonymous;
623644
checkWritableRData = checkRData;
624645
m_classInfo = {};
625646
virtualFunctionTableSweep = vftSweep;

plugins/msvc_rtti/rtti.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ namespace BinaryNinja {
9595
Ref<BinaryView> m_view;
9696
Ref<Logger> m_logger;
9797
bool allowMangledClassNames;
98+
bool allowAnonymousClassNames;
9899
bool checkWritableRData;
99100
bool virtualFunctionTableSweep;
100101

@@ -109,7 +110,7 @@ namespace BinaryNinja {
109110
std::optional<VirtualFunctionTableInfo> ProcessVFT(uint64_t vftAddr, const ClassInfo &classInfo);
110111

111112
public:
112-
MicrosoftRTTIProcessor(const Ref<BinaryView> &view, bool useMangled = true, bool checkRData = true, bool vftSweep = true);
113+
MicrosoftRTTIProcessor(const Ref<BinaryView> &view, bool useMangled = true, bool checkRData = true, bool vftSweep = true, bool allowAnonymous = true);
113114

114115
Ref<Metadata> SerializedMetadata();
115116

0 commit comments

Comments
 (0)