mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-24 21:21:56 +00:00
Merge branch 'GP-2176_ryanmkurtz_dyld-iOS16' (Closes #4346,
Closes #4406)
This commit is contained in:
commit
61b135acd9
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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 + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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...");
|
||||
|
Loading…
Reference in New Issue
Block a user