11import struct
2+ from typing import Union , Type
23
34from DyldExtractor .extraction_context import ExtractionContext
45
56from DyldExtractor .dyld .dyld_structs import (
67 dyld_cache_local_symbols_info ,
7- dyld_cache_local_symbols_entry
8+ dyld_cache_local_symbols_entry ,
9+ dyld_cache_local_symbols_entry2
810)
11+ from DyldExtractor .file_context import FileContext
912
1013from DyldExtractor .macho .macho_constants import *
1114from DyldExtractor .macho .macho_structs import (
@@ -211,6 +214,39 @@ def startSymbolContext(self, newLinkedit: bytearray) -> None:
211214 self .newSymbolTableOffset = len (newLinkedit )
212215 pass
213216
217+ def getLocalSymsEntryStruct (
218+ self ,
219+ symbolsCache : FileContext ,
220+ symbolsInfo : dyld_cache_local_symbols_info
221+ ) -> Union [
222+ Type [dyld_cache_local_symbols_entry ],
223+ Type [dyld_cache_local_symbols_entry2 ]
224+ ]:
225+ """Get the correct struct for the local symbol entries.
226+
227+ If the struct version could not be found,
228+ return None.
229+ """
230+
231+ # get the offset to the first image, and to the
232+ # second image. Assumes that they are next to each other.
233+ image1 = self .dyldCtx .convertAddr (self .dyldCtx .images [0 ].address )[0 ]
234+ image1 = struct .pack ("<I" , image1 )
235+ image2 = self .dyldCtx .convertAddr (self .dyldCtx .images [1 ].address )[0 ]
236+ image2 = struct .pack ("<I" , image2 )
237+
238+ entriesOff = symbolsInfo ._fileOff_ + symbolsInfo .entriesOffset
239+ image1Off = symbolsCache .file .find (image1 , entriesOff )
240+ image2Off = symbolsCache .file .find (image2 , entriesOff )
241+
242+ structSize = image2Off - image1Off
243+ if structSize == dyld_cache_local_symbols_entry .SIZE :
244+ return dyld_cache_local_symbols_entry
245+ elif structSize == dyld_cache_local_symbols_entry2 .SIZE :
246+ return dyld_cache_local_symbols_entry2
247+ else :
248+ return None
249+
214250 def copyLocalSymbols (self , newLinkedit : bytearray ) -> None :
215251 self .statusBar .update (status = "Copy Local Symbols" )
216252
@@ -220,13 +256,26 @@ def copyLocalSymbols(self, newLinkedit: bytearray) -> None:
220256 symbolsCache .header .localSymbolsOffset
221257 )
222258
259+ entryStruct = self .getLocalSymsEntryStruct (
260+ symbolsCache .fileCtx ,
261+ localSymbolsInfo
262+ )
263+ if not entryStruct :
264+ self .logger .error ("Unable to get local symbol entries structure." )
265+ return
266+
267+ dylibOffset = (
268+ self .machoCtx .segments [b"__TEXT" ].seg .vmaddr
269+ - self .dyldCtx .header .sharedRegionStart
270+ )
271+
223272 localSymbolsEntriesInfo = None
224273 for i in range (localSymbolsInfo .entriesCount ):
225- entryOff = (i * dyld_cache_local_symbols_entry .SIZE )
274+ entryOff = (i * entryStruct .SIZE )
226275 entryOff += localSymbolsInfo ._fileOff_ + localSymbolsInfo .entriesOffset
227276
228- entry = dyld_cache_local_symbols_entry (symbolsCache .fileCtx .file , entryOff )
229- if entry .dylibOffset == self . machoCtx . fileOffset :
277+ entry = entryStruct (symbolsCache .fileCtx .file , entryOff )
278+ if entry .dylibOffset == dylibOffset :
230279 localSymbolsEntriesInfo = entry
231280 break
232281
@@ -251,7 +300,7 @@ def copyLocalSymbols(self, newLinkedit: bytearray) -> None:
251300 symbolStrOff = localSymbolsInfo ._fileOff_ + localSymbolsInfo .stringsOffset
252301
253302 for offset in range (entriesStart , entriesEnd , nlist_64 .SIZE ):
254- symbolEnt = nlist_64 (self . dyldCtx .file , offset )
303+ symbolEnt = nlist_64 (symbolsCache . fileCtx .file , offset )
255304 name = symbolsCache .fileCtx .readString (symbolStrOff + symbolEnt .n_strx )
256305
257306 # copy data
@@ -282,10 +331,10 @@ def copyExportedSymbols(self, newLinkedit: bytearray) -> None:
282331
283332 for entryIndex in range (entriesStart , entriesEnd ):
284333 entryOff = self .symTabCmd .symoff + (entryIndex * nlist_64 .SIZE )
285- entry = nlist_64 (self .dyldCtx .file , entryOff )
334+ entry = nlist_64 (self .linkeditFile .file , entryOff )
286335
287336 nameOff = symbolStrOff + entry .n_strx
288- name = self .dyldCtx .readString (nameOff )
337+ name = self .linkeditFile .readString (nameOff )
289338
290339 # update variables and copy
291340 self .oldToNewSymbolIndexes [entryIndex ] = self .symbolCtx .symbolsSize
@@ -317,10 +366,10 @@ def copyImportedSymbols(self, newLinkedit: bytearray) -> None:
317366
318367 for entryIndex in range (entriesStart , entriesEnd ):
319368 entryOff = self .symTabCmd .symoff + (entryIndex * nlist_64 .SIZE )
320- entry = nlist_64 (self .dyldCtx .file , entryOff )
369+ entry = nlist_64 (self .linkeditFile .file , entryOff )
321370
322371 nameOff = symbolStrOff + entry .n_strx
323- name = self .dyldCtx .readString (nameOff )
372+ name = self .linkeditFile .readString (nameOff )
324373
325374 # update variables and copy
326375 self .oldToNewSymbolIndexes [entryIndex ] = self .symbolCtx .symbolsSize
@@ -357,7 +406,7 @@ def addRedactedSymbol(self, newLinkedit: bytearray) -> None:
357406 indirectStart = self .dynSymTabCmd .indirectsymoff
358407 indirectEnd = indirectStart + (self .dynSymTabCmd .nindirectsyms * 4 )
359408 for offset in range (indirectStart , indirectEnd , 4 ):
360- symbolIndex = self .dyldCtx .getBytes (offset , 4 )
409+ symbolIndex = self .linkeditFile .getBytes (offset , 4 )
361410 if symbolIndex == b"\x00 \x00 \x00 \x00 " :
362411 self .redactedSymbolCount += 1
363412
@@ -385,7 +434,10 @@ def copyFunctionStarts(self, newLinkedit: bytearray) -> None:
385434 self .newFunctionStartsOffset = len (newLinkedit )
386435
387436 size = self .functionStartsCmd .datasize
388- functionStarts = self .machoCtx .getBytes (self .functionStartsCmd .dataoff , size )
437+ functionStarts = self .linkeditFile .getBytes (
438+ self .functionStartsCmd .dataoff ,
439+ size
440+ )
389441 newLinkedit .extend (functionStarts )
390442
391443 self .statusBar .update ()
@@ -400,7 +452,7 @@ def copyDataInCode(self, newLinkedit: bytearray) -> None:
400452 self .newDataInCodeOffset = len (newLinkedit )
401453
402454 size = self .dataInCodeCmd .datasize
403- dataInCode = self .machoCtx .getBytes (self .dataInCodeCmd .dataoff , size )
455+ dataInCode = self .linkeditFile .getBytes (self .dataInCodeCmd .dataoff , size )
404456 newLinkedit .extend (dataInCode )
405457
406458 self .statusBar .update ()
@@ -421,7 +473,7 @@ def copyIndirectSymbolTable(self, newLinkedit: bytearray) -> None:
421473
422474 for offset in range (self .dynSymTabCmd .indirectsymoff , entriesEnd , 4 ):
423475 # Each entry is a 32bit index into the symbol table
424- symbol = self .dyldCtx .getBytes (offset , 4 )
476+ symbol = self .linkeditFile .getBytes (offset , 4 )
425477 symbolIndex = struct .unpack ("<I" , symbol )[0 ]
426478
427479 if (
@@ -565,10 +617,11 @@ def optimizeLinkedit(extractionCtx: ExtractionContext) -> None:
565617 newLinkedit .extend (b"\x00 " * 4 )
566618
567619 # Set the new linkedit in the same location
568- machoCtx = extractionCtx .machoCtx
569- newLinkeditOff = machoCtx .segments [b"__LINKEDIT" ].seg .fileoff
570- machoCtx .file .seek (newLinkeditOff )
571- machoCtx .file .write (newLinkedit )
620+ newLinkeditOff = extractionCtx .machoCtx .segments [b"__LINKEDIT" ].seg .fileoff
621+ linkeditFile = extractionCtx .machoCtx .fileForAddr (
622+ extractionCtx .machoCtx .segments [b"__LINKEDIT" ].seg .vmaddr
623+ )
624+ linkeditFile .writeBytes (newLinkeditOff , newLinkedit )
572625
573626 optimizer .updateLoadCommands (newLinkedit , newLinkeditOff )
574627
0 commit comments