def copyExportedSymbols(self, newLinkedit: bytearray) -> None: self.statusBar.update("Copy Exported Symbols") self.newExportedSymbolsStartIndex = self.symbolCtx.symbolsSize self.newExportedSymbolCount = 0 if not self.dynSymTabCmd: self.logger.warning("Unable to copy exported symbols.") return # Copy entries and symbols entriesStart = self.dynSymTabCmd.iextdefsym entriesEnd = entriesStart + self.dynSymTabCmd.nextdefsym symbolStrOff = self.symTabCmd.stroff for entryIndex in range(entriesStart, entriesEnd): entryOff = self.symTabCmd.symoff + (entryIndex * nlist_64.SIZE) entry = nlist_64(self.dyldCtx.file, entryOff) nameOff = symbolStrOff + entry.n_strx name = self.dyldCtx.readString(nameOff) # update variables and copy self.oldToNewSymbolIndexes[entryIndex] = self.symbolCtx.symbolsSize self.newExportedSymbolCount += 1 self.symbolCtx.symbolsSize += 1 entry.n_strx = self.symbolCtx.addString(name) newLinkedit.extend(entry) self.statusBar.update() pass
def copyLocalSymbols(self, newLinkedit: bytearray) -> None: self.statusBar.update(status="Copy Local Symbols") symbolsCache = self.dyldCtx.getSymbolsCache() localSymbolsInfo = dyld_cache_local_symbols_info( symbolsCache.file, symbolsCache.header.localSymbolsOffset) entryStruct = self.getLocalSymsEntryStruct(symbolsCache, localSymbolsInfo) if not entryStruct: self.logger.error("Unable to get local symbol entries structure.") return dylibOffset = (self.machoCtx.segments[b"__TEXT"].seg.vmaddr - self.dyldCtx.header.sharedRegionStart) localSymbolsEntriesInfo = None for i in range(localSymbolsInfo.entriesCount): entryOff = (i * entryStruct.SIZE) entryOff += localSymbolsInfo._fileOff_ + localSymbolsInfo.entriesOffset entry = entryStruct(symbolsCache.file, entryOff) if entry.dylibOffset == dylibOffset: localSymbolsEntriesInfo = entry break if not localSymbolsEntriesInfo: self.logger.warning("Unable to find local symbol entries.") return self.newLocalSymbolsStartIndex = self.symbolCtx.symbolsSize self.newLocalSymbolCount = 0 # copy local symbols and their strings entriesStart = ( localSymbolsInfo._fileOff_ + localSymbolsInfo.nlistOffset + (localSymbolsEntriesInfo.nlistStartIndex * nlist_64.SIZE)) entriesEnd = (entriesStart + (localSymbolsEntriesInfo.nlistCount * nlist_64.SIZE)) symbolStrOff = localSymbolsInfo._fileOff_ + localSymbolsInfo.stringsOffset for offset in range(entriesStart, entriesEnd, nlist_64.SIZE): symbolEnt = nlist_64(symbolsCache.file, offset) name = symbolsCache.readString(symbolStrOff + symbolEnt.n_strx) # copy data self.newLocalSymbolCount += 1 self.symbolCtx.symbolsSize += 1 symbolEnt.n_strx = self.symbolCtx.addString(name) newLinkedit.extend(symbolEnt) self.statusBar.update() pass
def copyLocalSymbols(self, newLinkedit: bytearray) -> None: self.statusBar.update(status="Copy Local Symbols") localSymbolsInfo = dyld_cache_local_symbols_info( self.dyldCtx.file, self.dyldCtx.header.localSymbolsOffset) localSymbolsEntriesInfo = None for i in range(localSymbolsInfo.entriesCount): entryOff = (i * dyld_cache_local_symbols_entry.SIZE) entryOff += localSymbolsInfo._fileOff_ + localSymbolsInfo.entriesOffset entry = dyld_cache_local_symbols_entry(self.dyldCtx.file, entryOff) if entry.dylibOffset == self.machoCtx.fileOffset: localSymbolsEntriesInfo = entry break if not localSymbolsEntriesInfo: self.logger.warning("Unable to find local symbol entries.") return self.newLocalSymbolsStartIndex = self.symbolCtx.symbolsSize self.newLocalSymbolCount = 0 # copy local symbols and their strings entriesStart = ( localSymbolsInfo._fileOff_ + localSymbolsInfo.nlistOffset + (localSymbolsEntriesInfo.nlistStartIndex * nlist_64.SIZE)) entriesEnd = (entriesStart + (localSymbolsEntriesInfo.nlistCount * nlist_64.SIZE)) symbolStrOff = localSymbolsInfo._fileOff_ + localSymbolsInfo.stringsOffset for offset in range(entriesStart, entriesEnd, nlist_64.SIZE): symbolEnt = nlist_64(self.dyldCtx.file, offset) name = self.dyldCtx.readString(symbolStrOff + symbolEnt.n_strx) # copy data self.newLocalSymbolCount += 1 self.symbolCtx.symbolsSize += 1 symbolEnt.n_strx = self.symbolCtx.addString(name) newLinkedit.extend(symbolEnt) self.statusBar.update() pass
def copyImportedSymbols(self, newLinkedit: bytearray) -> None: self.statusBar.update(status="Copy Imported Symbols") self.newImportedSymbolsStartIndex = self.symbolCtx.symbolsSize self.newImportedSymbolCount = 0 if not self.dynSymTabCmd: self.logger.warning("Unable to copy imported symbols") return # Copy entries and symbols entriesStart = self.dynSymTabCmd.iundefsym entriesEnd = entriesStart + self.dynSymTabCmd.nundefsym symbolStrOff = self.symTabCmd.stroff for entryIndex in range(entriesStart, entriesEnd): entryOff = self.symTabCmd.symoff + (entryIndex * nlist_64.SIZE) entry = nlist_64(self.dyldCtx.file, entryOff) nameOff = symbolStrOff + entry.n_strx name = self.dyldCtx.readString(nameOff) # update variables and copy self.oldToNewSymbolIndexes[entryIndex] = self.symbolCtx.symbolsSize self.newImportedSymbolCount += 1 self.symbolCtx.symbolsSize += 1 entry.n_strx = self.symbolCtx.addString(name) newLinkedit.extend(entry) self.statusBar.update() # make room for the indirect symbol entries that may # be fixed in stub_fixer if self.redactedSymbolCount: newLinkedit.extend(b"\x00" * (self.redactedSymbolCount * nlist_64.SIZE)) pass
def addRedactedSymbol(self, newLinkedit: bytearray) -> None: """Adds a redacted symbol entry if needed. Some images have indirect symbols that point to the zeroth symbol entry. This is probaby a stripped symbol and is basically unrecoverable. This provides a "redacted" entry for those special cases so that some disassemblers don't name functions incorrectly. """ self.statusBar.update(status="Search Redacted Symbols") self.redactedSymbolCount = 0 indirectStart = self.dynSymTabCmd.indirectsymoff indirectEnd = indirectStart + (self.dynSymTabCmd.nindirectsyms * 4) for offset in range(indirectStart, indirectEnd, 4): symbolIndex = self.dyldCtx.getBytes(offset, 4) if symbolIndex == b"\x00\x00\x00\x00": self.redactedSymbolCount += 1 self.statusBar.update() pass if self.redactedSymbolCount: stringIndex = self.symbolCtx.addString(b"<redacted>\x00") self.symbolCtx.symbolsSize += 1 symbolEntry = nlist_64() symbolEntry.n_strx = stringIndex symbolEntry.n_type = 1 newLinkedit.extend(symbolEntry) self.extractionCtx.hasRedactedIndirect = True pass