From 43d3144c714ce78dc942c0021f337ea12ac2bfa1 Mon Sep 17 00:00:00 2001 From: WeiN76LQh Date: Thu, 21 Nov 2024 19:01:44 +0000 Subject: [PATCH 1/3] [SharedCache] Fix post-processing of Objective-C sections Prior to this commit the function `DSCObjCProcessor::PostProcessObjCSections` never does anything because it doesn't use the correct names to get the Objective-C sections of the recently loaded library. In fact it never does anything because the DSC never has sections with the names its searching for. This commit passes the `baseName` (the name of the library that was loaded), which is what other Objective-C section processing code does. Combining the base name with the section names it will now find them and process them as intended. This was resulting in alot of Objective-C related stuff being missed. There is however still an issue of the fact that the way this DSC plugin works means it only analyzes Objective-C sections once. This catches alot of things but there are a number of cases where other libraries need to be loaded first due to information being referenced in another library. For instance errors like `Failed to determine base classname for category` can be caused by the class reference in the category being to a class outside of the loaded library. Once the library containing the class has been loaded, the section containing the category should be re-proccessed. --- view/sharedcache/core/ObjC.cpp | 16 ++++++++-------- view/sharedcache/core/ObjC.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) 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); From a7318825dd0c53a85dfcffc2525e6c8c7e72162c Mon Sep 17 00:00:00 2001 From: WeiN76LQh Date: Mon, 25 Nov 2024 19:54:44 +0000 Subject: [PATCH 2/3] [SharedCache] Add the ability to skip Objective-C processing when loading a library This is useful when batch loading libraries to avoid extra processing (once the next commit has landed). --- .../api/python/_sharedcachecore.py | 12 ++-- view/sharedcache/api/python/sharedcache.py | 8 +-- view/sharedcache/api/sharedcache.cpp | 8 +-- view/sharedcache/api/sharedcacheapi.h | 4 +- view/sharedcache/api/sharedcachecore.h | 4 +- view/sharedcache/core/SharedCache.cpp | 59 ++++++++++--------- view/sharedcache/core/SharedCache.h | 4 +- 7 files changed, 53 insertions(+), 46 deletions(-) diff --git a/view/sharedcache/api/python/_sharedcachecore.py b/view/sharedcache/api/python/_sharedcachecore.py index d208048bc..bd9e0764c 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) # ------------------------------------------------------- diff --git a/view/sharedcache/api/python/sharedcache.py b/view/sharedcache/api/python/sharedcache.py index b660d9d97..7902c76ae 100644 --- a/view/sharedcache/api/python/sharedcache.py +++ b/view/sharedcache/api/python/sharedcache.py @@ -108,14 +108,14 @@ 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) @property def caches(self): diff --git a/view/sharedcache/api/sharedcache.cpp b/view/sharedcache/api/sharedcache.cpp index 5ca7c480e..355f31c1e 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() diff --git a/view/sharedcache/api/sharedcacheapi.h b/view/sharedcache/api/sharedcacheapi.h index 19f021e7c..d7e78624b 100644 --- a/view/sharedcache/api/sharedcacheapi.h +++ b/view/sharedcache/api/sharedcacheapi.h @@ -660,9 +660,9 @@ 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(); std::vector LoadAllSymbolsAndWait(); diff --git a/view/sharedcache/api/sharedcachecore.h b/view/sharedcache/api/sharedcachecore.h index 9fc332756..967a7d0be 100644 --- a/view/sharedcache/api/sharedcachecore.h +++ b/view/sharedcache/api/sharedcachecore.h @@ -120,9 +120,9 @@ 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 char* BNDSCViewGetNameForAddress(BNSharedCache* cache, uint64_t address); SHAREDCACHE_FFI_API char* BNDSCViewGetImageNameForAddress(BNSharedCache* cache, uint64_t address); diff --git a/view/sharedcache/core/SharedCache.cpp b/view/sharedcache/core/SharedCache.cpp index a7c7ffb01..91257e8c4 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,7 @@ bool SharedCache::LoadSectionAtAddress(uint64_t address) return true; } -bool SharedCache::LoadImageWithInstallName(std::string installName) +bool SharedCache::LoadImageWithInstallName(std::string installName, bool skipObjC) { auto settings = m_dscView->GetLoadSettings(VIEW_NAME); @@ -1817,28 +1817,31 @@ 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); + try + { + auto objc = std::make_unique(m_dscView, this, false); - 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"); + 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"); + } } m_dscView->AddAnalysisOption("linearsweep"); @@ -3011,13 +3014,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,11 +3035,11 @@ 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; diff --git a/view/sharedcache/core/SharedCache.h b/view/sharedcache/core/SharedCache.h index 81c026203..dd809525f 100644 --- a/view/sharedcache/core/SharedCache.h +++ b/view/sharedcache/core/SharedCache.h @@ -1159,9 +1159,9 @@ 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); std::string NameForAddress(uint64_t address); std::string ImageNameForAddress(uint64_t address); std::vector GetAvailableImages(); From 96cfc3d9b557ab48ac5ee2a00b5eb0c9d3b58e1b Mon Sep 17 00:00:00 2001 From: WeiN76LQh Date: Tue, 26 Nov 2024 00:09:03 +0000 Subject: [PATCH 3/3] [SharedCache] Add the ability to manually trigger Objective-C processing A problem with processing Objective-C sections at the time a library is loaded is that some of the references within those sections may refer to unload sections. This results in things like selectors not being correctly typed and named. This commit provides a way for users to manually trigger Objective-C parsing against sections for a specific library or all libraries, via the API. Combined with the previous commit a user can use the API to batch load a number of libraries and skip Objective-C processing for each one and then run it across the entire of the DSC once they are all loaded. Further improvement would be to provide a way to trigger Objective-C processing through the UI. --- .../api/python/_sharedcachecore.py | 38 ++++++ view/sharedcache/api/python/sharedcache.py | 6 + view/sharedcache/api/sharedcache.cpp | 11 ++ view/sharedcache/api/sharedcacheapi.h | 3 + view/sharedcache/api/sharedcachecore.h | 3 + view/sharedcache/core/SharedCache.cpp | 117 ++++++++++++++---- view/sharedcache/core/SharedCache.h | 2 + 7 files changed, 158 insertions(+), 22 deletions(-) diff --git a/view/sharedcache/api/python/_sharedcachecore.py b/view/sharedcache/api/python/_sharedcachecore.py index bd9e0764c..5f31697ed 100644 --- a/view/sharedcache/api/python/_sharedcachecore.py +++ b/view/sharedcache/api/python/_sharedcachecore.py @@ -581,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 7902c76ae..e0e18bde0 100644 --- a/view/sharedcache/api/python/sharedcache.py +++ b/view/sharedcache/api/python/sharedcache.py @@ -117,6 +117,12 @@ def load_section_at_address(self, 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): count = ctypes.c_ulonglong() diff --git a/view/sharedcache/api/sharedcache.cpp b/view/sharedcache/api/sharedcache.cpp index 355f31c1e..dff8bfddf 100644 --- a/view/sharedcache/api/sharedcache.cpp +++ b/view/sharedcache/api/sharedcache.cpp @@ -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 d7e78624b..d9ad1230d 100644 --- a/view/sharedcache/api/sharedcacheapi.h +++ b/view/sharedcache/api/sharedcacheapi.h @@ -664,6 +664,9 @@ namespace SharedCacheAPI { 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(); diff --git a/view/sharedcache/api/sharedcachecore.h b/view/sharedcache/api/sharedcachecore.h index 967a7d0be..155f39de3 100644 --- a/view/sharedcache/api/sharedcachecore.h +++ b/view/sharedcache/api/sharedcachecore.h @@ -123,6 +123,9 @@ extern "C" 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, 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/SharedCache.cpp b/view/sharedcache/core/SharedCache.cpp index 91257e8c4..c35458e77 100644 --- a/view/sharedcache/core/SharedCache.cpp +++ b/view/sharedcache/core/SharedCache.cpp @@ -1713,6 +1713,81 @@ bool SharedCache::LoadSectionAtAddress(uint64_t address) return true; } +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); @@ -1819,29 +1894,11 @@ bool SharedCache::LoadImageWithInstallName(std::string installName, bool skipObj if (!skipObjC) { - try - { - 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"); @@ -3045,6 +3102,22 @@ extern "C" 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 dd809525f..f16cfeb3c 100644 --- a/view/sharedcache/core/SharedCache.h +++ b/view/sharedcache/core/SharedCache.h @@ -1162,6 +1162,8 @@ namespace SharedCacheCore { bool LoadImageWithInstallName(std::string installName, bool skipObjC); bool LoadSectionAtAddress(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();