@@ -4,6 +4,22 @@ using namespace BinaryNinja;
44using namespace BinaryNinja ::RTTI;
55
66
7+ Ref<Symbol> RTTI::GetRealSymbol (BinaryView *view, uint64_t relocAddr, uint64_t symAddr)
8+ {
9+ if (view->IsOffsetExternSemantics (symAddr))
10+ {
11+ // Because bases in the extern section are not 8 byte width only they will
12+ // overlap with other externs, until https://github.com/Vector35/binaryninja-api/issues/6387 is fixed.
13+ // Check relocation at objectAddr for symbol
14+ for (const auto & r : view->GetRelocationsAt (relocAddr))
15+ if (auto relocSym = r->GetSymbol ())
16+ return relocSym;
17+ }
18+
19+ return view->GetSymbolByAddress (symAddr);
20+ }
21+
22+
723std::optional<std::string> RTTI::DemangleNameMS (BinaryView* view, bool allowMangled, const std::string &mangledName)
824{
925 QualifiedName demangledName = {};
@@ -213,6 +229,59 @@ Ref<Metadata> RTTIProcessor::SerializedMetadata()
213229}
214230
215231
232+ bool RTTIProcessor::IsLikelyFunction (uint64_t addr) const
233+ {
234+ // Disassemble to just make a little extra certain this is a function.
235+ auto vftPlatform = m_view->GetDefaultPlatform ()->GetAssociatedPlatformByAddress (addr);
236+ Ref<Architecture> arch = vftPlatform->GetArchitecture ();
237+ const size_t maxInstrLen = arch->GetMaxInstructionLength ();
238+ DataBuffer instrBuffer = m_view->ReadBuffer (addr, maxInstrLen);
239+ InstructionInfo instrInfo;
240+ const bool validInstr = arch->GetInstructionInfo (static_cast <uint8_t *>(instrBuffer.GetData ()), addr, maxInstrLen, instrInfo);
241+ return validInstr;
242+ }
243+
244+ RTTIProcessor::FunctionDiscoverState RTTIProcessor::DiscoverVirtualFunction (uint64_t vftEntryAddr, uint64_t & vFuncAddr)
245+ {
246+ if (!m_view->IsValidOffset (vftEntryAddr))
247+ return FunctionDiscoverState::Failed;
248+ BinaryReader reader = BinaryReader (m_view);
249+ reader.Seek (vftEntryAddr);
250+ vFuncAddr = reader.ReadPointer ();
251+ auto funcs = m_view->GetAnalysisFunctionsForAddress (vFuncAddr);
252+ if (!funcs.empty ())
253+ return FunctionDiscoverState::AlreadyExists;
254+
255+ // Handle external virtual functions, we won't have a backing function for them.
256+ if (!m_view->IsOffsetCodeSemantics (vFuncAddr))
257+ {
258+ // TODO: Sometimes vFunc idx will be zeroed iirc.
259+ // We allow vfuncs to point to extern functions.
260+ // TODO: Until https://github.com/Vector35/binaryninja-api/issues/5982 is fixed we need to check extern sym relocs instead of the symbol directly
261+ auto vFuncSym = GetRealSymbol (m_view, reader.GetOffset (), vFuncAddr);
262+ if (!vFuncSym)
263+ return FunctionDiscoverState::Failed;
264+ DataVariable dv;
265+ bool foundDv = m_view->GetDataVariableAtAddress (vFuncAddr, dv);
266+ // Last virtual function, or hit the next vtable.
267+ if (!foundDv || !dv.type ->m_object )
268+ return FunctionDiscoverState::Failed;
269+ // Void externs are very likely to be a func.
270+ // TODO: Add some sanity checks for this!
271+ if (!dv.type ->IsFunction () && !(dv.type ->IsVoid () && vFuncSym->GetType () == ExternalSymbol))
272+ return FunctionDiscoverState::Failed;
273+ return FunctionDiscoverState::Extern;
274+ }
275+
276+ if (!IsLikelyFunction (vFuncAddr))
277+ return FunctionDiscoverState::Failed;
278+ m_logger->LogDebugF (" Discovered function from virtual function table... {:#x}" , vFuncAddr);
279+ Ref<Platform> vftPlatform = m_view->GetDefaultPlatform ()->GetAssociatedPlatformByAddress (vFuncAddr);
280+ m_view->AddFunctionForAnalysis (vftPlatform, vFuncAddr, true );
281+ return FunctionDiscoverState::Discovered;
282+ }
283+
284+
216285void RTTIProcessor::DeserializedMetadata (RTTIProcessorType type, const Ref<Metadata> &metadata)
217286{
218287 std::map<std::string, Ref<Metadata>> msvcMeta = metadata->GetKeyValueStore ();
@@ -228,4 +297,4 @@ void RTTIProcessor::DeserializedMetadata(RTTIProcessorType type, const Ref<Metad
228297 m_unhandledClassInfo[objectAddr] = classInfo;
229298 }
230299 }
231- }
300+ }
0 commit comments