From ee500220baa1a46f3d7ca1486fa43dc1587f20d0 Mon Sep 17 00:00:00 2001 From: WeiN76LQh Date: Fri, 3 Jan 2025 17:55:10 +0000 Subject: [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. --- view/sharedcache/core/ObjC.h | 248 ++++++------------------------------------- 1 file changed, 31 insertions(+), 217 deletions(-) (limited to 'view/sharedcache/core/ObjC.h') 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 -#include "VM.h" +#include #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 methodList; - std::map ivarList; - }; - - struct Class { - std::string name; - ClassBase instanceClass; - ClassBase metaClass; - - // Loaded by type processing - QualifiedName associatedName; - }; - - class Protocol { public: - std::string name; - std::vector protocols; - ClassBase instanceMethods; - ClassBase classMethods; - ClassBase optionalInstanceMethods; - ClassBase optionalClassMethods; - }; - - struct QualifiedNameOrType { - BinaryNinja::Ref type = nullptr; - BinaryNinja::QualifiedName name; - size_t ptrCount = 0; - }; - - 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 m_logger; - std::map m_classes; - std::map m_categories; - std::map m_protocols; - std::unordered_map m_selectorCache; - std::unordered_map m_localMethods; - - // Required for workflow_objc type heuristics, should be removed when that is no longer a thing. - std::map m_selRefToName; - std::map> m_selRefToImplementations; - std::map> m_selToImplementations; - // -- - - + 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; + + VMReader& GetVMReader(); + + DSCObjCReader(SharedCacheCore::SharedCache* cache, size_t addressSize); + }; + + class DSCObjCProcessor : public ObjCProcessor { std::optional m_customRelativeMethodSelectorBase = std::nullopt; SharedCacheCore::SharedCache* m_cache; - uint64_t ReadPointerAccountingForRelocations(VMReader* reader); - std::unordered_map m_relocationPointerRewrites; - - static Ref SerializeMethod(uint64_t loc, const Method& method); - static Ref SerializeClass(uint64_t loc, const Class& cls); - - Ref SerializeMetadata(); - std::vector 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, 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
listSection); - void LoadCategories(VMReader* reader, Ref
listSection); - void LoadProtocols(VMReader* reader, Ref
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 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, std::string baseName); - void ProcessCFStrings(std::shared_ptr vm, std::string baseName); - void AddRelocatedPointer(uint64_t location, uint64_t rewrite); + + uint64_t GetObjCRelativeMethodBaseAddress(ObjCReader* reader) override; }; } #endif //SHAREDCACHE_OBJC_H -- cgit v1.3.1