#pragma once #include #include "../core/MetadataSerializable.hpp" #include "view/macho/machoview.h" #include "sharedcachecore.h" using namespace BinaryNinja; namespace SharedCacheAPI { template class SCRefCountObject { void AddRefInternal() { m_refs.fetch_add(1); } void ReleaseInternal() { if (m_refs.fetch_sub(1) == 1) delete this; } public: std::atomic m_refs; T *m_object; SCRefCountObject() : m_refs(0), m_object(nullptr) {} virtual ~SCRefCountObject() {} T *GetObject() const { return m_object; } static T *GetObject(SCRefCountObject *obj) { if (!obj) return nullptr; return obj->GetObject(); } void AddRef() { AddRefInternal(); } void Release() { ReleaseInternal(); } void AddRefForRegistration() { AddRefInternal(); } }; template class SCCoreRefCountObject { void AddRefInternal() { m_refs.fetch_add(1); } void ReleaseInternal() { if (m_refs.fetch_sub(1) == 1) { if (!m_registeredRef) delete this; } } public: std::atomic m_refs; bool m_registeredRef = false; T *m_object; SCCoreRefCountObject() : m_refs(0), m_object(nullptr) {} virtual ~SCCoreRefCountObject() {} T *GetObject() const { return m_object; } static T *GetObject(SCCoreRefCountObject *obj) { if (!obj) return nullptr; return obj->GetObject(); } void AddRef() { if (m_object && (m_refs != 0)) AddObjectReference(m_object); AddRefInternal(); } void Release() { if (m_object) FreeObjectReference(m_object); ReleaseInternal(); } void AddRefForRegistration() { m_registeredRef = true; } void ReleaseForRegistration() { m_object = nullptr; m_registeredRef = false; if (m_refs == 0) delete this; } }; struct DSCMemoryRegion { uint64_t vmAddress; uint64_t size; std::string prettyName; }; struct BackingCacheMapping { uint64_t vmAddress; uint64_t size; uint64_t fileOffset; }; struct BackingCache { std::string path; bool isPrimary; std::vector mappings; }; struct DSCImageMemoryMapping { std::string filePath; std::string name; uint64_t vmAddress; uint64_t size; bool loaded; uint64_t rawViewOffset; }; struct DSCImage { std::string name; uint64_t headerAddress; std::vector mappings; }; struct DSCSymbol { uint64_t address; std::string name; std::string image; }; using namespace BinaryNinja; struct SharedCacheMachOHeader : public SharedCacheCore::MetadataSerializable { uint64_t textBase = 0; uint64_t loadCommandOffset = 0; mach_header_64 ident; std::string identifierPrefix; std::string installName; std::vector> entryPoints; std::vector m_entryPoints; //list of entrypoints symtab_command symtab; dysymtab_command dysymtab; dyld_info_command dyldInfo; routines_command_64 routines64; function_starts_command functionStarts; std::vector moduleInitSections; linkedit_data_command exportTrie; linkedit_data_command chainedFixups {}; uint64_t relocationBase; // Section and program headers, internally use 64-bit form as it is a superset of 32-bit std::vector segments; //only three types of sections __TEXT, __DATA, __IMPORT segment_command_64 linkeditSegment; std::vector sections; std::vector sectionNames; std::vector symbolStubSections; std::vector symbolPointerSections; std::vector dylibs; build_version_command buildVersion; std::vector buildToolVersions; std::string exportTriePath; bool dysymPresent = false; bool dyldInfoPresent = false; bool exportTriePresent = false; bool chainedFixupsPresent = false; bool routinesPresent = false; bool functionStartsPresent = false; bool relocatable = false; void Store(SharedCacheCore::SerializationContext& context) const { MSS(textBase); MSS(loadCommandOffset); MSS_SUBCLASS(ident); MSS(identifierPrefix); MSS(installName); MSS(entryPoints); MSS(m_entryPoints); MSS_SUBCLASS(symtab); MSS_SUBCLASS(dysymtab); MSS_SUBCLASS(dyldInfo); // MSS_SUBCLASS(routines64); MSS_SUBCLASS(functionStarts); MSS_SUBCLASS(moduleInitSections); MSS_SUBCLASS(exportTrie); MSS_SUBCLASS(chainedFixups); MSS(relocationBase); MSS_SUBCLASS(segments); MSS_SUBCLASS(linkeditSegment); MSS_SUBCLASS(sections); MSS(sectionNames); MSS_SUBCLASS(symbolStubSections); MSS_SUBCLASS(symbolPointerSections); MSS(dylibs); MSS_SUBCLASS(buildVersion); MSS_SUBCLASS(buildToolVersions); MSS(exportTriePath); MSS(dysymPresent); MSS(dyldInfoPresent); MSS(exportTriePresent); MSS(chainedFixupsPresent); MSS(routinesPresent); MSS(functionStartsPresent); MSS(relocatable); } void Load(SharedCacheCore::DeserializationContext& context) { MSL(textBase); MSL(loadCommandOffset); MSL_SUBCLASS(ident); MSL(identifierPrefix); MSL(installName); MSL(entryPoints); MSL(m_entryPoints); MSL_SUBCLASS(symtab); MSL_SUBCLASS(dysymtab); MSL_SUBCLASS(dyldInfo); // MSL_SUBCLASS(routines64); // FIXME CRASH but also do we even use this? MSL_SUBCLASS(functionStarts); MSL_SUBCLASS(moduleInitSections); MSL_SUBCLASS(exportTrie); MSL_SUBCLASS(chainedFixups); MSL(relocationBase); MSL_SUBCLASS(segments); MSL_SUBCLASS(linkeditSegment); MSL_SUBCLASS(sections); MSL(sectionNames); MSL_SUBCLASS(symbolStubSections); MSL_SUBCLASS(symbolPointerSections); MSL(dylibs); MSL_SUBCLASS(buildVersion); MSL_SUBCLASS(buildToolVersions); MSL(exportTriePath); MSL(dysymPresent); MSL(dyldInfoPresent); MSL(exportTriePresent); MSL(chainedFixupsPresent); // MSL(routinesPresent); MSL(functionStartsPresent); MSL(relocatable); } }; class SharedCache : public SCCoreRefCountObject { public: SharedCache(Ref view); BNDSCViewState GetState(); static BNDSCViewLoadProgress GetLoadProgress(Ref view); static uint64_t FastGetBackingCacheCount(Ref view); bool LoadImageWithInstallName(std::string installName, bool skipObjC = false); bool LoadSectionAtAddress(uint64_t addr); bool LoadImageContainingAddress(uint64_t addr, bool skipObjC = false); std::vector GetAvailableImages(); void ProcessObjCSectionsForImageWithInstallName(std::string installName); void ProcessAllObjCSections(); std::vector LoadAllSymbolsAndWait(); std::string GetNameForAddress(uint64_t address); std::string GetImageNameForAddress(uint64_t address); std::vector GetBackingCaches(); std::vector GetImages(); std::optional GetMachOHeaderForImage(std::string name); std::optional GetMachOHeaderForAddress(uint64_t address); std::vector GetLoadedMemoryRegions(); void FindSymbolAtAddrAndApplyToAddr(uint64_t symbolLocation, uint64_t targetLocation, bool triggerReanalysis = true) const; }; }