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

Commit 3d3f2db

Browse files
committed
update
1 parent 689b1ce commit 3d3f2db

File tree

2 files changed

+67
-41
lines changed

2 files changed

+67
-41
lines changed

bin/dyldex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ def _extractImage(
163163

164164
slide_info.processSlideInfo(extractionCtx)
165165
linkedit_optimizer.optimizeLinkedit(extractionCtx)
166-
# stub_fixer.fixStubs(extractionCtx)
166+
stub_fixer.fixStubs(extractionCtx)
167167
# objc_fixer.fixObjC(extractionCtx)
168168

169169
writeProcedures = macho_offset.optimizeOffsets(extractionCtx)

src/DyldExtractor/converter/stub_fixer.py

Lines changed: 66 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def __init__(self, extractionCtx: ExtractionContext) -> None:
5353
# create a map of image paths and their addresses
5454
self._images: dict[bytes, int] = {}
5555
for image in self._dyldCtx.images:
56-
imagePath = self._dyldCtx.readString(image.pathFileOffset)
56+
imagePath = self._dyldCtx.fileCtx.readString(image.pathFileOffset)
5757
self._images[imagePath] = image.address
5858
pass
5959

@@ -166,14 +166,16 @@ def _getDepInfo(self, dylib: dylib_command) -> _DependencyInfo:
166166
"""
167167

168168
dylibPathOff = dylib._fileOff_ + dylib.dylib.name.offset
169-
dylibPath = self._dyldCtx.readString(dylibPathOff)
169+
dylibPath = self._machoCtx.fileCtx.readString(dylibPathOff)
170170
if dylibPath not in self._images:
171171
self._logger.warning(f"Unable to find dependency: {dylibPath}")
172172
return None
173173

174174
imageAddr = self._images[dylibPath]
175-
imageOff = self._dyldCtx.convertAddr(imageAddr)
176-
context = MachOContext(self._dyldCtx.file, imageOff)
175+
imageOff, dyldCtx = self._dyldCtx.convertAddr(imageAddr)
176+
177+
# Since we're not editing the dependencies, this should be fine.
178+
context = MachOContext(dyldCtx.fileCtx, imageOff)
177179
return _DependencyInfo(dylibPath, imageAddr, context)
178180

179181
def _readDepExports(
@@ -201,9 +203,13 @@ def _readDepExports(
201203
# Some images like UIKit don't have exports
202204
return []
203205

206+
linkeditFile = self._dyldCtx.convertAddr(
207+
depInfo.context.segments[b"__LINKEDIT"].seg.vmaddr
208+
)[1].fileCtx.file
209+
204210
try:
205211
depExports = dyld_trie.ReadExports(
206-
depInfo.context.file,
212+
linkeditFile,
207213
exportOff,
208214
exportSize,
209215
)
@@ -250,21 +256,19 @@ def _enumerateSymbols(self) -> None:
250256
self._logger.warning("Unable to find LC_SYMTAB.")
251257
return
252258

253-
dysymtab: dysymtab_command = self._machoCtx.getLoadCommand(
254-
(LoadCommands.LC_DYSYMTAB,)
259+
linkeditFile = self._machoCtx.fileForAddr(
260+
self._machoCtx.segments[b"__LINKEDIT"].seg.vmaddr
255261
)
256-
if not dysymtab:
257-
self._logger.warning("Unable to find LC_DYSYMTAB.")
258262

259263
for i in range(symtab.nsyms):
260264
self._statusBar.update()
261265

262266
# Get the symbol and its address
263267
entryOff = symtab.symoff + (i * nlist_64.SIZE)
264-
symbolEntry = nlist_64(self._machoCtx.file, entryOff)
268+
symbolEntry = nlist_64(linkeditFile.file, entryOff)
265269

266270
symbolAddr = symbolEntry.n_value
267-
symbol = self._machoCtx.readString(symtab.stroff + symbolEntry.n_strx)
271+
symbol = linkeditFile.readString(symtab.stroff + symbolEntry.n_strx)
268272

269273
if symbolAddr == 0:
270274
continue
@@ -450,10 +454,11 @@ def getStubHelperData(self, address: int) -> int:
450454
If unable to get the bind data, return None.
451455
"""
452456

453-
if not (helperOff := self._dyldCtx.convertAddr(address)):
457+
helperOff, ctx = self._dyldCtx.convertAddr(address) or (None, None)
458+
if helperOff is None:
454459
return None
455460

456-
ldr, b, data = self._dyldCtx.readFormat(helperOff, "<III")
461+
ldr, b, data = ctx.fileCtx.readFormat(helperOff, "<III")
457462

458463
# verify
459464
if (
@@ -516,19 +521,20 @@ def getResolverData(self, address: int) -> Tuple[int, int]:
516521

517522
SEARCH_LIMIT = 0xC8
518523

519-
if not (stubOff := self._dyldCtx.convertAddr(address)):
524+
stubOff, ctx = self._dyldCtx.convertAddr(address) or (None, None)
525+
if stubOff is None:
520526
return None
521527

522528
# test stp and mov
523-
stp, mov = self._dyldCtx.readFormat(stubOff, "<II")
529+
stp, mov = ctx.fileCtx.readFormat(stubOff, "<II")
524530
if (
525531
(stp & 0x7FC00000) != 0x29800000
526532
or (mov & 0x7F3FFC00) != 0x11000000
527533
):
528534
return None
529535

530536
# Find the branch instruction
531-
dataSource = self._dyldCtx.file
537+
dataSource = ctx.fileCtx.file
532538
branchInstrOff = None
533539
for instrOff in range(stubOff, stubOff + SEARCH_LIMIT, 4):
534540
# (instr & 0xFE9FF000) == 0xD61F0000
@@ -557,16 +563,16 @@ def getResolverData(self, address: int) -> Tuple[int, int]:
557563
return None
558564

559565
# Test if there is a stp before the bl and a ldp before the braaz
560-
adrp = self._dyldCtx.readFormat(blInstrOff + 4, "<I")[0]
561-
ldp = self._dyldCtx.readFormat(branchInstrOff - 4, "<I")[0]
566+
adrp = ctx.fileCtx.readFormat(blInstrOff + 4, "<I")[0]
567+
ldp = ctx.fileCtx.readFormat(branchInstrOff - 4, "<I")[0]
562568
if (
563569
(adrp & 0x9F00001F) != 0x90000010
564570
or (ldp & 0x7FC00000) != 0x28C00000
565571
):
566572
return None
567573

568574
# Hopefully it's a resolver...
569-
imm = (self._dyldCtx.readFormat(blInstrOff, "<I")[0] & 0x3FFFFFF) << 2
575+
imm = (ctx.fileCtx.readFormat(blInstrOff, "<I")[0] & 0x3FFFFFF) << 2
570576
imm = self.signExtend(imm, 28)
571577
blResult = address + (blInstrOff - stubOff) + imm
572578

@@ -609,10 +615,11 @@ def _getStubNormalLdrAddr(self, address: int) -> int:
609615
be determined.
610616
"""
611617

612-
if not (stubOff := self._dyldCtx.convertAddr(address)):
618+
stubOff, ctx = self._dyldCtx.convertAddr(address) or (None, None)
619+
if stubOff is None:
613620
return None
614621

615-
adrp, ldr, br = self._dyldCtx.readFormat(stubOff, "<III")
622+
adrp, ldr, br = ctx.fileCtx.readFormat(stubOff, "<III")
616623

617624
# verify
618625
if (
@@ -645,10 +652,11 @@ def _getAuthStubNormalLdrAddr(self, address: int) -> int:
645652
not be determined.
646653
"""
647654

648-
if not (stubOff := self._dyldCtx.convertAddr(address)):
655+
stubOff, ctx = self._dyldCtx.convertAddr(address) or (None, None)
656+
if stubOff is None:
649657
return None
650658

651-
adrp, add, ldr, braa = self._dyldCtx.readFormat(
659+
adrp, add, ldr, braa = ctx.fileCtx.readFormat(
652660
stubOff,
653661
"<IIII"
654662
)
@@ -684,10 +692,11 @@ def _getStubNormalTarget(self, address: int) -> int:
684692
BR x16
685693
"""
686694

687-
if not (stubOff := self._dyldCtx.convertAddr(address)):
695+
stubOff, ctx = self._dyldCtx.convertAddr(address) or (None, None)
696+
if stubOff is None:
688697
return None
689698

690-
adrp, ldr, br = self._dyldCtx.readFormat(stubOff, "<III")
699+
adrp, ldr, br = ctx.fileCtx.readFormat(stubOff, "<III")
691700

692701
# verify
693702
if (
@@ -716,10 +725,11 @@ def _getStubOptimizedTarget(self, address: int) -> int:
716725
BR x16
717726
"""
718727

719-
if not (stubOff := self._dyldCtx.convertAddr(address)):
728+
stubOff, ctx = self._dyldCtx.convertAddr(address)
729+
if stubOff is None:
720730
return None
721731

722-
adrp, add, br = self._dyldCtx.readFormat(stubOff, "<III")
732+
adrp, add, br = ctx.fileCtx.readFormat(stubOff, "<III")
723733

724734
# verify
725735
if (
@@ -748,10 +758,11 @@ def _getAuthStubNormalTarget(self, address: int) -> int:
748758
11 0a 1f d7 braa x16=>__auth_stubs::_CCRandomCopyBytes,x17
749759
"""
750760

751-
if not (stubOff := self._dyldCtx.convertAddr(address)):
761+
stubOff, ctx = self._dyldCtx.convertAddr(address)
762+
if stubOff is None:
752763
return None
753764

754-
adrp, add, ldr, braa = self._dyldCtx.readFormat(stubOff, "<IIII")
765+
adrp, add, ldr, braa = ctx.fileCtx.readFormat(stubOff, "<IIII")
755766

756767
# verify
757768
if (
@@ -787,10 +798,11 @@ def _getAuthStubOptimizedTarget(self, address: int) -> int:
787798
1bfcb5d2c 20 00 20 d4 trap
788799
"""
789800

790-
if not (stubOff := self._dyldCtx.convertAddr(address)):
801+
stubOff, ctx = self._dyldCtx.convertAddr(address)
802+
if stubOff is None:
791803
return None
792804

793-
adrp, add, br, trap = self._dyldCtx.readFormat(stubOff, "<IIII")
805+
adrp, add, br, trap = ctx.fileCtx.readFormat(stubOff, "<IIII")
794806

795807
# verify
796808
if (
@@ -819,10 +831,11 @@ def _getAuthStubResolverTarget(self, address: int) -> int:
819831
1f 0a 1f d6 braaz x16=>FUN_195bee070
820832
"""
821833

822-
if not (stubOff := self._dyldCtx.convertAddr(address)):
834+
stubOff, ctx = self._dyldCtx.convertAddr(address)
835+
if stubOff is None:
823836
return None
824837

825-
adrp, ldr, braaz = self._dyldCtx.readFormat(stubOff, "<III")
838+
adrp, ldr, braaz = ctx.fileCtx.readFormat(stubOff, "<III")
826839

827840
# verify
828841
if (
@@ -1024,14 +1037,19 @@ def _enumerateSymbolPointers(self) -> Dict[bytes, Tuple[int]]:
10241037
dyldInfo: dyld_info_command = self._machoCtx.getLoadCommand(
10251038
(LoadCommands.LC_DYLD_INFO, LoadCommands.LC_DYLD_INFO_ONLY)
10261039
)
1040+
1041+
linkeditFile = self._machoCtx.fileForAddr(
1042+
self._machoCtx.segments[b"__LINKEDIT"].seg.vmaddr
1043+
)
1044+
10271045
if dyldInfo:
10281046
records: List[_BindRecord] = []
10291047
try:
10301048
if dyldInfo.weak_bind_size:
10311049
# usually contains records for c++ symbols like "new"
10321050
records.extend(
10331051
_bindReader(
1034-
self._machoCtx,
1052+
linkeditFile,
10351053
dyldInfo.weak_bind_off,
10361054
dyldInfo.weak_bind_size
10371055
)
@@ -1041,7 +1059,7 @@ def _enumerateSymbolPointers(self) -> Dict[bytes, Tuple[int]]:
10411059
if dyldInfo.lazy_bind_off:
10421060
records.extend(
10431061
_bindReader(
1044-
self._machoCtx,
1062+
linkeditFile,
10451063
dyldInfo.lazy_bind_off,
10461064
dyldInfo.lazy_bind_size
10471065
)
@@ -1098,7 +1116,7 @@ def _addToMap(ptrSymbol: bytes, ptrAddr: int, section: section_64):
10981116
continue
10991117

11001118
# Try to symbolize though indirect symbol entries
1101-
symbolIndex = self._machoCtx.readFormat(
1119+
symbolIndex = linkeditFile.readFormat(
11021120
self._dysymtab.indirectsymoff + ((sect.reserved1 + i) * 4),
11031121
"<I"
11041122
)[0]
@@ -1109,10 +1127,10 @@ def _addToMap(ptrSymbol: bytes, ptrAddr: int, section: section_64):
11091127
and symbolIndex != (INDIRECT_SYMBOL_ABS | INDIRECT_SYMBOL_LOCAL)
11101128
):
11111129
symbolEntry = nlist_64(
1112-
self._machoCtx.file,
1130+
linkeditFile,
11131131
self._symtab.symoff + (symbolIndex * nlist_64.SIZE)
11141132
)
1115-
symbol = self._machoCtx.readString(
1133+
symbol = linkeditFile.readString(
11161134
self._symtab.stroff + symbolEntry.n_strx
11171135
)
11181136

@@ -1157,6 +1175,14 @@ def _fixStubHelpers(self) -> None:
11571175
if not dyldInfo:
11581176
return
11591177

1178+
textFile = self._machoCtx.fileForAddr(
1179+
self._machoCtx.segments[b"__TEXT"].seg.vmaddr
1180+
)
1181+
1182+
linkeditFile = self._machoCtx.fileForAddr(
1183+
self._machoCtx.segments[b"__LINKEDIT"].seg.vmaddr
1184+
)
1185+
11601186
# the stub helper section has the stub binder in
11611187
# beginning, skip it.
11621188
helperAddr = helperSect.addr + STUB_BINDER_SIZE
@@ -1168,7 +1194,7 @@ def _fixStubHelpers(self) -> None:
11681194
if (bindOff := self._arm64Utils.getStubHelperData(helperAddr)) is not None:
11691195
record = next(
11701196
_bindReader(
1171-
self._machoCtx,
1197+
linkeditFile,
11721198
dyldInfo.lazy_bind_off + bindOff,
11731199
dyldInfo.lazy_bind_size,
11741200
),
@@ -1190,7 +1216,7 @@ def _fixStubHelpers(self) -> None:
11901216
bindPtrOff += record.offset
11911217

11921218
newBindPtr = struct.pack("<Q", helperAddr)
1193-
self._machoCtx.writeBytes(bindPtrOff, newBindPtr)
1219+
textFile.writeBytes(bindPtrOff, newBindPtr)
11941220
helperAddr += REG_HELPER_SIZE
11951221
continue
11961222

0 commit comments

Comments
 (0)