Skip to content
This repository was archived by the owner on Dec 28, 2025. It is now read-only.

Commit d12b5a6

Browse files
committed
Added support for relative_list_list_t for iOS17
1 parent 3eb1f5f commit d12b5a6

File tree

2 files changed

+93
-17
lines changed

2 files changed

+93
-17
lines changed

src/DyldExtractor/converter/objc_fixer.py

Lines changed: 67 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@
2929
objc_property_list_t,
3030
objc_property_t,
3131
objc_protocol_list_t,
32-
objc_protocol_t
32+
objc_protocol_t,
33+
relative_list_list_t,
34+
relative_list_t
3335
)
3436

3537
from DyldExtractor.macho.macho_structs import (
@@ -415,6 +417,15 @@ def run(self):
415417
else:
416418
self._logger.error("Unable to find libobjc.A.dylib")
417419
return
420+
421+
# 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+
418429

419430
self._checkMethodNameStorage()
420431

@@ -918,17 +929,22 @@ def _processClassData(self, classDataAddr: int, isStubClass=False) -> int:
918929
classDataDef.name = self._processString(classDataDef.name)
919930
pass
920931

921-
if classDataDef.baseMethods:
932+
baseMethodsAddr = classDataDef.baseMethods
933+
if baseMethodsAddr & 0x1:
934+
baseMethodsAddr = self._findInImageRelList(baseMethodsAddr & ~0x1)
935+
if baseMethodsAddr:
922936
classDataDef.baseMethods = self._processMethodList(
923-
classDataDef.baseMethods,
937+
baseMethodsAddr,
924938
noImp=isStubClass
925939
)
926940
pass
941+
927942

928-
if classDataDef.baseProtocols:
929-
classDataDef.baseProtocols = self._processProtocolList(
930-
classDataDef.baseProtocols
931-
)
943+
baseProtocolsAddr = classDataDef.baseProtocols
944+
if baseProtocolsAddr & 0x1:
945+
baseProtocolsAddr = self._findInImageRelList(baseProtocolsAddr & ~0x1)
946+
if baseProtocolsAddr:
947+
classDataDef.baseProtocols = self._processProtocolList(baseProtocolsAddr)
932948
pass
933949

934950
if classDataDef.ivars:
@@ -942,10 +958,11 @@ def _processClassData(self, classDataAddr: int, isStubClass=False) -> int:
942958
)
943959
pass
944960

945-
if classDataDef.baseProperties:
946-
classDataDef.baseProperties = self._processPropertyList(
947-
classDataDef.baseProperties
948-
)
961+
basePropertiesAddr = classDataDef.baseProperties
962+
if basePropertiesAddr & 0x1:
963+
basePropertiesAddr = self._findInImageRelList(basePropertiesAddr & ~0x1)
964+
if basePropertiesAddr:
965+
classDataDef.baseProperties = self._processPropertyList(basePropertiesAddr)
949966
pass
950967

951968
# add or update data
@@ -1219,12 +1236,13 @@ def _processMethodList(self, methodListAddr: int, noImp=False) -> int:
12191236
pass
12201237

12211238
# check if size is correct
1222-
if usesRelativeMethods and entsize != objc_method_small_t.SIZE:
1223-
self._logger.error(f"Small method list at {hex(methodListAddr)}, has an entsize that doesn't match the size of objc_method_small_t") # noqa
1224-
return 0
1225-
elif not usesRelativeMethods and entsize != objc_method_large_t.SIZE:
1226-
self._logger.error(f"Large method list at {hex(methodListAddr)}, has an entsize that doesn't match the size of objc_method_large_t") # noqa
1227-
return 0
1239+
if methodListDef.count != 0:
1240+
if usesRelativeMethods and entsize != objc_method_small_t.SIZE:
1241+
self._logger.error(f"Small method list at {hex(methodListAddr)}, has an entsize that doesn't match the size of objc_method_small_t") # noqa
1242+
return 0
1243+
elif not usesRelativeMethods and entsize != objc_method_large_t.SIZE:
1244+
self._logger.error(f"Large method list at {hex(methodListAddr)}, has an entsize that doesn't match the size of objc_method_large_t") # noqa
1245+
return 0
12281246

12291247
methodListData = bytearray(methodListDef)
12301248

@@ -1376,6 +1394,38 @@ def _processMethodName(self, stringAddr: int) -> int:
13761394
self._methodNameCache[stringAddr] = ptrAddr
13771395
return ptrAddr
13781396

1397+
def _findInImageRelList(self, relListListAddr: int) -> int:
1398+
"""Find the in image list in a relative list list.
1399+
1400+
Args:
1401+
relListListAddr: Address to the relative_list_list_t
1402+
1403+
returns:
1404+
The address to the in image list, or 0 if not found.
1405+
"""
1406+
1407+
relListList = self._slider.slideStruct(relListListAddr, relative_list_list_t)
1408+
1409+
# Check entsize
1410+
if relListList.entsize != relative_list_t.SIZE:
1411+
self._logger.error(f"relative_list_list_t at {hex(relListListAddr)} has an entsize that doesn't match relative_list_t") # noqa
1412+
return 0
1413+
1414+
for i in range(relListList.count):
1415+
relListAddr = (
1416+
relListListAddr
1417+
+ relative_list_list_t.SIZE
1418+
+ (i * relative_list_t.SIZE)
1419+
)
1420+
relList = self._slider.slideStruct(relListAddr, relative_list_t)
1421+
if (
1422+
relList.getImageIndex() == self._imageIndex
1423+
and (offset := relList.getOffset()) != 0
1424+
):
1425+
return relListAddr + offset
1426+
1427+
return 0
1428+
13791429
def _finalizeFutureClasses(self) -> None:
13801430
extraSegStart = self._extraDataHead - len(self._extraData)
13811431

src/DyldExtractor/objc/objc_structs.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,3 +285,29 @@ class objc_category_t(Structure):
285285
"protocols",
286286
"instanceProperties",
287287
]
288+
289+
290+
class relative_list_list_t(Structure):
291+
SIZE = 8
292+
293+
entsize: int
294+
count: int
295+
296+
_fields_ = [
297+
("entsize", c_uint32),
298+
("count", c_uint32),
299+
]
300+
301+
302+
class relative_list_t(Structure):
303+
SIZE = 8
304+
305+
offsetAndIndex: int
306+
307+
_fields_ = [("offsetAndIndex", c_uint64)]
308+
309+
def getOffset(self) -> int:
310+
return c_int64(self.offsetAndIndex).value >> 0x10
311+
312+
def getImageIndex(self) -> int:
313+
return self.offsetAndIndex & 0xFFFF

0 commit comments

Comments
 (0)