diff options
| author | Mason Reed <mason@vector35.com> | 2026-01-12 10:58:59 -0800 |
|---|---|---|
| committer | Mason Reed <35282038+emesare@users.noreply.github.com> | 2026-01-13 19:37:46 -0800 |
| commit | e299a6c1bf74f0ca6d2c3d79135e8c23e6b9fbba (patch) | |
| tree | 132683a047f4a97c0dc18a1f01df8f46b79105b1 /plugins/rtti/rtti.cpp | |
| parent | 0893694568345908163262785097878460604855 (diff) | |
[RTTI] Improve virtual function discovery
- Allow extern functions to show up in a MSVC vtable
- Fix https://github.com/Vector35/binaryninja-api/issues/7871
- Share code between itanium and msvc vft analysis, it is the same logic basically
Diffstat (limited to 'plugins/rtti/rtti.cpp')
| -rw-r--r-- | plugins/rtti/rtti.cpp | 71 |
1 files changed, 70 insertions, 1 deletions
diff --git a/plugins/rtti/rtti.cpp b/plugins/rtti/rtti.cpp index 23b13fde..fde5a6ab 100644 --- a/plugins/rtti/rtti.cpp +++ b/plugins/rtti/rtti.cpp @@ -4,6 +4,22 @@ using namespace BinaryNinja; using namespace BinaryNinja::RTTI; +Ref<Symbol> RTTI::GetRealSymbol(BinaryView *view, uint64_t relocAddr, uint64_t symAddr) +{ + if (view->IsOffsetExternSemantics(symAddr)) + { + // Because bases in the extern section are not 8 byte width only they will + // overlap with other externs, until https://github.com/Vector35/binaryninja-api/issues/6387 is fixed. + // Check relocation at objectAddr for symbol + for (const auto& r : view->GetRelocationsAt(relocAddr)) + if (auto relocSym = r->GetSymbol()) + return relocSym; + } + + return view->GetSymbolByAddress(symAddr); +} + + std::optional<std::string> RTTI::DemangleNameMS(BinaryView* view, bool allowMangled, const std::string &mangledName) { QualifiedName demangledName = {}; @@ -213,6 +229,59 @@ Ref<Metadata> RTTIProcessor::SerializedMetadata() } +bool RTTIProcessor::IsLikelyFunction(uint64_t addr) const +{ + // Disassemble to just make a little extra certain this is a function. + auto vftPlatform = m_view->GetDefaultPlatform()->GetAssociatedPlatformByAddress(addr); + Ref<Architecture> arch = vftPlatform->GetArchitecture(); + const size_t maxInstrLen = arch->GetMaxInstructionLength(); + DataBuffer instrBuffer = m_view->ReadBuffer(addr, maxInstrLen); + InstructionInfo instrInfo; + const bool validInstr = arch->GetInstructionInfo(static_cast<uint8_t*>(instrBuffer.GetData()), addr, maxInstrLen, instrInfo); + return validInstr; +} + +RTTIProcessor::FunctionDiscoverState RTTIProcessor::DiscoverVirtualFunction(uint64_t vftEntryAddr, uint64_t& vFuncAddr) +{ + if (!m_view->IsValidOffset(vftEntryAddr)) + return FunctionDiscoverState::Failed; + BinaryReader reader = BinaryReader(m_view); + reader.Seek(vftEntryAddr); + vFuncAddr = reader.ReadPointer(); + auto funcs = m_view->GetAnalysisFunctionsForAddress(vFuncAddr); + if (!funcs.empty()) + return FunctionDiscoverState::AlreadyExists; + + // Handle external virtual functions, we won't have a backing function for them. + if (!m_view->IsOffsetCodeSemantics(vFuncAddr)) + { + // TODO: Sometimes vFunc idx will be zeroed iirc. + // We allow vfuncs to point to extern functions. + // TODO: Until https://github.com/Vector35/binaryninja-api/issues/5982 is fixed we need to check extern sym relocs instead of the symbol directly + auto vFuncSym = GetRealSymbol(m_view, reader.GetOffset(), vFuncAddr); + if (!vFuncSym) + return FunctionDiscoverState::Failed; + DataVariable dv; + bool foundDv = m_view->GetDataVariableAtAddress(vFuncAddr, dv); + // Last virtual function, or hit the next vtable. + if (!foundDv || !dv.type->m_object) + return FunctionDiscoverState::Failed; + // Void externs are very likely to be a func. + // TODO: Add some sanity checks for this! + if (!dv.type->IsFunction() && !(dv.type->IsVoid() && vFuncSym->GetType() == ExternalSymbol)) + return FunctionDiscoverState::Failed; + return FunctionDiscoverState::Extern; + } + + if (!IsLikelyFunction(vFuncAddr)) + return FunctionDiscoverState::Failed; + m_logger->LogDebugF("Discovered function from virtual function table... {:#x}", vFuncAddr); + Ref<Platform> vftPlatform = m_view->GetDefaultPlatform()->GetAssociatedPlatformByAddress(vFuncAddr); + m_view->AddFunctionForAnalysis(vftPlatform, vFuncAddr, true); + return FunctionDiscoverState::Discovered; +} + + void RTTIProcessor::DeserializedMetadata(RTTIProcessorType type, const Ref<Metadata> &metadata) { std::map<std::string, Ref<Metadata>> msvcMeta = metadata->GetKeyValueStore(); @@ -228,4 +297,4 @@ void RTTIProcessor::DeserializedMetadata(RTTIProcessorType type, const Ref<Metad m_unhandledClassInfo[objectAddr] = classInfo; } } -}
\ No newline at end of file +} |
