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. * 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") @SuppressWarnings("unused")
public class DyldCacheAccelerateInfo implements StructConverter { public class DyldCacheAccelerateInfo implements StructConverter {

View File

@ -26,7 +26,7 @@ import ghidra.util.exception.DuplicateNameException;
/** /**
* Represents a dyld_cache_accelerator_dof structure. * 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") @SuppressWarnings("unused")
public class DyldCacheAcceleratorDof implements StructConverter { public class DyldCacheAcceleratorDof implements StructConverter {

View File

@ -26,7 +26,7 @@ import ghidra.util.exception.DuplicateNameException;
/** /**
* Represents a dyld_cache_accelerator_initializer structure. * 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") @SuppressWarnings("unused")
public class DyldCacheAcceleratorInitializer implements StructConverter { 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.listing.*;
import ghidra.program.model.mem.MemoryBlock; import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.util.CodeUnitInsertionException; import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.util.NumericUtilities;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
@ -34,7 +35,7 @@ import ghidra.util.task.TaskMonitor;
/** /**
* Represents a dyld_cache_header structure. * 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") @SuppressWarnings("unused")
public class DyldCacheHeader implements StructConverter { public class DyldCacheHeader implements StructConverter {
@ -42,8 +43,8 @@ public class DyldCacheHeader implements StructConverter {
private byte[] magic; private byte[] magic;
private int mappingOffset; private int mappingOffset;
private int mappingCount; private int mappingCount;
private int imagesOffset; private int imagesOffsetOld;
private int imagesCount; private int imagesCountOld;
private long dyldBaseAddress; private long dyldBaseAddress;
private long codeSignatureOffset; private long codeSignatureOffset;
private long codeSignatureSize; private long codeSignatureSize;
@ -61,20 +62,20 @@ public class DyldCacheHeader implements StructConverter {
private long imagesTextCount; private long imagesTextCount;
private long patchInfoAddr; private long patchInfoAddr;
private long patchInfoSize; private long patchInfoSize;
private long otherImageGroupAddrUnused; // unused private long otherImageGroupAddrUnused;
private long otherImageGroupSizeUnused; // unused private long otherImageGroupSizeUnused;
private long progClosuresAddr; private long progClosuresAddr;
private long progClosuresSize; private long progClosuresSize;
private long progClosuresTrieAddr; private long progClosuresTrieAddr;
private long progClosuresTrieSize; private long progClosuresTrieSize;
private int platform; private int platform;
private int dyld_info; private int dyld_info;
private int formatVersion; // Extracted from dyld_info private int formatVersion;
private boolean dylibsExpectedOnDisk; // Extracted from dyld_info private boolean dylibsExpectedOnDisk;
private boolean simulator; // Extracted from dyld_info private boolean simulator;
private boolean locallyBuiltCache; // Extracted from dyld_info private boolean locallyBuiltCache;
private boolean builtFromChainedFixups; // Extracted from dyld_info private boolean builtFromChainedFixups;
private int padding; // Extracted from dyld_info private int padding;
private long sharedRegionStart; private long sharedRegionStart;
private long sharedRegionSize; private long sharedRegionSize;
private long maxSlide; private long maxSlide;
@ -88,6 +89,26 @@ public class DyldCacheHeader implements StructConverter {
private long otherTrieSize; private long otherTrieSize;
private int mappingWithSlideOffset; private int mappingWithSlideOffset;
private int mappingWithSlideCount; 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 headerType;
private int headerSize; private int headerSize;
@ -100,6 +121,7 @@ public class DyldCacheHeader implements StructConverter {
private List<Long> branchPoolList; private List<Long> branchPoolList;
private DyldCacheAccelerateInfo accelerateInfo; private DyldCacheAccelerateInfo accelerateInfo;
private List<DyldCacheImageTextInfo> imageTextInfoList; private List<DyldCacheImageTextInfo> imageTextInfoList;
private List<DyldSubcacheEntry> subcacheEntryList;
private DyldArchitecture architecture; private DyldArchitecture architecture;
private List<DyldCacheMappingAndSlideInfo> cacheMappingAndSlideInfoList; private List<DyldCacheMappingAndSlideInfo> cacheMappingAndSlideInfoList;
private MemoryBlock fileBlock; private MemoryBlock fileBlock;
@ -119,8 +141,8 @@ public class DyldCacheHeader implements StructConverter {
magic = reader.readNextByteArray(16); magic = reader.readNextByteArray(16);
mappingOffset = reader.readNextInt(); mappingOffset = reader.readNextInt();
mappingCount = reader.readNextInt(); mappingCount = reader.readNextInt();
imagesOffset = reader.readNextInt(); imagesOffsetOld = reader.readNextInt();
imagesCount = reader.readNextInt(); imagesCountOld = reader.readNextInt();
dyldBaseAddress = reader.readNextLong(); dyldBaseAddress = reader.readNextLong();
// HEADER 2: https://opensource.apple.com/source/dyld/dyld-195.5/launch-cache/dyld_cache_format.h.auto.html // 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; headerType = 7;
} }
if (reader.getPointerIndex() < mappingOffset) { if (reader.getPointerIndex() < mappingOffset) {
patchInfoAddr = reader.readNextLong(); // (unslid) address of dyld_cache_patch_info patchInfoAddr = reader.readNextLong();
} }
if (reader.getPointerIndex() < mappingOffset) { 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) { if (reader.getPointerIndex() < mappingOffset) {
otherImageGroupAddrUnused = reader.readNextLong(); // unused otherImageGroupAddrUnused = reader.readNextLong();
} }
if (reader.getPointerIndex() < mappingOffset) { if (reader.getPointerIndex() < mappingOffset) {
otherImageGroupSizeUnused = reader.readNextLong(); // unused otherImageGroupSizeUnused = reader.readNextLong();
} }
if (reader.getPointerIndex() < mappingOffset) { if (reader.getPointerIndex() < mappingOffset) {
progClosuresAddr = reader.readNextLong(); // (unslid) address of list of program launch closures progClosuresAddr = reader.readNextLong();
} }
if (reader.getPointerIndex() < mappingOffset) { if (reader.getPointerIndex() < mappingOffset) {
progClosuresSize = reader.readNextLong(); // size of list of program launch closures progClosuresSize = reader.readNextLong();
} }
if (reader.getPointerIndex() < mappingOffset) { if (reader.getPointerIndex() < mappingOffset) {
progClosuresTrieAddr = reader.readNextLong(); // (unslid) address of trie of indexes into program launch closures progClosuresTrieAddr = reader.readNextLong();
} }
if (reader.getPointerIndex() < mappingOffset) { if (reader.getPointerIndex() < mappingOffset) {
progClosuresTrieSize = reader.readNextLong(); // size of trie of indexes into program launch closures progClosuresTrieSize = reader.readNextLong();
} }
if (reader.getPointerIndex() < mappingOffset) { if (reader.getPointerIndex() < mappingOffset) {
platform = reader.readNextInt(); // platform number (macOS=1, etc) platform = reader.readNextInt();
} }
if (reader.getPointerIndex() < mappingOffset) { if (reader.getPointerIndex() < mappingOffset) {
dyld_info = reader.readNextInt(); dyld_info = reader.readNextInt();
formatVersion = dyld_info & 0xff; // dyld3::closure::kFormatVersion formatVersion = dyld_info & 0xff;
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 dylibsExpectedOnDisk = (dyld_info >>> 8 & 1) == 1;
simulator = (dyld_info >>> 9 & 1) == 1; // for simulator of specified platform simulator = (dyld_info >>> 9 & 1) == 1;
locallyBuiltCache = (dyld_info >> 10 & 1) == 1; // 0 for B&I built cache, 1 for locally built cache locallyBuiltCache = (dyld_info >> 10 & 1) == 1;
builtFromChainedFixups = (dyld_info >> 11 & 1) == 1; // some dylib in cache was built using chained fixups, so patch tables must be used for overrides builtFromChainedFixups = (dyld_info >> 11 & 1) == 1;
padding = (dyld_info >> 12) & 0xfffff; // TBD padding = (dyld_info >> 12) & 0xfffff;
} }
if (reader.getPointerIndex() < mappingOffset) { if (reader.getPointerIndex() < mappingOffset) {
sharedRegionStart = reader.readNextLong(); // base load address of cache if not slid sharedRegionStart = reader.readNextLong();
} }
if (reader.getPointerIndex() < mappingOffset) { if (reader.getPointerIndex() < mappingOffset) {
sharedRegionSize = reader.readNextLong(); // overall size of region cache can be mapped into sharedRegionSize = reader.readNextLong();
} }
if (reader.getPointerIndex() < mappingOffset) { 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) { if (reader.getPointerIndex() < mappingOffset) {
dylibsImageArrayAddr = reader.readNextLong(); // (unslid) address of ImageArray for dylibs in this cache dylibsImageArrayAddr = reader.readNextLong();
} }
if (reader.getPointerIndex() < mappingOffset) { if (reader.getPointerIndex() < mappingOffset) {
dylibsImageArraySize = reader.readNextLong(); // size of ImageArray for dylibs in this cache dylibsImageArraySize = reader.readNextLong();
} }
if (reader.getPointerIndex() < mappingOffset) { if (reader.getPointerIndex() < mappingOffset) {
dylibsTrieAddr = reader.readNextLong(); // (unslid) address of trie of indexes of all cached dylibs dylibsTrieAddr = reader.readNextLong();
} }
if (reader.getPointerIndex() < mappingOffset) { if (reader.getPointerIndex() < mappingOffset) {
dylibsTrieSize = reader.readNextLong(); // size of trie of cached dylib paths dylibsTrieSize = reader.readNextLong();
} }
if (reader.getPointerIndex() < mappingOffset) { 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) { if (reader.getPointerIndex() < mappingOffset) {
otherImageArraySize = reader.readNextLong(); // size of ImageArray for dylibs and bundles with dlopen closures otherImageArraySize = reader.readNextLong();
} }
if (reader.getPointerIndex() < mappingOffset) { 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) { if (reader.getPointerIndex() < mappingOffset) {
otherTrieSize = reader.readNextLong(); // size of trie of dylibs and bundles with dlopen closures otherTrieSize = reader.readNextLong();
} }
if (reader.getPointerIndex() < mappingOffset) { if (reader.getPointerIndex() < mappingOffset) {
mappingWithSlideOffset = reader.readNextInt(); // file offset to first dyld_cache_mapping_and_slide_info mappingWithSlideOffset = reader.readNextInt();
} }
if (reader.getPointerIndex() < mappingOffset) { 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); headerSize = (int) (reader.getPointerIndex() - startIndex);
@ -252,9 +339,10 @@ public class DyldCacheHeader implements StructConverter {
mappingInfoList = new ArrayList<>(mappingCount); mappingInfoList = new ArrayList<>(mappingCount);
cacheMappingAndSlideInfoList = new ArrayList<>(mappingWithSlideCount); cacheMappingAndSlideInfoList = new ArrayList<>(mappingWithSlideCount);
slideInfoList = new ArrayList<>(); slideInfoList = new ArrayList<>();
imageInfoList = new ArrayList<>(imagesCount); imageInfoList = new ArrayList<>(imagesCountOld);
branchPoolList = new ArrayList<>(branchPoolsCount); branchPoolList = new ArrayList<>(branchPoolsCount);
imageTextInfoList = new ArrayList<>(); imageTextInfoList = new ArrayList<>();
subcacheEntryList = new ArrayList<>();
} }
/** /**
@ -280,6 +368,9 @@ public class DyldCacheHeader implements StructConverter {
parseBranchPools(log, monitor); parseBranchPools(log, monitor);
parseImageTextInfo(log, monitor); parseImageTextInfo(log, monitor);
} }
if (headerType >= 8) {
parseSubcaches(log, monitor);
}
parseCacheMappingSlideInfo(log, monitor); parseCacheMappingSlideInfo(log, monitor);
if (hasSlideInfo()) { if (hasSlideInfo()) {
parseSlideInfos(log, monitor); parseSlideInfos(log, monitor);
@ -376,6 +467,9 @@ public class DyldCacheHeader implements StructConverter {
markupAcceleratorInfo(program, space, monitor, log); markupAcceleratorInfo(program, space, monitor, log);
markupImageTextInfo(program, space, monitor, log); markupImageTextInfo(program, space, monitor, log);
} }
if (headerType >= 8) {
markupSubcacheEntries(program, space, monitor, log);
}
if (mappingWithSlideOffset >= 0) { if (mappingWithSlideOffset >= 0) {
markupCacheMappingSlideInfo(program, space, log, monitor); markupCacheMappingSlideInfo(program, space, log, monitor);
} }
@ -400,6 +494,24 @@ public class DyldCacheHeader implements StructConverter {
return magic; 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. * 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} * @return The file offset to first {@link DyldCacheImageInfo}
*/ */
public int getImagesOffset() { 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 * @return The number of {@link DyldCacheImageInfo}s
*/ */
public int getImagesCount() { 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 * Generates a {@link List} of {@link DyldCacheImage}s that are mapped in by this
* {@link DyldCacheHeader}. Requires header to have been parsed. * {@link DyldCacheHeader}. Requires header to have been parsed.
* <p> * <p>
* NOTE: A "split" DYLD Cache header may declare an image, but that image may get loaded at an * 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 split header. This method will only return * address defined by the memory map of a different subcache header. This method will only
* the images that are mapped by "this" header's memory map. * 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} * @return A {@link List} of {@link DyldCacheImage}s mapped by this {@link DyldCacheHeader}
*/ */
public List<DyldCacheImage> getMappedImages() { 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<>(); List<DyldCacheImage> images = new ArrayList<>();
if (imageInfoList.size() > 0) { for (DyldCacheImage imageInfo : imageInfoList) {
// The old, simple way for (DyldCacheMappingInfo mappingInfo : mappingInfoList) {
images.addAll(imageInfoList); if (mappingInfo.contains(imageInfo.getAddress())) {
} images.add(imageInfo);
else { break;
// 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;
}
} }
} }
} }
return images; 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. * 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, 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, "mappingOffset","file offset to first dyld_cache_mapping_info");
addHeaderField(struct, DWORD, "mappingCount", "number of dyld_cache_mapping_info entries"); 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, "imagesOffsetOld", "UNUSED: moved to imagesOffset to prevent older dsc_extarctors from crashing");
addHeaderField(struct, DWORD, "imagesCount", "number of dyld_cache_image_info entries"); 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"); addHeaderField(struct, QWORD, "dyldBaseAddress","base address of dyld when cache was built");
// headerType 2 // 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, "mappingWithSlideOffset","file offset to first dyld_cache_mapping_and_slide_info");
addHeaderField(struct, DWORD, "mappingWithSlideCount","number of dyld_cache_mapping_and_slide_info entries"); 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 // @formatter:on
struct.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY)); 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 { 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; return;
} }
monitor.setMessage("Parsing DYLD image info..."); monitor.setMessage("Parsing DYLD image info...");
monitor.initialize(imagesCount); monitor.initialize(count);
try { try {
reader.setPointerIndex(imagesOffset); reader.setPointerIndex(offset);
for (int i = 0; i < imagesCount; ++i) { for (int i = 0; i < count; ++i) {
imageInfoList.add(new DyldCacheImageInfo(reader)); imageInfoList.add(new DyldCacheImageInfo(reader));
monitor.checkCanceled(); monitor.checkCanceled();
monitor.incrementProgress(1); 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, private void parseAcceleratorInfo(Program program, AddressSpace space, MessageLog log,
TaskMonitor monitor) throws CancelledException { TaskMonitor monitor) throws CancelledException {
if (accelerateInfoAddr == 0) { if (accelerateInfoAddr == 0 || cacheType >= 2) {
return; return;
} }
monitor.setMessage("Parsing DYLD accelerateor info..."); monitor.setMessage("Parsing DYLD accelerateor info...");
@ -770,7 +943,8 @@ public class DyldCacheHeader implements StructConverter {
monitor.setMessage("Marking up DYLD image info..."); monitor.setMessage("Marking up DYLD image info...");
monitor.initialize(imageInfoList.size()); monitor.initialize(imageInfoList.size());
try { try {
Address addr = fileOffsetToAddr(imagesOffset, program, space); Address addr = fileOffsetToAddr(imagesOffset != 0 ? imagesOffset : imagesOffsetOld,
program, space);
for (DyldCacheImageInfo imageInfo : imageInfoList) { for (DyldCacheImageInfo imageInfo : imageInfoList) {
Data d = DataUtilities.createData(program, addr, imageInfo.toDataType(), -1, false, Data d = DataUtilities.createData(program, addr, imageInfo.toDataType(), -1, false,
DataUtilities.ClearDataMode.CHECK_FOR_SPACE); DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
@ -868,7 +1042,7 @@ public class DyldCacheHeader implements StructConverter {
monitor.setMessage("Marking up DYLD accelerator info..."); monitor.setMessage("Marking up DYLD accelerator info...");
monitor.initialize(1); monitor.initialize(1);
try { try {
if (accelerateInfo != null) { if (accelerateInfo != null && cacheType < 2) {
Address addr = space.getAddress(accelerateInfoAddr); Address addr = space.getAddress(accelerateInfoAddr);
DataUtilities.createData(program, addr, accelerateInfo.toDataType(), -1, false, DataUtilities.createData(program, addr, accelerateInfo.toDataType(), -1, false,
DataUtilities.ClearDataMode.CHECK_FOR_SPACE); 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. * Sets the {@link MemoryBlock} associated with this header's FILE block.
* *
@ -976,4 +1170,13 @@ public class DyldCacheHeader implements StructConverter {
public long unslidLoadAddress() { public long unslidLoadAddress() {
return mappingInfoList.get(0).getAddress(); 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. * 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") @SuppressWarnings("unused")
public class DyldCacheImageInfo implements DyldCacheImage, StructConverter { 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. * 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") @SuppressWarnings("unused")
public class DyldCacheImageInfoExtra implements StructConverter { public class DyldCacheImageInfoExtra implements StructConverter {

View File

@ -26,7 +26,7 @@ import ghidra.util.exception.DuplicateNameException;
/** /**
* Represents a dyld_cache_image_text_info structure. * 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") @SuppressWarnings("unused")
public class DyldCacheImageTextInfo implements DyldCacheImage, StructConverter { 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. * 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") @SuppressWarnings("unused")
public class DyldCacheLocalSymbolsEntry implements StructConverter { public class DyldCacheLocalSymbolsEntry implements StructConverter {

View File

@ -38,7 +38,7 @@ import ghidra.util.task.TaskMonitor;
/** /**
* Represents a dyld_cache_local_symbols_info structure. * 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") @SuppressWarnings("unused")
public class DyldCacheLocalSymbolsInfo implements StructConverter { 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. * 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") @SuppressWarnings("unused")
public class DyldCacheMappingAndSlideInfo implements StructConverter { public class DyldCacheMappingAndSlideInfo implements StructConverter {

View File

@ -27,7 +27,7 @@ import ghidra.util.exception.DuplicateNameException;
/** /**
* Represents a dyld_cache_mapping_info structure. * 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") @SuppressWarnings("unused")
public class DyldCacheMappingInfo implements StructConverter { public class DyldCacheMappingInfo implements StructConverter {

View File

@ -26,7 +26,7 @@ import ghidra.util.exception.DuplicateNameException;
/** /**
* Represents a dyld_cache_range_entry structure. * 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") @SuppressWarnings("unused")
public class DyldCacheRangeEntry implements StructConverter { public class DyldCacheRangeEntry implements StructConverter {

View File

@ -34,7 +34,7 @@ import ghidra.util.task.TaskMonitor;
/** /**
* Represents a dyld_cache_slide_info structure. * 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 { public class DyldCacheSlideInfo1 extends DyldCacheSlideInfoCommon {

View File

@ -34,7 +34,7 @@ import ghidra.util.task.TaskMonitor;
/** /**
* Represents a dyld_cache_slide_info2 structure. * 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 { public class DyldCacheSlideInfo2 extends DyldCacheSlideInfoCommon {

View File

@ -34,7 +34,7 @@ import ghidra.util.task.TaskMonitor;
/** /**
* Represents a dyld_cache_slide_info3 structure. * 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 { public class DyldCacheSlideInfo3 extends DyldCacheSlideInfoCommon {

View File

@ -34,7 +34,7 @@ import ghidra.util.task.TaskMonitor;
/** /**
* Represents a dyld_cache_slide_info3 structure. * 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 { 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 * The intent is for the the full dyld_cache_slide_info structures to extend this and add their
* specific parts. * 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 { 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 */ /** Default value for loader option to process symbols */
static final boolean PROCESS_SYMBOLS_OPTION_DEFAULT = true; 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 */ /** Loader option to add relocation entries for chained fixups */
static final String ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_NAME = static final String ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_NAME =
"Add relocation entries for chained fixups"; "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; 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 @Override
public Collection<LoadSpec> findSupportedLoadSpecs(ByteProvider provider) throws IOException { public Collection<LoadSpec> findSupportedLoadSpecs(ByteProvider provider) throws IOException {
@ -69,6 +59,9 @@ public class DyldCacheLoader extends AbstractLibrarySupportLoader {
try { try {
DyldCacheHeader header = new DyldCacheHeader(new BinaryReader(provider, true)); DyldCacheHeader header = new DyldCacheHeader(new BinaryReader(provider, true));
if (header.isSubcache()) {
return loadSpecs;
}
DyldArchitecture architecture = header.getArchitecture(); DyldArchitecture architecture = header.getArchitecture();
if (architecture != null) { if (architecture != null) {
List<QueryResult> results = List<QueryResult> results =
@ -94,8 +87,8 @@ public class DyldCacheLoader extends AbstractLibrarySupportLoader {
try { try {
DyldCacheProgramBuilder.buildProgram(program, provider, DyldCacheProgramBuilder.buildProgram(program, provider,
MemoryBlockUtils.createFileBytes(program, provider, monitor), MemoryBlockUtils.createFileBytes(program, provider, monitor),
shouldProcessSymbols(options), shouldAddChainedFixupsRelocations(options), shouldProcessSymbols(options), shouldAddChainedFixupsRelocations(options), log,
shouldCombineSplitFiles(options), log, monitor); monitor);
} }
catch (CancelledException e) { catch (CancelledException e) {
return; return;
@ -116,8 +109,6 @@ public class DyldCacheLoader extends AbstractLibrarySupportLoader {
list.add(new Option(ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_NAME, list.add(new Option(ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_NAME,
ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_DEFAULT, Boolean.class, ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_DEFAULT, Boolean.class,
Loader.COMMAND_LINE_ARG_PREFIX + "-addChainedFixupsRelocations")); 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; return list;
} }
@ -132,11 +123,6 @@ public class DyldCacheLoader extends AbstractLibrarySupportLoader {
ADD_CHAINED_FIXUPS_RELOCATIONS_OPTION_DEFAULT); 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 @Override
public String getName() { public String getName() {
return DYLD_CACHE_NAME; return DYLD_CACHE_NAME;

View File

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

View File

@ -21,8 +21,7 @@ import java.util.*;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.ByteProvider; import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.format.macho.dyld.DyldArchitecture; import ghidra.app.util.bin.format.macho.dyld.*;
import ghidra.app.util.bin.format.macho.dyld.DyldCacheHeader;
import ghidra.app.util.importer.MessageLog; import ghidra.app.util.importer.MessageLog;
import ghidra.formats.gfilesystem.*; import ghidra.formats.gfilesystem.*;
import ghidra.program.model.address.Address; 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, * Class to store a "split" DYLD Cache, which is split across several subcache files (base file,
* .symbols, etc). * .1, .2, .symbols, etc).
*/ */
public static class SplitDyldCache implements Closeable { public static class SplitDyldCache implements Closeable {
private List<ByteProvider> providers = new ArrayList<>(); private List<ByteProvider> providers = new ArrayList<>();
private List<DyldCacheHeader> headers = new ArrayList<>(); private List<DyldCacheHeader> headers = new ArrayList<>();
private List<String> names = new ArrayList<>();
private FileSystemService fsService; private FileSystemService fsService;
/** /**
@ -112,15 +112,13 @@ public class DyldCacheUtils {
* *
* @param baseProvider The {@link ByteProvider} of the "base" DYLD Cache file * @param baseProvider The {@link ByteProvider} of the "base" DYLD Cache file
* @param shouldProcessSymbols True if symbols should be processed; otherwise, false * @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 log The log
* @param monitor A cancelable task monitor * @param monitor A cancelable task monitor
* @throws IOException If there was an IO-related issue with processing the split DYLD Cache * @throws IOException If there was an IO-related issue with processing the split DYLD Cache
* @throws CancelledException If the user canceled the operation * @throws CancelledException If the user canceled the operation
*/ */
public SplitDyldCache(ByteProvider baseProvider, boolean shouldProcessSymbols, public SplitDyldCache(ByteProvider baseProvider, boolean shouldProcessSymbols,
boolean shouldCombineSplitFiles, MessageLog log, TaskMonitor monitor) MessageLog log, TaskMonitor monitor) throws IOException, CancelledException {
throws IOException, CancelledException {
// Setup "base" DYLD Cache // Setup "base" DYLD Cache
monitor.setMessage("Parsing " + baseProvider.getName() + " headers..."); monitor.setMessage("Parsing " + baseProvider.getName() + " headers...");
@ -128,12 +126,14 @@ public class DyldCacheUtils {
DyldCacheHeader baseHeader = new DyldCacheHeader(new BinaryReader(baseProvider, true)); DyldCacheHeader baseHeader = new DyldCacheHeader(new BinaryReader(baseProvider, true));
baseHeader.parseFromFile(shouldProcessSymbols, log, monitor); baseHeader.parseFromFile(shouldProcessSymbols, log, monitor);
headers.add(baseHeader); headers.add(baseHeader);
names.add(baseProvider.getName());
// Setup additional "split" DYLD Caches (if applicable) // Setup additional "split" DYLD subcaches (if applicable)
if (!shouldCombineSplitFiles) { if (baseHeader.getSubcacheEntries().size() == 0) {
return; return;
} }
fsService = FileSystemService.getInstance(); fsService = FileSystemService.getInstance();
Map<String, FSRL> uuidToFileMap = new HashMap<>();
for (FSRL splitFSRL : findSplitDyldCacheFiles(baseProvider.getFSRL(), monitor)) { for (FSRL splitFSRL : findSplitDyldCacheFiles(baseProvider.getFSRL(), monitor)) {
monitor.setMessage("Parsing " + splitFSRL.getName() + " headers..."); monitor.setMessage("Parsing " + splitFSRL.getName() + " headers...");
ByteProvider splitProvider = fsService.getByteProvider(splitFSRL, false, monitor); ByteProvider splitProvider = fsService.getByteProvider(splitFSRL, false, monitor);
@ -146,7 +146,33 @@ public class DyldCacheUtils {
new DyldCacheHeader(new BinaryReader(splitProvider, true)); new DyldCacheHeader(new BinaryReader(splitProvider, true));
splitHeader.parseFromFile(shouldProcessSymbols, log, monitor); splitHeader.parseFromFile(shouldProcessSymbols, log, monitor);
headers.add(splitHeader); 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); 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 * 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 // 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)); 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; package ghidra.file.formats.ios.dyldcache;
import java.io.IOException; 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.*;
import ghidra.app.util.bin.format.macho.*; import ghidra.app.util.bin.format.macho.*;
@ -84,7 +85,7 @@ public class DyldCacheDylibExtractor {
TaskMonitor monitor) throws MachException, IOException { TaskMonitor monitor) throws MachException, IOException {
ByteProvider provider = splitDyldCache.getProvider(index); ByteProvider provider = splitDyldCache.getProvider(index);
this.reader = new BinaryReader(provider, true); 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; this.monitor = monitor;
// Keep track of each segment's file offset in the DYLD cache. // 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.io.IOException;
import java.util.*; import java.util.*;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.ByteProvider; import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.format.macho.MachException; import ghidra.app.util.bin.format.macho.MachException;
import ghidra.app.util.bin.format.macho.dyld.DyldCacheHeader; import ghidra.app.util.bin.format.macho.dyld.DyldCacheHeader;
@ -95,7 +96,16 @@ public class DyldCacheFileSystem extends GFileSystemBase {
@Override @Override
public boolean isValid(TaskMonitor monitor) throws IOException { 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 @Override
@ -103,7 +113,7 @@ public class DyldCacheFileSystem extends GFileSystemBase {
MessageLog log = new MessageLog(); MessageLog log = new MessageLog();
monitor.setMessage("Opening DYLD cache..."); 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++) { for (int i = 0; i < splitDyldCache.size(); i++) {
DyldCacheHeader header = splitDyldCache.getDyldCacheHeader(i); DyldCacheHeader header = splitDyldCache.getDyldCacheHeader(i);
monitor.setMessage("Find files..."); monitor.setMessage("Find files...");