summaryrefslogtreecommitdiff
path: root/view/macho
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/macho
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/macho')
-rw-r--r--view/macho/CMakeLists.txt4
-rw-r--r--view/macho/machoview.cpp10
-rw-r--r--view/macho/machoview.h2
-rw-r--r--view/macho/objc.cpp1485
-rw-r--r--view/macho/objc.h228
5 files changed, 67 insertions, 1662 deletions
diff --git a/view/macho/CMakeLists.txt b/view/macho/CMakeLists.txt
index 6f89250a..fc8a8f7b 100644
--- a/view/macho/CMakeLists.txt
+++ b/view/macho/CMakeLists.txt
@@ -6,9 +6,7 @@ if(NOT BN_INTERNAL_BUILD)
add_subdirectory(${PROJECT_SOURCE_DIR}/../.. ${PROJECT_BINARY_DIR}/api)
endif()
-file(GLOB SOURCES
- *.cpp
- *.h)
+file(GLOB SOURCES *.cpp *.h ../../objectivec/*)
if(DEMO)
add_library(view_macho STATIC ${SOURCES})
diff --git a/view/macho/machoview.cpp b/view/macho/machoview.cpp
index 2a927671..8a320545 100644
--- a/view/macho/machoview.cpp
+++ b/view/macho/machoview.cpp
@@ -1840,13 +1840,13 @@ bool MachoView::InitializeHeader(MachOHeader& header, bool isMainHeader, uint64_
parseObjCStructs = settings->Get<bool>("loader.macho.processObjectiveC", this);
if (settings && settings->Contains("loader.macho.processCFStrings"))
parseCFStrings = settings->Get<bool>("loader.macho.processCFStrings", this);
- if (!ObjCProcessor::ViewHasObjCMetadata(this))
+ if (!MachoObjCProcessor::ViewHasObjCMetadata(this))
parseObjCStructs = false;
if (!GetSectionByName("__cfstring"))
parseCFStrings = false;
if (parseObjCStructs || parseCFStrings)
{
- m_objcProcessor = new ObjCProcessor(this, m_backedByDatabase);
+ m_objcProcessor = new MachoObjCProcessor(this, m_backedByDatabase);
}
if (parseObjCStructs)
{
@@ -2332,7 +2332,7 @@ bool MachoView::InitializeHeader(MachOHeader& header, bool isMainHeader, uint64_
if (parseCFStrings)
{
try {
- m_objcProcessor->ProcessCFStrings();
+ m_objcProcessor->ProcessCFStrings(std::nullopt);
}
catch (std::exception& ex)
{
@@ -2344,7 +2344,7 @@ bool MachoView::InitializeHeader(MachOHeader& header, bool isMainHeader, uint64_
if (parseObjCStructs)
{
try {
- m_objcProcessor->ProcessObjCData();
+ m_objcProcessor->ProcessObjCData(std::nullopt);
}
catch (std::exception& ex)
{
@@ -3872,7 +3872,7 @@ Ref<Settings> MachoViewType::GetLoadSettingsForData(BinaryView* data)
settings->UpdateProperty(override, "readOnly", false);
}
- if (ObjCProcessor::ViewHasObjCMetadata(viewRef))
+ if (MachoObjCProcessor::ViewHasObjCMetadata(viewRef))
{
settings->RegisterSetting("loader.macho.processObjectiveC",
R"({
diff --git a/view/macho/machoview.h b/view/macho/machoview.h
index e7927383..11a17bff 100644
--- a/view/macho/machoview.h
+++ b/view/macho/machoview.h
@@ -1446,7 +1446,7 @@ namespace BinaryNinja
QualifiedName filesetEntryCommandQualName;
} m_typeNames;
- ObjCProcessor* m_objcProcessor = nullptr;
+ MachoObjCProcessor* m_objcProcessor = nullptr;
uint64_t m_universalImageOffset;
bool m_parseOnly, m_backedByDatabase;
diff --git a/view/macho/objc.cpp b/view/macho/objc.cpp
index 5dec6e90..6663a44b 100644
--- a/view/macho/objc.cpp
+++ b/view/macho/objc.cpp
@@ -1,1506 +1,93 @@
#include "objc.h"
-#include "machoview.h"
-#include "inttypes.h"
-#include "rapidjson/rapidjson.h"
-#include "rapidjson/document.h"
-#include "rapidjson/stringbuffer.h"
-#include "rapidjson/prettywriter.h"
using namespace BinaryNinja;
-Ref<Metadata> ObjCProcessor::SerializeMethod(uint64_t loc, const Method& method)
+MachoObjCReader::MachoObjCReader(BinaryView* data) : m_reader(BinaryReader(data))
{
- 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> ObjCProcessor::SerializeClass(uint64_t loc, const Class& cls)
-{
- 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);
-}
-
-Ref<Metadata> ObjCProcessor::SerializeMetadata()
-{
- 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);
-}
-
-std::vector<QualifiedNameOrType> ObjCProcessor::ParseEncodedType(const std::string& encodedType)
-{
- 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;
}
-void ObjCProcessor::DefineObjCSymbol(
- BNSymbolType type, QualifiedName typeName, const std::string& name, uint64_t addr, bool deferred)
+void MachoObjCReader::Read(void* dest, size_t len)
{
- DefineObjCSymbol(type, m_data->GetTypeByName(typeName), name, addr, deferred);
+ m_reader.Read(dest, len);
}
-void ObjCProcessor::DefineObjCSymbol(
- BNSymbolType type, Ref<Type> typeRef, const std::string& name, uint64_t addr, bool deferred)
+std::string MachoObjCReader::ReadCString()
{
- 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);
- }
- }
-}
-
-void ObjCProcessor::LoadClasses(BinaryReader* reader, Ref<Section> classPtrSection)
-{
- 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 (ReadException& ex)
- {
- 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 (ReadException& ex)
- {
- 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(500);
- }
- catch (ReadException& ex)
- {
- 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), "%" PRIx64, 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 (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 (ReadException& ex)
- {
- 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 (ReadException& ex)
- {
- 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 (ReadException& ex)
- {
- 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 (ReadException& ex)
- {
- 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 (ReadException& ex)
- {
- m_logger->LogError("Failed to process ivars for class at 0x%llx", clsStruct.data);
- }
- }
- m_classes[classPtr] = cls;
- }
-}
-
-void ObjCProcessor::LoadCategories(BinaryReader* 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 (ReadException& ex)
- {
- 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();
- }
- catch (ReadException& ex)
- {
- 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 (ReadException& ex)
- {
- 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 (ReadException& ex)
- {
- m_logger->LogError(
- "Failed to read the class method list for category pointed to by 0x%llx", catLocation);
- }
- }
- m_categories[catLocation] = category;
- }
-}
-
-void ObjCProcessor::LoadProtocols(BinaryReader* reader, Ref<Section> listSection)
-{
- 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 (ReadException& ex)
- {
- 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();
- DefineObjCSymbol(BNSymbolType::DataSymbol,
- Type::ArrayType(Type::IntegerType(1, true), protocolName.size() + 1), "protocolName_" + protocolName,
- protocol.mangledName, true);
- }
- catch (ReadException& ex)
- {
- 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 (ReadException& ex)
- {
- 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 (ReadException& ex)
- {
- 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 (ReadException& ex)
- {
- 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 (ReadException& ex)
- {
- 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.ReadCString();
}
-void ObjCProcessor::ReadMethodList(BinaryReader* reader, ClassBase& cls, std::string name, view_ptr_t start)
+uint8_t MachoObjCReader::Read8()
{
- reader->Seek(start);
- method_list_t head;
- head.entsizeAndFlags = reader->Read32();
- head.count = reader->Read32();
- 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_" + 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)
- {
- meth.name = cursor + static_cast<int32_t>(reader->Read32());
- meth.types = cursor + 4 + static_cast<int32_t>(reader->Read32());
- meth.imp = cursor + 8 + static_cast<int32_t>(reader->Read32());
- }
- else
- {
- meth.name = ReadPointerAccountingForRelocations(reader);
- meth.types = ReadPointerAccountingForRelocations(reader);
- meth.imp = ReadPointerAccountingForRelocations(reader);
- }
- if (!relativeOffsets || directSelectors)
- {
- reader->Seek(meth.name);
- selAddr = meth.name;
- method.name = reader->ReadCString();
- reader->Seek(meth.types);
- method.types = reader->ReadCString();
- 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();
- 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 (ReadException& ex)
- {
- m_logger->LogError(
- "Failed to process a method at offset 0x%llx", start + sizeof(method_list_t) + (i * methodSize));
- }
- }
+ return m_reader.Read8();
}
-void ObjCProcessor::ReadIvarList(BinaryReader* reader, ClassBase& cls, std::string name, view_ptr_t start)
+uint16_t MachoObjCReader::Read16()
{
- 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_" + name, start, true);
- 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();
- reader->Seek(ivarStruct.type);
- ivar.type = reader->ReadCString();
-
- 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 (ReadException& ex)
- {
- m_logger->LogError("Failed to process an ivar at offset 0x%llx",
- start + (sizeof(ivar_list_t)) + (i * ((addressSize * 3) + 8)));
- }
- }
+ return m_reader.Read16();
}
-bool ObjCProcessor::ViewHasObjCMetadata(BinaryNinja::BinaryView* data)
+uint32_t MachoObjCReader::Read32()
{
- return (data->GetSectionByName("__objc_classlist") || data->GetSectionByName("__objc_catlist")
- || data->GetSectionByName("__objc_protolist"));
+ return m_reader.Read32();
}
-
-std::pair<QualifiedName, Ref<Type>> finalizeStructureBuilder(
- Ref<BinaryView> m_data, StructureBuilder sb, std::string name)
+uint64_t MachoObjCReader::Read64()
{
- 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.Read64();
}
-std::pair<QualifiedName, Ref<Type>> finalizeEnumerationBuilder(
- Ref<BinaryView> m_data, EnumerationBuilder eb, uint64_t size, QualifiedName name)
+int8_t MachoObjCReader::ReadS8()
{
- 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 static_cast<int8_t>(m_reader.Read8());
}
-inline QualifiedName defineTypedef(Ref<BinaryView> m_data, const QualifiedName name, Ref<Type> type)
+int16_t MachoObjCReader::ReadS16()
{
- auto typeID = Type::GenerateAutoTypeId("objc", name);
- m_data->DefineType(typeID, name, type);
- return m_data->GetTypeNameById(typeID);
+ return static_cast<int16_t>(m_reader.Read16());
}
-void ObjCProcessor::GenerateClassTypes()
+int32_t MachoObjCReader::ReadS32()
{
- 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;
- }
+ return static_cast<int32_t>(m_reader.Read32());
}
-bool ObjCProcessor::ApplyMethodType(Class& cls, Method& method, bool isInstanceMethod)
+int64_t MachoObjCReader::ReadS64()
{
- 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 static_cast<int64_t>(m_reader.Read64());
}
-void ObjCProcessor::ApplyMethodTypes(Class& cls)
+uint64_t MachoObjCReader::ReadPointer()
{
- for (auto& [_, method] : cls.instanceClass.methodList)
- {
- ApplyMethodType(cls, method, true);
- }
- for (auto& [_, method] : cls.metaClass.methodList)
- {
- ApplyMethodType(cls, method, false);
- }
+ return m_reader.ReadPointer();
}
-void ObjCProcessor::PostProcessObjCSections(BinaryReader* reader)
+uint64_t MachoObjCReader::GetOffset() const
{
- auto ptrSize = m_data->GetAddressSize();
- if (auto imageInfo = m_data->GetSectionByName("__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("__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();
- 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("__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("__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("__objc_protorefs"))
- {
- 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);
- }
- }
- }
- if (auto ivars = m_data->GetSectionByName("__objc_ivar"))
- {
- 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);
- }
- }
+ return m_reader.GetOffset();
}
-uint64_t ObjCProcessor::ReadPointerAccountingForRelocations(BinaryReader* reader)
+void MachoObjCReader::Seek(uint64_t offset)
{
- if (auto it = m_relocationPointerRewrites.find(reader->GetOffset()); it != m_relocationPointerRewrites.end())
- {
- reader->SeekRelative(m_data->GetAddressSize());
- return it->second;
- }
- return reader->ReadPointer();
+ m_reader.Seek(offset);
}
-
-ObjCProcessor::ObjCProcessor(BinaryNinja::BinaryView* data, bool isBackedByDatabase) :
- m_isBackedByDatabase(isBackedByDatabase), m_data(data)
+void MachoObjCReader::SeekRelative(int64_t offset)
{
- m_logger = m_data->CreateLogger("macho.objc");
+ m_reader.SeekRelative(offset);
}
-void ObjCProcessor::ProcessObjCData()
+std::shared_ptr<ObjCReader> MachoObjCProcessor::GetReader()
{
- m_symbolQueue = new SymbolQueue();
- auto addrSize = m_data->GetAddressSize();
-
- // m_typeNames.relativePtr = defineTypedef(m_data, {"rptr_t"}, Type::IntegerType(4, true));
- // auto rptr_t = Type::NamedType(m_data, 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));
-
- // 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(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;
-
- auto reader = BinaryReader(m_data);
- m_data->BeginBulkModifySymbols();
- if (auto classList = m_data->GetSectionByName("__objc_classlist"))
- LoadClasses(&reader, classList);
- if (auto nonLazyClassList = m_data->GetSectionByName("__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("__objc_catlist")) // Do this after loading class type data.
- LoadCategories(&reader, catList);
- if (auto nonLazyCatList = m_data->GetSectionByName("__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("__objc_protolist"))
- LoadProtocols(&reader, protoList);
-
- PostProcessObjCSections(&reader);
-
- 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();
+ return std::make_shared<MachoObjCReader>(m_data);
}
-
-void ObjCProcessor::ProcessCFStrings()
+bool MachoObjCProcessor::ViewHasObjCMetadata(BinaryView* data)
{
- 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 = BinaryReader(m_data);
- if (auto cfstrings = m_data->GetSectionByName("__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 == '\r') {
- str.push_back('\\');
- str.push_back('r');
- } else if (c == '\n') {
- str.push_back('\\');
- str.push_back('n');
- } else if (c == '\t') {
- str.push_back('\\');
- str.push_back('t');
- } else if (c > 0x20 && 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);
- std::string rawStr = reader.ReadCString(size + 1);
- str = "";
- for (signed char c : rawStr)
- {
- if (c == 0x20) {
- str.push_back('_');
- } else if (c == '\r') {
- str.push_back('\\');
- str.push_back('r');
- } else if (c == '\n') {
- str.push_back('\\');
- str.push_back('n');
- } else if (c == '\t') {
- str.push_back('\\');
- str.push_back('t');
- } else if (c > 0x20 || c < 0) {
- str.push_back(c);
- } else {
- str.push_back('?');
- }
- }
- 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;
+ return (data->GetSectionByName("__objc_classlist") || data->GetSectionByName("__objc_catlist")
+ || data->GetSectionByName("__objc_protolist"));
}
-void ObjCProcessor::AddRelocatedPointer(uint64_t location, uint64_t rewrite)
+MachoObjCProcessor::MachoObjCProcessor(BinaryView* data, bool isBackedByDatabase) :
+ ObjCProcessor(data, "macho.objc", isBackedByDatabase)
{
- m_relocationPointerRewrites[location] = rewrite;
}
diff --git a/view/macho/objc.h b/view/macho/objc.h
index 452cfed0..42aec8d0 100644
--- a/view/macho/objc.h
+++ b/view/macho/objc.h
@@ -1,219 +1,39 @@
#pragma once
#include <binaryninjaapi.h>
+#include <objectivec/objc.h>
namespace BinaryNinja {
- // This set of structs is based on the objc4 source,
- // however pointers have been replaced with view_ptr_t
+ class MachoObjCReader : public ObjCReader {
+ private:
+ BinaryReader m_reader;
- // 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;
- 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;
- };
+ 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;
- struct QualifiedNameOrType {
- BinaryNinja::Ref<BinaryNinja::Type> type = nullptr;
- BinaryNinja::QualifiedName name;
- size_t ptrCount = 0;
+ MachoObjCReader(BinaryView* data);
};
- class ObjCProcessor {
- 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;
- // --
-
- uint64_t ReadPointerAccountingForRelocations(BinaryReader* 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(BinaryReader* reader, ClassBase& cls, std::string name, view_ptr_t start);
- void ReadMethodList(BinaryReader* reader, ClassBase& cls, std::string name, view_ptr_t start);
- void LoadClasses(BinaryReader* reader, Ref<Section> listSection);
- void LoadCategories(BinaryReader* reader, Ref<Section> listSection);
- void LoadProtocols(BinaryReader* reader, Ref<Section> listSection);
- void GenerateClassTypes();
- bool ApplyMethodType(Class& cls, Method& method, bool isInstanceMethod);
- void ApplyMethodTypes(Class& cls);
- void PostProcessObjCSections(BinaryReader* reader);
+ class MachoObjCProcessor : public ObjCProcessor {
+ std::shared_ptr<ObjCReader> GetReader() override;
+
public:
+ MachoObjCProcessor(BinaryView* data, bool isBackedByDatabase);
+
static bool ViewHasObjCMetadata(BinaryView* data);
- ObjCProcessor(BinaryView* data, bool isBackedByDatabase);
- void ProcessObjCData();
- void ProcessCFStrings();
- void AddRelocatedPointer(uint64_t location, uint64_t rewrite);
};
}