#include "rtti.h" using namespace BinaryNinja; using namespace BinaryNinja::RTTI; std::optional RTTI::DemangleNameMS(BinaryView* view, bool allowMangled, const std::string &mangledName) { QualifiedName demangledName = {}; Ref outType = {}; if (!DemangleMS(view->GetDefaultArchitecture(), mangledName, outType, demangledName, true)) return DemangleNameLLVM(allowMangled, mangledName); return demangledName.GetString(); } std::string RemoveItaniumPrefix(const std::string& name) { // Remove class prefixes. // 7 is class_type // 9 is si_class_type // 14 is vmi_class_type if (name.rfind('7', 0) == 0) return name.substr(1); if (name.rfind('9', 0) == 0) return name.substr(1); if (name.rfind("14", 0) == 0) return name.substr(2); return name; } std::optional RTTI::DemangleNameItanium(BinaryView* view, bool allowMangled, const std::string &mangledName) { if (auto demangledName = DemangleNameLLVM(allowMangled, mangledName)) return RemoveItaniumPrefix(demangledName.value()); return std::nullopt; } std::optional RTTI::DemangleNameLLVM(bool allowMangled, const std::string &mangledName) { QualifiedName demangledName = {}; Ref outType = {}; if (!DemangleLLVM(mangledName, demangledName, true)) return allowMangled ? std::optional(mangledName) : std::nullopt; auto demangledNameStr = demangledName.GetString(); size_t beginFind = demangledNameStr.find_first_of(' '); if (beginFind != std::string::npos) demangledNameStr.erase(0, beginFind + 1); size_t endFind = demangledNameStr.find(" `RTTI Type Descriptor Name'"); if (endFind != std::string::npos) demangledNameStr.erase(endFind, demangledNameStr.length()); return demangledNameStr; } Ref ClassInfo::SerializedMetadata() { std::map > classInfoMeta; classInfoMeta["className"] = new Metadata(className); if (baseClassName.has_value()) classInfoMeta["baseClassName"] = new Metadata(baseClassName.value()); if (classOffset.has_value()) classInfoMeta["classOffset"] = new Metadata(classOffset.value()); if (vft.has_value()) classInfoMeta["vft"] = vft->SerializedMetadata(); // NOTE: We omit baseVft as it can be resolved manually and just bloats the size. return new Metadata(classInfoMeta); } ClassInfo ClassInfo::DeserializedMetadata(const Ref &metadata) { std::map > classInfoMeta = metadata->GetKeyValueStore(); ClassInfo info = {classInfoMeta["className"]->GetString()}; if (classInfoMeta.find("baseClassName") != classInfoMeta.end()) info.baseClassName = classInfoMeta["baseClassName"]->GetString(); if (classInfoMeta.find("classOffset") != classInfoMeta.end()) info.classOffset = classInfoMeta["classOffset"]->GetUnsignedInteger(); if (classInfoMeta.find("vft") != classInfoMeta.end()) info.vft = VirtualFunctionTableInfo::DeserializedMetadata(classInfoMeta["vft"]); return info; } Ref VirtualFunctionTableInfo::SerializedMetadata() { std::vector > funcsMeta; funcsMeta.reserve(virtualFunctions.size()); for (auto &vFunc: virtualFunctions) funcsMeta.emplace_back(vFunc.SerializedMetadata()); std::map > vftMeta; vftMeta["address"] = new Metadata(address); vftMeta["functions"] = new Metadata(funcsMeta); return new Metadata(vftMeta); } VirtualFunctionTableInfo VirtualFunctionTableInfo::DeserializedMetadata(const Ref &metadata) { std::map > vftMeta = metadata->GetKeyValueStore(); VirtualFunctionTableInfo vftInfo = {vftMeta["address"]->GetUnsignedInteger()}; if (vftMeta.find("functions") != vftMeta.end()) { for (auto &entry: vftMeta["functions"]->GetArray()) vftInfo.virtualFunctions.emplace_back(VirtualFunctionInfo::DeserializedMetadata(entry)); } return vftInfo; } Ref VirtualFunctionInfo::SerializedMetadata() { std::map > vFuncMeta; vFuncMeta["address"] = new Metadata(funcAddr); return new Metadata(vFuncMeta); } VirtualFunctionInfo VirtualFunctionInfo::DeserializedMetadata(const Ref &metadata) { std::map > vFuncMeta = metadata->GetKeyValueStore(); VirtualFunctionInfo vFuncInfo = {vFuncMeta["address"]->GetUnsignedInteger()}; return vFuncInfo; }