Merge branch 'GP-2176_ryanmkurtz_dyld-iOS16' (Closes #4346,

Closes #4406)
This commit is contained in:
Ryan Kurtz 2022-07-05 04:39:07 -04:00
commit 61b135acd9
24 changed files with 489 additions and 145 deletions

View File

@ -36,7 +36,7 @@ import ghidra.util.task.TaskMonitor;
/**
* Represents a dyld_cache_accelerator_info structure.
*
* @see <a href="https://opensource.apple.com/source/dyld/dyld-852.2/dyld3/shared-cache/dyld_cache_format.h.auto.html">dyld3/shared-cache/dyld_cache_format.h</a>
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
*/
@SuppressWarnings("unused")
public class DyldCacheAccelerateInfo implements StructConverter {

View File

@ -26,7 +26,7 @@ import ghidra.util.exception.DuplicateNameException;
/**
* Represents a dyld_cache_accelerator_dof structure.
*
* @see <a href="https://opensource.apple.com/source/dyld/dyld-852.2/dyld3/shared-cache/dyld_cache_format.h.auto.html">dyld3/shared-cache/dyld_cache_format.h</a>
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
*/
@SuppressWarnings("unused")
public class DyldCacheAcceleratorDof implements StructConverter {

View File

@ -26,7 +26,7 @@ import ghidra.util.exception.DuplicateNameException;
/**
* Represents a dyld_cache_accelerator_initializer structure.
*
* @see <a href="https://opensource.apple.com/source/dyld/dyld-852.2/dyld3/shared-cache/dyld_cache_format.h.auto.html">dyld3/shared-cache/dyld_cache_format.h</a>
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
*/
@SuppressWarnings("unused")
public class DyldCacheAcceleratorInitializer implements StructConverter {

View File

@ -27,6 +27,7 @@ import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.util.NumericUtilities;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.task.TaskMonitor;
@ -34,7 +35,7 @@ import ghidra.util.task.TaskMonitor;
/**
* Represents a dyld_cache_header structure.
*
* @see <a href="https://opensource.apple.com/source/dyld/dyld-852.2/dyld3/shared-cache/dyld_cache_format.h.auto.html">dyld3/shared-cache/dyld_cache_format.h</a>
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
*/
@SuppressWarnings("unused")
public class DyldCacheHeader implements StructConverter {
@ -42,8 +43,8 @@ public class DyldCacheHeader implements StructConverter {
private byte[] magic;
private int mappingOffset;
private int mappingCount;
private int imagesOffset;
private int imagesCount;
private int imagesOffsetOld;
private int imagesCountOld;
private long dyldBaseAddress;
private long codeSignatureOffset;
private long codeSignatureSize;
@ -61,20 +62,20 @@ public class DyldCacheHeader implements StructConverter {
private long imagesTextCount;
private long patchInfoAddr;
private long patchInfoSize;
private long otherImageGroupAddrUnused; // unused
private long otherImageGroupSizeUnused; // unused
private long otherImageGroupAddrUnused;
private long otherImageGroupSizeUnused;
private long progClosuresAddr;
private long progClosuresSize;
private long progClosuresTrieAddr;
private long progClosuresTrieSize;
private int platform;
private int dyld_info;
private int formatVersion; // Extracted from dyld_info
private boolean dylibsExpectedOnDisk; // Extracted from dyld_info
private boolean simulator; // Extracted from dyld_info
private boolean locallyBuiltCache; // Extracted from dyld_info
private boolean builtFromChainedFixups; // Extracted from dyld_info
private int padding; // Extracted from dyld_info
private int formatVersion;
private boolean dylibsExpectedOnDisk;
private boolean simulator;
private boolean locallyBuiltCache;
private boolean builtFromChainedFixups;
private int padding;
private long sharedRegionStart;
private long sharedRegionSize;
private long maxSlide;
@ -88,6 +89,26 @@ public class DyldCacheHeader implements StructConverter {
private long otherTrieSize;
private int mappingWithSlideOffset;
private int mappingWithSlideCount;
private long dylibsPBLStateArrayAddrUnused;
private long dylibsPBLSetAddr;
private long programsPBLSetPoolAddr;
private long programsPBLSetPoolSize;
private long programTrieAddr;
private int programTrieSize;
private int osVersion;
private int altPlatform;
private int altOsVersion;
private long swiftOptsOffset;
private long swiftOptsSize;
private int subCacheArrayOffset;
private int subCacheArrayCount;
private byte[] symbolFileUUID;
private long rosettaReadOnlyAddr;
private long rosettaReadOnlySize;
private long rosettaReadWriteAddr;
private long rosettaReadWriteSize;
private int imagesOffset;
private int imagesCount;
private int headerType;
private int headerSize;
@ -100,6 +121,7 @@ public class DyldCacheHeader implements StructConverter {
private List<Long> branchPoolList;
private DyldCacheAccelerateInfo accelerateInfo;
private List<DyldCacheImageTextInfo> imageTextInfoList;
private List<DyldSubcacheEntry> subcacheEntryList;
private DyldArchitecture architecture;
private List<DyldCacheMappingAndSlideInfo> cacheMappingAndSlideInfoList;
private MemoryBlock fileBlock;
@ -119,8 +141,8 @@ public class DyldCacheHeader implements StructConverter {
magic = reader.readNextByteArray(16);
mappingOffset = reader.readNextInt();
mappingCount = reader.readNextInt();
imagesOffset = reader.readNextInt();
imagesCount = reader.readNextInt();
imagesOffsetOld = reader.readNextInt();
imagesCountOld = reader.readNextInt();
dyldBaseAddress = reader.readNextLong();
// HEADER 2: https://opensource.apple.com/source/dyld/dyld-195.5/launch-cache/dyld_cache_format.h.auto.html
@ -169,79 +191,144 @@ public class DyldCacheHeader implements StructConverter {
headerType = 7;
}
if (reader.getPointerIndex() < mappingOffset) {
patchInfoAddr = reader.readNextLong(); // (unslid) address of dyld_cache_patch_info
patchInfoAddr = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
patchInfoSize = reader.readNextLong(); // Size of all of the patch information pointed to via the dyld_cache_patch_info
patchInfoSize = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
otherImageGroupAddrUnused = reader.readNextLong(); // unused
otherImageGroupAddrUnused = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
otherImageGroupSizeUnused = reader.readNextLong(); // unused
otherImageGroupSizeUnused = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
progClosuresAddr = reader.readNextLong(); // (unslid) address of list of program launch closures
progClosuresAddr = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
progClosuresSize = reader.readNextLong(); // size of list of program launch closures
progClosuresSize = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
progClosuresTrieAddr = reader.readNextLong(); // (unslid) address of trie of indexes into program launch closures
progClosuresTrieAddr = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
progClosuresTrieSize = reader.readNextLong(); // size of trie of indexes into program launch closures
progClosuresTrieSize = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
platform = reader.readNextInt(); // platform number (macOS=1, etc)
platform = reader.readNextInt();
}
if (reader.getPointerIndex() < mappingOffset) {
dyld_info = reader.readNextInt();
formatVersion = dyld_info & 0xff; // dyld3::closure::kFormatVersion
dylibsExpectedOnDisk = (dyld_info >>> 8 & 1) == 1; // dyld should expect the dylib exists on disk and to compare inode/mtime to see if cache is valid
simulator = (dyld_info >>> 9 & 1) == 1; // for simulator of specified platform
locallyBuiltCache = (dyld_info >> 10 & 1) == 1; // 0 for B&I built cache, 1 for locally built cache
builtFromChainedFixups = (dyld_info >> 11 & 1) == 1; // some dylib in cache was built using chained fixups, so patch tables must be used for overrides
padding = (dyld_info >> 12) & 0xfffff; // TBD
formatVersion = dyld_info & 0xff;
dylibsExpectedOnDisk = (dyld_info >>> 8 & 1) == 1;
simulator = (dyld_info >>> 9 & 1) == 1;
locallyBuiltCache = (dyld_info >> 10 & 1) == 1;
builtFromChainedFixups = (dyld_info >> 11 & 1) == 1;
padding = (dyld_info >> 12) & 0xfffff;
}
if (reader.getPointerIndex() < mappingOffset) {
sharedRegionStart = reader.readNextLong(); // base load address of cache if not slid
sharedRegionStart = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
sharedRegionSize = reader.readNextLong(); // overall size of region cache can be mapped into
sharedRegionSize = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
maxSlide = reader.readNextLong(); // runtime slide of cache can be between zero and this value
maxSlide = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
dylibsImageArrayAddr = reader.readNextLong(); // (unslid) address of ImageArray for dylibs in this cache
dylibsImageArrayAddr = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
dylibsImageArraySize = reader.readNextLong(); // size of ImageArray for dylibs in this cache
dylibsImageArraySize = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
dylibsTrieAddr = reader.readNextLong(); // (unslid) address of trie of indexes of all cached dylibs
dylibsTrieAddr = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
dylibsTrieSize = reader.readNextLong(); // size of trie of cached dylib paths
dylibsTrieSize = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
otherImageArrayAddr = reader.readNextLong(); // (unslid) address of ImageArray for dylibs and bundles with dlopen closures
otherImageArrayAddr = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
otherImageArraySize = reader.readNextLong(); // size of ImageArray for dylibs and bundles with dlopen closures
otherImageArraySize = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
otherTrieAddr = reader.readNextLong(); // (unslid) address of trie of indexes of all dylibs and bundles with dlopen closures
otherTrieAddr = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
otherTrieSize = reader.readNextLong(); // size of trie of dylibs and bundles with dlopen closures
otherTrieSize = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
mappingWithSlideOffset = reader.readNextInt(); // file offset to first dyld_cache_mapping_and_slide_info
mappingWithSlideOffset = reader.readNextInt();
}
if (reader.getPointerIndex() < mappingOffset) {
mappingWithSlideCount = reader.readNextInt(); // number of dyld_cache_mapping_and_slide_info entries
mappingWithSlideCount = reader.readNextInt();
}
// HEADER 8: https://github.com/apple-oss-distributions/dyld/blob/dyld-940/cache-builder/dyld_cache_format.h
if (reader.getPointerIndex() < mappingOffset) {
headerType = 8;
}
if (reader.getPointerIndex() < mappingOffset) {
dylibsPBLStateArrayAddrUnused = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
dylibsPBLSetAddr = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
programsPBLSetPoolAddr = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
programsPBLSetPoolSize = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
programTrieAddr = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
programTrieSize = reader.readNextInt();
}
if (reader.getPointerIndex() < mappingOffset) {
osVersion = reader.readNextInt();
}
if (reader.getPointerIndex() < mappingOffset) {
altPlatform = reader.readNextInt();
}
if (reader.getPointerIndex() < mappingOffset) {
altOsVersion = reader.readNextInt();
}
if (reader.getPointerIndex() < mappingOffset) {
swiftOptsOffset = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
swiftOptsSize = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
subCacheArrayOffset = reader.readNextInt();
}
if (reader.getPointerIndex() < mappingOffset) {
subCacheArrayCount = reader.readNextInt();
}
if (reader.getPointerIndex() < mappingOffset) {
symbolFileUUID = reader.readNextByteArray(16);
}
if (reader.getPointerIndex() < mappingOffset) {
rosettaReadOnlyAddr = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
rosettaReadOnlySize = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
rosettaReadWriteAddr = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
rosettaReadWriteSize = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
imagesOffset = reader.readNextInt();
}
if (reader.getPointerIndex() < mappingOffset) {
imagesCount = reader.readNextInt();
}
headerSize = (int) (reader.getPointerIndex() - startIndex);
@ -252,9 +339,10 @@ public class DyldCacheHeader implements StructConverter {
mappingInfoList = new ArrayList<>(mappingCount);
cacheMappingAndSlideInfoList = new ArrayList<>(mappingWithSlideCount);
slideInfoList = new ArrayList<>();
imageInfoList = new ArrayList<>(imagesCount);
imageInfoList = new ArrayList<>(imagesCountOld);
branchPoolList = new ArrayList<>(branchPoolsCount);
imageTextInfoList = new ArrayList<>();
subcacheEntryList = new ArrayList<>();
}
/**
@ -280,6 +368,9 @@ public class DyldCacheHeader implements StructConverter {
parseBranchPools(log, monitor);
parseImageTextInfo(log, monitor);
}
if (headerType >= 8) {
parseSubcaches(log, monitor);
}
parseCacheMappingSlideInfo(log, monitor);
if (hasSlideInfo()) {
parseSlideInfos(log, monitor);
@ -376,6 +467,9 @@ public class DyldCacheHeader implements StructConverter {
markupAcceleratorInfo(program, space, monitor, log);
markupImageTextInfo(program, space, monitor, log);
}
if (headerType >= 8) {
markupSubcacheEntries(program, space, monitor, log);
}
if (mappingWithSlideOffset >= 0) {
markupCacheMappingSlideInfo(program, space, log, monitor);
}
@ -400,6 +494,24 @@ public class DyldCacheHeader implements StructConverter {
return magic;
}
/**
* Gets the UUID in {@link String} form
*
* @return The UUID in {@link String} form, or null if a UUID is not defined
*/
public String getUUID() {
return NumericUtilities.convertBytesToString(uuid);
}
/**
* Gets the cache type
*
* @return The cache type
*/
public long getCacheType() {
return cacheType;
}
/**
* Gets the {@link List} of {@link DyldCacheMappingInfo}s. Requires header to have been parsed.
*
@ -415,7 +527,10 @@ public class DyldCacheHeader implements StructConverter {
* @return The file offset to first {@link DyldCacheImageInfo}
*/
public int getImagesOffset() {
return imagesOffset;
if (imagesOffset != 0) {
return imagesOffset;
}
return imagesOffsetOld;
}
/**
@ -424,41 +539,55 @@ public class DyldCacheHeader implements StructConverter {
* @return The number of {@link DyldCacheImageInfo}s
*/
public int getImagesCount() {
return imagesCount;
if (imagesOffset != 0) {
return imagesCount;
}
return imagesCountOld;
}
/**
* Generates a {@link List} of {@link DyldCacheImage}s that are mapped in by this
* {@link DyldCacheHeader}. Requires header to have been parsed.
* <p>
* NOTE: A "split" DYLD Cache header may declare an image, but that image may get loaded at an
* address defined by the memory map of a different split header. This method will only return
* the images that are mapped by "this" header's memory map.
*
* NOTE: A DYLD subcache header may declare an image, but that image may get loaded at an
* address defined by the memory map of a different subcache header. This method will only
* return the images that are mapped by "this" header's memory map.
*
* @return A {@link List} of {@link DyldCacheImage}s mapped by this {@link DyldCacheHeader}
*/
public List<DyldCacheImage> getMappedImages() {
// NOTE: A subcache will have an entry for every image, but not every image will be mapped
List<DyldCacheImage> images = new ArrayList<>();
if (imageInfoList.size() > 0) {
// The old, simple way
images.addAll(imageInfoList);
}
else {
// The new, split file way. A split file will have an entry for every image, but
// not every image will be mapped.
for (DyldCacheImageTextInfo imageTextInfo : imageTextInfoList) {
for (DyldCacheMappingInfo mappingInfo : mappingInfoList) {
if (mappingInfo.contains(imageTextInfo.getAddress())) {
images.add(imageTextInfo);
break;
}
for (DyldCacheImage imageInfo : imageInfoList) {
for (DyldCacheMappingInfo mappingInfo : mappingInfoList) {
if (mappingInfo.contains(imageInfo.getAddress())) {
images.add(imageInfo);
break;
}
}
}
return images;
}
/**
* Gets the {@link List} of {@link DyldSubcacheEntry}s. Requires header to have been parsed.
*
* @return The {@link List} of {@link DyldSubcacheEntry}s
*/
public List<DyldSubcacheEntry> getSubcacheEntries() {
return subcacheEntryList;
}
/**
* Gets the symbol file UUID in {@link String} form
*
* @return The symbol file UUID in {@link String} form, or null if a symbol file UUID is not
* defined
*/
public String getSymbolFileUUID() {
return NumericUtilities.convertBytesToString(symbolFileUUID);
}
/**
* Gets the {@link List} of {@link DyldCacheMappingAndSlideInfo}s. Requires header to have been parsed.
*
@ -515,8 +644,8 @@ public class DyldCacheHeader implements StructConverter {
addHeaderField(struct, new ArrayDataType(ASCII, 16, 1), "magic","e.g. \"dyld_v0 i386\"");
addHeaderField(struct, DWORD, "mappingOffset","file offset to first dyld_cache_mapping_info");
addHeaderField(struct, DWORD, "mappingCount", "number of dyld_cache_mapping_info entries");
addHeaderField(struct, DWORD, "imagesOffset", "file offset to first dyld_cache_image_info");
addHeaderField(struct, DWORD, "imagesCount", "number of dyld_cache_image_info entries");
addHeaderField(struct, DWORD, "imagesOffsetOld", "UNUSED: moved to imagesOffset to prevent older dsc_extarctors from crashing");
addHeaderField(struct, DWORD, "imagesCountOld", "UNUSED: moved to imagesCount to prevent older dsc_extarctors from crashing");
addHeaderField(struct, QWORD, "dyldBaseAddress","base address of dyld when cache was built");
// headerType 2
@ -574,6 +703,28 @@ public class DyldCacheHeader implements StructConverter {
addHeaderField(struct, DWORD, "mappingWithSlideOffset","file offset to first dyld_cache_mapping_and_slide_info");
addHeaderField(struct, DWORD, "mappingWithSlideCount","number of dyld_cache_mapping_and_slide_info entries");
// headerType 8
//
addHeaderField(struct, QWORD, "dylibsPBLStateArrayAddrUnused", "unused");
addHeaderField(struct, QWORD, "dylibsPBLSetAddr", "(unslid) address of PrebuiltLoaderSet of all cached dylibs");
addHeaderField(struct, QWORD, "programsPBLSetPoolAddr", "(unslid) address of pool of PrebuiltLoaderSet for each program ");
addHeaderField(struct, QWORD, "programsPBLSetPoolSize", "size of pool of PrebuiltLoaderSet for each program");
addHeaderField(struct, QWORD, "programTrieAddr", "(unslid) address of trie mapping program path to PrebuiltLoaderSet");
addHeaderField(struct, DWORD, "programTrieSize", "");
addHeaderField(struct, DWORD, "osVersion", "OS Version of dylibs in this cache for the main platform");
addHeaderField(struct, DWORD, "altPlatform", "e.g. iOSMac on macOS");
addHeaderField(struct, DWORD, "altOsVersion", "e.g. 14.0 for iOSMac");
addHeaderField(struct, QWORD, "swiftOptsOffset", "file offset to Swift optimizations header");
addHeaderField(struct, QWORD, "swiftOptsOffset", "size of Swift optimizations header");
addHeaderField(struct, DWORD, "subCacheArrayOffset", "file offset to first dyld_subcache_entry");
addHeaderField(struct, DWORD, "subCacheArrayCount", "number of subcache entries");
addHeaderField(struct, new ArrayDataType(BYTE, 16, 1), "symbolFileUUID","unique value for the shared cache file containing unmapped local symbols");
addHeaderField(struct, QWORD, "rosettaReadOnlyAddr", "(unslid) address of the start of where Rosetta can add read-only/executable data");
addHeaderField(struct, QWORD, "rosettaReadOnlySize", "maximum size of the Rosetta read-only/executable region");
addHeaderField(struct, QWORD, "rosettaReadWriteAddr", "(unslid) address of the start of where Rosetta can add read-write data");
addHeaderField(struct, QWORD, "rosettaReadWriteSize", "maximum size of the Rosetta read-write region");
addHeaderField(struct, DWORD, "imagesOffset", "file offset to first dyld_cache_image_info");
addHeaderField(struct, DWORD, "imagesCount", "number of dyld_cache_image_info entries");
// @formatter:on
struct.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY));
@ -605,14 +756,16 @@ public class DyldCacheHeader implements StructConverter {
}
private void parseImageInfo(MessageLog log, TaskMonitor monitor) throws CancelledException {
if (imagesOffset == 0) {
int offset = imagesOffset != 0 ? imagesOffset : imagesOffsetOld;
int count = imagesOffset != 0 ? imagesCount : imagesCountOld;
if (offset == 0) {
return;
}
monitor.setMessage("Parsing DYLD image info...");
monitor.initialize(imagesCount);
monitor.initialize(count);
try {
reader.setPointerIndex(imagesOffset);
for (int i = 0; i < imagesCount; ++i) {
reader.setPointerIndex(offset);
for (int i = 0; i < count; ++i) {
imageInfoList.add(new DyldCacheImageInfo(reader));
monitor.checkCanceled();
monitor.incrementProgress(1);
@ -689,9 +842,29 @@ public class DyldCacheHeader implements StructConverter {
}
}
private void parseSubcaches(MessageLog log, TaskMonitor monitor) throws CancelledException {
if (subCacheArrayOffset == 0) {
return;
}
monitor.setMessage("Parsing DYLD subcaches...");
monitor.initialize(subCacheArrayCount);
try {
reader.setPointerIndex(subCacheArrayOffset);
for (int i = 0; i < subCacheArrayCount; ++i) {
subcacheEntryList.add(new DyldSubcacheEntry(reader, cacheType));
monitor.checkCanceled();
monitor.incrementProgress(1);
}
}
catch (IOException e) {
log.appendMsg(DyldCacheHeader.class.getSimpleName(),
"Failed to parse dyld_subcache_entry.");
}
}
private void parseAcceleratorInfo(Program program, AddressSpace space, MessageLog log,
TaskMonitor monitor) throws CancelledException {
if (accelerateInfoAddr == 0) {
if (accelerateInfoAddr == 0 || cacheType >= 2) {
return;
}
monitor.setMessage("Parsing DYLD accelerateor info...");
@ -770,7 +943,8 @@ public class DyldCacheHeader implements StructConverter {
monitor.setMessage("Marking up DYLD image info...");
monitor.initialize(imageInfoList.size());
try {
Address addr = fileOffsetToAddr(imagesOffset, program, space);
Address addr = fileOffsetToAddr(imagesOffset != 0 ? imagesOffset : imagesOffsetOld,
program, space);
for (DyldCacheImageInfo imageInfo : imageInfoList) {
Data d = DataUtilities.createData(program, addr, imageInfo.toDataType(), -1, false,
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
@ -868,7 +1042,7 @@ public class DyldCacheHeader implements StructConverter {
monitor.setMessage("Marking up DYLD accelerator info...");
monitor.initialize(1);
try {
if (accelerateInfo != null) {
if (accelerateInfo != null && cacheType < 2) {
Address addr = space.getAddress(accelerateInfoAddr);
DataUtilities.createData(program, addr, accelerateInfo.toDataType(), -1, false,
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
@ -904,6 +1078,26 @@ public class DyldCacheHeader implements StructConverter {
}
}
private void markupSubcacheEntries(Program program, AddressSpace space, TaskMonitor monitor,
MessageLog log) throws CancelledException {
monitor.setMessage("Marking up DYLD subcache entries...");
monitor.initialize(subcacheEntryList.size());
try {
Address addr = fileOffsetToAddr(subCacheArrayOffset, program, space);
for (DyldSubcacheEntry subcacheEntry : subcacheEntryList) {
Data d = DataUtilities.createData(program, addr, subcacheEntry.toDataType(), -1,
false, DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
addr = addr.add(d.getLength());
monitor.checkCanceled();
monitor.incrementProgress(1);
}
}
catch (CodeUnitInsertionException | DuplicateNameException | IOException e) {
log.appendMsg(DyldCacheHeader.class.getSimpleName(),
"Failed to markup dyld_subcache_entry.");
}
}
/**
* Sets the {@link MemoryBlock} associated with this header's FILE block.
*
@ -976,4 +1170,13 @@ public class DyldCacheHeader implements StructConverter {
public long unslidLoadAddress() {
return mappingInfoList.get(0).getAddress();
}
/**
* Checks to see whether or not this is a subcache
*
* @return True if this is a subcache; otherwise, false if its a base cache
*/
public boolean isSubcache() {
return headerType >= 8 && subCacheArrayCount == 0;
}
}

View File

@ -26,7 +26,7 @@ import ghidra.util.exception.DuplicateNameException;
/**
* Represents a dyld_cache_image_info structure.
*
* @see <a href="https://opensource.apple.com/source/dyld/dyld-852.2/dyld3/shared-cache/dyld_cache_format.h.auto.html">dyld3/shared-cache/dyld_cache_format.h</a>
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
*/
@SuppressWarnings("unused")
public class DyldCacheImageInfo implements DyldCacheImage, StructConverter {

View File

@ -26,7 +26,7 @@ import ghidra.util.exception.DuplicateNameException;
/**
* Represents a dyld_cache_image_info_extra structure.
*
* @see <a href="https://opensource.apple.com/source/dyld/dyld-852.2/dyld3/shared-cache/dyld_cache_format.h.auto.html">dyld3/shared-cache/dyld_cache_format.h</a>
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
*/
@SuppressWarnings("unused")
public class DyldCacheImageInfoExtra implements StructConverter {

View File

@ -26,7 +26,7 @@ import ghidra.util.exception.DuplicateNameException;
/**
* Represents a dyld_cache_image_text_info structure.
*
* @see <a href="https://opensource.apple.com/source/dyld/dyld-852.2/dyld3/shared-cache/dyld_cache_format.h.auto.html">dyld3/shared-cache/dyld_cache_format.h</a>
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
*/
@SuppressWarnings("unused")
public class DyldCacheImageTextInfo implements DyldCacheImage, StructConverter {

View File

@ -26,7 +26,7 @@ import ghidra.util.exception.DuplicateNameException;
/**
* Represents a dyld_cache_local_symbols_entry structure.
*
* @see <a href="https://opensource.apple.com/source/dyld/dyld-852.2/dyld3/shared-cache/dyld_cache_format.h.auto.html">dyld3/shared-cache/dyld_cache_format.h</a>
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
*/
@SuppressWarnings("unused")
public class DyldCacheLocalSymbolsEntry implements StructConverter {

View File

@ -38,7 +38,7 @@ import ghidra.util.task.TaskMonitor;
/**
* Represents a dyld_cache_local_symbols_info structure.
*
* @see <a href="https://opensource.apple.com/source/dyld/dyld-852.2/dyld3/shared-cache/dyld_cache_format.h.auto.html">dyld3/shared-cache/dyld_cache_format.h</a>
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
*/
@SuppressWarnings("unused")
public class DyldCacheLocalSymbolsInfo implements StructConverter {

View File

@ -27,7 +27,7 @@ import ghidra.util.exception.DuplicateNameException;
/**
* Represents a dyld_cache_mapping_and_slide_info structure.
*
* @see <a href="https://opensource.apple.com/source/dyld/dyld-852.2/dyld3/shared-cache/dyld_cache_format.h.auto.html">dyld3/shared-cache/dyld_cache_format.h</a>
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
*/
@SuppressWarnings("unused")
public class DyldCacheMappingAndSlideInfo implements StructConverter {

View File

@ -27,7 +27,7 @@ import ghidra.util.exception.DuplicateNameException;
/**
* Represents a dyld_cache_mapping_info structure.
*
* @see <a href="https://opensource.apple.com/source/dyld/dyld-852.2/dyld3/shared-cache/dyld_cache_format.h.auto.html">dyld3/shared-cache/dyld_cache_format.h</a>
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
*/
@SuppressWarnings("unused")
public class DyldCacheMappingInfo implements StructConverter {

View File

@ -26,7 +26,7 @@ import ghidra.util.exception.DuplicateNameException;
/**
* Represents a dyld_cache_range_entry structure.
*
* @see <a href="https://opensource.apple.com/source/dyld/dyld-852.2/dyld3/shared-cache/dyld_cache_format.h.auto.html">dyld3/shared-cache/dyld_cache_format.h</a>
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
*/
@SuppressWarnings("unused")
public class DyldCacheRangeEntry implements StructConverter {

View File

@ -34,7 +34,7 @@ import ghidra.util.task.TaskMonitor;
/**
* Represents a dyld_cache_slide_info structure.
*
* @see <a href="https://opensource.apple.com/source/dyld/dyld-852.2/dyld3/shared-cache/dyld_cache_format.h.auto.html">dyld3/shared-cache/dyld_cache_format.h</a>
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
*/
public class DyldCacheSlideInfo1 extends DyldCacheSlideInfoCommon {

View File

@ -34,7 +34,7 @@ import ghidra.util.task.TaskMonitor;
/**
* Represents a dyld_cache_slide_info2 structure.
*
* @see <a href="https://opensource.apple.com/source/dyld/dyld-852.2/dyld3/shared-cache/dyld_cache_format.h.auto.html">dyld3/shared-cache/dyld_cache_format.h</a>
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
*/
public class DyldCacheSlideInfo2 extends DyldCacheSlideInfoCommon {

View File

@ -34,7 +34,7 @@ import ghidra.util.task.TaskMonitor;
/**
* Represents a dyld_cache_slide_info3 structure.
*
* @see <a href="https://opensource.apple.com/source/dyld/dyld-852.2/dyld3/shared-cache/dyld_cache_format.h.auto.html">dyld3/shared-cache/dyld_cache_format.h</a>
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
*/
public class DyldCacheSlideInfo3 extends DyldCacheSlideInfoCommon {

View File

@ -34,7 +34,7 @@ import ghidra.util.task.TaskMonitor;
/**
* Represents a dyld_cache_slide_info3 structure.
*
* @see <a href="https://opensource.apple.com/source/dyld/dyld-852.2/dyld3/shared-cache/dyld_cache_format.h.auto.html">dyld3/shared-cache/dyld_cache_format.h</a>
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
*/
public class DyldCacheSlideInfo4 extends DyldCacheSlideInfoCommon {

View File

@ -36,7 +36,7 @@ import ghidra.util.task.TaskMonitor;
* The intent is for the the full dyld_cache_slide_info structures to extend this and add their
* specific parts.
*
* @see <a href="https://opensource.apple.com/source/dyld/dyld-852.2/dyld3/shared-cache/dyld_cache_format.h.auto.html">dyld3/shared-cache/dyld_cache_format.h</a>
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
*/
public abstract class DyldCacheSlideInfoCommon implements StructConverter {

View File

@ -0,0 +1,110 @@
/* ###
* 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.app.util.bin.format.macho.dyld;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.app.util.bin.format.macho.MachConstants;
import ghidra.program.model.data.*;
import ghidra.util.NumericUtilities;
import ghidra.util.exception.DuplicateNameException;
/**
* Represents a dyld_subcache_entry structure.
*
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
*/
public class DyldSubcacheEntry implements StructConverter {
private byte[] uuid;
private long cacheVMOffset;
private byte[] cacheExtension;
private long cacheType;
/**
* Create a new {@link DyldSubcacheEntry}.
*
* @param reader A {@link BinaryReader} positioned at the start of a DYLD subCache entry
* @param cacheType The cache type value
* @throws IOException if there was an IO-related problem creating the DYLD subCache entry
*/
public DyldSubcacheEntry(BinaryReader reader, long cacheType) throws IOException {
this.cacheType = cacheType;
uuid = reader.readNextByteArray(16);
cacheVMOffset = reader.readNextLong();
if (supportsCacheExtension()) {
cacheExtension = reader.readNextByteArray(32);
}
}
/**
* Gets the UUID of the subCache file
*
* @return The UUID of the subCache file
*/
public String getUuid() {
return NumericUtilities.convertBytesToString(uuid);
}
/**
* Gets the offset of this subCache from the main cache base address
*
* @return The offset of this subCache from the main cache base address
*/
public long getCacheVMOffset() {
return cacheVMOffset;
}
/**
* Gets the extension of this subCache, if it is known
*
* @return The extension of this subCache, or null if it is not known
*/
public String getCacheExtension() {
if (cacheExtension == null) {
return null;
}
return new String(cacheExtension, StandardCharsets.US_ASCII);
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType struct = new StructureDataType("dyld_subcache_entry", 0);
struct.add(new ArrayDataType(BYTE, 16, 1), "uuid", "The UUID of the subCache file");
struct.add(QWORD, "cacheVMOffset",
"The offset of this subcache from the main cache base address");
if (supportsCacheExtension()) {
struct.add(new ArrayDataType(ASCII, 32, 1), "cacheExtension",
"The extension of the subCache file");
}
struct.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY));
return struct;
}
/**
* Checks to see if the subCache extension is known
*
* @return True if the subCache extension is known; otherwise, false
*/
private boolean supportsCacheExtension() {
return cacheType >= 2;
}
}

View File

@ -42,22 +42,12 @@ public class DyldCacheLoader extends AbstractLibrarySupportLoader {
/** Default value for loader option to process symbols */
static final boolean PROCESS_SYMBOLS_OPTION_DEFAULT = true;
/** Loader option to create memory blocks for DYLIB sections */
static final String CREATE_DYLIB_SECTIONS_OPTION_NAME = "Create DYLIB section memory blocks";
/** Loader option to add relocation entries for chained fixups */
static final String ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_NAME =
"Add relocation entries for chained fixups";
/** Default value for loader option add chained fixups relocation entries */
/** Default value for loader option to add chained fixups relocation entries */
static final boolean ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_DEFAULT = false;
/** Loader option to combine split DYLD Cache files (.1, .2, .symbol, etc) into one program */
static final String COMBINE_SPLIT_FILES_OPTION_NAME =
"Auto import and combine split DYLD Cache files";
/** Default value for loader option add relocation entries */
static final boolean COMBINE_SPLIT_FILES_OPTION_DEFAULT = true;
@Override
public Collection<LoadSpec> findSupportedLoadSpecs(ByteProvider provider) throws IOException {
@ -69,6 +59,9 @@ public class DyldCacheLoader extends AbstractLibrarySupportLoader {
try {
DyldCacheHeader header = new DyldCacheHeader(new BinaryReader(provider, true));
if (header.isSubcache()) {
return loadSpecs;
}
DyldArchitecture architecture = header.getArchitecture();
if (architecture != null) {
List<QueryResult> results =
@ -94,8 +87,8 @@ public class DyldCacheLoader extends AbstractLibrarySupportLoader {
try {
DyldCacheProgramBuilder.buildProgram(program, provider,
MemoryBlockUtils.createFileBytes(program, provider, monitor),
shouldProcessSymbols(options), shouldAddChainedFixupsRelocations(options),
shouldCombineSplitFiles(options), log, monitor);
shouldProcessSymbols(options), shouldAddChainedFixupsRelocations(options), log,
monitor);
}
catch (CancelledException e) {
return;
@ -116,8 +109,6 @@ public class DyldCacheLoader extends AbstractLibrarySupportLoader {
list.add(new Option(ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_NAME,
ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_DEFAULT, Boolean.class,
Loader.COMMAND_LINE_ARG_PREFIX + "-addChainedFixupsRelocations"));
list.add(new Option(COMBINE_SPLIT_FILES_OPTION_NAME, COMBINE_SPLIT_FILES_OPTION_DEFAULT,
Boolean.class, Loader.COMMAND_LINE_ARG_PREFIX + "-combineSplitFiles"));
}
return list;
}
@ -132,11 +123,6 @@ public class DyldCacheLoader extends AbstractLibrarySupportLoader {
ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_DEFAULT);
}
private boolean shouldCombineSplitFiles(List<Option> options) {
return OptionUtils.getOption(COMBINE_SPLIT_FILES_OPTION_NAME, options,
COMBINE_SPLIT_FILES_OPTION_DEFAULT);
}
@Override
public String getName() {
return DYLD_CACHE_NAME;

View File

@ -45,7 +45,6 @@ import ghidra.util.task.TaskMonitor;
public class DyldCacheProgramBuilder extends MachoProgramBuilder {
private boolean shouldProcessSymbols;
private boolean shouldCombineSplitFiles;
/**
* Creates a new {@link DyldCacheProgramBuilder} based on the given information.
@ -56,17 +55,15 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
* @param shouldProcessSymbols True if symbols should be processed; otherwise, false
* @param shouldAddChainedFixupsRelocations True if relocations should be added for chained
* fixups; otherwise, false
* @param shouldCombineSplitFiles True if split DYLD Cache files should be automatically
* imported and combined into 1 program; otherwise, false
* @param log The log
* @param monitor A cancelable task monitor
*/
protected DyldCacheProgramBuilder(Program program, ByteProvider provider, FileBytes fileBytes,
boolean shouldProcessSymbols, boolean shouldAddChainedFixupsRelocations,
boolean shouldCombineSplitFiles, MessageLog log, TaskMonitor monitor) {
boolean shouldProcessSymbols, boolean shouldAddChainedFixupsRelocations, MessageLog log,
TaskMonitor monitor) {
super(program, provider, fileBytes, shouldAddChainedFixupsRelocations, log, monitor);
this.shouldProcessSymbols = shouldProcessSymbols;
this.shouldCombineSplitFiles = shouldCombineSplitFiles;
}
/**
@ -78,26 +75,24 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
* @param shouldProcessSymbols True if symbols should be processed; otherwise, false
* @param shouldAddChainedFixupsRelocations True if relocations should be added for chained
* fixups; otherwise, false
* @param shouldCombineSplitFiles True if split DYLD Cache files should be automatically
* imported and combined into 1 program; otherwise, false
* @param log The log
* @param monitor A cancelable task monitor
* @throws Exception if a problem occurs
*/
public static void buildProgram(Program program, ByteProvider provider, FileBytes fileBytes,
boolean shouldProcessSymbols, boolean shouldAddChainedFixupsRelocations,
boolean shouldCombineSplitFiles, MessageLog log, TaskMonitor monitor) throws Exception {
boolean shouldProcessSymbols, boolean shouldAddChainedFixupsRelocations, MessageLog log,
TaskMonitor monitor) throws Exception {
DyldCacheProgramBuilder dyldCacheProgramBuilder = new DyldCacheProgramBuilder(program,
provider, fileBytes, shouldProcessSymbols, shouldAddChainedFixupsRelocations,
shouldCombineSplitFiles, log, monitor);
provider, fileBytes, shouldProcessSymbols, shouldAddChainedFixupsRelocations, log,
monitor);
dyldCacheProgramBuilder.build();
}
@Override
protected void build() throws Exception {
try (SplitDyldCache splitDyldCache = new SplitDyldCache(provider, shouldProcessSymbols,
shouldCombineSplitFiles, log, monitor)) {
try (SplitDyldCache splitDyldCache =
new SplitDyldCache(provider, shouldProcessSymbols, log, monitor)) {
// Set image base
setDyldCacheImageBase(splitDyldCache.getDyldCacheHeader(0));
@ -108,8 +103,9 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
for (int i = 0; i < splitDyldCache.size(); i++) {
DyldCacheHeader header = splitDyldCache.getDyldCacheHeader(i);
ByteProvider bp = splitDyldCache.getProvider(i);
String name = splitDyldCache.getName(i);
processDyldCacheMemoryBlocks(header, bp);
processDyldCacheMemoryBlocks(header, name, bp);
if (header.getLocalSymbolsInfo() != null) {
localSymbolsPresent = true;
@ -147,26 +143,36 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
* Processes the DYLD Cache's memory mappings and creates memory blocks for them.
*
* @param dyldCacheHeader The {@link DyldCacheHeader}
* @param name The name of the DYLD Cache
* @param bp The corresponding {@link ByteProvider}
* @throws Exception if there was a problem creating the memory blocks
*/
private void processDyldCacheMemoryBlocks(DyldCacheHeader dyldCacheHeader, ByteProvider bp)
throws Exception {
private void processDyldCacheMemoryBlocks(DyldCacheHeader dyldCacheHeader, String name,
ByteProvider bp) throws Exception {
List<DyldCacheMappingInfo> mappingInfos = dyldCacheHeader.getMappingInfos();
monitor.setMessage("Processing DYLD mapped memory blocks...");
monitor.initialize(mappingInfos.size());
FileBytes fb = MemoryBlockUtils.createFileBytes(program, bp, monitor);
long endOfMappedOffset = 0;
boolean bookmarkSet = false;
for (DyldCacheMappingInfo mappingInfo : mappingInfos) {
long offset = mappingInfo.getFileOffset();
long size = mappingInfo.getSize();
MemoryBlockUtils.createInitializedBlock(program, false, "DYLD",
MemoryBlock block = MemoryBlockUtils.createInitializedBlock(program, false, "DYLD",
space.getAddress(mappingInfo.getAddress()), fb, offset, size, "", "",
mappingInfo.isRead(), mappingInfo.isWrite(), mappingInfo.isExecute(), log);
if (offset + size > endOfMappedOffset) {
endOfMappedOffset = offset + size;
}
if (!bookmarkSet) {
program.getBookmarkManager()
.setBookmark(block.getStart(), BookmarkType.INFO, "Dyld Cache Header",
name + " - " + dyldCacheHeader.getUUID());
bookmarkSet = true;
}
monitor.checkCanceled();
monitor.incrementProgress(1);
}

View File

@ -21,8 +21,7 @@ import java.util.*;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.format.macho.dyld.DyldArchitecture;
import ghidra.app.util.bin.format.macho.dyld.DyldCacheHeader;
import ghidra.app.util.bin.format.macho.dyld.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.formats.gfilesystem.*;
import ghidra.program.model.address.Address;
@ -98,13 +97,14 @@ public class DyldCacheUtils {
}
/**
* Class to store a "split" DYLD Cache, which is split across several files (base file, .1, .2,
* .symbols, etc).
* Class to store a "split" DYLD Cache, which is split across several subcache files (base file,
* .1, .2, .symbols, etc).
*/
public static class SplitDyldCache implements Closeable {
private List<ByteProvider> providers = new ArrayList<>();
private List<DyldCacheHeader> headers = new ArrayList<>();
private List<String> names = new ArrayList<>();
private FileSystemService fsService;
/**
@ -112,15 +112,13 @@ public class DyldCacheUtils {
*
* @param baseProvider The {@link ByteProvider} of the "base" DYLD Cache file
* @param shouldProcessSymbols True if symbols should be processed; otherwise, false
* @param shouldCombineSplitFiles True if split DYLD Cache files should be automatically
* @param log The log
* @param monitor A cancelable task monitor
* @throws IOException If there was an IO-related issue with processing the split DYLD Cache
* @throws CancelledException If the user canceled the operation
*/
public SplitDyldCache(ByteProvider baseProvider, boolean shouldProcessSymbols,
boolean shouldCombineSplitFiles, MessageLog log, TaskMonitor monitor)
throws IOException, CancelledException {
MessageLog log, TaskMonitor monitor) throws IOException, CancelledException {
// Setup "base" DYLD Cache
monitor.setMessage("Parsing " + baseProvider.getName() + " headers...");
@ -128,12 +126,14 @@ public class DyldCacheUtils {
DyldCacheHeader baseHeader = new DyldCacheHeader(new BinaryReader(baseProvider, true));
baseHeader.parseFromFile(shouldProcessSymbols, log, monitor);
headers.add(baseHeader);
names.add(baseProvider.getName());
// Setup additional "split" DYLD Caches (if applicable)
if (!shouldCombineSplitFiles) {
// Setup additional "split" DYLD subcaches (if applicable)
if (baseHeader.getSubcacheEntries().size() == 0) {
return;
}
fsService = FileSystemService.getInstance();
Map<String, FSRL> uuidToFileMap = new HashMap<>();
for (FSRL splitFSRL : findSplitDyldCacheFiles(baseProvider.getFSRL(), monitor)) {
monitor.setMessage("Parsing " + splitFSRL.getName() + " headers...");
ByteProvider splitProvider = fsService.getByteProvider(splitFSRL, false, monitor);
@ -146,7 +146,33 @@ public class DyldCacheUtils {
new DyldCacheHeader(new BinaryReader(splitProvider, true));
splitHeader.parseFromFile(shouldProcessSymbols, log, monitor);
headers.add(splitHeader);
log.appendMsg("Including split DYLD: " + splitProvider.getName());
names.add(splitFSRL.getName());
uuidToFileMap.put(splitHeader.getUUID(), splitFSRL);
}
// Validate the subcaches
for (DyldSubcacheEntry subcacheEntry : baseHeader.getSubcacheEntries()) {
String uuid = subcacheEntry.getUuid();
String extension = subcacheEntry.getCacheExtension();
FSRL fsrl = uuidToFileMap.get(uuid);
if (fsrl != null) {
log.appendMsg("Including subcache: " + fsrl.getName() + " - " + uuid);
}
else {
log.appendMsg(String.format("Missing subcache: %s%s",
extension != null ? (baseProvider.getName() + "." + extension + " - ") : "",
uuid));
}
}
String symbolUUID = baseHeader.getSymbolFileUUID();
FSRL symbolFSRL = uuidToFileMap.get(symbolUUID);
if (symbolFSRL != null) {
log.appendMsg(
"Including symbols subcache: " + symbolFSRL.getName() + " - " + symbolUUID);
}
else {
log.appendMsg(String.format("Missing symbols subcache: %s%s",
baseProvider.getName() + ".symbols - " + symbolUUID));
}
}
@ -170,6 +196,16 @@ public class DyldCacheUtils {
return headers.get(i);
}
/**
* Gets the i'th {@link String name} in the split DYLD Cache
*
* @param i The index of the {@link String name} to get
* @return The i'th {@link String name} in the split DYLD Cache
*/
public String getName(int i) {
return names.get(i);
}
/**
* Gets the number of split DYLD Cache files
*

View File

@ -279,10 +279,6 @@ public class MachoProgramBuilder {
}
}
}
else {
log.appendMsg(
"Skipping segment: " + segment.getSegmentName() + " (" + source + ")");
}
}
// Create memory blocks for sections. They will be in the segments we just created, so the
@ -304,10 +300,6 @@ public class MachoProgramBuilder {
section.getAddress(), section.getSize(), source));
}
}
else {
log.appendMsg("Skipping section: " + section.getSegmentName() + "." +
section.getSectionName() + " (" + source + ")");
}
}
}
}

View File

@ -16,7 +16,8 @@
package ghidra.file.formats.ios.dyldcache;
import java.io.IOException;
import java.util.*;
import java.util.HashMap;
import java.util.Map;
import ghidra.app.util.bin.*;
import ghidra.app.util.bin.format.macho.*;
@ -84,7 +85,7 @@ public class DyldCacheDylibExtractor {
TaskMonitor monitor) throws MachException, IOException {
ByteProvider provider = splitDyldCache.getProvider(index);
this.reader = new BinaryReader(provider, true);
this.header = new MachHeader(provider, dylibOffset, false).parse();
this.header = new MachHeader(provider, dylibOffset, false).parse(splitDyldCache);
this.monitor = monitor;
// Keep track of each segment's file offset in the DYLD cache.

View File

@ -18,6 +18,7 @@ package ghidra.file.formats.ios.dyldcache;
import java.io.IOException;
import java.util.*;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.format.macho.MachException;
import ghidra.app.util.bin.format.macho.dyld.DyldCacheHeader;
@ -95,7 +96,16 @@ public class DyldCacheFileSystem extends GFileSystemBase {
@Override
public boolean isValid(TaskMonitor monitor) throws IOException {
return DyldCacheUtils.isDyldCache(provider);
if (!DyldCacheUtils.isDyldCache(provider)) {
return false;
}
try {
DyldCacheHeader header = new DyldCacheHeader(new BinaryReader(provider, true));
return !header.isSubcache();
}
catch (IOException e) {
return false;
}
}
@Override
@ -103,7 +113,7 @@ public class DyldCacheFileSystem extends GFileSystemBase {
MessageLog log = new MessageLog();
monitor.setMessage("Opening DYLD cache...");
splitDyldCache = new SplitDyldCache(provider, false, true, log, monitor);
splitDyldCache = new SplitDyldCache(provider, false, log, monitor);
for (int i = 0; i < splitDyldCache.size(); i++) {
DyldCacheHeader header = splitDyldCache.getDyldCacheHeader(i);
monitor.setMessage("Find files...");