3131 objc_protocol_list_t ,
3232 objc_protocol_t ,
3333 relative_list_list_t ,
34- relative_list_t
34+ relative_list_t ,
35+ objc_opt_t_V12 ,
36+ objc_opt_t_V15a ,
37+ objc_headeropt_ro_t ,
38+ objc_header_info_ro_t_64
3539)
3640
3741from DyldExtractor .macho .macho_structs import (
@@ -419,13 +423,10 @@ def run(self):
419423 return
420424
421425 # Get image index
422- imageAddr = self ._machoCtx .segments [b"__TEXT" ].seg .vmaddr
423- for i , image in enumerate (self ._dyldCtx .images ):
424- if image .address == imageAddr :
425- self ._imageIndex = i
426- break
427- pass
428-
426+ self ._imageIndex = self ._getImageIndex ()
427+ if self ._imageIndex == - 1 :
428+ self ._logger .error ("Unable to get objc image index" )
429+ return
429430
430431 self ._checkMethodNameStorage ()
431432
@@ -929,22 +930,20 @@ def _processClassData(self, classDataAddr: int, isStubClass=False) -> int:
929930 classDataDef .name = self ._processString (classDataDef .name )
930931 pass
931932
932- baseMethodsAddr = classDataDef .baseMethods
933- if baseMethodsAddr & 0x1 :
934- baseMethodsAddr = self ._findInImageRelList (baseMethodsAddr & ~ 0x1 )
935- if baseMethodsAddr :
933+ if classDataDef .baseMethods & 0x1 :
934+ classDataDef .baseMethods = self ._findInImageRelList (classDataDef .baseMethods & ~ 0x1 )
935+ if classDataDef .baseMethods :
936936 classDataDef .baseMethods = self ._processMethodList (
937- baseMethodsAddr ,
937+ classDataDef . baseMethods ,
938938 noImp = isStubClass
939939 )
940940 pass
941941
942942
943- baseProtocolsAddr = classDataDef .baseProtocols
944- if baseProtocolsAddr & 0x1 :
945- baseProtocolsAddr = self ._findInImageRelList (baseProtocolsAddr & ~ 0x1 )
946- if baseProtocolsAddr :
947- classDataDef .baseProtocols = self ._processProtocolList (baseProtocolsAddr )
943+ if classDataDef .baseProtocols & 0x1 :
944+ classDataDef .baseProtocols = self ._findInImageRelList (classDataDef .baseProtocols & ~ 0x1 )
945+ if classDataDef .baseProtocols :
946+ classDataDef .baseProtocols = self ._processProtocolList (classDataDef .baseProtocols )
948947 pass
949948
950949 if classDataDef .ivars :
@@ -958,11 +957,10 @@ def _processClassData(self, classDataAddr: int, isStubClass=False) -> int:
958957 )
959958 pass
960959
961- basePropertiesAddr = classDataDef .baseProperties
962- if basePropertiesAddr & 0x1 :
963- basePropertiesAddr = self ._findInImageRelList (basePropertiesAddr & ~ 0x1 )
964- if basePropertiesAddr :
965- classDataDef .baseProperties = self ._processPropertyList (basePropertiesAddr )
960+ if classDataDef .baseProperties & 0x1 :
961+ classDataDef .baseProperties = self ._findInImageRelList (classDataDef .baseProperties & ~ 0x1 )
962+ if classDataDef .baseProperties :
963+ classDataDef .baseProperties = self ._processPropertyList (classDataDef .baseProperties )
966964 pass
967965
968966 # add or update data
@@ -1425,6 +1423,56 @@ def _findInImageRelList(self, relListListAddr: int) -> int:
14251423 return relListAddr + offset
14261424
14271425 return 0
1426+
1427+ def _getImageIndex (self ) -> int :
1428+ """Get the ObjC specific image index.
1429+
1430+ Returns:
1431+ The image index or -1 if not found.
1432+ """
1433+
1434+ # Read headeropt offset
1435+ objcOptAddr = None
1436+ for seg in self ._libobjcImage .segments .values ():
1437+ if b"__objc_opt_ro" in seg .sects :
1438+ objcOptAddr = seg .sects [b"__objc_opt_ro" ].addr
1439+ break
1440+ if objcOptAddr is None :
1441+ self ._logger .error ("Unable to find __objc_opt_ro section" )
1442+ return - 1
1443+
1444+ # Get header opt offset
1445+ objcOptOff , objcOptFile = self ._dyldCtx .convertAddr (objcOptAddr )
1446+ objcOptVer = objcOptFile .readFormat ("<I" , objcOptOff )[0 ]
1447+
1448+ if objcOptVer in (12 , 13 ):
1449+ headerOptOff = objc_opt_t_V12 (objcOptFile .file , objcOptOff ).headeropt_offset
1450+ elif objcOptVer in (15 , 16 ):
1451+ headerOptOff = objc_opt_t_V15a (objcOptFile .file , objcOptOff ).headeropt_ro_offset
1452+ else :
1453+ self ._logger .error (f"Unknown objc_opt_t version: { objcOptVer } " )
1454+ return - 1
1455+ if headerOptOff == 0 :
1456+ self ._logger .error ("libobjc does not have objc_headeropt_ro_t" )
1457+ return - 1
1458+ headerOptAddr = objcOptAddr + headerOptOff
1459+
1460+ # Find image index
1461+ imageAddr = self ._machoCtx .segments [b"__TEXT" ].seg .vmaddr
1462+ headerOptDataOff , headerOptFile = self ._dyldCtx .convertAddr (headerOptAddr )
1463+ headerOpt = objc_headeropt_ro_t (headerOptFile .file , headerOptDataOff )
1464+
1465+ for i in range (headerOpt .count ):
1466+ infoOff = objc_headeropt_ro_t .SIZE + (i * headerOpt .entsize )
1467+ infoAddr = headerOptAddr + infoOff
1468+ infoDataOff = headerOptDataOff + infoOff
1469+ info = objc_header_info_ro_t_64 (headerOptFile .file , infoDataOff )
1470+
1471+ if info .mhdr_offset + infoAddr == imageAddr :
1472+ return i
1473+
1474+ return - 1
1475+
14281476
14291477 def _finalizeFutureClasses (self ) -> None :
14301478 extraSegStart = self ._extraDataHead - len (self ._extraData )
0 commit comments