GP-719: Improvements to the DYLD DYLIB extractor

This commit is contained in:
Ryan Kurtz
2021-05-17 11:03:57 -04:00
parent 519dbd1ac1
commit 6737d991e2
3 changed files with 26 additions and 14 deletions

View File

@@ -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;

View File

@@ -24,7 +24,6 @@ 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.formats.gfilesystem.GFile;
import ghidra.util.*;
import ghidra.util.exception.NotFoundException;
import ghidra.util.task.TaskMonitor;
@@ -38,7 +37,6 @@ 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 file The {@link GFile DYLIB}
* @param dylibOffset The offset of the DYLIB in the given provider
* @param provider The DYLD
* @param monitor A cancellable {@link TaskMonitor}
@@ -47,7 +45,7 @@ public class DyldCacheDylibExtractor {
* @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(GFile file, long dylibOffset, ByteProvider provider,
public static InputStream extractDylib(long dylibOffset, ByteProvider provider,
TaskMonitor monitor) throws IOException, MachException {
// Make sure Mach-O header is valid
@@ -56,7 +54,7 @@ public class DyldCacheDylibExtractor {
header.parse();
// Pack the DYLIB
PackedDylib packedDylib = new PackedDylib(header, provider);
PackedDylib packedDylib = new PackedDylib(header, dylibOffset, provider);
// Fixup indices, offsets, etc in the packed DYLIB's header
for (LoadCommand cmd : header.getLoadCommands()) {
@@ -206,20 +204,34 @@ public class DyldCacheDylibExtractor {
* 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, ByteProvider provider) throws IOException {
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()) {
byte[] bytes = provider.readBytes(segment.getFileOffset(), segment.getFileSize());
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);
}
}
@@ -246,8 +258,7 @@ public class DyldCacheDylibExtractor {
if (size != 4 && size != 8) {
throw new IllegalArgumentException("Size must be 4 or 8 (got " + size + ")");
}
long orig = size == 8 ? reader.readLong(fileOffset)
: Conv.intToLong(reader.readInt(fileOffset));
long orig = reader.readUnsignedValue(fileOffset, size);
try {
byte[] newBytes = toBytes(getPackedOffset(orig), size);
System.arraycopy(newBytes, 0, packed, (int) getPackedOffset(fileOffset),

View File

@@ -57,8 +57,8 @@ public class DyldCacheFileSystem extends GFileSystemBase {
}
long machHeaderStartIndexInProvider = data.getAddress() - header.getBaseAddress();
try {
return DyldCacheDylibExtractor.extractDylib(file, machHeaderStartIndexInProvider,
provider, monitor);
return DyldCacheDylibExtractor.extractDylib(machHeaderStartIndexInProvider, provider,
monitor);
}
catch (MachException e) {
throw new IOException("Invalid Mach-O header detected at 0x" +
@@ -153,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()));
}
}