summaryrefslogtreecommitdiff
path: root/view/sharedcache
diff options
context:
space:
mode:
authorWeiN76LQh <WeiN76LQh@github.com>2025-01-03 17:55:10 +0000
committerMason Reed <mason@vector35.com>2025-04-02 05:36:54 -0400
commitee500220baa1a46f3d7ca1486fa43dc1587f20d0 (patch)
treeee3e1549997e60849f040f5745cdac8840f25303 /view/sharedcache
parent90e9ff91f02f2cb902bf0564de1f403e23172f36 (diff)
[ObjC] Create a shared ObjC processor for Macho and DSC views
Both the Macho and DSC views need to process Objective-C but have separate processor classes. It would appear that the DSC version was largely a copy and paste of the Macho view one, with some modifications. The majority of code overlaps between the 2 so it doesn't make sense to maintain 2 and copy and paste improvements/fixes between them. This commit fixes that by creating a base Objective-C processor that contains the shared code. View specific code is implemented in the respective subclasses for the views. Although there is very little view specific code for each.
Diffstat (limited to 'view/sharedcache')
-rw-r--r--view/sharedcache/core/CMakeLists.txt7
-rw-r--r--view/sharedcache/core/ObjC.cpp1518
-rw-r--r--view/sharedcache/core/ObjC.h242
-rw-r--r--view/sharedcache/core/SharedCache.cpp4
4 files changed, 79 insertions, 1692 deletions
diff --git a/view/sharedcache/core/CMakeLists.txt b/view/sharedcache/core/CMakeLists.txt
index 22c7ea28..03766920 100644
--- a/view/sharedcache/core/CMakeLists.txt
+++ b/view/sharedcache/core/CMakeLists.txt
@@ -8,11 +8,8 @@ if((NOT BN_API_PATH) AND (NOT BN_INTERNAL_BUILD))
message(FATAL_ERROR "Provide path to Binary Ninja API source in BN_API_PATH")
endif()
endif()
-file(GLOB COMMON_SOURCES
- *.cpp
- *.h
- )
-set(SOURCES ${COMMON_SOURCES})
+
+file(GLOB SOURCES *.cpp *.h ../../../objectivec/*)
add_library(sharedcachecore OBJECT ${SOURCES})
diff --git a/view/sharedcache/core/ObjC.cpp b/view/sharedcache/core/ObjC.cpp
index fa0e603c..c763b321 100644
--- a/view/sharedcache/core/ObjC.cpp
+++ b/view/sharedcache/core/ObjC.cpp
@@ -1,1540 +1,116 @@
#include "ObjC.h"
-#include "inttypes.h"
-#include "rapidjson/rapidjson.h"
-#include "rapidjson/document.h"
-#include "rapidjson/stringbuffer.h"
-#include "rapidjson/prettywriter.h"
using namespace BinaryNinja;
using namespace DSCObjC;
using namespace SharedCacheCore;
-Ref<Metadata> DSCObjCProcessor::SerializeMethod(uint64_t loc, const Method& method)
+DSCObjCReader::DSCObjCReader(SharedCache* cache, size_t addressSize) :
+ m_reader(VMReader(cache->GetVMMap())), m_addressSize(addressSize)
{
- std::map<std::string, Ref<Metadata>> methodMeta;
-
- methodMeta["loc"] = new Metadata(loc);
- methodMeta["name"] = new Metadata(method.name);
- methodMeta["types"] = new Metadata(method.types);
- methodMeta["imp"] = new Metadata(method.imp);
-
- return new Metadata(methodMeta);
}
-
-Ref<Metadata> DSCObjCProcessor::SerializeClass(uint64_t loc, const Class& cls)
+void DSCObjCReader::Read(void* dest, size_t len)
{
- std::map<std::string, Ref<Metadata>> clsMeta;
-
- clsMeta["loc"] = new Metadata(loc);
- clsMeta["name"] = new Metadata(cls.name);
- clsMeta["typeName"] = new Metadata(cls.associatedName.GetString());
-
- std::vector<uint64_t> instanceMethods;
- std::vector<uint64_t> classMethods;
- instanceMethods.reserve(cls.instanceClass.methodList.size());
- classMethods.reserve(cls.metaClass.methodList.size());
- for (const auto& [location, _] : cls.instanceClass.methodList)
- instanceMethods.push_back(location);
-
- clsMeta["instanceMethods"] = new Metadata(instanceMethods);
- clsMeta["classMethods"] = new Metadata(classMethods);
-
- return new Metadata(clsMeta);
+ m_reader.Read(dest, len);
}
-Ref<Metadata> DSCObjCProcessor::SerializeMetadata()
+std::string DSCObjCReader::ReadCString()
{
- std::map<std::string, Ref<Metadata>> viewMeta;
- viewMeta["version"] = new Metadata((uint64_t)1);
-
- std::vector<Ref<Metadata>> classes;
- classes.reserve(m_classes.size());
- std::vector<Ref<Metadata>> categories;
- categories.reserve(m_categories.size());
- std::vector<Ref<Metadata>> methods;
- methods.reserve(m_localMethods.size());
-
- for (const auto& [clsLoc, cls] : m_classes)
- classes.push_back(SerializeClass(clsLoc, cls));
- viewMeta["classes"] = new Metadata(classes);
- for (const auto& [catLoc, cat] : m_categories)
- categories.push_back(SerializeClass(catLoc, cat));
- viewMeta["categories"] = new Metadata(categories);
- for (const auto& [methodLoc, method] : m_localMethods)
- methods.push_back(SerializeMethod(methodLoc, method));
- viewMeta["methods"] = new Metadata(methods);
-
- // Required for workflow_objc type guessing, should be removed when that is no longer a thing.
- std::vector<Ref<Metadata>> selRefToImps;
- selRefToImps.reserve(m_selRefToImplementations.size());
- for (const auto& [selRef, imps] : m_selRefToImplementations)
- {
- std::vector<Ref<Metadata>> mapBase = {new Metadata(selRef), new Metadata(imps)};
- Ref<Metadata> mapObject = new Metadata(mapBase);
- selRefToImps.push_back(mapObject);
- }
- viewMeta["selRefImplementations"] = new Metadata(selRefToImps);
-
- std::vector<Ref<Metadata>> selToImps;
- selToImps.reserve(m_selToImplementations.size());
- for (const auto& [selRef, imps] : m_selToImplementations)
- {
- std::vector<Ref<Metadata>> mapBase = {new Metadata(selRef), new Metadata(imps)};
- Ref<Metadata> mapObject = new Metadata(mapBase);
- selToImps.push_back(mapObject);
- }
- viewMeta["selImplementations"] = new Metadata(selToImps);
-
- std::vector<Ref<Metadata>> selRefToName;
- selRefToName.reserve(m_selRefToName.size());
- for (const auto& [selRef, name] : m_selRefToName)
- {
- std::vector<Ref<Metadata>> mapBase = {new Metadata(selRef), new Metadata(name)};
- Ref<Metadata> mapObject = new Metadata(mapBase);
- selRefToName.push_back(mapObject);
- }
- viewMeta["selRefToName"] = new Metadata(selRefToName);
- // ---
-
-
- return new Metadata(viewMeta);
+ return m_reader.ReadCString(m_reader.GetOffset());
}
-std::vector<DSCObjC::QualifiedNameOrType> DSCObjCProcessor::ParseEncodedType(const std::string& encodedType)
+uint8_t DSCObjCReader::Read8()
{
- std::vector<QualifiedNameOrType> result;
- int pointerDepth = 0;
-
- bool readingNamedType = false;
- std::string namedType;
- int readingStructDepth = 0;
- std::string structType;
- char last;
-
- for (char c : encodedType)
- {
- if (readingNamedType && c != '"')
- {
- namedType.push_back(c);
- last = c;
- continue;
- }
- else if (readingStructDepth > 0 && c != '{' && c != '}')
- {
- structType.push_back(c);
- last = c;
- continue;
- }
-
- if (std::isdigit(c))
- continue;
-
- QualifiedNameOrType nameOrType;
- std::string qualifiedName;
-
- switch (c)
- {
- case '^':
- pointerDepth++;
- last = c;
- continue;
-
- case '"':
- if (!readingNamedType)
- {
- readingNamedType = true;
- if (last == '@')
- result.pop_back(); // We added an 'id' in the last cycle, remove it
- last = c;
- continue;
- }
- else
- {
- readingNamedType = false;
- nameOrType.name = QualifiedName(namedType);
- nameOrType.ptrCount = 1;
- break;
- }
- case '{':
- readingStructDepth++;
- last = c;
- continue;
- case '}':
- readingStructDepth--;
- if (readingStructDepth < 0)
- return {}; // seriously malformed type.
-
- if (readingStructDepth == 0)
- {
- // TODO: Emit real struct types
- nameOrType.type = Type::PointerType(m_data->GetAddressSize(), Type::VoidType());
- break;
- }
- last = c;
- continue;
- case 'v':
- nameOrType.type = Type::VoidType();
- break;
- case 'c':
- nameOrType.type = Type::IntegerType(1, true);
- break;
- case 'A':
- case 'C':
- nameOrType.type = Type::IntegerType(1, false);
- break;
- case 's':
- nameOrType.type = Type::IntegerType(2, true);
- break;
- case 'S':
- nameOrType.type = Type::IntegerType(1, false);
- break;
- case 'i':
- nameOrType.type = Type::IntegerType(4, true);
- break;
- case 'I':
- nameOrType.type = Type::IntegerType(4, false);
- break;
- case 'l':
- nameOrType.type = Type::IntegerType(8, true);
- break;
- case 'L':
- nameOrType.type = Type::IntegerType(8, true);
- break;
- case 'f':
- nameOrType.type = Type::IntegerType(4, true);
- break;
- case 'b':
- case 'B':
- nameOrType.type = Type::BoolType();
- break;
- case 'q':
- qualifiedName = "NSInteger";
- break;
- case 'Q':
- qualifiedName = "NSUInteger";
- break;
- case 'd':
- qualifiedName = "CGFloat";
- break;
- case '*':
- nameOrType.type = Type::PointerType(m_data->GetAddressSize(), Type::IntegerType(1, true));
- break;
- case '@':
- qualifiedName = "id";
- // There can be a type after this, like @"NSString", that overrides this
- // The handler for " will catch it and drop this "id" entry.
- break;
- case ':':
- qualifiedName = "SEL";
- break;
- case '#':
- qualifiedName = "objc_class_t";
- break;
- case '?':
- case 'T':
- nameOrType.type = Type::PointerType(8, Type::VoidType());
- break;
- default:
- // BNLogWarn("Unknown type specifier %c", c);
- last = c;
- continue;
- }
-
- while (pointerDepth)
- {
- if (nameOrType.type)
- nameOrType.type = Type::PointerType(8, nameOrType.type);
- else
- nameOrType.ptrCount++;
-
- pointerDepth--;
- }
-
- if (!qualifiedName.empty())
- nameOrType.name = QualifiedName(qualifiedName);
-
- if (nameOrType.type == nullptr && nameOrType.name.IsEmpty())
- {
- nameOrType.type = Type::VoidType();
- }
-
- result.push_back(nameOrType);
- last = c;
- }
-
- return result;
+ return m_reader.Read8();
}
-void DSCObjCProcessor::DefineObjCSymbol(
- BNSymbolType type, QualifiedName typeName, const std::string& name, uint64_t addr, bool deferred)
+uint16_t DSCObjCReader::Read16()
{
- DefineObjCSymbol(type, m_data->GetTypeByName(typeName), name, addr, deferred);
+ return m_reader.Read16();
}
-void DSCObjCProcessor::DefineObjCSymbol(
- BNSymbolType type, Ref<Type> typeRef, const std::string& name, uint64_t addr, bool deferred)
+uint32_t DSCObjCReader::Read32()
{
- if (name.size() == 0 || addr == 0)
- return;
-
- auto process = [=]() {
- NameSpace nameSpace = m_data->GetInternalNameSpace();
- if (type == ExternalSymbol)
- {
- nameSpace = m_data->GetExternalNameSpace();
- }
-
- std::string shortName = name;
- std::string fullName = name;
-
- QualifiedName varName;
-
- return std::pair<Ref<Symbol>, Ref<Type>>(
- new Symbol(type, shortName, fullName, name, addr, GlobalBinding, nameSpace), typeRef);
- };
-
- if (deferred)
- {
- m_symbolQueue->Append(process, [this, addr = addr](Symbol* symbol, Type* type) {
- // Armv7/Thumb: This will rewrite the symbol's address.
- // e.g. We pass in 0xc001, it will rewrite it to 0xc000 and create the function w/ the "thumb2" arch.
- if (Ref<Symbol> existingSymbol = m_data->GetSymbolByAddress(addr))
- m_data->UndefineAutoSymbol(existingSymbol);
- auto funcSym = m_data->DefineAutoSymbolAndVariableOrFunction(m_data->GetDefaultPlatform(), symbol, type);
- if (funcSym->GetType() == FunctionSymbol)
- {
- uint64_t target = symbol->GetAddress();
- Ref<Platform> targetPlatform =
- m_data->GetDefaultPlatform()->GetAssociatedPlatformByAddress(target); // rewrites target.
- if (Ref<Function> targetFunction = m_data->GetAnalysisFunction(targetPlatform, target))
- {
- if (!m_isBackedByDatabase)
- targetFunction->SetUserType(type);
- }
- }
- });
- return;
- }
-
- if (Ref<Symbol> existingSymbol = m_data->GetSymbolByAddress(addr))
- m_data->UndefineAutoSymbol(existingSymbol);
- auto result = process();
- auto sym = m_data->DefineAutoSymbolAndVariableOrFunction(m_data->GetDefaultPlatform(), result.first, result.second);
- if (sym->GetType() == FunctionSymbol)
- {
- uint64_t target = result.first->GetAddress();
- Ref<Platform> targetPlatform = m_data->GetDefaultPlatform()->GetAssociatedPlatformByAddress(target); // rewrites
- // target.
- if (Ref<Function> targetFunction = m_data->GetAnalysisFunction(targetPlatform, target))
- {
- if (!m_isBackedByDatabase)
- targetFunction->SetUserType(result.second);
- }
- }
+ return m_reader.Read32();
}
-void DSCObjCProcessor::LoadClasses(VMReader* reader, Ref<Section> classPtrSection)
+uint64_t DSCObjCReader::Read64()
{
- if (!classPtrSection)
- return;
- auto size = classPtrSection->GetEnd() - classPtrSection->GetStart();
- if (size == 0)
- return;
- auto ptrSize = m_data->GetAddressSize();
- auto ptrCount = size / ptrSize;
-
- auto classPtrSectionStart = classPtrSection->GetStart();
- for (size_t i = 0; i < ptrCount; i++)
- {
- Class cls;
-
- view_ptr_t classPtr;
- class_t clsStruct;
- class_ro_t classRO;
-
- bool hasValidMetaClass = false;
- bool hasValidMetaClassRO = false;
- class_t metaClsStruct;
- class_ro_t metaClassRO;
-
- view_ptr_t classPointerLocation = classPtrSectionStart + (i * m_data->GetAddressSize());
- reader->Seek(classPointerLocation);
-
- classPtr = ReadPointerAccountingForRelocations(reader);
- reader->Seek(classPtr);
- try
- {
- clsStruct.isa = ReadPointerAccountingForRelocations(reader);
- clsStruct.super = reader->ReadPointer();
- clsStruct.cache = reader->ReadPointer();
- clsStruct.vtable = reader->ReadPointer();
- clsStruct.data = ReadPointerAccountingForRelocations(reader);
- }
- catch (...)
- {
- m_logger->LogError("Failed to read class data at 0x%llx pointed to by @ 0x%llx", reader->GetOffset(),
- classPointerLocation);
- continue;
- }
- if (clsStruct.data & 1)
- {
- m_logger->LogInfo("Skipping class at 0x%llx as it contains swift types", classPtr);
- continue;
- }
- // unset first two bits
- view_ptr_t classROPtr = clsStruct.data & ~3;
- reader->Seek(classROPtr);
- try
- {
- classRO.flags = reader->Read32();
- classRO.instanceStart = reader->Read32();
- classRO.instanceSize = reader->Read32();
- if (m_data->GetAddressSize() == 8)
- classRO.reserved = reader->Read32();
- classRO.ivarLayout = ReadPointerAccountingForRelocations(reader);
- classRO.name = ReadPointerAccountingForRelocations(reader);
- classRO.baseMethods = ReadPointerAccountingForRelocations(reader);
- classRO.baseProtocols = ReadPointerAccountingForRelocations(reader);
- classRO.ivars = ReadPointerAccountingForRelocations(reader);
- classRO.weakIvarLayout = ReadPointerAccountingForRelocations(reader);
- classRO.baseProperties = ReadPointerAccountingForRelocations(reader);
- }
- catch (...)
- {
- m_logger->LogError("Failed to read class RO data at 0x%llx. 0x%llx, objc_class_t @ 0x%llx",
- reader->GetOffset(), classPointerLocation, classROPtr);
- continue;
- }
-
- auto namePtr = classRO.name;
-
- std::string name;
-
- reader->Seek(namePtr);
- try
- {
- name = reader->ReadCString(namePtr);
- }
- catch (...)
- {
- m_logger->LogWarn(
- "Failed to read class name at 0x%llx. Class has been given the placeholder name \"0x%llx\" ", namePtr,
- classPtr);
- char hexString[9];
- hexString[8] = 0;
- snprintf(hexString, sizeof(hexString), "%llx", classPtr);
- name = "0x" + std::string(hexString);
- }
-
- cls.name = name;
-
- DefineObjCSymbol(BNSymbolType::DataSymbol,
- Type::PointerType(m_data->GetAddressSize(), m_data->GetTypeByName(m_typeNames.cls)), "clsPtr_" + name,
- classPointerLocation, true);
- DefineObjCSymbol(BNSymbolType::DataSymbol, m_typeNames.cls, "cls_" + name, classPtr, true);
- DefineObjCSymbol(BNSymbolType::DataSymbol, m_typeNames.classRO, "cls_ro_" + name, classROPtr, true);
- DefineObjCSymbol(BNSymbolType::DataSymbol, Type::ArrayType(Type::IntegerType(1, true), name.size() + 1),
- "clsName_" + name, classRO.name, true);
- if (0 && classRO.baseProtocols)
- {
- DefineObjCSymbol(BNSymbolType::DataSymbol, Type::NamedType(m_data, m_typeNames.protocolList),
- "clsProtocols_" + name, classRO.baseProtocols, true);
- reader->Seek(classRO.baseProtocols);
- uint32_t count = reader->Read64();
- view_ptr_t addr = reader->GetOffset();
- for (uint32_t j = 0; j < count; j++)
- {
- m_data->DefineDataVariable(
- addr, Type::PointerType(ptrSize, Type::NamedType(m_data, m_typeNames.protocol)));
- addr += ptrSize;
- }
- }
-
- if (clsStruct.isa)
- {
- reader->Seek(clsStruct.isa);
- try
- {
- metaClsStruct.isa = ReadPointerAccountingForRelocations(reader);
- metaClsStruct.super = reader->ReadPointer();
- metaClsStruct.cache = reader->ReadPointer();
- metaClsStruct.vtable = reader->ReadPointer();
- metaClsStruct.data = ReadPointerAccountingForRelocations(reader) & ~1;
- DefineObjCSymbol(BNSymbolType::DataSymbol, m_typeNames.cls, "metacls_" + name, clsStruct.isa, true);
- hasValidMetaClass = true;
- }
- catch (...)
- {
- m_logger->LogWarn("Failed to read metaclass data at 0x%llx pointed to by objc_class_t @ 0x%llx",
- reader->GetOffset(), classPtr);
- }
- }
- if (hasValidMetaClass && (metaClsStruct.data & 1))
- {
- m_logger->LogInfo("Skipping metaclass at 0x%llx as it contains swift types", classPtr);
- hasValidMetaClass = false;
- }
- if (hasValidMetaClass)
- {
- reader->Seek(metaClsStruct.data);
- try
- {
- metaClassRO.flags = reader->Read32();
- metaClassRO.instanceStart = reader->Read32();
- metaClassRO.instanceSize = reader->Read32();
- if (m_data->GetAddressSize() == 8)
- metaClassRO.reserved = reader->Read32();
- metaClassRO.ivarLayout = ReadPointerAccountingForRelocations(reader);
- metaClassRO.name = ReadPointerAccountingForRelocations(reader);
- metaClassRO.baseMethods = ReadPointerAccountingForRelocations(reader);
- metaClassRO.baseProtocols = ReadPointerAccountingForRelocations(reader);
- metaClassRO.ivars = ReadPointerAccountingForRelocations(reader);
- metaClassRO.weakIvarLayout = ReadPointerAccountingForRelocations(reader);
- metaClassRO.baseProperties = ReadPointerAccountingForRelocations(reader);
- DefineObjCSymbol(
- BNSymbolType::DataSymbol, m_typeNames.classRO, "metacls_ro_" + name, metaClsStruct.data, true);
- hasValidMetaClassRO = true;
- }
- catch (...)
- {
- m_logger->LogWarn("Failed to read metaclass RO data at 0x%llx pointed to by meta objc_class_t @ 0x%llx",
- reader->GetOffset(), clsStruct.isa);
- }
- }
-
- if (classRO.baseMethods)
- {
- try
- {
- ReadMethodList(reader, cls.instanceClass, name, classRO.baseMethods);
- }
- catch (...)
- {
- m_logger->LogError("Failed to read the method list for class pointed to by 0x%llx", clsStruct.data);
- }
- }
- if (hasValidMetaClassRO && metaClassRO.baseMethods)
- {
- try
- {
- ReadMethodList(reader, cls.metaClass, name, metaClassRO.baseMethods);
- }
- catch (...)
- {
- m_logger->LogError("Failed to read the method list for metaclass pointed to by 0x%llx", clsStruct.data);
- }
- }
-
- if (classRO.ivars)
- {
- try
- {
- ReadIvarList(reader, cls.instanceClass, name, classRO.ivars);
- }
- catch (...)
- {
- m_logger->LogError("Failed to process ivars for class at 0x%llx", clsStruct.data);
- }
- }
- m_classes[classPtr] = cls;
- }
-}
-
-void DSCObjCProcessor::LoadCategories(VMReader* reader, Ref<Section> classPtrSection)
-{
- if (!classPtrSection)
- return;
- auto size = classPtrSection->GetEnd() - classPtrSection->GetStart();
- if (size == 0)
- return;
- auto ptrSize = m_data->GetAddressSize();
-
- auto classPtrSectionStart = classPtrSection->GetStart();
- auto classPtrSectionEnd = classPtrSection->GetEnd();
-
- auto catType = Type::NamedType(m_data, m_typeNames.category);
- auto ptrType = Type::PointerType(m_data->GetDefaultArchitecture(), catType);
- for (size_t i = classPtrSectionStart; i < classPtrSectionEnd; i += ptrSize)
- {
- Class category;
- category_t cat;
-
- reader->Seek(i);
- auto catLocation = ReadPointerAccountingForRelocations(reader);
- reader->Seek(catLocation);
-
- try
- {
- cat.name = ReadPointerAccountingForRelocations(reader);
- cat.cls = ReadPointerAccountingForRelocations(reader);
- cat.instanceMethods = ReadPointerAccountingForRelocations(reader);
- cat.classMethods = ReadPointerAccountingForRelocations(reader);
- cat.protocols = ReadPointerAccountingForRelocations(reader);
- cat.instanceProperties = ReadPointerAccountingForRelocations(reader);
- }
- catch (...)
- {
- m_logger->LogError("Failed to read category pointed to by 0x%llx", i);
- continue;
- }
-
- std::string categoryAdditionsName;
- std::string categoryBaseClassName;
-
- if (const auto& it = m_classes.find(cat.cls); it != m_classes.end())
- {
- categoryBaseClassName = it->second.name;
- category.associatedName = it->second.associatedName;
- }
- else if (auto symbol = m_data->GetSymbolByAddress(catLocation + m_data->GetAddressSize()))
- {
- if (symbol->GetType() == ImportedDataSymbol || symbol->GetType() == ImportAddressSymbol)
- {
- const auto& symbolName = symbol->GetFullName();
- if (symbolName.size() > 14 && symbolName.rfind("_OBJC_CLASS_$_", 0) == 0)
- categoryBaseClassName = symbolName.substr(14, symbolName.size() - 14);
- }
- }
- if (categoryBaseClassName.empty())
- {
- m_logger->LogError(
- "Failed to determine base classname for category at 0x%llx. Using base address as stand-in classname",
- catLocation);
- categoryBaseClassName = std::to_string(catLocation);
- }
- try
- {
- reader->Seek(cat.name);
- categoryAdditionsName = reader->ReadCString(cat.name);
- }
- catch (...)
- {
- m_logger->LogError(
- "Failed to read category name for category at 0x%llx. Using base address as stand-in category name",
- catLocation);
- categoryAdditionsName = std::to_string(catLocation);
- }
- category.name = categoryBaseClassName + " (" + categoryAdditionsName + ")";
- DefineObjCSymbol(BNSymbolType::DataSymbol, ptrType, "categoryPtr_" + category.name, i, true);
- DefineObjCSymbol(BNSymbolType::DataSymbol, catType, "category_" + category.name, catLocation, true);
-
- if (cat.instanceMethods)
- {
- try
- {
- ReadMethodList(reader, category.instanceClass, category.name, cat.instanceMethods);
- }
- catch (...)
- {
- m_logger->LogError(
- "Failed to read the instance method list for category pointed to by 0x%llx", catLocation);
- }
- }
- if (cat.classMethods)
- {
- try
- {
- ReadMethodList(reader, category.metaClass, category.name, cat.classMethods);
- }
- catch (...)
- {
- m_logger->LogError(
- "Failed to read the class method list for category pointed to by 0x%llx", catLocation);
- }
- }
- m_categories[catLocation] = category;
- }
+ return m_reader.Read64();
}
-void DSCObjCProcessor::LoadProtocols(VMReader* reader, Ref<Section> listSection)
+int8_t DSCObjCReader::ReadS8()
{
- if (!listSection)
- return;
- auto size = listSection->GetEnd() - listSection->GetStart();
- if (size == 0)
- return;
- auto ptrSize = m_data->GetAddressSize();
-
- auto listSectionStart = listSection->GetStart();
- auto listSectionEnd = listSection->GetEnd();
-
- auto protocolType = Type::NamedType(m_data, m_typeNames.protocol);
- auto ptrType = Type::PointerType(m_data->GetDefaultArchitecture(), protocolType);
- for (size_t i = listSectionStart; i < listSectionEnd; i += ptrSize)
- {
- protocol_t protocol;
- reader->Seek(i);
- auto protocolLocation = ReadPointerAccountingForRelocations(reader);
- reader->Seek(protocolLocation);
-
- try
- {
- protocol.isa = ReadPointerAccountingForRelocations(reader);
- protocol.mangledName = ReadPointerAccountingForRelocations(reader);
- protocol.protocols = ReadPointerAccountingForRelocations(reader);
- protocol.instanceMethods = ReadPointerAccountingForRelocations(reader);
- protocol.classMethods = ReadPointerAccountingForRelocations(reader);
- protocol.optionalInstanceMethods = ReadPointerAccountingForRelocations(reader);
- protocol.optionalClassMethods = ReadPointerAccountingForRelocations(reader);
- protocol.instanceProperties = ReadPointerAccountingForRelocations(reader);
- }
- catch (...)
- {
- m_logger->LogError("Failed to read protocol pointed to by 0x%llx", i);
- continue;
- }
-
- std::string protocolName;
- try
- {
- reader->Seek(protocol.mangledName);
- protocolName = reader->ReadCString(protocol.mangledName);
- DefineObjCSymbol(BNSymbolType::DataSymbol,
- Type::ArrayType(Type::IntegerType(1, true), protocolName.size() + 1), "protocolName_" + protocolName,
- protocol.mangledName, true);
- }
- catch (...)
- {
- m_logger->LogError(
- "Failed to read protocol name for protocol at 0x%llx. Using base address as stand-in protocol name",
- protocolLocation);
- protocolName = std::to_string(protocolLocation);
- }
-
- Protocol protocolClass;
- protocolClass.name = protocolName;
- DefineObjCSymbol(BNSymbolType::DataSymbol, ptrType, "protocolPtr_" + protocolName, i, true);
- DefineObjCSymbol(BNSymbolType::DataSymbol, protocolType, "protocol_" + protocolName, protocolLocation, true);
- if (protocol.protocols)
- {
- DefineObjCSymbol(BNSymbolType::DataSymbol, Type::NamedType(m_data, m_typeNames.protocolList),
- "protoProtocols_" + protocolName, protocol.protocols, true);
- reader->Seek(protocol.protocols);
- uint32_t count = reader->Read64();
- view_ptr_t addr = reader->GetOffset();
- for (uint32_t j = 0; j < count; j++)
- {
- m_data->DefineDataVariable(
- addr, Type::PointerType(ptrSize, Type::NamedType(m_data, m_typeNames.protocol)));
- addr += ptrSize;
- }
- }
-
- if (protocol.instanceMethods)
- {
- try
- {
- ReadMethodList(reader, protocolClass.instanceMethods, protocolName, protocol.instanceMethods);
- }
- catch (...)
- {
- m_logger->LogError(
- "Failed to read the instance method list for protocol pointed to by 0x%llx", protocolLocation);
- }
- }
- if (protocol.classMethods)
- {
- try
- {
- ReadMethodList(reader, protocolClass.classMethods, protocolName, protocol.classMethods);
- }
- catch (...)
- {
- m_logger->LogError(
- "Failed to read the class method list for protocol pointed to by 0x%llx", protocolLocation);
- }
- }
- if (protocol.optionalInstanceMethods)
- {
- try
- {
- ReadMethodList(
- reader, protocolClass.optionalInstanceMethods, protocolName, protocol.optionalInstanceMethods);
- }
- catch (...)
- {
- m_logger->LogError("Failed to read the optional instance method list for protocol pointed to by 0x%llx",
- protocolLocation);
- }
- }
- if (protocol.optionalClassMethods)
- {
- try
- {
- ReadMethodList(reader, protocolClass.optionalClassMethods, protocolName, protocol.optionalClassMethods);
- }
- catch (...)
- {
- m_logger->LogError("Failed to read the optional class method list for protocol pointed to by 0x%llx",
- protocolLocation);
- }
- }
- m_protocols[protocolLocation] = protocolClass;
- }
+ return m_reader.ReadS8();
}
-void DSCObjCProcessor::ReadListOfMethodLists(VMReader* reader, ClassBase& cls, std::string_view name, view_ptr_t start)
+int16_t DSCObjCReader::ReadS16()
{
- reader->Seek(start);
- method_list_t head;
- head.entsizeAndFlags = reader->Read32();
- head.count = reader->Read32();
- if (head.count > 0x1000)
- {
- m_logger->LogError("List of method lists at 0x%llx has an invalid count of 0x%x", start, head.count);
- return;
- }
-
- for (size_t i = 0; i < head.count; ++i) {
- relative_list_list_entry_t list_entry;
- reader->Read(&list_entry, sizeof(list_entry));
-
- ReadMethodList(reader, cls, name, reader->GetOffset() - sizeof(list_entry) + list_entry.listOffset);
- // Reset the cursor to immediately past the list entry.
- reader->Seek(start + sizeof(method_list_t) + ((i + 1) * sizeof(relative_list_list_entry_t)));
- }
+ return m_reader.ReadS16();
}
-void DSCObjCProcessor::ReadMethodList(VMReader* reader, ClassBase& cls, std::string_view name, view_ptr_t start)
+int32_t DSCObjCReader::ReadS32()
{
- // Lower two bits indicate the type of method list.
- switch (start & 0b11) {
- case 0:
- break;
- case 1:
- return ReadListOfMethodLists(reader, cls, name, start - 1);
- default:
- m_logger->LogDebug("ReadMethodList: Unknown method list type at 0x%llx: %d", start, start & 0x3);
- return;
- }
-
- reader->Seek(start);
- method_list_t head;
- head.entsizeAndFlags = reader->Read32();
- head.count = reader->Read32();
-
- if (head.count > 0x1000)
- {
- m_logger->LogError("Method list at 0x%llx has an invalid count of 0x%x", start, head.count);
- return;
- }
-
- uint64_t pointerSize = m_data->GetAddressSize();
- bool relativeOffsets = (head.entsizeAndFlags & 0xFFFF0000) & 0x80000000;
- bool directSelectors = (head.entsizeAndFlags & 0xFFFF0000) & 0x40000000;
- auto methodSize = relativeOffsets ? 12 : pointerSize * 3;
- DefineObjCSymbol(DataSymbol, m_typeNames.methodList, "method_list_" + std::string(name), start, true);
-
- for (unsigned i = 0; i < head.count; i++)
- {
- try
- {
- Method method;
- auto cursor = start + sizeof(method_list_t) + (i * methodSize);
- reader->Seek(cursor);
- method_t meth;
- // workflow_objc support
- uint64_t selRefAddr = 0;
- uint64_t selAddr = 0;
- // --
- if (relativeOffsets)
- {
- auto selectorBaseOffset = reader->GetOffset();
- if (directSelectors && m_customRelativeMethodSelectorBase.has_value()) {
- selectorBaseOffset = m_customRelativeMethodSelectorBase.value();
- }
-
- meth.name = selectorBaseOffset + reader->Read32();
- meth.types = reader->GetOffset() + reader->ReadS32();
- meth.imp = reader->GetOffset() + reader->ReadS32();
- }
- else
- {
- meth.name = ReadPointerAccountingForRelocations(reader);
- meth.types = ReadPointerAccountingForRelocations(reader);
- meth.imp = ReadPointerAccountingForRelocations(reader);
- }
- if (!relativeOffsets || directSelectors)
- {
- selAddr = meth.name;
- method.name = reader->ReadCString(meth.name);
- reader->Seek(meth.types);
- method.types = reader->ReadCString(meth.types);
- DefineObjCSymbol(DataSymbol, Type::ArrayType(Type::IntegerType(1, true), method.name.size() + 1),
- "sel_" + method.name, meth.name, true);
- DefineObjCSymbol(DataSymbol, Type::ArrayType(Type::IntegerType(1, true), method.types.size() + 1),
- "selTypes_" + method.name, meth.types, true);
- }
- else
- {
- std::string sel;
- view_ptr_t selRef;
- reader->Seek(meth.name);
- selRefAddr = meth.name;
- selRef = ReadPointerAccountingForRelocations(reader);
- reader->Seek(meth.types);
- method.types = reader->ReadCString(meth.types);
- selAddr = selRef;
- if (const auto& it = m_selectorCache.find(selRef); it != m_selectorCache.end())
- method.name = it->second;
- else
- {
- reader->Seek(selRef);
- method.name = reader->ReadCString(selRef);
- m_selectorCache[selRef] = method.name;
- }
- auto selType = Type::ArrayType(Type::IntegerType(1, true), method.name.size() + 1);
- DefineObjCSymbol(DataSymbol, selType, "sel_" + method.name, selRef, true);
- DefineObjCSymbol(DataSymbol, Type::ArrayType(Type::IntegerType(1, true), method.types.size() + 1),
- "selTypes_" + method.name, meth.types, true);
- DefineObjCSymbol(DataSymbol, Type::PointerType(m_data->GetAddressSize(), selType),
- "selRef_" + method.name, meth.name, true);
- }
- // workflow objc support
- if (selAddr)
- m_selToImplementations[selAddr].push_back(meth.imp);
- if (selRefAddr)
- m_selRefToImplementations[selRefAddr].push_back(meth.imp);
- // --
-
- DefineObjCSymbol(DataSymbol, relativeOffsets ? m_typeNames.methodEntry : m_typeNames.method,
- "method_" + method.name, cursor, true);
- method.imp = meth.imp;
- cls.methodList[cursor] = method;
- m_localMethods[cursor] = method;
- }
- catch (...)
- {
- // m_logger->LogError("Failed to process a method at offset 0x%llx", start + sizeof(method_list_t) + (i * methodSize));
- }
- }
+ return m_reader.ReadS32();
}
-void DSCObjCProcessor::ReadIvarList(VMReader* reader, ClassBase& cls, std::string_view name, view_ptr_t start)
+int64_t DSCObjCReader::ReadS64()
{
- reader->Seek(start);
- ivar_list_t head;
- head.entsizeAndFlags = reader->Read32();
- head.count = reader->Read32();
- auto addressSize = m_data->GetAddressSize();
- DefineObjCSymbol(DataSymbol, m_typeNames.ivarList, "ivar_list_" + std::string(name), start, true);
- if (head.count > 0x1000)
- {
- m_logger->LogError("Ivar list at 0x%llx has an invalid count of 0x%llx", start, head.count);
- return;
- }
- for (unsigned i = 0; i < head.count; i++)
- {
- try
- {
- Ivar ivar;
- ivar_t ivarStruct;
- uint64_t cursor = start + (sizeof(ivar_list_t)) + (i * ((addressSize * 3) + 8));
- reader->Seek(cursor);
- ivarStruct.offset = ReadPointerAccountingForRelocations(reader);
- ivarStruct.name = ReadPointerAccountingForRelocations(reader);
- ivarStruct.type = ReadPointerAccountingForRelocations(reader);
- ivarStruct.alignmentRaw = reader->Read32();
- ivarStruct.size = reader->Read32();
-
- reader->Seek(ivarStruct.offset);
- ivar.offset = reader->Read32();
- reader->Seek(ivarStruct.name);
- ivar.name = reader->ReadCString(ivarStruct.name);
- reader->Seek(ivarStruct.type);
- ivar.type = reader->ReadCString(ivarStruct.type);
-
- DefineObjCSymbol(DataSymbol, m_typeNames.ivar, "ivar_" + ivar.name, cursor, true);
- DefineObjCSymbol(DataSymbol, Type::ArrayType(Type::IntegerType(1, true), ivar.name.size() + 1),
- "ivarName_" + ivar.name, ivarStruct.name, true);
- DefineObjCSymbol(DataSymbol, Type::ArrayType(Type::IntegerType(1, true), ivar.type.size() + 1),
- "ivarType_" + ivar.name, ivarStruct.type, true);
-
- cls.ivarList[cursor] = ivar;
- }
- catch (...)
- {
- m_logger->LogError("Failed to process an ivar at offset 0x%llx",
- start + (sizeof(ivar_list_t)) + (i * ((addressSize * 3) + 8)));
- }
- }
+ return m_reader.ReadS64();
}
-
-std::pair<QualifiedName, Ref<Type>> finalizeStructureBuilder(
- Ref<BinaryView> m_data, StructureBuilder sb, std::string name)
+uint64_t DSCObjCReader::ReadPointer()
{
- auto classTypeStruct = sb.Finalize();
-
- QualifiedName classTypeName(name);
- auto classTypeId = Type::GenerateAutoTypeId("objc", classTypeName);
- auto classType = Type::StructureType(classTypeStruct);
- auto classQualName = m_data->DefineType(classTypeId, classTypeName, classType);
-
- return {classQualName, classType};
+ return m_reader.ReadPointer();
}
-std::pair<QualifiedName, Ref<Type>> finalizeEnumerationBuilder(
- Ref<BinaryView> m_data, EnumerationBuilder eb, uint64_t size, QualifiedName name)
+uint64_t DSCObjCReader::GetOffset() const
{
- auto enumTypeStruct = eb.Finalize();
-
- auto enumTypeId = Type::GenerateAutoTypeId("objc", name);
- auto enumType = Type::EnumerationType(enumTypeStruct, size);
- auto enumQualName = m_data->DefineType(enumTypeId, name, enumType);
-
- return {enumQualName, enumType};
+ return m_reader.GetOffset();
}
-inline QualifiedName defineTypedef(Ref<BinaryView> m_data, const QualifiedName name, Ref<Type> type)
+void DSCObjCReader::Seek(uint64_t offset)
{
- auto typeID = Type::GenerateAutoTypeId("objc", name);
- m_data->DefineType(typeID, name, type);
- return m_data->GetTypeNameById(typeID);
+ m_reader.Seek(offset);
}
-void DSCObjCProcessor::GenerateClassTypes()
+void DSCObjCReader::SeekRelative(int64_t offset)
{
- for (auto& [_, cls] : m_classes)
- {
- QualifiedName typeName;
- StructureBuilder classTypeBuilder;
- bool failedToDecodeType = false;
- for (const auto& [ivarLoc, ivar] : cls.instanceClass.ivarList)
- {
- auto encodedTypeList = ParseEncodedType(ivar.type);
- if (encodedTypeList.empty())
- {
- failedToDecodeType = true;
- break;
- }
- auto encodedType = encodedTypeList.at(0);
-
- Ref<Type> type;
-
- if (encodedType.type)
- type = encodedType.type;
- else
- {
- type = Type::NamedType(encodedType.name, Type::PointerType(m_data->GetAddressSize(), Type::VoidType()));
- for (size_t i = encodedType.ptrCount; i > 0; i--)
- type = Type::PointerType(m_data->GetAddressSize(), type);
- }
-
- if (!type)
- type = Type::PointerType(m_data->GetAddressSize(), Type::VoidType());
-
- classTypeBuilder.AddMemberAtOffset(type, ivar.name, ivar.offset);
- }
- if (failedToDecodeType)
- continue;
- auto classTypeStruct = classTypeBuilder.Finalize();
- QualifiedName classTypeName = cls.name;
- std::string classTypeId = Type::GenerateAutoTypeId("objc", classTypeName);
- Ref<Type> classType = Type::StructureType(classTypeStruct);
- QualifiedName classQualName = m_data->DefineType(classTypeId, classTypeName, classType);
- cls.associatedName = classTypeName;
- }
+ m_reader.SeekRelative(offset);
}
-bool DSCObjCProcessor::ApplyMethodType(Class& cls, Method& method, bool isInstanceMethod)
+VMReader& DSCObjCReader::GetVMReader()
{
- if (!method.imp || !m_data->IsValidOffset(method.imp)) {
- return false;
- }
-
- std::stringstream r(method.name);
-
- std::string token;
- std::vector<std::string> selectorTokens;
- while (std::getline(r, token, ':'))
- selectorTokens.push_back(token);
-
- std::vector<QualifiedNameOrType> typeTokens = ParseEncodedType(method.types);
- if (typeTokens.empty())
- return false;
-
- auto typeForQualifiedNameOrType = [this](QualifiedNameOrType nameOrType) {
- Ref<Type> type;
-
- if (nameOrType.type)
- {
- type = nameOrType.type;
- if (!type)
- type = Type::PointerType(m_data->GetAddressSize(), Type::VoidType());
- }
- else
- {
- type = Type::NamedType(nameOrType.name, Type::PointerType(m_data->GetAddressSize(), Type::VoidType()));
- for (size_t i = nameOrType.ptrCount; i > 0; i--)
- type = Type::PointerType(m_data->GetAddressSize(), type);
- }
-
- return type;
- };
-
- BinaryNinja::QualifiedNameAndType nameAndType;
- std::set<BinaryNinja::QualifiedName> typesAllowRedefinition;
-
- auto retType = typeForQualifiedNameOrType(typeTokens[0]);
-
- std::vector<BinaryNinja::FunctionParameter> params;
- auto cc = m_data->GetDefaultPlatform()->GetDefaultCallingConvention();
-
- params.push_back({"self",
- cls.associatedName.IsEmpty() ?
- Type::NamedType(m_data, {"id"}) :
- Type::PointerType(m_data->GetAddressSize(), Type::NamedType(m_data, cls.associatedName)),
- true, BinaryNinja::Variable()});
-
- params.push_back({"sel", Type::NamedType(m_data, {"SEL"}), true, BinaryNinja::Variable()});
-
- for (size_t i = 3; i < typeTokens.size(); i++)
- {
- std::string suffix;
-
- params.push_back({selectorTokens.size() > i - 3 ? selectorTokens[i - 3] : "arg",
- typeForQualifiedNameOrType(typeTokens[i]), true, BinaryNinja::Variable()});
- }
-
- auto funcType = BinaryNinja::Type::FunctionType(retType, cc, params);
-
- // Search for the method's implementation function; apply the type if found.
- std::string prefix = isInstanceMethod ? "-" : "+";
- auto name = prefix + "[" + cls.name + " " + method.name + "]";
-
- DefineObjCSymbol(FunctionSymbol, funcType, name, method.imp, true);
-
- return true;
+ return m_reader;
}
-void DSCObjCProcessor::ApplyMethodTypes(Class& cls)
+std::shared_ptr<ObjCReader> DSCObjCProcessor::GetReader()
{
- for (auto& [_, method] : cls.instanceClass.methodList)
- {
- ApplyMethodType(cls, method, true);
- }
- for (auto& [_, method] : cls.metaClass.methodList)
- {
- ApplyMethodType(cls, method, false);
- }
+ return std::make_shared<DSCObjCReader>(m_cache, m_data->GetAddressSize());
}
-void DSCObjCProcessor::PostProcessObjCSections(VMReader* reader, std::string baseName)
+void DSCObjCProcessor::GetRelativeMethod(ObjCReader* reader, method_t& meth)
{
- auto ptrSize = m_data->GetAddressSize();
- if (auto imageInfo = m_data->GetSectionByName(baseName + "::__objc_imageinfo"))
- {
- auto start = imageInfo->GetStart();
- auto type = Type::NamedType(m_data, m_typeNames.imageInfo);
- m_data->DefineDataVariable(start, type);
- }
- if (auto selrefs = m_data->GetSectionByName(baseName + "::__objc_selrefs"))
- {
- auto start = selrefs->GetStart();
- auto end = selrefs->GetEnd();
- auto type = Type::PointerType(ptrSize, Type::IntegerType(1, false));
- for (view_ptr_t i = start; i < end; i += ptrSize)
- {
- reader->Seek(i);
- auto selLoc = ReadPointerAccountingForRelocations(reader);
- std::string sel;
- if (const auto& it = m_selectorCache.find(selLoc); it != m_selectorCache.end())
- sel = it->second;
- else
- {
- reader->Seek(selLoc);
- sel = reader->ReadCString(selLoc);
- m_selectorCache[selLoc] = sel;
- DefineObjCSymbol(DataSymbol, Type::ArrayType(Type::IntegerType(1, true), sel.size() + 1), "sel_" + sel,
- selLoc, true);
- }
- DefineObjCSymbol(DataSymbol, type, "selRef_" + sel, i, true);
- }
- }
- if (auto superRefs = m_data->GetSectionByName(baseName + "::__objc_classrefs"))
- {
- auto start = superRefs->GetStart();
- auto end = superRefs->GetEnd();
- auto type = Type::PointerType(ptrSize, Type::NamedType(m_data, m_typeNames.cls));
- for (view_ptr_t i = start; i < end; i += ptrSize)
- {
- reader->Seek(i);
- auto clsLoc = ReadPointerAccountingForRelocations(reader);
- if (const auto& it = m_classes.find(clsLoc); it != m_classes.end())
- {
- auto& cls = it->second;
- std::string name = cls.name;
- if (!name.empty())
- DefineObjCSymbol(DataSymbol, type, "clsRef_" + name, i, true);
- }
- }
- }
- if (auto superRefs = m_data->GetSectionByName(baseName + "::__objc_superrefs"))
- {
- auto start = superRefs->GetStart();
- auto end = superRefs->GetEnd();
- auto type = Type::PointerType(ptrSize, Type::NamedType(m_data, m_typeNames.cls));
- for (view_ptr_t i = start; i < end; i += ptrSize)
- {
- reader->Seek(i);
- auto clsLoc = ReadPointerAccountingForRelocations(reader);
- if (const auto& it = m_classes.find(clsLoc); it != m_classes.end())
- {
- auto& cls = it->second;
- std::string name = cls.name;
- if (!name.empty())
- DefineObjCSymbol(DataSymbol, type, "superRef_" + name, i, true);
- }
- }
- }
- if (auto protoRefs = m_data->GetSectionByName(baseName + "::__objc_protorefs"))
+ if (m_customRelativeMethodSelectorBase.has_value())
{
- auto start = protoRefs->GetStart();
- auto end = protoRefs->GetEnd();
- auto type = Type::PointerType(ptrSize, Type::NamedType(m_data, m_typeNames.protocol));
- for (view_ptr_t i = start; i < end; i += ptrSize)
- {
- reader->Seek(i);
- auto protoLoc = ReadPointerAccountingForRelocations(reader);
- if (const auto& it = m_protocols.find(protoLoc); it != m_protocols.end())
- {
- auto& proto = it->second;
- std::string name = proto.name;
- if (!name.empty())
- DefineObjCSymbol(DataSymbol, type, "protoRef_" + name, i, true);
- }
- }
+ meth.name = m_customRelativeMethodSelectorBase.value() + reader->ReadS32();
+ meth.types = reader->GetOffset() + reader->ReadS32();
+ meth.imp = reader->GetOffset() + reader->ReadS32();
}
- if (auto ivars = m_data->GetSectionByName(baseName + "::__objc_ivar"))
+ else
{
- auto start = ivars->GetStart();
- auto end = ivars->GetEnd();
- auto ivarSectionEntryTypeBuilder = new TypeBuilder(Type::IntegerType(8, false));
- ivarSectionEntryTypeBuilder->SetConst(true);
- auto type = ivarSectionEntryTypeBuilder->Finalize();
- for (view_ptr_t i = start; i < end; i += ptrSize)
- {
- m_data->DefineDataVariable(i, type);
- }
+ ObjCProcessor::GetRelativeMethod(reader, meth);
}
}
-uint64_t DSCObjCProcessor::ReadPointerAccountingForRelocations(VMReader* reader)
+uint64_t DSCObjCProcessor::GetObjCRelativeMethodBaseAddress(ObjCReader* reader)
{
- if (auto it = m_relocationPointerRewrites.find(reader->GetOffset()); it != m_relocationPointerRewrites.end())
- {
- reader->SeekRelative(m_data->GetAddressSize());
- return it->second;
- }
- // hack
- return reader->ReadPointer();
-}
-
-
-DSCObjCProcessor::DSCObjCProcessor(BinaryNinja::BinaryView* data, SharedCache* cache, bool isBackedByDatabase) :
- m_isBackedByDatabase(isBackedByDatabase), m_data(data), m_cache(cache)
-{
- m_logger = LogRegistry::GetLogger("SharedCache.ObjC", m_data->GetFile()->GetSessionId());
-}
-
-void DSCObjCProcessor::ProcessObjCData(std::shared_ptr<VM> vm, std::string baseName)
-{
- m_symbolQueue = new SymbolQueue();
- auto addrSize = m_data->GetAddressSize();
-
- // m_typeNames.relativePtr = );
- auto rptr_t = Type::NamedType(m_data, defineTypedef(m_data, {"rptr_t"}, Type::IntegerType(4, true)));
- //
- // m_typeNames.id = defineTypedef(m_data, {"id"}, Type::PointerType(addrSize, Type::VoidType()));
- // m_typeNames.sel = defineTypedef(m_data, {"SEL"}, Type::PointerType(addrSize, Type::IntegerType(1, false)));
- //
- // m_typeNames.BOOL = defineTypedef(m_data, {"BOOL"}, Type::IntegerType(1, false));
- // m_typeNames.nsInteger = defineTypedef(m_data, {"NSInteger"}, Type::IntegerType(addrSize, true));
- // m_typeNames.nsuInteger = defineTypedef(m_data, {"NSUInteger"}, Type::IntegerType(addrSize, false));
- // m_typeNames.cgFloat = defineTypedef(m_data, {"CGFloat"}, Type::FloatType(addrSize));
-
- Ref<Type> relativeSelectorPtr;
- auto reader = VMReader(vm);
- if (auto objCRelativeMethodsBaseAddr = m_cache->GetObjCRelativeMethodBaseAddress(reader)) {
- m_logger->LogDebug("RelativeMethodSelector Base: 0x%llx", objCRelativeMethodsBaseAddr);
- m_customRelativeMethodSelectorBase = objCRelativeMethodsBaseAddr;
-
- auto type = TypeBuilder::PointerType(4, Type::PointerType(addrSize, Type::IntegerType(1, false)))
- .SetPointerBase(RelativeToConstantPointerBaseType, objCRelativeMethodsBaseAddr)
- .Finalize();
- auto relativeSelectorPtrName = defineTypedef(m_data, {"relative_SEL"}, type);
- relativeSelectorPtr = Type::NamedType(m_data, relativeSelectorPtrName);
- }
-
- // https://github.com/apple-oss-distributions/objc4/blob/196363c165b175ed925ef6b9b99f558717923c47/runtime/objc-abi.h
- EnumerationBuilder imageInfoFlagBuilder;
- imageInfoFlagBuilder.AddMemberWithValue("IsReplacement", 1 << 0);
- imageInfoFlagBuilder.AddMemberWithValue("SupportsGC", 1 << 1);
- imageInfoFlagBuilder.AddMemberWithValue("RequiresGC", 1 << 2);
- imageInfoFlagBuilder.AddMemberWithValue("OptimizedByDyld", 1 << 3);
- imageInfoFlagBuilder.AddMemberWithValue("CorrectedSynthesize", 1 << 4);
- imageInfoFlagBuilder.AddMemberWithValue("IsSimulated", 1 << 5);
- imageInfoFlagBuilder.AddMemberWithValue("HasCategoryClassProperties", 1 << 6);
- imageInfoFlagBuilder.AddMemberWithValue("OptimizedByDyldClosure", 1 << 7);
- imageInfoFlagBuilder.AddMemberWithValue("SwiftUnstableVersionMask", 0xff << 8);
- imageInfoFlagBuilder.AddMemberWithValue("SwiftStableVersionMask", 0xFFFF << 16);
- auto imageInfoFlagType = finalizeEnumerationBuilder(m_data, imageInfoFlagBuilder, 4, {"objc_image_info_flags"});
- m_typeNames.imageInfoFlags = imageInfoFlagType.first;
-
- EnumerationBuilder swiftVersionBuilder;
- swiftVersionBuilder.AddMemberWithValue("SwiftVersion1", 1);
- swiftVersionBuilder.AddMemberWithValue("SwiftVersion1_2", 2);
- swiftVersionBuilder.AddMemberWithValue("SwiftVersion2", 3);
- swiftVersionBuilder.AddMemberWithValue("SwiftVersion3", 4);
- swiftVersionBuilder.AddMemberWithValue("SwiftVersion4", 5);
- swiftVersionBuilder.AddMemberWithValue("SwiftVersion4_1", 6); // [sic]
- swiftVersionBuilder.AddMemberWithValue("SwiftVersion4_2", 6);
- swiftVersionBuilder.AddMemberWithValue("SwiftVersion5", 7);
- auto swiftVersionType =
- finalizeEnumerationBuilder(m_data, swiftVersionBuilder, 4, {"objc_image_info_swift_version"});
- m_typeNames.imageInfoSwiftVersion = swiftVersionType.first;
-
- StructureBuilder imageInfoBuilder;
- imageInfoBuilder.AddMember(Type::IntegerType(4, false), "version");
- imageInfoBuilder.AddMember(Type::NamedType(m_data, m_typeNames.imageInfoFlags), "flags");
- auto imageInfoType = finalizeStructureBuilder(m_data, imageInfoBuilder, "objc_image_info_t");
- m_typeNames.imageInfo = imageInfoType.first;
-
- StructureBuilder methodEntry;
- methodEntry.AddMember(relativeSelectorPtr ? relativeSelectorPtr : rptr_t, "name");
- methodEntry.AddMember(rptr_t, "types");
- methodEntry.AddMember(rptr_t, "imp");
- auto type = finalizeStructureBuilder(m_data, methodEntry, "objc_method_entry_t");
- m_typeNames.methodEntry = type.first;
-
- StructureBuilder method;
- method.AddMember(Type::PointerType(addrSize, Type::IntegerType(1, true)), "name");
- method.AddMember(Type::PointerType(addrSize, Type::IntegerType(1, true)), "types");
- method.AddMember(Type::PointerType(addrSize, Type::VoidType()), "imp");
- type = finalizeStructureBuilder(m_data, method, "objc_method_t");
- m_typeNames.method = type.first;
-
- StructureBuilder methList;
- methList.AddMember(Type::IntegerType(4, false), "obsolete");
- methList.AddMember(Type::IntegerType(4, false), "count");
- type = finalizeStructureBuilder(m_data, methList, "objc_method_list_t");
- m_typeNames.methodList = type.first;
-
- StructureBuilder ivarBuilder;
- ivarBuilder.AddMember(Type::PointerType(addrSize, Type::IntegerType(4, false)), "offset");
- ivarBuilder.AddMember(Type::PointerType(addrSize, Type::IntegerType(1, true)), "name");
- ivarBuilder.AddMember(Type::PointerType(addrSize, Type::IntegerType(1, true)), "type");
- ivarBuilder.AddMember(Type::IntegerType(4, false), "alignment");
- ivarBuilder.AddMember(Type::IntegerType(4, false), "size");
- type = finalizeStructureBuilder(m_data, ivarBuilder, "objc_ivar_t");
- m_typeNames.ivar = type.first;
-
- StructureBuilder ivarList;
- ivarList.AddMember(Type::IntegerType(4, false), "entsize");
- ivarList.AddMember(Type::IntegerType(4, false), "count");
- type = finalizeStructureBuilder(m_data, ivarList, "objc_ivar_list_t");
- m_typeNames.ivarList = type.first;
-
- StructureBuilder protocolListBuilder;
- protocolListBuilder.AddMember(Type::IntegerType(addrSize, false), "count");
- m_typeNames.protocolList = finalizeStructureBuilder(m_data, protocolListBuilder, "objc_protocol_list_t").first;
-
- StructureBuilder classROBuilder;
- classROBuilder.AddMember(Type::IntegerType(4, false), "flags");
- classROBuilder.AddMember(Type::IntegerType(4, false), "start");
- classROBuilder.AddMember(Type::IntegerType(4, false), "size");
- if (addrSize == 8)
- classROBuilder.AddMember(Type::IntegerType(4, false), "reserved");
- classROBuilder.AddMember(Type::PointerType(addrSize, Type::VoidType()), "ivar_layout");
- classROBuilder.AddMember(Type::PointerType(addrSize, Type::IntegerType(1, true)), "name");
- classROBuilder.AddMember(Type::PointerType(addrSize, Type::NamedType(m_data, m_typeNames.methodList)), "methods");
- classROBuilder.AddMember(
- Type::PointerType(addrSize, Type::NamedType(m_data, m_typeNames.protocolList)), "protocols");
- classROBuilder.AddMember(Type::PointerType(addrSize, Type::NamedType(m_data, m_typeNames.ivarList)), "ivars");
- classROBuilder.AddMember(Type::PointerType(addrSize, Type::VoidType()), "weak_ivar_layout");
- classROBuilder.AddMember(Type::PointerType(addrSize, Type::VoidType()), "properties");
- type = finalizeStructureBuilder(m_data, classROBuilder, "objc_class_ro_t");
- m_typeNames.classRO = type.first;
-
- QualifiedName classTypeName("objc_class_t");
- auto classTypeId = Type::GenerateAutoTypeId("objc", classTypeName);
- auto isaType = Type::PointerType(m_data->GetDefaultArchitecture(),
- TypeBuilder::NamedType(
- new NamedTypeReferenceBuilder(StructNamedTypeClass, "", classTypeName), m_data->GetAddressSize(), 4)
- .Finalize());
-
- StructureBuilder classBuilder;
- classBuilder.AddMember(isaType, "isa");
- classBuilder.AddMember(Type::PointerType(addrSize, Type::VoidType()), "super");
- classBuilder.AddMember(Type::PointerType(addrSize, Type::VoidType()), "cache");
- classBuilder.AddMember(Type::PointerType(addrSize, Type::VoidType()), "vtable");
- classBuilder.AddMember(Type::PointerType(addrSize, Type::NamedType(m_data, m_typeNames.classRO)), "data");
-
- auto classTypeStruct = classBuilder.Finalize();
- auto classType = Type::StructureType(classTypeStruct);
- auto classQualName = m_data->DefineType(classTypeId, classTypeName, classType);
-
- m_typeNames.cls = classQualName;
-
- StructureBuilder categoryBuilder;
- categoryBuilder.AddMember(Type::PointerType(addrSize, Type::IntegerType(1, true)), "category_name");
- categoryBuilder.AddMember(Type::PointerType(addrSize, Type::NamedType(m_data, m_typeNames.cls)), "class");
- categoryBuilder.AddMember(
- Type::PointerType(addrSize, Type::NamedType(m_data, m_typeNames.methodList)), "inst_methods");
- categoryBuilder.AddMember(
- Type::PointerType(addrSize, Type::NamedType(m_data, m_typeNames.methodList)), "class_methods");
- categoryBuilder.AddMember(Type::PointerType(addrSize, Type::VoidType()), "protocols");
- categoryBuilder.AddMember(Type::PointerType(addrSize, Type::VoidType()), "properties");
- m_typeNames.category = finalizeStructureBuilder(m_data, categoryBuilder, "objc_category_t").first;
-
- StructureBuilder protocolBuilder;
- protocolBuilder.AddMember(Type::PointerType(addrSize, Type::VoidType()), "isa");
- protocolBuilder.AddMember(Type::PointerType(addrSize, Type::IntegerType(1, true)), "mangledName");
- protocolBuilder.AddMember(
- Type::PointerType(addrSize, Type::NamedType(m_data, m_typeNames.protocolList)), "protocols");
- protocolBuilder.AddMember(
- Type::PointerType(addrSize, Type::NamedType(m_data, m_typeNames.methodList)), "instanceMethods");
- protocolBuilder.AddMember(
- Type::PointerType(addrSize, Type::NamedType(m_data, m_typeNames.methodList)), "classMethods");
- protocolBuilder.AddMember(
- Type::PointerType(addrSize, Type::NamedType(m_data, m_typeNames.methodList)), "optionalInstanceMethods");
- protocolBuilder.AddMember(
- Type::PointerType(addrSize, Type::NamedType(m_data, m_typeNames.methodList)), "optionalClassMethods");
- protocolBuilder.AddMember(Type::PointerType(addrSize, Type::VoidType()), "instanceProperties");
- protocolBuilder.AddMember(Type::IntegerType(4, false), "size");
- protocolBuilder.AddMember(Type::IntegerType(4, false), "flags");
- m_typeNames.protocol = finalizeStructureBuilder(m_data, protocolBuilder, "objc_protocol_t").first;
-
- m_data->BeginBulkModifySymbols();
- if (auto classList = m_data->GetSectionByName(baseName + "::__objc_classlist"))
- LoadClasses(&reader, classList);
- if (auto nonLazyClassList = m_data->GetSectionByName(baseName + "::__objc_nlclslist"))
- LoadClasses(&reader, nonLazyClassList); // See: https://stackoverflow.com/a/15318325
-
- GenerateClassTypes();
- for (auto& [_, cls] : m_classes)
- ApplyMethodTypes(cls);
-
- if (auto catList = m_data->GetSectionByName(baseName + "::__objc_catlist")) // Do this after loading class type data.
- LoadCategories(&reader, catList);
- if (auto nonLazyCatList = m_data->GetSectionByName(baseName + "::__objc_nlcatlist")) // Do this after loading class type data.
- LoadCategories(&reader, nonLazyCatList);
- for (auto& [_, cat] : m_categories)
- ApplyMethodTypes(cat);
-
- if (auto protoList = m_data->GetSectionByName(baseName + "::__objc_protolist"))
- LoadProtocols(&reader, protoList);
-
- PostProcessObjCSections(&reader, baseName);
-
- auto id = m_data->BeginUndoActions();
- m_symbolQueue->Process();
- m_data->EndBulkModifySymbols();
- delete m_symbolQueue;
- m_data->ForgetUndoActions(id);
-
- auto meta = SerializeMetadata();
- m_data->StoreMetadata("Objective-C", meta, true);
-
- m_relocationPointerRewrites.clear();
-}
-
-
-void DSCObjCProcessor::ProcessCFStrings(std::shared_ptr<VM> vm, std::string baseName)
-{
- m_symbolQueue = new SymbolQueue();
- uint64_t ptrSize = m_data->GetAddressSize();
- // https://github.com/apple/llvm-project/blob/next/clang/lib/CodeGen/CodeGenModule.cpp#L6129
- // See also ASTContext.cpp ctrl+f __NSConstantString_tag
-
- // The place these flags are used is unclear, along with any clear flag definitions, but they are useful for
- // introspection
- EnumerationBuilder __cfStringFlagBuilder;
- __cfStringFlagBuilder.AddMemberWithValue("SwiftABI", 0b1);
- __cfStringFlagBuilder.AddMemberWithValue("Swift4_1", 0b100);
- // LLVM also sets 0x7c0 (0b11111000000) on both UTF8 and UTF16 strings however it is unclear what this denotes.
- __cfStringFlagBuilder.AddMemberWithValue("UTF8", 0b1000);
- __cfStringFlagBuilder.AddMemberWithValue("UTF16", 0b10000);
- auto type = finalizeEnumerationBuilder(m_data, __cfStringFlagBuilder, ptrSize, {"CFStringFlag"});
- m_typeNames.cfStringFlag = type.first;
-
- StructureBuilder __cfStringStructBuilder;
- __cfStringStructBuilder.AddMember(Type::PointerType(ptrSize, Type::VoidType()), "isa");
- __cfStringStructBuilder.AddMember(Type::NamedType(m_data, m_typeNames.cfStringFlag), "flags");
- __cfStringStructBuilder.AddMember(Type::PointerType(ptrSize, Type::IntegerType(1, true)), "data");
- __cfStringStructBuilder.AddMember(Type::IntegerType(ptrSize, false), "length");
- type = finalizeStructureBuilder(m_data, __cfStringStructBuilder, "__NSConstantString");
- m_typeNames.cfString = type.first;
-
- StructureBuilder __cfStringUTF16StructBuilder;
- __cfStringUTF16StructBuilder.AddMember(Type::PointerType(ptrSize, Type::VoidType()), "isa");
- __cfStringUTF16StructBuilder.AddMember(Type::NamedType(m_data, m_typeNames.cfStringFlag), "flags");
- __cfStringUTF16StructBuilder.AddMember(Type::PointerType(ptrSize, Type::IntegerType(2, true)), "data");
- __cfStringUTF16StructBuilder.AddMember(Type::IntegerType(ptrSize, false), "length");
- type = finalizeStructureBuilder(m_data, __cfStringUTF16StructBuilder, "__NSConstantString_UTF16");
- m_typeNames.cfStringUTF16 = type.first;
-
- auto reader = VMReader(vm);
- if (auto cfstrings = m_data->GetSectionByName(baseName + "::__cfstring"))
- {
- auto start = cfstrings->GetStart();
- auto end = cfstrings->GetEnd();
- auto typeWidth = Type::NamedType(m_data, m_typeNames.cfString)->GetWidth();
- m_data->BeginBulkModifySymbols();
- for (view_ptr_t i = start; i < end; i += typeWidth)
- {
- reader.Seek(i + ptrSize);
- uint64_t flags = reader.ReadPointer();
- auto strLoc = ReadPointerAccountingForRelocations(&reader);
- auto size = reader.ReadPointer();
- std::string str;
- if (flags & 0b10000) // UTF16
- {
- auto data = m_data->ReadBuffer(strLoc, size * 2);
-
- str = "";
- for (uint64_t bufferOff = 0; bufferOff < size * 2; bufferOff += 2)
- {
- uint8_t* rawData = static_cast<uint8_t*>(data.GetData());
- uint8_t* offsetAddress = rawData + bufferOff;
- uint16_t c = *reinterpret_cast<uint16_t*>(offsetAddress);
- if (c == 0x20)
- str.push_back('_');
- else if (c < 0x80)
- str.push_back(c);
- else
- str.push_back('?');
- }
- DefineObjCSymbol(
- DataSymbol, Type::ArrayType(Type::WideCharType(2), size + 1), "ustr_" + str, strLoc, true);
- DefineObjCSymbol(
- DataSymbol, Type::NamedType(m_data, m_typeNames.cfStringUTF16), "cfstr_" + str, i, true);
- }
- else // UTF8 / ASCII
- {
- reader.Seek(strLoc);
- str = reader.ReadCString(strLoc);
- for (auto& c : str)
- {
- if (c == ' ')
- c = '_';
- }
- DefineObjCSymbol(DataSymbol, Type::ArrayType(Type::IntegerType(1, true), str.size() + 1), "cstr_" + str,
- strLoc, true);
- DefineObjCSymbol(DataSymbol, Type::NamedType(m_data, m_typeNames.cfString), "cfstr_" + str, i, true);
- }
- }
- auto id = m_data->BeginUndoActions();
- m_symbolQueue->Process();
- m_data->EndBulkModifySymbols();
- m_data->ForgetUndoActions(id);
- }
- delete m_symbolQueue;
+ auto objCRelativeMethodsBaseAddr = m_cache->GetObjCRelativeMethodBaseAddress(static_cast<DSCObjCReader*>(reader)->GetVMReader());
+ m_customRelativeMethodSelectorBase = objCRelativeMethodsBaseAddr;
+ return objCRelativeMethodsBaseAddr;
}
-void DSCObjCProcessor::AddRelocatedPointer(uint64_t location, uint64_t rewrite)
+DSCObjCProcessor::DSCObjCProcessor(BinaryView* data, SharedCache* cache, bool isBackedByDatabase) :
+ ObjCProcessor(data, "SharedCache.ObjC", isBackedByDatabase, true), m_cache(cache)
{
- m_relocationPointerRewrites[location] = rewrite;
}
diff --git a/view/sharedcache/core/ObjC.h b/view/sharedcache/core/ObjC.h
index a308c23a..13790364 100644
--- a/view/sharedcache/core/ObjC.h
+++ b/view/sharedcache/core/ObjC.h
@@ -6,233 +6,47 @@
#define SHAREDCACHE_OBJC_H
#include <binaryninjaapi.h>
-#include "VM.h"
+#include <objectivec/objc.h>
#include "SharedCache.h"
-using namespace BinaryNinja;
-
-
namespace DSCObjC {
+ class DSCObjCReader : public ObjCReader {
+ private:
+ VMReader m_reader;
+ size_t m_addressSize;
- // This set of structs is based on the objc4 source,
- // however pointers have been replaced with view_ptr_t
-
- // Used for pointers within BinaryView, primarily to make it far more clear in typedefs
- // whether the size of a field can vary between architectures.
- // These should _not_ be used in sizeof or direct Read() calls.
- typedef uint64_t view_ptr_t;
-
- typedef struct {
- view_ptr_t name;
- view_ptr_t types;
- view_ptr_t imp;
- } method_t;
- typedef struct {
- uint32_t name;
- uint32_t types;
- uint32_t imp;
- } method_entry_t;
- typedef struct {
- view_ptr_t offset;
- view_ptr_t name;
- view_ptr_t type;
- uint32_t alignmentRaw;
- uint32_t size;
- } ivar_t;
- typedef struct {
- view_ptr_t name;
- view_ptr_t attributes;
- } property_t;
- typedef struct {
- uint32_t entsizeAndFlags;
- uint32_t count;
- } method_list_t;
- typedef struct {
- uint32_t entsizeAndFlags;
- uint32_t count;
- } ivar_list_t;
- typedef struct {
- uint32_t entsizeAndFlags;
- uint32_t count;
- } property_list_t;
- typedef struct {
- uint64_t count;
- } protocol_list_t;
- struct relative_list_list_entry_t {
- uint64_t imageIndex: 16;
- int64_t listOffset: 48;
- };
- typedef struct {
- view_ptr_t isa;
- view_ptr_t mangledName;
- view_ptr_t protocols;
- view_ptr_t instanceMethods;
- view_ptr_t classMethods;
- view_ptr_t optionalInstanceMethods;
- view_ptr_t optionalClassMethods;
- view_ptr_t instanceProperties;
- uint32_t size;
- uint32_t flags;
- } protocol_t;
- typedef struct {
- uint32_t flags;
- uint32_t instanceStart;
- uint32_t instanceSize;
- uint32_t reserved;
- view_ptr_t ivarLayout;
- view_ptr_t name;
- view_ptr_t baseMethods;
- view_ptr_t baseProtocols;
- view_ptr_t ivars;
- view_ptr_t weakIvarLayout;
- view_ptr_t baseProperties;
- } class_ro_t;
- typedef struct {
- view_ptr_t isa;
- view_ptr_t super;
- view_ptr_t cache;
- view_ptr_t vtable;
- view_ptr_t data;
- } class_t;
- typedef struct {
- view_ptr_t name;
- view_ptr_t cls;
- view_ptr_t instanceMethods;
- view_ptr_t classMethods;
- view_ptr_t protocols;
- view_ptr_t instanceProperties;
- } category_t;
- typedef struct {
- view_ptr_t receiver;
- view_ptr_t current_class;
- } objc_super2;
- typedef struct {
- view_ptr_t imp;
- view_ptr_t sel;
- } message_ref_t;
-
- struct Method {
- std::string name;
- std::string types;
- view_ptr_t imp;
- };
-
- struct Ivar {
- uint32_t offset;
- std::string name;
- std::string type;
- uint32_t alignment;
- uint32_t size;
- };
-
- struct Property {
- std::string name;
- std::string attributes;
- };
-
- struct ClassBase {
- std::map<uint64_t, Method> methodList;
- std::map<uint64_t, Ivar> ivarList;
- };
-
- struct Class {
- std::string name;
- ClassBase instanceClass;
- ClassBase metaClass;
-
- // Loaded by type processing
- QualifiedName associatedName;
- };
-
- class Protocol {
public:
- std::string name;
- std::vector<QualifiedName> protocols;
- ClassBase instanceMethods;
- ClassBase classMethods;
- ClassBase optionalInstanceMethods;
- ClassBase optionalClassMethods;
- };
-
- struct QualifiedNameOrType {
- BinaryNinja::Ref<BinaryNinja::Type> type = nullptr;
- BinaryNinja::QualifiedName name;
- size_t ptrCount = 0;
- };
+ void Read(void* dest, size_t len) override;
+ std::string ReadCString() override;
+ uint8_t Read8() override;
+ uint16_t Read16() override;
+ uint32_t Read32() override;
+ uint64_t Read64() override;
+ int8_t ReadS8() override;
+ int16_t ReadS16() override;
+ int32_t ReadS32() override;
+ int64_t ReadS64() override;
+ uint64_t ReadPointer() override;
+ uint64_t GetOffset() const override;
+ void Seek(uint64_t offset) override;
+ void SeekRelative(int64_t offset) override;
- class DSCObjCProcessor {
- struct Types {
- // QualifiedName relativePtr;
- // QualifiedName id;
- // QualifiedName sel;
- // QualifiedName BOOL;
- // QualifiedName nsInteger;
- // QualifiedName nsuInteger;
- // QualifiedName cgFloat;
- QualifiedName cfStringFlag;
- QualifiedName cfString;
- QualifiedName cfStringUTF16;
- QualifiedName imageInfoFlags;
- QualifiedName imageInfoSwiftVersion;
- QualifiedName imageInfo;
- QualifiedName methodEntry;
- QualifiedName method;
- QualifiedName methodList;
- QualifiedName classRO;
- QualifiedName cls;
- QualifiedName category;
- QualifiedName protocol;
- QualifiedName protocolList;
- QualifiedName ivar;
- QualifiedName ivarList;
- } m_typeNames;
-
- bool m_isBackedByDatabase;
-
- BinaryView* m_data;
- SymbolQueue* m_symbolQueue = nullptr;
- Ref<Logger> m_logger;
- std::map<uint64_t, Class> m_classes;
- std::map<uint64_t, Class> m_categories;
- std::map<uint64_t, Protocol> m_protocols;
- std::unordered_map<uint64_t, std::string> m_selectorCache;
- std::unordered_map<uint64_t, Method> m_localMethods;
-
- // Required for workflow_objc type heuristics, should be removed when that is no longer a thing.
- std::map<uint64_t, std::string> m_selRefToName;
- std::map<uint64_t, std::vector<uint64_t>> m_selRefToImplementations;
- std::map<uint64_t, std::vector<uint64_t>> m_selToImplementations;
- // --
+ VMReader& GetVMReader();
+ DSCObjCReader(SharedCacheCore::SharedCache* cache, size_t addressSize);
+ };
+ class DSCObjCProcessor : public ObjCProcessor {
std::optional<uint64_t> m_customRelativeMethodSelectorBase = std::nullopt;
SharedCacheCore::SharedCache* m_cache;
- uint64_t ReadPointerAccountingForRelocations(VMReader* reader);
- std::unordered_map<uint64_t, uint64_t> m_relocationPointerRewrites;
-
- static Ref<Metadata> SerializeMethod(uint64_t loc, const Method& method);
- static Ref<Metadata> SerializeClass(uint64_t loc, const Class& cls);
-
- Ref<Metadata> SerializeMetadata();
- std::vector<QualifiedNameOrType> ParseEncodedType(const std::string& type);
- void DefineObjCSymbol(BNSymbolType symbolType, QualifiedName typeName, const std::string& name, uint64_t addr, bool deferred);
- void DefineObjCSymbol(BNSymbolType symbolType, Ref<Type> type, const std::string& name, uint64_t addr, bool deferred);
- void ReadIvarList(VMReader* reader, ClassBase& cls, std::string_view name, view_ptr_t start);
- void ReadMethodList(VMReader* reader, ClassBase& cls, std::string_view name, view_ptr_t start);
- void ReadListOfMethodLists(VMReader* reader, ClassBase& cls, std::string_view name, view_ptr_t start);
- void LoadClasses(VMReader* reader, Ref<Section> listSection);
- void LoadCategories(VMReader* reader, Ref<Section> listSection);
- void LoadProtocols(VMReader* reader, Ref<Section> listSection);
- void GenerateClassTypes();
- bool ApplyMethodType(Class& cls, Method& method, bool isInstanceMethod);
- void ApplyMethodTypes(Class& cls);
- void PostProcessObjCSections(VMReader* reader, std::string baseName);
+ std::shared_ptr<ObjCReader> GetReader() override;
+ void GetRelativeMethod(ObjCReader* reader, method_t& meth) override;
+
public:
DSCObjCProcessor(BinaryView* data, SharedCacheCore::SharedCache* cache, bool isBackedByDatabase);
- void ProcessObjCData(std::shared_ptr<VM> vm, std::string baseName);
- void ProcessCFStrings(std::shared_ptr<VM> vm, std::string baseName);
- void AddRelocatedPointer(uint64_t location, uint64_t rewrite);
+
+ uint64_t GetObjCRelativeMethodBaseAddress(ObjCReader* reader) override;
};
}
#endif //SHAREDCACHE_OBJC_H
diff --git a/view/sharedcache/core/SharedCache.cpp b/view/sharedcache/core/SharedCache.cpp
index 5709759b..2b18c064 100644
--- a/view/sharedcache/core/SharedCache.cpp
+++ b/view/sharedcache/core/SharedCache.cpp
@@ -1673,9 +1673,9 @@ static void ProcessObjCSectionsForImageWithName(std::string baseName, std::share
try
{
if (processObjCMetadata)
- objc->ProcessObjCData(vm, baseName);
+ objc->ProcessObjCData(baseName);
if (processCFStrings)
- objc->ProcessCFStrings(vm, baseName);
+ objc->ProcessCFStrings(baseName);
}
catch (const std::exception& ex)
{