mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-25 05:32:14 +00:00
Merge remote-tracking branch 'origin/GP-719_ryanmkurtz_dyld-filesystem'
(Closes #682, Closes #2934)
This commit is contained in:
commit
147e6b8f13
@ -132,6 +132,10 @@ public class SegmentCommand extends LoadCommand {
|
||||
public long getFileOffset() {
|
||||
return fileoff;
|
||||
}
|
||||
|
||||
public void setFileOffset(long fileOffset) {
|
||||
fileoff = fileOffset;
|
||||
}
|
||||
|
||||
public long getFileSize() {
|
||||
return filesize;
|
||||
|
@ -0,0 +1,307 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.file.formats.ios.dyldcache;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import generic.continues.RethrowContinuesFactory;
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.format.macho.*;
|
||||
import ghidra.app.util.bin.format.macho.commands.*;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.NotFoundException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* A class for extracting DYLIB files from a {@link DyldCacheFileSystem}
|
||||
*/
|
||||
public class DyldCacheDylibExtractor {
|
||||
|
||||
/**
|
||||
* Gets an {@link InputStream} that reads a DYLIB from a {@link DyldCacheFileSystem}. The
|
||||
* DYLIB's header will be altered to account for its segment bytes being packed down.
|
||||
*
|
||||
* @param dylibOffset The offset of the DYLIB in the given provider
|
||||
* @param provider The DYLD
|
||||
* @param monitor A cancellable {@link TaskMonitor}
|
||||
* @return An {@link InputStream} that reads the specified DYLIB from the given DYLD
|
||||
* {@link ByteProvider}
|
||||
* @throws IOException If there was an IO-related issue with extracting the DYLIB
|
||||
* @throws MachException If there was an error parsing the DYLIB headers
|
||||
*/
|
||||
public static InputStream extractDylib(long dylibOffset, ByteProvider provider,
|
||||
TaskMonitor monitor) throws IOException, MachException {
|
||||
|
||||
// Make sure Mach-O header is valid
|
||||
MachHeader header = MachHeader.createMachHeader(RethrowContinuesFactory.INSTANCE, provider,
|
||||
dylibOffset, false);
|
||||
header.parse();
|
||||
|
||||
// Pack the DYLIB
|
||||
PackedDylib packedDylib = new PackedDylib(header, dylibOffset, provider);
|
||||
|
||||
// Fixup indices, offsets, etc in the packed DYLIB's header
|
||||
for (LoadCommand cmd : header.getLoadCommands()) {
|
||||
if (monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
switch (cmd.getCommandType()) {
|
||||
case LoadCommandTypes.LC_SEGMENT:
|
||||
fixupSegment((SegmentCommand) cmd, packedDylib, false, monitor);
|
||||
break;
|
||||
case LoadCommandTypes.LC_SEGMENT_64:
|
||||
fixupSegment((SegmentCommand) cmd, packedDylib, true, monitor);
|
||||
break;
|
||||
case LoadCommandTypes.LC_SYMTAB:
|
||||
fixupSymbolTable((SymbolTableCommand) cmd, packedDylib);
|
||||
break;
|
||||
case LoadCommandTypes.LC_DYSYMTAB:
|
||||
fixupDynamicSymbolTable((DynamicSymbolTableCommand) cmd, packedDylib);
|
||||
break;
|
||||
case LoadCommandTypes.LC_DYLD_INFO:
|
||||
case LoadCommandTypes.LC_DYLD_INFO_ONLY:
|
||||
fixupDyldInfo((DyldInfoCommand) cmd, packedDylib);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return packedDylib.getInputStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes-up the old DYLD file offsets in the given segment so they are correct for the newly
|
||||
* packed DYLIB
|
||||
*
|
||||
* @param cmd The segment to fix-up
|
||||
* @param packedDylib The packed DYLIB
|
||||
* @param is64bit True if the segment is 64-bit; false if 32-bit
|
||||
* @param monitor A cancellable {@link TaskMonitor}
|
||||
* @throws IOException If there was an IO-related issue performing the fix-up
|
||||
*/
|
||||
private static void fixupSegment(SegmentCommand cmd, PackedDylib packedDylib, boolean is64bit,
|
||||
TaskMonitor monitor) throws IOException {
|
||||
if (cmd.getFileOffset() > 0 && cmd.getFileSize() > 0) {
|
||||
packedDylib.fixup(cmd.getStartIndex() + (is64bit ? 0x28 : 0x20), is64bit ? 8 : 4);
|
||||
}
|
||||
long sectionStartIndex = cmd.getStartIndex() + (is64bit ? 0x48 : 0x38);
|
||||
for (Section section : cmd.getSections()) {
|
||||
if (monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
if (section.getOffset() > 0 && section.getSize() > 0) {
|
||||
packedDylib.fixup(sectionStartIndex + (is64bit ? 0x30 : 0x28), 4);
|
||||
}
|
||||
if (section.getRelocationOffset() > 0) {
|
||||
packedDylib.fixup(sectionStartIndex + (is64bit ? 0x38 : 0x30), 4);
|
||||
}
|
||||
sectionStartIndex += is64bit ? 0x50 : 0x44;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes-up the old DYLD file offsets in the given symbol table so they are correct for the
|
||||
* newly packed DYLIB
|
||||
*
|
||||
* @param cmd The symbol table to fix-up
|
||||
* @param packedDylib The packed DYLIB
|
||||
* @throws IOException If there was an IO-related issue performing the fix-up
|
||||
*/
|
||||
private static void fixupSymbolTable(SymbolTableCommand cmd, PackedDylib packedDylib)
|
||||
throws IOException {
|
||||
if (cmd.getSymbolOffset() > 0) {
|
||||
packedDylib.fixup(cmd.getStartIndex() + 0x8, 4);
|
||||
}
|
||||
if (cmd.getStringTableOffset() > 0) {
|
||||
packedDylib.fixup(cmd.getStartIndex() + 0x10, 4);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes-up the old DYLD file offsets in the given dynamic symbol table so they are correct for
|
||||
* the newly packed DYLIB
|
||||
*
|
||||
* @param cmd The dynamic symbol table to fix-up
|
||||
* @param packedDylib The packed DYLIB
|
||||
* @throws IOException If there was an IO-related issue performing the fix-up
|
||||
*/
|
||||
private static void fixupDynamicSymbolTable(DynamicSymbolTableCommand cmd,
|
||||
PackedDylib packedDylib) throws IOException {
|
||||
if (cmd.getTableOfContentsOffset() > 0) {
|
||||
packedDylib.fixup(cmd.getStartIndex() + 0x20, 4);
|
||||
}
|
||||
if (cmd.getModuleTableOffset() > 0) {
|
||||
packedDylib.fixup(cmd.getStartIndex() + 0x28, 4);
|
||||
}
|
||||
if (cmd.getReferencedSymbolTableOffset() > 0) {
|
||||
packedDylib.fixup(cmd.getStartIndex() + 0x30, 4);
|
||||
}
|
||||
if (cmd.getIndirectSymbolTableOffset() > 0) {
|
||||
packedDylib.fixup(cmd.getStartIndex() + 0x38, 4);
|
||||
}
|
||||
if (cmd.getExternalRelocationOffset() > 0) {
|
||||
packedDylib.fixup(cmd.getStartIndex() + 0x40, 4);
|
||||
}
|
||||
if (cmd.getLocalRelocationOffset() > 0) {
|
||||
packedDylib.fixup(cmd.getStartIndex() + 0x48, 4);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes-up the old DYLD file offsets in the given DYLD Info command so they are correct for the
|
||||
* newly packed DYLIB
|
||||
*
|
||||
* @param cmd The DYLD Info command to fix-up
|
||||
* @param packedDylib The packed DYLIB
|
||||
* @throws IOException If there was an IO-related issue performing the fix-up
|
||||
*/
|
||||
private static void fixupDyldInfo(DyldInfoCommand cmd, PackedDylib packedDylib)
|
||||
throws IOException {
|
||||
if (cmd.getRebaseOffset() > 0) {
|
||||
packedDylib.fixup(cmd.getStartIndex() + 0x8, 4);
|
||||
}
|
||||
if (cmd.getBindOffset() > 0) {
|
||||
packedDylib.fixup(cmd.getStartIndex() + 0x10, 4);
|
||||
}
|
||||
if (cmd.getWeakBindOffset() > 0) {
|
||||
packedDylib.fixup(cmd.getStartIndex() + 0x18, 4);
|
||||
}
|
||||
if (cmd.getLazyBindOffset() > 0) {
|
||||
packedDylib.fixup(cmd.getStartIndex() + 0x20, 4);
|
||||
}
|
||||
if (cmd.getExportOffset() > 0) {
|
||||
packedDylib.fixup(cmd.getStartIndex() + 0x28, 4);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A packed DYLIB that was once living inside of a DYLD. The DYLIB is said to be packed
|
||||
* because its segment file bytes, which were not adjacent in its containing DYLD, are now
|
||||
* adjacent in its new array.
|
||||
*/
|
||||
private static class PackedDylib {
|
||||
|
||||
private BinaryReader reader;
|
||||
private Map<SegmentCommand, Integer> packedStarts;
|
||||
private byte[] packed;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PackedDylib} object
|
||||
*
|
||||
* @param header The DYLD's DYLIB's Mach-O header
|
||||
* @param dylibOffset The offset of the DYLIB in the given provider
|
||||
* @param provider The DYLD's bytes
|
||||
* @throws IOException If there was an IO-related error
|
||||
*/
|
||||
public PackedDylib(MachHeader header, long dylibOffset, ByteProvider provider)
|
||||
throws IOException {
|
||||
reader = new BinaryReader(provider, true);
|
||||
packedStarts = new HashMap<>();
|
||||
int size = 0;
|
||||
for (SegmentCommand segment : header.getAllSegments()) {
|
||||
packedStarts.put(segment, size);
|
||||
size += segment.getFileSize();
|
||||
|
||||
// Some older DYLDs use relative file offsets for only their __TEXT segment.
|
||||
// Adjust these segments to be consistent with all the other segments.
|
||||
if (segment.getFileOffset() == 0) {
|
||||
segment.setFileOffset(dylibOffset);
|
||||
}
|
||||
}
|
||||
packed = new byte[size];
|
||||
for (SegmentCommand segment : header.getAllSegments()) {
|
||||
long segmentSize = segment.getFileSize();
|
||||
if (segment.getFileOffset() + segmentSize > provider.length()) {
|
||||
segmentSize = provider.length() - segment.getFileOffset();
|
||||
Msg.warn(this, segment.getSegmentName() +
|
||||
" segment extends beyond end of file. Truncating...");
|
||||
}
|
||||
byte[] bytes = provider.readBytes(segment.getFileOffset(), segmentSize);
|
||||
System.arraycopy(bytes, 0, packed, packedStarts.get(segment), bytes.length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an {@link InputStream} that reads the packed DYLIB
|
||||
*
|
||||
* @return An {@link InputStream} that reads the packed DYLIB
|
||||
*/
|
||||
public InputStream getInputStream() {
|
||||
return new ByteArrayInputStream(packed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes up the bytes at the given DYLD file offset to map to the correct offset in the
|
||||
* packed DYLIB
|
||||
*
|
||||
* @param fileOffset The DYLD file offset to fix-up
|
||||
* @param size The number of bytes to fix-up (must be 4 or 8)
|
||||
* @throws IOException If there was an IO-related error
|
||||
* @throws IllegalArgumentException if size is an unsupported value
|
||||
*/
|
||||
public void fixup(long fileOffset, int size) throws IOException {
|
||||
if (size != 4 && size != 8) {
|
||||
throw new IllegalArgumentException("Size must be 4 or 8 (got " + size + ")");
|
||||
}
|
||||
long orig = reader.readUnsignedValue(fileOffset, size);
|
||||
try {
|
||||
byte[] newBytes = toBytes(getPackedOffset(orig), size);
|
||||
System.arraycopy(newBytes, 0, packed, (int) getPackedOffset(fileOffset),
|
||||
newBytes.length);
|
||||
}
|
||||
catch (NotFoundException e) {
|
||||
Msg.warn(this, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given DYLD file offset to an offset into the packed DYLIB
|
||||
*
|
||||
* @param fileOffset The DYLD file offset to convert
|
||||
* @return An offset into the packed DYLIB
|
||||
* @throws NotFoundException If there was no corresponding DYLIB offset
|
||||
*/
|
||||
private long getPackedOffset(long fileOffset) throws NotFoundException {
|
||||
for (SegmentCommand segment : packedStarts.keySet()) {
|
||||
if (fileOffset >= segment.getFileOffset() &&
|
||||
fileOffset < segment.getFileOffset() + segment.getFileSize()) {
|
||||
return fileOffset - segment.getFileOffset() + packedStarts.get(segment);
|
||||
}
|
||||
}
|
||||
throw new NotFoundException(
|
||||
"Failed to convert DYLD file offset to packed DYLIB offset: " +
|
||||
Long.toHexString(fileOffset));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given value to a byte array
|
||||
*
|
||||
* @param value The value to convert to a byte array
|
||||
* @param size The number of bytes to convert (must be 4 or 8)
|
||||
* @return The value as a byte array of the given size
|
||||
* @throws IllegalArgumentException if size is an unsupported value
|
||||
*/
|
||||
private byte[] toBytes(long value, int size) throws IllegalArgumentException {
|
||||
if (size != 4 && size != 8) {
|
||||
throw new IllegalArgumentException("Size must be 4 or 8 (got " + size + ")");
|
||||
}
|
||||
DataConverter converter = LittleEndianDataConverter.INSTANCE;
|
||||
return size == 8 ? converter.getBytes(value) : converter.getBytes((int) value);
|
||||
}
|
||||
}
|
||||
}
|
@ -57,19 +57,8 @@ public class DyldCacheFileSystem extends GFileSystemBase {
|
||||
}
|
||||
long machHeaderStartIndexInProvider = data.getAddress() - header.getBaseAddress();
|
||||
try {
|
||||
/*
|
||||
* //check to make sure mach-o header is valid MachHeader header =
|
||||
* MachHeader.createMachHeader( RethrowContinuesFactory.INSTANCE,
|
||||
* provider, machHeaderStartIndexInProvider, false );
|
||||
* header.parse();
|
||||
*
|
||||
* return new ByteProviderInputStream( provider,
|
||||
* machHeaderStartIndexInProvider, provider.length() -
|
||||
* machHeaderStartIndexInProvider );
|
||||
*/
|
||||
|
||||
FixupMacho32bitArmOffsets fixer = new FixupMacho32bitArmOffsets();
|
||||
return fixer.fix(file, machHeaderStartIndexInProvider, provider, monitor);
|
||||
return DyldCacheDylibExtractor.extractDylib(machHeaderStartIndexInProvider, provider,
|
||||
monitor);
|
||||
}
|
||||
catch (MachException e) {
|
||||
throw new IOException("Invalid Mach-O header detected at 0x" +
|
||||
@ -164,11 +153,8 @@ public class DyldCacheFileSystem extends GFileSystemBase {
|
||||
|
||||
monitor.incrementProgress(1);
|
||||
|
||||
GFileImpl file = GFileImpl.fromPathString(this, root, data.getPath(), null, false,
|
||||
0/*TODO compute length?*/ );
|
||||
GFileImpl file = GFileImpl.fromPathString(this, root, data.getPath(), null, false, -1);
|
||||
storeFile(file, data);
|
||||
|
||||
file.setLength(provider.length() - (data.getAddress() - header.getBaseAddress()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,177 +0,0 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.file.formats.ios.dyldcache;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import generic.continues.RethrowContinuesFactory;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.format.macho.*;
|
||||
import ghidra.app.util.bin.format.macho.commands.*;
|
||||
import ghidra.formats.gfilesystem.GFile;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class FixupMacho32bitArmOffsets {
|
||||
private DataConverter converter = LittleEndianDataConverter.INSTANCE;
|
||||
|
||||
public InputStream fix(GFile file, long offsetAdjustment, ByteProvider provider,
|
||||
TaskMonitor monitor) throws IOException, MachException {
|
||||
Map<Long, byte []> changeMap = new HashMap<Long, byte []>();
|
||||
|
||||
//check to make sure mach-o header is valid
|
||||
MachHeader header = MachHeader.createMachHeader( RethrowContinuesFactory.INSTANCE, provider, offsetAdjustment, false );
|
||||
header.parse();
|
||||
|
||||
//fix up index, offsets, etc in the header
|
||||
List<LoadCommand> commands = header.getLoadCommands();
|
||||
for ( LoadCommand loadCommand : commands ) {
|
||||
if ( monitor.isCancelled() ) {
|
||||
break;
|
||||
}
|
||||
switch ( loadCommand.getCommandType() ) {
|
||||
case LoadCommandTypes.LC_SEGMENT: {
|
||||
SegmentCommand segmentCommand = (SegmentCommand) loadCommand;
|
||||
if ( segmentCommand.getFileOffset() > 0 ) {
|
||||
long newOffset = segmentCommand.getFileOffset() - offsetAdjustment;
|
||||
changeMap.put( segmentCommand.getStartIndex() + 0x20 - offsetAdjustment, converter.getBytes( (int)newOffset ) );
|
||||
}
|
||||
if ( segmentCommand.getNumberOfSections() > 0 ) {
|
||||
long sectionStartIndex = segmentCommand.getStartIndex() + 0x38 - offsetAdjustment;
|
||||
for ( Section section : segmentCommand.getSections() ) {
|
||||
if ( monitor.isCancelled() ) {
|
||||
break;
|
||||
}
|
||||
if ( section.getOffset() > 0 && section.getOffset() > offsetAdjustment ) {
|
||||
long newOffset = Conv.intToLong( section.getOffset() ) - offsetAdjustment;
|
||||
changeMap.put( sectionStartIndex + 0x28, converter.getBytes( (int)newOffset ) );
|
||||
}
|
||||
if ( section.getRelocationOffset() > 0 && section.getRelocationOffset() > offsetAdjustment ) {
|
||||
long newOffset = Conv.intToLong( section.getRelocationOffset() ) - offsetAdjustment;
|
||||
changeMap.put( sectionStartIndex + 0x30, converter.getBytes( (int)newOffset ) );
|
||||
}
|
||||
try {
|
||||
sectionStartIndex += section.toDataType().getLength();
|
||||
}
|
||||
catch ( DuplicateNameException e ) {
|
||||
throw new IOException( e );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LoadCommandTypes.LC_SYMTAB: {
|
||||
SymbolTableCommand symbolTableCommand = (SymbolTableCommand) loadCommand;
|
||||
if ( symbolTableCommand.getSymbolOffset() > 0 ) {
|
||||
long newOffset = Conv.intToLong( symbolTableCommand.getSymbolOffset() ) - offsetAdjustment;
|
||||
changeMap.put( symbolTableCommand.getStartIndex() + 0x8 - offsetAdjustment, converter.getBytes( (int)newOffset ) );
|
||||
}
|
||||
if ( symbolTableCommand.getStringTableOffset() > 0 ) {
|
||||
long newOffset = Conv.intToLong( symbolTableCommand.getStringTableOffset() ) - offsetAdjustment;
|
||||
changeMap.put( symbolTableCommand.getStartIndex() + 0x10 - offsetAdjustment, converter.getBytes( (int)newOffset ) );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LoadCommandTypes.LC_DYSYMTAB: {
|
||||
DynamicSymbolTableCommand dynamicSymbolTableCommand = (DynamicSymbolTableCommand) loadCommand;
|
||||
if ( dynamicSymbolTableCommand.getTableOfContentsOffset() > 0 ) {
|
||||
long newOffset = Conv.intToLong( dynamicSymbolTableCommand.getTableOfContentsOffset() ) - offsetAdjustment;
|
||||
changeMap.put( dynamicSymbolTableCommand.getStartIndex() + 0x20 - offsetAdjustment, converter.getBytes( (int)newOffset ) );
|
||||
}
|
||||
if ( dynamicSymbolTableCommand.getModuleTableOffset() > 0 ) {
|
||||
long newOffset = Conv.intToLong( dynamicSymbolTableCommand.getModuleTableOffset() ) - offsetAdjustment;
|
||||
changeMap.put( dynamicSymbolTableCommand.getStartIndex() + 0x28 - offsetAdjustment, converter.getBytes( (int)newOffset ) );
|
||||
}
|
||||
if ( dynamicSymbolTableCommand.getReferencedSymbolTableOffset() > 0 ) {
|
||||
long newOffset = Conv.intToLong( dynamicSymbolTableCommand.getReferencedSymbolTableOffset() ) - offsetAdjustment;
|
||||
changeMap.put( dynamicSymbolTableCommand.getStartIndex() + 0x30 - offsetAdjustment, converter.getBytes( (int)newOffset ) );
|
||||
}
|
||||
if ( dynamicSymbolTableCommand.getIndirectSymbolTableOffset() > 0 ) {
|
||||
long newOffset = Conv.intToLong( dynamicSymbolTableCommand.getIndirectSymbolTableOffset() ) - offsetAdjustment;
|
||||
changeMap.put( dynamicSymbolTableCommand.getStartIndex() + 0x38 - offsetAdjustment, converter.getBytes( (int)newOffset ) );
|
||||
}
|
||||
if ( dynamicSymbolTableCommand.getExternalRelocationOffset() > 0 ) {
|
||||
long newOffset = Conv.intToLong( dynamicSymbolTableCommand.getExternalRelocationOffset() ) - offsetAdjustment;
|
||||
changeMap.put( dynamicSymbolTableCommand.getStartIndex() + 0x40 - offsetAdjustment, converter.getBytes( (int)newOffset ) );
|
||||
}
|
||||
if ( dynamicSymbolTableCommand.getLocalRelocationOffset() > 0 ) {
|
||||
long newOffset = Conv.intToLong( dynamicSymbolTableCommand.getLocalRelocationOffset() ) - offsetAdjustment;
|
||||
changeMap.put( dynamicSymbolTableCommand.getStartIndex() + 0x48 - offsetAdjustment, converter.getBytes( (int)newOffset ) );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LoadCommandTypes.LC_DYLD_INFO:
|
||||
case LoadCommandTypes.LC_DYLD_INFO_ONLY: {
|
||||
DyldInfoCommand dyldInfoCommand = (DyldInfoCommand) loadCommand;
|
||||
if ( dyldInfoCommand.getRebaseOffset() > 0 ) {
|
||||
long newOffset = Conv.intToLong( dyldInfoCommand.getRebaseOffset() ) - offsetAdjustment;
|
||||
changeMap.put( dyldInfoCommand.getStartIndex() + 0x8 - offsetAdjustment, converter.getBytes( (int)newOffset ) );
|
||||
}
|
||||
if ( dyldInfoCommand.getBindOffset() > 0 ) {
|
||||
long newOffset = Conv.intToLong( dyldInfoCommand.getBindOffset() ) - offsetAdjustment;
|
||||
changeMap.put( dyldInfoCommand.getStartIndex() + 0x10 - offsetAdjustment, converter.getBytes( (int)newOffset ) );
|
||||
}
|
||||
if ( dyldInfoCommand.getWeakBindOffset() > 0 ) {
|
||||
long newOffset = Conv.intToLong( dyldInfoCommand.getWeakBindOffset() ) - offsetAdjustment;
|
||||
changeMap.put( dyldInfoCommand.getStartIndex() + 0x18 - offsetAdjustment, converter.getBytes( (int)newOffset ) );
|
||||
}
|
||||
if ( dyldInfoCommand.getLazyBindOffset() > 0 ) {
|
||||
long newOffset = Conv.intToLong( dyldInfoCommand.getLazyBindOffset() ) - offsetAdjustment;
|
||||
changeMap.put( dyldInfoCommand.getStartIndex() + 0x20 - offsetAdjustment, converter.getBytes( (int)newOffset ) );
|
||||
}
|
||||
if ( dyldInfoCommand.getExportOffset() > 0 ) {
|
||||
long newOffset = Conv.intToLong(dyldInfoCommand.getExportOffset() ) - offsetAdjustment;
|
||||
changeMap.put( dyldInfoCommand.getStartIndex() + 0x28 - offsetAdjustment, converter.getBytes( (int)newOffset ) );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<Long> indexList = new ArrayList<Long>( changeMap.keySet() );
|
||||
Collections.sort( indexList );
|
||||
|
||||
ByteArrayOutputStream tempOut = new ByteArrayOutputStream();
|
||||
try {
|
||||
long tempIndex = offsetAdjustment;
|
||||
while ( !monitor.isCancelled() ) {
|
||||
final int length = 0x10000;
|
||||
byte [] buffer = provider.readBytes( tempIndex, length );
|
||||
|
||||
for ( Long index : indexList ) {
|
||||
if ( index + offsetAdjustment >= tempIndex && index + offsetAdjustment < tempIndex + length ) {
|
||||
byte [] changedBytes = changeMap.get( index );
|
||||
System.arraycopy( changedBytes, 0, buffer, index.intValue(), changedBytes.length );
|
||||
}
|
||||
}
|
||||
|
||||
tempOut.write( buffer );
|
||||
tempIndex += buffer.length;
|
||||
monitor.setMessage( "0x" + Long.toHexString( tempIndex ) );
|
||||
if ( tempIndex > provider.length() ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
tempOut.close();
|
||||
}
|
||||
|
||||
return new ByteArrayInputStream(tempOut.toByteArray());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user