summaryrefslogtreecommitdiff
path: root/plugins/rtti/itanium.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/rtti/itanium.cpp')
-rw-r--r--plugins/rtti/itanium.cpp104
1 files changed, 50 insertions, 54 deletions
diff --git a/plugins/rtti/itanium.cpp b/plugins/rtti/itanium.cpp
index 9570c37b..e1af724b 100644
--- a/plugins/rtti/itanium.cpp
+++ b/plugins/rtti/itanium.cpp
@@ -238,35 +238,6 @@ std::optional<TypeInfoVariant> ReadTypeInfoVariant(BinaryView *view, uint64_t ob
}
-Ref<Metadata> ItaniumRTTIProcessor::SerializedMetadata()
-{
- std::map<std::string, Ref<Metadata> > classesMeta;
- for (auto &[coLocatorAddr, classInfo]: m_classInfo)
- {
- auto addrStr = std::to_string(coLocatorAddr);
- classesMeta[addrStr] = classInfo.SerializedMetadata();
- }
-
- std::map<std::string, Ref<Metadata> > msvcMeta;
- msvcMeta["classes"] = new Metadata(classesMeta);
- return new Metadata(msvcMeta);
-}
-
-
-void ItaniumRTTIProcessor::DeserializedMetadata(const Ref<Metadata> &metadata)
-{
- std::map<std::string, Ref<Metadata> > msvcMeta = metadata->GetKeyValueStore();
- if (msvcMeta.find("classes") != msvcMeta.end())
- {
- for (auto &[objectAddrStr, classInfoMeta]: msvcMeta["classes"]->GetKeyValueStore())
- {
- uint64_t objectAddr = std::stoull(objectAddrStr);
- m_classInfo[objectAddr] = ClassInfo::DeserializedMetadata(classInfoMeta);
- }
- }
-}
-
-
std::optional<ClassInfo> ItaniumRTTIProcessor::ProcessRTTI(uint64_t objectAddr)
{
// TODO: You cant get subobject offsets from rtti, its stored above this ptr in vtable.
@@ -279,7 +250,7 @@ std::optional<ClassInfo> ItaniumRTTIProcessor::ProcessRTTI(uint64_t objectAddr)
auto className = DemangleNameItanium(m_view, allowMangledClassNames, typeInfo.type_name);
if (!className.has_value())
return std::nullopt;
- auto classInfo = ClassInfo{className.value()};
+ auto classInfo = ClassInfo{RTTIProcessorType::Itanium, className.value()};
auto typeInfoName = fmt::format("_typeinfo_for_{}", classInfo.className);
auto typeInfoSymbol = m_view->GetSymbolByAddress(objectAddr);
@@ -303,6 +274,8 @@ std::optional<ClassInfo> ItaniumRTTIProcessor::ProcessRTTI(uint64_t objectAddr)
return std::nullopt;
}
classInfo.baseClassName = baseClassName;
+ // NOTE: The base class offset is not able to be resolved here.
+ // NOTE: To resolve the base class offset you must go to the vtable.
m_view->DefineDataVariable(objectAddr, Confidence(SIClassTypeInfoType(m_view), 255));
}
else if (typeInfoVariant == TIVVMIClass)
@@ -321,12 +294,12 @@ std::optional<ClassInfo> ItaniumRTTIProcessor::ProcessRTTI(uint64_t objectAddr)
}
-std::optional<VirtualFunctionTableInfo> ItaniumRTTIProcessor::ProcessVTT(uint64_t vttAddr, const ClassInfo &classInfo)
+std::optional<VirtualFunctionTableInfo> ItaniumRTTIProcessor::ProcessVFT(uint64_t vftAddr, ClassInfo &classInfo)
{
- VirtualFunctionTableInfo vttInfo = {vttAddr};
- // Gather all virtual functions
+ VirtualFunctionTableInfo vftInfo = {vftAddr};
BinaryReader reader = BinaryReader(m_view);
- reader.Seek(vttAddr);
+ reader.Seek(vftAddr);
+ // Gather all virtual functions
std::vector<Ref<Function> > virtualFunctions = {};
while (true)
{
@@ -340,6 +313,7 @@ std::optional<VirtualFunctionTableInfo> ItaniumRTTIProcessor::ProcessVTT(uint64_
// Last CompleteObjectLocator or hit the next CompleteObjectLocator
break;
}
+ // TODO: Sometimes vFunc idx will be zeroed.
// TODO: Is likely a function check here?
m_logger->LogDebug("Discovered function from virtual function table... %llx", vFuncAddr);
auto vFunc = m_view->AddFunctionForAnalysis(m_view->GetDefaultPlatform(), vFuncAddr, true);
@@ -351,19 +325,33 @@ std::optional<VirtualFunctionTableInfo> ItaniumRTTIProcessor::ProcessVTT(uint64_
if (virtualFunctions.empty())
{
- m_logger->LogDebug("Skipping empty virtual function table... %llx", vttAddr);
+ m_logger->LogDebug("Skipping empty virtual function table... %llx", vftAddr);
return std::nullopt;
}
+ // All vft verification has been done, we can write the classOffset now.
+ if (classInfo.baseClassName.has_value() && !classInfo.classOffset.has_value())
+ {
+ // Because we have this we _need_ to have the adjustment stuff.
+ // NOTE: We assume two 0x4 ints with the first being what we want.
+ // NOTE: This is where we actually classOffset is pulled.
+ reader.Seek(vftAddr - 0x10);
+ auto adjustmentOffset = static_cast<int32_t>(reader.Read32());
+ auto _what = static_cast<int32_t>(reader.Read32());
+ uint64_t classOffset = std::abs(adjustmentOffset);
+ classInfo.classOffset = classOffset;
+ }
+
+
for (auto &func: virtualFunctions)
- vttInfo.virtualFunctions.emplace_back(VirtualFunctionInfo{func->GetStart()});
+ vftInfo.virtualFunctions.emplace_back(VirtualFunctionInfo{func->GetStart()});
// Create virtual function table type
auto vftTypeName = fmt::format("{}::VTable", classInfo.className);
if (classInfo.baseClassName.has_value())
{
- vftTypeName = fmt::format("{}::{}", classInfo.baseClassName.value(), vftTypeName);
// TODO: What is the correct form for the name?
+ vftTypeName = fmt::format("{}::{}", classInfo.baseClassName.value(), vftTypeName);
}
// TODO: Hack the debug type id is used here to allow the PDB type (debug info) to overwrite the RTTI vtable type.
auto typeId = Type::GenerateAutoDebugTypeId(vftTypeName);
@@ -376,16 +364,16 @@ std::optional<VirtualFunctionTableInfo> ItaniumRTTIProcessor::ProcessVTT(uint64_
vftBuilder.SetPropagateDataVariableReferences(true);
size_t vFuncIdx = 0;
- // Until https://github.com/Vector35/binaryninja-api/issues/5982 is fixed
+ // TODO: Until https://github.com/Vector35/binaryninja-api/issues/5982 is fixed
auto vftSize = virtualFunctions.size() * addrSize;
vftBuilder.SetWidth(vftSize);
if (auto baseVft = classInfo.baseVft)
{
- if (classInfo.baseVft->virtualFunctions.size() <= virtualFunctions.size())
+ if (baseVft->virtualFunctions.size() <= virtualFunctions.size())
{
// Adjust the current vFunc index to the end of the shared vFuncs.
- vFuncIdx = classInfo.baseVft->virtualFunctions.size();
+ vFuncIdx = baseVft->virtualFunctions.size();
virtualFunctions.erase(virtualFunctions.begin(), virtualFunctions.begin() + vFuncIdx);
// We should set the vtable as a base class so that xrefs are propagated (among other things).
// NOTE: this means that `this` params will be assumed pre-adjusted, this is normally fine assuming type propagation
@@ -399,7 +387,7 @@ std::optional<VirtualFunctionTableInfo> ItaniumRTTIProcessor::ProcessVTT(uint64_
}
else
{
- LogWarn("Skipping adjustments for base VFT with more functions than sub VFT... %llx", vttAddr);
+ LogWarn("Skipping adjustments for base VFT with more functions than sub VFT... %llx", vftAddr);
}
}
@@ -425,20 +413,22 @@ std::optional<VirtualFunctionTableInfo> ItaniumRTTIProcessor::ProcessVTT(uint64_
Confidence(TypeBuilder::StructureType(vftBuilder.Finalize()).Finalize(), RTTI_CONFIDENCE));
}
- auto vftName = fmt::format("_vtable_for_", classInfo.className);
+ auto vftName = fmt::format("_vtable_for_{}", classInfo.className);
+ // TODO: How to display base classes?
if (classInfo.baseClassName.has_value())
vftName += fmt::format("{{for `{}'}}", classInfo.baseClassName.value());
- auto vttSymbol = m_view->GetSymbolByAddress(vttAddr);
- if (vttSymbol != nullptr)
- m_view->UndefineAutoSymbol(vttSymbol);
- m_view->DefineAutoSymbol(new Symbol{DataSymbol, vftName, vttAddr});
- m_view->DefineDataVariable(vttAddr, Confidence(Type::NamedType(m_view, vftTypeName), RTTI_CONFIDENCE));
- return vttInfo;
+ auto vftSymbol = m_view->GetSymbolByAddress(vftAddr);
+ if (vftSymbol != nullptr)
+ m_view->UndefineAutoSymbol(vftSymbol);
+ m_view->DefineAutoSymbol(new Symbol{DataSymbol, vftName, vftAddr});
+ m_view->DefineDataVariable(vftAddr, Confidence(Type::NamedType(m_view, vftTypeName), RTTI_CONFIDENCE));
+ return vftInfo;
}
-ItaniumRTTIProcessor::ItaniumRTTIProcessor(const Ref<BinaryView> &view, bool useMangled, bool checkRData, bool vftSweep) : m_view(view)
+ItaniumRTTIProcessor::ItaniumRTTIProcessor(const Ref<BinaryView> &view, bool useMangled, bool checkRData, bool vftSweep)
{
+ m_view = view;
m_logger = new Logger("Itanium RTTI");
allowMangledClassNames = useMangled;
checkWritableRData = checkRData;
@@ -449,7 +439,7 @@ ItaniumRTTIProcessor::ItaniumRTTIProcessor(const Ref<BinaryView> &view, bool use
if (metadata != nullptr)
{
// Load in metadata to the processor.
- DeserializedMetadata(metadata);
+ DeserializedMetadata(RTTIProcessorType::Itanium, metadata);
}
}
@@ -485,7 +475,7 @@ void ItaniumRTTIProcessor::ProcessRTTI()
}
-void ItaniumRTTIProcessor::ProcessVTT()
+void ItaniumRTTIProcessor::ProcessVFT()
{
std::map<uint64_t, uint64_t> vftMap = {};
std::map<uint64_t, std::optional<VirtualFunctionTableInfo>> vftFinishedMap = {};
@@ -494,6 +484,10 @@ void ItaniumRTTIProcessor::ProcessVTT()
{
for (auto &ref: m_view->GetDataReferences(coLocatorAddr))
{
+ // Skip refs from other type info.
+ DataVariable dv;
+ if (m_view->GetDataVariableAtAddress(ref, dv) && m_classInfo.find(dv.address) != m_classInfo.end())
+ continue;
// TODO: This is not pointing at where it should, remember that the vtable will be inside another structure.
auto vftAddr = ref + m_view->GetAddressSize();
vftMap[coLocatorAddr] = vftAddr;
@@ -537,12 +531,12 @@ void ItaniumRTTIProcessor::ProcessVTT()
}
}
- auto GetCachedVFTInfo = [&](uint64_t vftAddr, const ClassInfo& classInfo) {
+ auto GetCachedVFTInfo = [&](uint64_t vftAddr, ClassInfo& classInfo) {
// Check in the cache so that we don't process vfts more than once.
auto cachedVftInfo = vftFinishedMap.find(vftAddr);
if (cachedVftInfo != vftFinishedMap.end())
return cachedVftInfo->second;
- auto vftInfo = ProcessVTT(vftAddr, classInfo);
+ auto vftInfo = ProcessVFT(vftAddr, classInfo);
vftFinishedMap[vftAddr] = vftInfo;
return vftInfo;
};
@@ -553,7 +547,7 @@ void ItaniumRTTIProcessor::ProcessVTT()
if (classInfo.baseClassName.has_value())
{
// Process base vtable and add it to the class info.
- for (auto& [baseCoLocAddr, baseClassInfo] : m_classInfo)
+ for (auto [baseCoLocAddr, baseClassInfo] : m_classInfo)
{
if (baseClassInfo.className == classInfo.baseClassName.value())
{
@@ -569,6 +563,8 @@ void ItaniumRTTIProcessor::ProcessVTT()
if (auto vftInfo = GetCachedVFTInfo(vftAddr, classInfo))
classInfo.vft = vftInfo.value();
+
+ m_classInfo[coLocatorAddr] = classInfo;
}
auto end_time = std::chrono::high_resolution_clock::now();