From 808a5ad2477b9bf4c8ad128bf1c9d8612093ee65 Mon Sep 17 00:00:00 2001 From: ArandomDev Date: Sat, 15 Jul 2023 18:19:24 -0400 Subject: [PATCH] Fixed issue with objc image index --- src/DyldExtractor/converter/objc_fixer.py | 94 ++++++++++++---- src/DyldExtractor/objc/objc_structs.py | 128 ++++++++++++++++++++++ 2 files changed, 199 insertions(+), 23 deletions(-) diff --git a/src/DyldExtractor/converter/objc_fixer.py b/src/DyldExtractor/converter/objc_fixer.py index db1f45f..c26022a 100644 --- a/src/DyldExtractor/converter/objc_fixer.py +++ b/src/DyldExtractor/converter/objc_fixer.py @@ -31,7 +31,11 @@ objc_protocol_list_t, objc_protocol_t, relative_list_list_t, - relative_list_t + relative_list_t, + objc_opt_t_V12, + objc_opt_t_V15a, + objc_headeropt_ro_t, + objc_header_info_ro_t_64 ) from DyldExtractor.macho.macho_structs import ( @@ -419,13 +423,10 @@ def run(self): return # Get image index - imageAddr = self._machoCtx.segments[b"__TEXT"].seg.vmaddr - for i, image in enumerate(self._dyldCtx.images): - if image.address == imageAddr: - self._imageIndex = i - break - pass - + self._imageIndex = self._getImageIndex() + if self._imageIndex == -1: + self._logger.error("Unable to get objc image index") + return self._checkMethodNameStorage() @@ -929,22 +930,20 @@ def _processClassData(self, classDataAddr: int, isStubClass=False) -> int: classDataDef.name = self._processString(classDataDef.name) pass - baseMethodsAddr = classDataDef.baseMethods - if baseMethodsAddr & 0x1: - baseMethodsAddr = self._findInImageRelList(baseMethodsAddr & ~0x1) - if baseMethodsAddr: + if classDataDef.baseMethods & 0x1: + classDataDef.baseMethods = self._findInImageRelList(classDataDef.baseMethods & ~0x1) + if classDataDef.baseMethods: classDataDef.baseMethods = self._processMethodList( - baseMethodsAddr, + classDataDef.baseMethods, noImp=isStubClass ) pass - baseProtocolsAddr = classDataDef.baseProtocols - if baseProtocolsAddr & 0x1: - baseProtocolsAddr = self._findInImageRelList(baseProtocolsAddr & ~0x1) - if baseProtocolsAddr: - classDataDef.baseProtocols = self._processProtocolList(baseProtocolsAddr) + if classDataDef.baseProtocols & 0x1: + classDataDef.baseProtocols = self._findInImageRelList(classDataDef.baseProtocols & ~0x1) + if classDataDef.baseProtocols: + classDataDef.baseProtocols = self._processProtocolList(classDataDef.baseProtocols) pass if classDataDef.ivars: @@ -958,11 +957,10 @@ def _processClassData(self, classDataAddr: int, isStubClass=False) -> int: ) pass - basePropertiesAddr = classDataDef.baseProperties - if basePropertiesAddr & 0x1: - basePropertiesAddr = self._findInImageRelList(basePropertiesAddr & ~0x1) - if basePropertiesAddr: - classDataDef.baseProperties = self._processPropertyList(basePropertiesAddr) + if classDataDef.baseProperties & 0x1: + classDataDef.baseProperties = self._findInImageRelList(classDataDef.baseProperties & ~0x1) + if classDataDef.baseProperties: + classDataDef.baseProperties = self._processPropertyList(classDataDef.baseProperties) pass # add or update data @@ -1425,6 +1423,56 @@ def _findInImageRelList(self, relListListAddr: int) -> int: return relListAddr + offset return 0 + + def _getImageIndex(self) -> int: + """Get the ObjC specific image index. + + Returns: + The image index or -1 if not found. + """ + + # Read headeropt offset + objcOptAddr = None + for seg in self._libobjcImage.segments.values(): + if b"__objc_opt_ro" in seg.sects: + objcOptAddr = seg.sects[b"__objc_opt_ro"].addr + break + if objcOptAddr is None: + self._logger.error("Unable to find __objc_opt_ro section") + return -1 + + # Get header opt offset + objcOptOff, objcOptFile = self._dyldCtx.convertAddr(objcOptAddr) + objcOptVer = objcOptFile.readFormat(" None: extraSegStart = self._extraDataHead - len(self._extraData) diff --git a/src/DyldExtractor/objc/objc_structs.py b/src/DyldExtractor/objc/objc_structs.py index 7d508af..7759887 100644 --- a/src/DyldExtractor/objc/objc_structs.py +++ b/src/DyldExtractor/objc/objc_structs.py @@ -312,3 +312,131 @@ def getOffset(self) -> int: def getImageIndex(self) -> int: return self.offsetAndIndex & 0xFFFF + + +class objc_opt_t_V12(Structure): + + version: int + selopt_offset: int + headeropt_offset: int + clsopt_offset: int + + _fields_ = [ + ("version", c_uint32), + ("selopt_offset", c_int32), + ("headeropt_offset", c_int32), + ("clsopt_offset", c_int32), + ] + + +class objc_opt_t_V13(Structure): + + version: int + selopt_offset: int + headeropt_offset: int + clsopt_offset: int + protocolopt_offset: int + + _fields_ = [ + ("version", c_uint32), + ("selopt_offset", c_int32), + ("headeropt_offset", c_int32), + ("clsopt_offset", c_int32), + ("protocolopt_offset", c_int32), + ] + + +class objc_opt_t_V15a(Structure): + + version: int + flags: int + selopt_offset: int + headeropt_ro_offset: int + clsopt_offset: int + protocolopt_offset: int + headeropt_rw_offset: int + + _fields_ = [ + ("version", c_uint32), + ("flags", c_uint32), + ("selopt_offset", c_int32), + ("headeropt_ro_offset", c_int32), + ("clsopt_offset", c_int32), + ("protocolopt_offset", c_int32), + ("headeropt_rw_offset", c_int32), + ] + + +class objc_opt_t_V15b(Structure): + + version: int + flags: int + selopt_offset: int + headeropt_ro_offset: int + clsopt_offset: int + unused_protocolopt_offset: int + headeropt_rw_offset: int + protocolopt_offset: int + + _fields_ = [ + ("version", c_uint32), + ("flags", c_uint32), + ("selopt_offset", c_int32), + ("headeropt_ro_offset", c_int32), + ("clsopt_offset", c_int32), + ("unused_protocolopt_offset", c_int32), + ("headeropt_rw_offset", c_int32), + ("protocolopt_offset", c_int32), + ] + + +class objc_opt_t_V16(Structure): + + version: int + flags: int + selopt_offset: int + headeropt_ro_offset: int + unused_clsopt_offset: int + unused_protocolopt_offset: int # This is now 0 as we've moved to the new protocolopt_offset # noqa + headeropt_rw_offset: int + unused_protocolopt2_offset: int + largeSharedCachesClassOffset: int + largeSharedCachesProtocolOffset: int + relativeMethodSelectorBaseAddressOffset: int # Relative method list selectors are offsets from this address # noqa + + _fields_ = [ + ("version", c_uint32), + ("flags", c_uint32), + ("selopt_offset", c_int32), + ("headeropt_ro_offset", c_int32), + ("unused_clsopt_offset", c_int32), + ("unused_protocolopt_offset", c_int32), + ("headeropt_rw_offset", c_int32), + ("unused_protocolopt2_offset", c_int32), + ("largeSharedCachesClassOffset", c_int32), + ("largeSharedCachesProtocolOffset", c_int32), + ("relativeMethodSelectorBaseAddressOffset", c_int64), + ] + + +class objc_headeropt_ro_t(Structure): + SIZE = 8 + + count: int + entsize: int + + _fields_ = [ + ("count", c_uint32), + ("entsize", c_uint32), + ] + + +class objc_header_info_ro_t_64(Structure): + + mhdr_offset: int + info_offset: int + + _fields_ = [ + ("mhdr_offset", c_int64), + ("info_offset", c_int64), + ] \ No newline at end of file