From 77171115175039b2aef96f754005fea13d2b4375 Mon Sep 17 00:00:00 2001 From: Mark Rowe Date: Fri, 9 May 2025 15:09:23 -0700 Subject: [RTTI] Handle cxxabi vtables being referenced via RELOC_COPY 32-bit ELF binaries that are dynamically linked to the C++ runtime may use a copy relocation for the vtable. The vtable itself will be defined in the `.bss` section, and the copy relocation will cause the dynamic linker to populate it at load time from the C++ runtime library. Detect this by looking for a symbol pointing to the start of the vtable data, two pointers before the vtable address. --- plugins/rtti/itanium.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'plugins/rtti/itanium.cpp') diff --git a/plugins/rtti/itanium.cpp b/plugins/rtti/itanium.cpp index a6e85b4d..5e1cf0a8 100644 --- a/plugins/rtti/itanium.cpp +++ b/plugins/rtti/itanium.cpp @@ -291,6 +291,32 @@ Ref VMIClassTypeInfoType(BinaryView *view, uint64_t baseCount) return TypeBuilder::StructureType(structureBuilder.Finalize()).Finalize(); } +static Ref DetectPotentialCopyRelocatedVTable(BinaryView* view, uint64_t address) +{ + // 32-bit ELF binaries that are dynamically linked to the C++ runtime may use a + // copy relocation for the vtable. The vtable itself will be defined in the .bss + // section, and the copy relocation will cause the dynamic linker to populate it + // at load time from the C++ runtime library. + // + // Detect this by looking for a symbol pointing to the start of the vtable data, + // two pointers before the vtable address. + + int64_t vtableSymbolOffset = -(view->GetAddressSize() * 2); + if (!view->IsValidOffset(address) || !view->IsValidOffset(address + vtableSymbolOffset)) + return nullptr; + + // ELFView does not add a relocation record for RELOC_COPY so we use hueristics here. + if (view->IsOffsetBackedByFile(address)) + return nullptr; + if (!view->IsOffsetWritableSemantics(address)) + return nullptr; + + auto sym = view->GetSymbolByAddress(address + vtableSymbolOffset); + if (!sym || sym->GetShortName().find("__cxxabiv1") == std::string::npos) + return nullptr; + + return sym; +} std::optional ReadTypeInfoVariant(BinaryView *view, uint64_t objectAddr) { @@ -301,6 +327,9 @@ std::optional ReadTypeInfoVariant(BinaryView *view, uint64_t ob // If there is a symbol at objectAddr pointing to a symbol starting with "vtable for __cxxabiv1" Ref baseSym = GetRealSymbol(view, objectAddr, typeInfo->base); + if (!baseSym) + baseSym = DetectPotentialCopyRelocatedVTable(view, typeInfo->base); + if (baseSym == nullptr) { // Verify first that we can even read a pointer sized value at the base. -- cgit v1.3.1