diff --git a/view/sharedcache/api/python/_sharedcachecore.py b/view/sharedcache/api/python/_sharedcachecore.py index d208048bc..5f31697ed 100644 --- a/view/sharedcache/api/python/_sharedcachecore.py +++ b/view/sharedcache/api/python/_sharedcachecore.py @@ -528,15 +528,17 @@ def BNDSCViewLoadAllSymbolsAndWait( _BNDSCViewLoadImageContainingAddress.argtypes = [ ctypes.POINTER(BNSharedCache), ctypes.c_ulonglong, + ctypes.c_bool, ] # noinspection PyPep8Naming def BNDSCViewLoadImageContainingAddress( cache: ctypes.POINTER(BNSharedCache), - address: int + address: int, + skipObjC: bool ) -> bool: - return _BNDSCViewLoadImageContainingAddress(cache, address) + return _BNDSCViewLoadImageContainingAddress(cache, address, skipObjC) # ------------------------------------------------------- @@ -547,15 +549,17 @@ def BNDSCViewLoadImageContainingAddress( _BNDSCViewLoadImageWithInstallName.argtypes = [ ctypes.POINTER(BNSharedCache), ctypes.c_char_p, + ctypes.c_bool, ] # noinspection PyPep8Naming def BNDSCViewLoadImageWithInstallName( cache: ctypes.POINTER(BNSharedCache), - name: Optional[str] + name: Optional[str], + skipObjC: bool ) -> bool: - return _BNDSCViewLoadImageWithInstallName(cache, cstr(name)) + return _BNDSCViewLoadImageWithInstallName(cache, cstr(name), skipObjC) # ------------------------------------------------------- @@ -577,6 +581,44 @@ def BNDSCViewLoadSectionAtAddress( return _BNDSCViewLoadSectionAtAddress(cache, name) +# ------------------------------------------------------- +# _BNDSCViewProcessAllObjCSections + +_BNDSCViewProcessAllObjCSections = core.BNDSCViewProcessAllObjCSections +_BNDSCViewProcessAllObjCSections.restype = None +_BNDSCViewProcessAllObjCSections.argtypes = [ + ctypes.POINTER(BNSharedCache), + ] + + +# noinspection PyPep8Naming +def BNDSCViewProcessAllObjCSections( + cache: ctypes.POINTER(BNSharedCache) + ) -> None: + return _BNDSCViewProcessAllObjCSections(cache) + + +# ------------------------------------------------------- +# _BNDSCViewProcessObjCSectionsForImageWithInstallName + +_BNDSCViewProcessObjCSectionsForImageWithInstallName = core.BNDSCViewProcessObjCSectionsForImageWithInstallName +_BNDSCViewProcessObjCSectionsForImageWithInstallName.restype = None +_BNDSCViewProcessObjCSectionsForImageWithInstallName.argtypes = [ + ctypes.POINTER(BNSharedCache), + ctypes.c_char_p, + ctypes.c_bool, + ] + + +# noinspection PyPep8Naming +def BNDSCViewProcessObjCSectionsForImageWithInstallName( + cache: ctypes.POINTER(BNSharedCache), + name: Optional[str], + deallocName: bool + ) -> None: + return _BNDSCViewProcessObjCSectionsForImageWithInstallName(cache, cstr(name), deallocName) + + # ------------------------------------------------------- # _BNFreeSharedCacheReference diff --git a/view/sharedcache/api/python/sharedcache.py b/view/sharedcache/api/python/sharedcache.py index b660d9d97..e0e18bde0 100644 --- a/view/sharedcache/api/python/sharedcache.py +++ b/view/sharedcache/api/python/sharedcache.py @@ -108,14 +108,20 @@ class SharedCache: def __init__(self, view): self.handle = sccore.BNGetSharedCache(view.handle) - def load_image_with_install_name(self, installName): - return sccore.BNDSCViewLoadImageWithInstallName(self.handle, installName) + def load_image_with_install_name(self, installName, skipObjC = False): + return sccore.BNDSCViewLoadImageWithInstallName(self.handle, installName, skipObjC) def load_section_at_address(self, addr): return sccore.BNDSCViewLoadSectionAtAddress(self.handle, addr) - def load_image_containing_address(self, addr): - return sccore.BNDSCViewLoadImageContainingAddress(self.handle, addr) + def load_image_containing_address(self, addr, skipObjC = False): + return sccore.BNDSCViewLoadImageContainingAddress(self.handle, addr, skipObjC) + + def process_objc_sections_for_image_with_install_name(self, installName): + return sccore.BNDSCViewProcessObjCSectionsForImageWithInstallName(self.handle, installName, False) + + def process_all_objc_sections(self): + return sccore.BNDSCViewProcessAllObjCSections(self.handle) @property def caches(self): diff --git a/view/sharedcache/api/sharedcache.cpp b/view/sharedcache/api/sharedcache.cpp index 5ca7c480e..dff8bfddf 100644 --- a/view/sharedcache/api/sharedcache.cpp +++ b/view/sharedcache/api/sharedcache.cpp @@ -20,10 +20,10 @@ namespace SharedCacheAPI { return BNDSCViewFastGetBackingCacheCount(view->GetObject()); } - bool SharedCache::LoadImageWithInstallName(std::string installName) + bool SharedCache::LoadImageWithInstallName(std::string installName, bool skipObjC) { char* str = BNAllocString(installName.c_str()); - return BNDSCViewLoadImageWithInstallName(m_object, str); + return BNDSCViewLoadImageWithInstallName(m_object, str, skipObjC); } bool SharedCache::LoadSectionAtAddress(uint64_t addr) @@ -31,9 +31,9 @@ namespace SharedCacheAPI { return BNDSCViewLoadSectionAtAddress(m_object, addr); } - bool SharedCache::LoadImageContainingAddress(uint64_t addr) + bool SharedCache::LoadImageContainingAddress(uint64_t addr, bool skipObjC) { - return BNDSCViewLoadImageContainingAddress(m_object, addr); + return BNDSCViewLoadImageContainingAddress(m_object, addr, skipObjC); } std::vector SharedCache::GetAvailableImages() @@ -55,6 +55,17 @@ namespace SharedCacheAPI { return result; } + void SharedCache::ProcessObjCSectionsForImageWithInstallName(std::string installName) + { + char* str = BNAllocString(installName.c_str()); + BNDSCViewProcessObjCSectionsForImageWithInstallName(m_object, str, true); + } + + void SharedCache::ProcessAllObjCSections() + { + BNDSCViewProcessAllObjCSections(m_object); + } + std::vector SharedCache::GetLoadedMemoryRegions() { size_t count; diff --git a/view/sharedcache/api/sharedcacheapi.h b/view/sharedcache/api/sharedcacheapi.h index 19f021e7c..d9ad1230d 100644 --- a/view/sharedcache/api/sharedcacheapi.h +++ b/view/sharedcache/api/sharedcacheapi.h @@ -660,10 +660,13 @@ namespace SharedCacheAPI { static BNDSCViewLoadProgress GetLoadProgress(Ref view); static uint64_t FastGetBackingCacheCount(Ref view); - bool LoadImageWithInstallName(std::string installName); + bool LoadImageWithInstallName(std::string installName, bool skipObjC = false); bool LoadSectionAtAddress(uint64_t addr); - bool LoadImageContainingAddress(uint64_t addr); + bool LoadImageContainingAddress(uint64_t addr, bool skipObjC = false); std::vector GetAvailableImages(); + + void ProcessObjCSectionsForImageWithInstallName(std::string installName); + void ProcessAllObjCSections(); std::vector LoadAllSymbolsAndWait(); diff --git a/view/sharedcache/api/sharedcachecore.h b/view/sharedcache/api/sharedcachecore.h index 9fc332756..155f39de3 100644 --- a/view/sharedcache/api/sharedcachecore.h +++ b/view/sharedcache/api/sharedcachecore.h @@ -120,9 +120,12 @@ extern "C" SHAREDCACHE_FFI_API char** BNDSCViewGetInstallNames(BNSharedCache* cache, size_t* count); - SHAREDCACHE_FFI_API bool BNDSCViewLoadImageWithInstallName(BNSharedCache* cache, char* name); + SHAREDCACHE_FFI_API bool BNDSCViewLoadImageWithInstallName(BNSharedCache* cache, char* name, bool skipObjC); SHAREDCACHE_FFI_API bool BNDSCViewLoadSectionAtAddress(BNSharedCache* cache, uint64_t name); - SHAREDCACHE_FFI_API bool BNDSCViewLoadImageContainingAddress(BNSharedCache* cache, uint64_t address); + SHAREDCACHE_FFI_API bool BNDSCViewLoadImageContainingAddress(BNSharedCache* cache, uint64_t address, bool skipObjC); + + SHAREDCACHE_FFI_API void BNDSCViewProcessObjCSectionsForImageWithInstallName(BNSharedCache* cache, char* name, bool deallocName); + SHAREDCACHE_FFI_API void BNDSCViewProcessAllObjCSections(BNSharedCache* cache); SHAREDCACHE_FFI_API char* BNDSCViewGetNameForAddress(BNSharedCache* cache, uint64_t address); SHAREDCACHE_FFI_API char* BNDSCViewGetImageNameForAddress(BNSharedCache* cache, uint64_t address); diff --git a/view/sharedcache/core/ObjC.cpp b/view/sharedcache/core/ObjC.cpp index 271e5c941..95fbb2a2d 100644 --- a/view/sharedcache/core/ObjC.cpp +++ b/view/sharedcache/core/ObjC.cpp @@ -1087,16 +1087,16 @@ void DSCObjCProcessor::ApplyMethodTypes(Class& cls) } } -void DSCObjCProcessor::PostProcessObjCSections(VMReader* reader) +void DSCObjCProcessor::PostProcessObjCSections(VMReader* reader, std::string baseName) { auto ptrSize = m_data->GetAddressSize(); - if (auto imageInfo = m_data->GetSectionByName("__objc_imageinfo")) + 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("__objc_selrefs")) + if (auto selrefs = m_data->GetSectionByName(baseName + "::__objc_selrefs")) { auto start = selrefs->GetStart(); auto end = selrefs->GetEnd(); @@ -1119,7 +1119,7 @@ void DSCObjCProcessor::PostProcessObjCSections(VMReader* reader) DefineObjCSymbol(DataSymbol, type, "selRef_" + sel, i, true); } } - if (auto superRefs = m_data->GetSectionByName("__objc_classrefs")) + if (auto superRefs = m_data->GetSectionByName(baseName + "::__objc_classrefs")) { auto start = superRefs->GetStart(); auto end = superRefs->GetEnd(); @@ -1137,7 +1137,7 @@ void DSCObjCProcessor::PostProcessObjCSections(VMReader* reader) } } } - if (auto superRefs = m_data->GetSectionByName("__objc_superrefs")) + if (auto superRefs = m_data->GetSectionByName(baseName + "::__objc_superrefs")) { auto start = superRefs->GetStart(); auto end = superRefs->GetEnd(); @@ -1155,7 +1155,7 @@ void DSCObjCProcessor::PostProcessObjCSections(VMReader* reader) } } } - if (auto protoRefs = m_data->GetSectionByName("__objc_protorefs")) + if (auto protoRefs = m_data->GetSectionByName(baseName + "::__objc_protorefs")) { auto start = protoRefs->GetStart(); auto end = protoRefs->GetEnd(); @@ -1173,7 +1173,7 @@ void DSCObjCProcessor::PostProcessObjCSections(VMReader* reader) } } } - if (auto ivars = m_data->GetSectionByName("__objc_ivar")) + if (auto ivars = m_data->GetSectionByName(baseName + "::__objc_ivar")) { auto start = ivars->GetStart(); auto end = ivars->GetEnd(); @@ -1416,7 +1416,7 @@ void DSCObjCProcessor::ProcessObjCData(std::shared_ptr vm, std::string baseN if (auto protoList = m_data->GetSectionByName(baseName + "::__objc_protolist")) LoadProtocols(&reader, protoList); - PostProcessObjCSections(&reader); + PostProcessObjCSections(&reader, baseName); auto id = m_data->BeginUndoActions(); m_symbolQueue->Process(); diff --git a/view/sharedcache/core/ObjC.h b/view/sharedcache/core/ObjC.h index 40f2441bb..016ff0224 100644 --- a/view/sharedcache/core/ObjC.h +++ b/view/sharedcache/core/ObjC.h @@ -222,7 +222,7 @@ namespace DSCObjC { void GenerateClassTypes(); bool ApplyMethodType(Class& cls, Method& method, bool isInstanceMethod); void ApplyMethodTypes(Class& cls); - void PostProcessObjCSections(VMReader* reader); + void PostProcessObjCSections(VMReader* reader, std::string baseName); public: DSCObjCProcessor(BinaryView* data, SharedCacheCore::SharedCache* cache, bool isBackedByDatabase); void ProcessObjCData(std::shared_ptr vm, std::string baseName); diff --git a/view/sharedcache/core/SharedCache.cpp b/view/sharedcache/core/SharedCache.cpp index a7c7ffb01..c35458e77 100644 --- a/view/sharedcache/core/SharedCache.cpp +++ b/view/sharedcache/core/SharedCache.cpp @@ -1392,7 +1392,7 @@ SharedCache::SharedCache(BinaryNinja::Ref dscView) : m_ { lock.unlock(); m_logger->LogInfo("Loading core libsystem_c.dylib library"); - LoadImageWithInstallName(header.installName); + LoadImageWithInstallName(header.installName, false); lock.lock(); break; } @@ -1506,7 +1506,7 @@ std::string SharedCache::ImageNameForAddress(uint64_t address) return ""; } -bool SharedCache::LoadImageContainingAddress(uint64_t address) +bool SharedCache::LoadImageContainingAddress(uint64_t address, bool skipObjC) { for (const auto& [start, header] : m_headers) { @@ -1514,7 +1514,7 @@ bool SharedCache::LoadImageContainingAddress(uint64_t address) { if (segment.vmaddr <= address && segment.vmaddr + segment.vmsize > address) { - return LoadImageWithInstallName(header.installName); + return LoadImageWithInstallName(header.installName, skipObjC); } } } @@ -1713,7 +1713,82 @@ bool SharedCache::LoadSectionAtAddress(uint64_t address) return true; } -bool SharedCache::LoadImageWithInstallName(std::string installName) +static void GetObjCSettings(Ref view, bool* processObjCMetadata, bool* processCFStrings) +{ + auto settings = view->GetLoadSettings(VIEW_NAME); + *processCFStrings = true; + *processObjCMetadata = true; + if (settings && settings->Contains("loader.dsc.processCFStrings")) + *processCFStrings = settings->Get("loader.dsc.processCFStrings", view); + if (settings && settings->Contains("loader.dsc.processObjC")) + *processObjCMetadata = settings->Get("loader.dsc.processObjC", view); +} + +static void ProcessObjCSectionsForImageWithName(std::string baseName, std::shared_ptr vm, std::shared_ptr objc, bool processCFStrings, bool processObjCMetadata, Ref logger) +{ + try + { + if (processObjCMetadata) + objc->ProcessObjCData(vm, baseName); + if (processCFStrings) + objc->ProcessCFStrings(vm, baseName); + } + catch (const std::exception& ex) + { + logger->LogWarn("Error processing ObjC data for image %s: %s", baseName.c_str(), ex.what()); + } + catch (...) + { + logger->LogWarn("Error processing ObjC data for image %s", baseName.c_str()); + } +} + +void SharedCache::ProcessObjCSectionsForImageWithInstallName(std::string installName) +{ + bool processCFStrings; + bool processObjCMetadata; + GetObjCSettings(m_dscView, &processCFStrings, &processObjCMetadata); + + if (!processObjCMetadata && !processCFStrings) + return; + + auto objc = std::make_shared(m_dscView, this, false); + auto vm = GetVMMap(); + + ProcessObjCSectionsForImageWithName(base_name(installName), vm, objc, processCFStrings, processObjCMetadata, m_logger); +} + +void SharedCache::ProcessAllObjCSections() +{ + bool processCFStrings; + bool processObjCMetadata; + GetObjCSettings(m_dscView, &processCFStrings, &processObjCMetadata); + + if (!processObjCMetadata && !processCFStrings) + return; + + auto objc = std::make_shared(m_dscView, this, false); + auto vm = GetVMMap(); + + std::set processedImageHeaders; + for (auto region : GetMappedRegions()) + { + if (!region.loaded) + continue; + + // Don't repeat the same images multiple times + auto header = HeaderForAddress(region.start); + if (!header) + continue; + if (processedImageHeaders.find(header->textBase) != processedImageHeaders.end()) + continue; + processedImageHeaders.insert(header->textBase); + + ProcessObjCSectionsForImageWithName(header->identifierPrefix, vm, objc, processCFStrings, processObjCMetadata, m_logger); + } +} + +bool SharedCache::LoadImageWithInstallName(std::string installName, bool skipObjC) { auto settings = m_dscView->GetLoadSettings(VIEW_NAME); @@ -1817,28 +1892,13 @@ bool SharedCache::LoadImageWithInstallName(std::string installName) SharedCache::InitializeHeader(m_dscView, vm.get(), *h, regions); - try + if (!skipObjC) { - auto objc = std::make_unique(m_dscView, this, false); + bool processCFStrings; + bool processObjCMetadata; + GetObjCSettings(m_dscView, &processCFStrings, &processObjCMetadata); - bool processCFStrings = true; - bool processObjCMetadata = true; - if (settings && settings->Contains("loader.dsc.processCFStrings")) - processCFStrings = settings->Get("loader.dsc.processCFStrings", m_dscView); - if (settings && settings->Contains("loader.dsc.processObjC")) - processObjCMetadata = settings->Get("loader.dsc.processObjC", m_dscView); - if (processObjCMetadata) - objc->ProcessObjCData(vm, h->identifierPrefix); - if (processCFStrings) - objc->ProcessCFStrings(vm, h->identifierPrefix); - } - catch (const std::exception& ex) - { - m_logger->LogWarn("Error processing ObjC data: %s", ex.what()); - } - catch (...) - { - m_logger->LogWarn("Error processing ObjC data"); + ProcessObjCSectionsForImageWithName(h->identifierPrefix, vm, std::make_shared(m_dscView, this, false), processCFStrings, processObjCMetadata, m_logger); } m_dscView->AddAnalysisOption("linearsweep"); @@ -3011,13 +3071,13 @@ extern "C" cache->object->ReleaseAPIRef(); } - bool BNDSCViewLoadImageWithInstallName(BNSharedCache* cache, char* name) + bool BNDSCViewLoadImageWithInstallName(BNSharedCache* cache, char* name, bool skipObjC) { std::string imageName = std::string(name); // FIXME !!!!!!!! BNFreeString(name); if (cache->object) - return cache->object->LoadImageWithInstallName(imageName); + return cache->object->LoadImageWithInstallName(imageName, skipObjC); return false; } @@ -3032,16 +3092,32 @@ extern "C" return false; } - bool BNDSCViewLoadImageContainingAddress(BNSharedCache* cache, uint64_t address) + bool BNDSCViewLoadImageContainingAddress(BNSharedCache* cache, uint64_t address, bool skipObjC) { if (cache->object) { - return cache->object->LoadImageContainingAddress(address); + return cache->object->LoadImageContainingAddress(address, skipObjC); } return false; } + void BNDSCViewProcessObjCSectionsForImageWithInstallName(BNSharedCache* cache, char* name, bool deallocName) + { + std::string imageName = std::string(name); + if (deallocName) + BNFreeString(name); + + if (cache->object) + cache->object->ProcessObjCSectionsForImageWithInstallName(imageName); + } + + void BNDSCViewProcessAllObjCSections(BNSharedCache* cache) + { + if (cache->object) + cache->object->ProcessAllObjCSections(); + } + char** BNDSCViewGetInstallNames(BNSharedCache* cache, size_t* count) { if (cache->object) diff --git a/view/sharedcache/core/SharedCache.h b/view/sharedcache/core/SharedCache.h index 81c026203..f16cfeb3c 100644 --- a/view/sharedcache/core/SharedCache.h +++ b/view/sharedcache/core/SharedCache.h @@ -1159,9 +1159,11 @@ namespace SharedCacheCore { void ParseAndApplySlideInfoForFile(std::shared_ptr file); std::optional GetImageStart(std::string installName); std::optional HeaderForAddress(uint64_t); - bool LoadImageWithInstallName(std::string installName); + bool LoadImageWithInstallName(std::string installName, bool skipObjC); bool LoadSectionAtAddress(uint64_t address); - bool LoadImageContainingAddress(uint64_t address); + bool LoadImageContainingAddress(uint64_t address, bool skipObjC); + void ProcessObjCSectionsForImageWithInstallName(std::string installName); + void ProcessAllObjCSections(); std::string NameForAddress(uint64_t address); std::string ImageNameForAddress(uint64_t address); std::vector GetAvailableImages();