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

Commit 65ca894

Browse files
committed
Fixed objc_fixer.
1 parent 83c9681 commit 65ca894

File tree

3 files changed

+50
-25
lines changed

3 files changed

+50
-25
lines changed

src/DyldExtractor/converter/objc_fixer.py

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,12 @@ def disasm_lite_new(self, code, offset, count=0, codeOffset=0):
4646
# Pass a bytearray by reference
4747
if isinstance(code, bytearray):
4848
code = ctypes.byref(ctypes.c_char.from_buffer(code, codeOffset))
49-
res = cp._cs.cs_disasm(self.csh, code, size, offset, count, ctypes.byref(all_insn))
49+
res = cp._cs.cs_disasm(self.csh, code, size, offset, count, ctypes.byref(all_insn)) # noqa
5050
if res > 0:
5151
try:
5252
for i in range(res):
5353
insn = all_insn[i]
54-
yield (insn.address, insn.size, insn.mnemonic.decode('ascii'), insn.op_str.decode('ascii'))
54+
yield (insn.address, insn.size, insn.mnemonic.decode('ascii'), insn.op_str.decode('ascii')) # noqa
5555
finally:
5656
cp._cs.cs_free(all_insn, res)
5757
else:
@@ -112,7 +112,10 @@ def run(self) -> None:
112112

113113
# enumerate the text
114114
textSectAddr = textSect.addr
115-
textSectOff = self._dyldCtx.convertAddr(textSectAddr)
115+
textSectOff, ctx = self._dyldCtx.convertAddr(textSectAddr)
116+
117+
textFile = ctx.fileCtx
118+
writableTextFile = self._machoCtx.fileForAddr(textSectAddr)
116119

117120
for i, instrData in enumerate(self._textInstr):
118121
if instrData[1] != "adrp":
@@ -126,7 +129,7 @@ def run(self) -> None:
126129

127130
adrpAddr = textSectAddr + (i * 4)
128131
adrpOff = textSectOff + (i * 4)
129-
adrpInstr = self._dyldCtx.readFormat(adrpOff, "<I")[0]
132+
adrpInstr = textFile.readFormat("<I", adrpOff)[0]
130133

131134
# Find the ADRP result
132135
immlo = (adrpInstr & 0x60000000) >> 29
@@ -139,7 +142,7 @@ def run(self) -> None:
139142

140143
for addInstrIdx in addInstrIdxs:
141144
addOff = textSectOff + (addInstrIdx * 4)
142-
addInstr = self._dyldCtx.readFormat(addOff, "<I")[0]
145+
addInstr = textFile.readFormat("<I", addOff)[0]
143146

144147
# Test for a special ADD cases
145148
if addInstr & 0xffc00000 != 0x91000000:
@@ -165,7 +168,7 @@ def run(self) -> None:
165168
immhi = (adrpDelta >> 9) & (0x00FFFFE0)
166169
immlo = (adrpDelta << 17) & (0x60000000)
167170
newAdrp = (0x90000000) | immlo | immhi | adrpInstr & 0x1F
168-
self._machoCtx.writeBytes(adrpOff, struct.pack("<I", newAdrp))
171+
writableTextFile.writeBytes(adrpOff, struct.pack("<I", newAdrp))
169172
pass
170173
else:
171174
# Make sure the new address is reachable with the new adrp
@@ -180,7 +183,7 @@ def run(self) -> None:
180183
imm12 = (ldrTargetOff << 7) & 0x3FFC00
181184
ldrRegisters = addInstr & 0x3FF
182185
newLdr = 0xF9400000 | imm12 | ldrRegisters
183-
self._machoCtx.writeBytes(addOff, struct.pack("<I", newLdr))
186+
writableTextFile.writeBytes(addOff, struct.pack("<I", newLdr))
184187

185188
self._statusBar.update(status="Fixing Selectors")
186189
pass
@@ -193,8 +196,8 @@ def _disasmText(self) -> Tuple[int, str, Tuple[str]]:
193196
self._statusBar.update(status="Disassembling Text (will appear frozen)")
194197

195198
textSect = self._machoCtx.segments[b"__TEXT"].sects[b"__text"]
196-
textSectOff = self._dyldCtx.convertAddr(textSect.addr)
197-
textData = bytearray(self._dyldCtx.getBytes(textSectOff, textSect.size))
199+
textSectOff, ctx = self._dyldCtx.convertAddr(textSect.addr)
200+
textData = bytearray(ctx.fileCtx.getBytes(textSectOff, textSect.size))
198201

199202
opStrTrans = str.maketrans("", "", "[]!")
200203
disassembler = cp.Cs(cp.CS_ARCH_ARM64, cp.CS_MODE_LITTLE_ENDIAN)
@@ -474,7 +477,7 @@ def _createExtraSegment(self) -> None:
474477
# Get a starting address for the new segment
475478
newSegStartAddr = (leftSeg.vmaddr + leftSeg.vmsize + 0x1000) & ~0xFFF
476479
newSegStartOff = (
477-
self._dyldCtx.convertAddr(leftSeg.vmaddr) + leftSeg.vmsize
480+
self._dyldCtx.convertAddr(leftSeg.vmaddr)[0] + leftSeg.vmsize
478481
+ 0x1000
479482
) & ~0xFFF
480483

@@ -543,15 +546,16 @@ def _processSections(self) -> None:
543546
pass
544547

545548
elif sect.sectname == b"__objc_selrefs":
549+
file = self._machoCtx.fileForAddr(sect.addr)
546550
for ptrAddr in range(sect.addr, sect.addr + sect.size, 8):
547551
self._statusBar.update(status="Processing Selector References")
548552
selRefAddr = self._slider.slideAddress(ptrAddr)
549553

550554
self._selRefCache[selRefAddr] = ptrAddr
551555

552556
newPtr = self._processString(selRefAddr)
553-
self._machoCtx.writeBytes(
554-
self._dyldCtx.convertAddr(ptrAddr),
557+
file.writeBytes(
558+
self._dyldCtx.convertAddr(ptrAddr)[0],
555559
struct.pack("<Q", newPtr)
556560
)
557561
pass
@@ -1238,7 +1242,9 @@ def _makeHeaderSpace(self, spaceNeeded: int) -> None:
12381242
if cmd in commandsToRemove:
12391243
continue
12401244

1241-
loadCommandsData.extend(self._machoCtx.fileCtx.getBytes(readHead, cmd.cmdsize))
1245+
loadCommandsData.extend(
1246+
self._machoCtx.fileCtx.getBytes(readHead, cmd.cmdsize)
1247+
)
12421248
readHead += cmd.cmdsize
12431249
pass
12441250

@@ -1249,8 +1255,7 @@ def _makeHeaderSpace(self, spaceNeeded: int) -> None:
12491255
loadCommandsData
12501256
)
12511257

1252-
self._machoCtx = MachOContext(self._machoCtx.fileCtx.file, self._machoCtx.fileOffset)
1253-
self._extractionCtx.machoCtx = self._machoCtx
1258+
self._machoCtx.reloadLoadCommands()
12541259
pass
12551260

12561261
def _addExtraDataSeg(self) -> None:
@@ -1266,25 +1271,30 @@ def _addExtraDataSeg(self) -> None:
12661271
+ self._machoCtx.header.sizeofcmds
12671272
- moveStart
12681273
)
1269-
self._machoCtx.file.move(
1274+
self._machoCtx.fileCtx.file.move(
12701275
moveStart + segment_command_64.SIZE,
12711276
moveStart,
12721277
bytesToMove
12731278
)
12741279

1280+
self._machoCtx.fileCtx.writeBytes(moveStart, self._extraSegment)
1281+
12751282
# add the new data and the segment command
1276-
self._machoCtx.writeBytes(self._extraSegment.fileoff, self._extraData)
1277-
self._machoCtx.writeBytes(moveStart, self._extraSegment)
1283+
file = self._machoCtx.fileForAddr(self._extraSegment.vmaddr)
1284+
if not file:
1285+
self._logger.error("Encountered edge case when adding extra data!")
1286+
return
1287+
1288+
file.writeBytes(
1289+
self._extraSegment.fileoff,
1290+
self._extraData
1291+
)
12781292

12791293
# update the header
12801294
self._machoCtx.header.ncmds += 1
12811295
self._machoCtx.header.sizeofcmds += segment_command_64.SIZE
12821296

1283-
# recreate the macho context to reflect the new segment
1284-
self._extractionCtx.machoCtx = MachOContext(
1285-
self._machoCtx.file,
1286-
self._machoCtx.fileOffset
1287-
)
1297+
self._machoCtx.reloadLoadCommands()
12881298
pass
12891299
pass
12901300

src/DyldExtractor/converter/stub_fixer.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,11 @@ def _enumerateExports(self) -> None:
161161
self._logger.warning(f"No root export for ReExport with symbol {name}")
162162
pass
163163

164-
def _getDepInfo(self, dylib: dylib_command, context: MachOContext) -> _DependencyInfo:
164+
def _getDepInfo(
165+
self,
166+
dylib: dylib_command,
167+
context: MachOContext
168+
) -> _DependencyInfo:
165169
"""Given a dylib command, get dependency info.
166170
"""
167171

src/DyldExtractor/macho/macho_context.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def __init__(
4343
self.fileCtx = fileCtx
4444
self.fileOffset = offset
4545

46-
self.header = mach_header_64(fileCtx.file, offset)
46+
self.header = mach_header_64(self.fileCtx.file, self.fileOffset)
4747
self._mappings: List[Tuple[dyld_cache_mapping_info, FileContext]] = []
4848

4949
# check to make sure the MachO file is 64 bit
@@ -110,6 +110,7 @@ def _parseLoadCommands(self) -> None:
110110
111111
Parse the load commands and set the loadCommands attribute.
112112
"""
113+
self.header = mach_header_64(self.fileCtx.file, self.fileOffset)
113114

114115
self.loadCommands = []
115116

@@ -141,6 +142,16 @@ def _parseLoadCommands(self) -> None:
141142
pass
142143
pass
143144

145+
def reloadLoadCommands(self) -> None:
146+
"""Reload the load commands.
147+
148+
Read the header and load commands with the
149+
same file and offset.
150+
"""
151+
152+
self._parseLoadCommands()
153+
pass
154+
144155
def addSubfiles(
145156
self,
146157
mainFileMap: dyld_cache_mapping_info,

0 commit comments

Comments
 (0)