summaryrefslogtreecommitdiff
path: root/plugins/rtti/rtti.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/rtti/rtti.cpp')
-rw-r--r--plugins/rtti/rtti.cpp71
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
+}