Merge remote-tracking branch 'origin/GP-3596_ryanmkurtz_dyld-header'

This commit is contained in:
Ryan Kurtz 2023-06-29 13:35:07 -04:00
commit 8a36f55a21
2 changed files with 116 additions and 142 deletions

View File

@ -56,8 +56,8 @@ public class DyldCacheHeader implements StructConverter {
private long cacheType;
private int branchPoolsOffset;
private int branchPoolsCount;
private long accelerateInfoAddr;
private long accelerateInfoSize;
private long accelerateInfoAddr_dyldInCacheMH;
private long accelerateInfoSize_dyldInCacheEntry;
private long imagesTextOffset;
private long imagesTextCount;
private long patchInfoAddr;
@ -101,7 +101,7 @@ public class DyldCacheHeader implements StructConverter {
private long swiftOptsOffset;
private long swiftOptsSize;
private int subCacheArrayOffset;
private int subCacheArrayCount;
private Integer subCacheArrayCount;
private byte[] symbolFileUUID;
private long rosettaReadOnlyAddr;
private long rosettaReadOnlySize;
@ -109,8 +109,14 @@ public class DyldCacheHeader implements StructConverter {
private long rosettaReadWriteSize;
private int imagesOffset;
private int imagesCount;
private Integer cacheSubType;
private long objcOptsOffset;
private long objcOptsSize;
private long cacheAtlasOffset;
private long cacheAtlasSize;
private long dynamicDataOffset;
private long dynamicDataMaxSize;
private int headerType;
private int headerSize;
private BinaryReader reader;
private long baseAddress;
@ -136,18 +142,13 @@ public class DyldCacheHeader implements StructConverter {
this.reader = reader;
long startIndex = reader.getPointerIndex();
// HEADER 1: https://opensource.apple.com/source/dyld/dyld-95.3/launch-cache/dyld_cache_format.h.auto.html
headerType = 1;
magic = reader.readNextByteArray(16);
mappingOffset = reader.readNextInt();
mappingCount = 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
if (reader.getPointerIndex() < mappingOffset) {
headerType = 2;
codeSignatureOffset = reader.readNextLong();
codeSignatureSize = reader.readNextLong();
}
@ -155,40 +156,33 @@ public class DyldCacheHeader implements StructConverter {
slideInfoOffset = reader.readNextLong();
slideInfoSize = reader.readNextLong();
}
// HEADER 3: No header file for this version (without the following UUID), but there are images of this version
if (reader.getPointerIndex() < mappingOffset) {
headerType = 3;
localSymbolsOffset = reader.readNextLong();
localSymbolsSize = reader.readNextLong();
}
// HEADER 4: https://opensource.apple.com/source/dyld/dyld-239.3/launch-cache/dyld_cache_format.h.auto.html
if (reader.getPointerIndex() < mappingOffset) {
headerType = 4;
uuid = reader.readNextByteArray(16);
}
// HEADER 5: https://opensource.apple.com/source/dyld/dyld-360.14/launch-cache/dyld_cache_format.h.auto.html
if (reader.getPointerIndex() < mappingOffset) {
headerType = 5;
cacheType = reader.readNextLong();
}
// HEADER 6: https://opensource.apple.com/source/dyld/dyld-421.1/launch-cache/dyld_cache_format.h.auto.html
if (reader.getPointerIndex() < mappingOffset) {
headerType = 6;
branchPoolsOffset = reader.readNextInt();
branchPoolsCount = reader.readNextInt();
accelerateInfoAddr = reader.readNextLong();
accelerateInfoSize = reader.readNextLong();
imagesTextOffset = reader.readNextLong();
imagesTextCount = reader.readNextLong();
}
// HEADER 7: https://opensource.apple.com/source/dyld/dyld-832.7.1/dyld3/shared-cache/dyld_cache_format.h.auto.html
if (reader.getPointerIndex() < mappingOffset) {
headerType = 7;
branchPoolsCount = reader.readNextInt();
}
if (reader.getPointerIndex() < mappingOffset) {
accelerateInfoAddr_dyldInCacheMH = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
accelerateInfoSize_dyldInCacheEntry = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
imagesTextOffset = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
imagesTextCount = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
patchInfoAddr = reader.readNextLong();
@ -265,11 +259,6 @@ public class DyldCacheHeader implements StructConverter {
if (reader.getPointerIndex() < mappingOffset) {
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();
}
@ -337,9 +326,29 @@ public class DyldCacheHeader implements StructConverter {
if (reader.getPointerIndex() < mappingOffset) {
imagesCount = reader.readNextInt();
}
// HEADER 9: <unknown>
if (reader.getPointerIndex() < mappingOffset) {
headerType = 9;
cacheSubType = reader.readNextInt();
}
if (reader.getPointerIndex() < mappingOffset) {
padding = reader.readNextInt();
}
if (reader.getPointerIndex() < mappingOffset) {
objcOptsOffset = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
objcOptsSize = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
cacheAtlasOffset = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
cacheAtlasSize = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
dynamicDataOffset = reader.readNextLong();
}
if (reader.getPointerIndex() < mappingOffset) {
dynamicDataMaxSize = reader.readNextLong();
}
headerSize = (int) (reader.getPointerIndex() - startIndex);
@ -366,29 +375,20 @@ public class DyldCacheHeader implements StructConverter {
*/
public void parseFromFile(boolean parseLocalSymbols, MessageLog log, TaskMonitor monitor)
throws CancelledException {
if (headerType >= 1) {
parseMappingInfo(log, monitor);
parseImageInfo(log, monitor);
}
if (headerType >= 3) {
if (parseLocalSymbols) {
parseLocalSymbolsInfo(log, monitor);
}
}
if (headerType >= 6) {
parseBranchPools(log, monitor);
parseImageTextInfo(log, monitor);
}
if (headerType >= 8) {
parseSubcaches(log, monitor);
}
parseMappingInfo(log, monitor);
parseImageInfo(log, monitor);
parseLocalSymbolsInfo(parseLocalSymbols, log, monitor);
parseBranchPools(log, monitor);
parseImageTextInfo(log, monitor);
parseSubcaches(log, monitor);
parseCacheMappingSlideInfo(log, monitor);
if (hasSlideInfo()) {
parseSlideInfos(log, monitor);
}
parseSlideInfos(log, monitor);
}
private void parseSlideInfos(MessageLog log, TaskMonitor monitor) throws CancelledException {
if (!hasSlideInfo()) {
return;
}
if (slideInfoOffset != 0) {
DyldCacheSlideInfoCommon slideInfo = parseSlideInfo(slideInfoOffset, log, monitor);
if (slideInfo != null) {
@ -445,9 +445,7 @@ public class DyldCacheHeader implements StructConverter {
*/
public void parseFromMemory(Program program, AddressSpace space, MessageLog log,
TaskMonitor monitor) throws CancelledException {
if (headerType >= 6) {
parseAcceleratorInfo(program, space, log, monitor);
}
parseAcceleratorInfo(program, space, log, monitor);
}
/**
@ -462,31 +460,17 @@ public class DyldCacheHeader implements StructConverter {
*/
public void markup(Program program, boolean markupLocalSymbols, AddressSpace space,
TaskMonitor monitor, MessageLog log) throws CancelledException {
if (headerType >= 1) {
markupHeader(program, space, monitor, log);
markupMappingInfo(program, space, monitor, log);
markupImageInfo(program, space, monitor, log);
}
if (headerType >= 2) {
markupCodeSignature(program, space, monitor, log);
markupSlideInfo(program, space, monitor, log);
}
if (headerType >= 3) {
if (markupLocalSymbols) {
markupLocalSymbolsInfo(program, space, monitor, log);
}
}
if (headerType >= 6) {
markupBranchPools(program, space, monitor, log);
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);
}
markupHeader(program, space, monitor, log);
markupMappingInfo(program, space, monitor, log);
markupImageInfo(program, space, monitor, log);
markupLocalSymbolsInfo(markupLocalSymbols, program, space, monitor, log);
markupCodeSignature(program, space, monitor, log);
markupSlideInfo(program, space, monitor, log);
markupBranchPools(program, space, monitor, log);
markupAcceleratorInfo(program, space, monitor, log);
markupImageTextInfo(program, space, monitor, log);
markupSubcacheEntries(program, space, monitor, log);
markupCacheMappingSlideInfo(program, space, log, monitor);
}
/**
@ -643,47 +627,32 @@ public class DyldCacheHeader implements StructConverter {
StructureDataType struct = new StructureDataType("dyld_cache_header", 0);
// @formatter:off
// headerType 1
//
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, "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
//
addHeaderField(struct, QWORD, "codeSignatureOffset", "file offset of code signature blob");
addHeaderField(struct, QWORD, "codeSignatureSize","size of code signature blob (zero means to end of file)");
addHeaderField(struct, QWORD, "slideInfoOffset", "file offset of kernel slid info");
addHeaderField(struct, QWORD, "slideInfoSize", "size of kernel slid info");
// headerType 3
//
addHeaderField(struct, QWORD, "localSymbolsOffset","file offset of where local symbols are stored");
addHeaderField(struct, QWORD, "localSymbolsSize", "size of local symbols information");
// headerType 4
//
addHeaderField(struct, new ArrayDataType(BYTE, 16, 1), "uuid","unique value for each shared cache file");
// headerType 5
//
addHeaderField(struct, QWORD, "cacheType", "0 for development, 1 for production");
// headerType 6
//
addHeaderField(struct, DWORD, "branchPoolsOffset","file offset to table of uint64_t pool addresses");
addHeaderField(struct, DWORD, "branchPoolsCount", "number of uint64_t entries");
addHeaderField(struct, QWORD, "accelerateInfoAddr","(unslid) address of optimization info");
addHeaderField(struct, QWORD, "accelerateInfoSize", "size of optimization info");
if (hasAccelerateInfo()) {
addHeaderField(struct, QWORD, "accelerateInfoAddr","(unslid) address of optimization info");
addHeaderField(struct, QWORD, "accelerateInfoSize", "size of optimization info");
}
else {
addHeaderField(struct, QWORD, "dyldInCacheMH","(unslid) address of mach_header of dyld in cache");
addHeaderField(struct, QWORD, "dyldInCacheEntry", "(unslid) address of entry point (_dyld_start) of dyld in cache");
}
addHeaderField(struct, QWORD, "imagesTextOffset","file offset to first dyld_cache_image_text_info");
addHeaderField(struct, QWORD, "imagesTextCount","number of dyld_cache_image_text_info entries");
// headerType 7
//
addHeaderField(struct, QWORD, "patchInfoAddr", "(unslid) address of dyld_cache_patch_info");
addHeaderField(struct, QWORD, "patchInfoSize", "Size of all of the patch information pointed to via the dyld_cache_patch_info");
addHeaderField(struct, QWORD, "otherImageGroupAddrUnused", "unused");
@ -707,9 +676,6 @@ public class DyldCacheHeader implements StructConverter {
addHeaderField(struct, QWORD, "otherTrieSize","size of trie of dylibs and bundles with dlopen closures");
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 ");
@ -730,6 +696,14 @@ public class DyldCacheHeader implements StructConverter {
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");
addHeaderField(struct, DWORD, "cacheSubType", "0 for development, 1 for production, when cacheType is multi-cache(2)");
addHeaderField(struct, DWORD, "padding", "");
addHeaderField(struct, QWORD, "objcOptsOffset", "VM offset from cache_header* to ObjC optimizations header");
addHeaderField(struct, QWORD, "objcOptsSize", "size of ObjC optimizations header");
addHeaderField(struct, QWORD, "cacheAtlasOffset", "VM offset from cache_header* to embedded cache atlas for process introspection");
addHeaderField(struct, QWORD, "cacheAtlasSize", "size of embedded cache atlas");
addHeaderField(struct, QWORD, "dynamicDataOffset", "VM offset from cache_header* to the location of dyld_cache_dynamic_data_header");
addHeaderField(struct, QWORD, "dynamicDataMaxSize", "maximum size of space reserved from dynamic data");
// @formatter:on
struct.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY));
@ -789,9 +763,9 @@ public class DyldCacheHeader implements StructConverter {
return slideInfo;
}
private void parseLocalSymbolsInfo(MessageLog log, TaskMonitor monitor)
private void parseLocalSymbolsInfo(boolean shouldParse, MessageLog log, TaskMonitor monitor)
throws CancelledException {
if (localSymbolsOffset == 0) {
if (!shouldParse || localSymbolsOffset == 0) {
return;
}
monitor.setMessage("Parsing DYLD local symbols info...");
@ -856,7 +830,7 @@ public class DyldCacheHeader implements StructConverter {
try {
reader.setPointerIndex(subCacheArrayOffset);
for (int i = 0; i < subCacheArrayCount; ++i) {
subcacheEntryList.add(new DyldSubcacheEntry(reader, headerType));
subcacheEntryList.add(new DyldSubcacheEntry(reader));
monitor.checkCancelled();
monitor.incrementProgress(1);
}
@ -869,12 +843,12 @@ public class DyldCacheHeader implements StructConverter {
private void parseAcceleratorInfo(Program program, AddressSpace space, MessageLog log,
TaskMonitor monitor) throws CancelledException {
if (accelerateInfoAddr == 0 || headerType >= 9) {
if (!hasAccelerateInfo() || accelerateInfoAddr_dyldInCacheMH == 0) {
return;
}
monitor.setMessage("Parsing DYLD accelerateor info...");
monitor.initialize(imagesTextCount);
Address addr = space.getAddress(accelerateInfoAddr);
Address addr = space.getAddress(accelerateInfoAddr_dyldInCacheMH);
try (ByteProvider bytes = new MemoryByteProvider(program.getMemory(), addr)) {
BinaryReader memoryReader =
new BinaryReader(bytes, !program.getLanguage().isBigEndian());
@ -1002,8 +976,11 @@ public class DyldCacheHeader implements StructConverter {
}
}
private void markupLocalSymbolsInfo(Program program, AddressSpace space, TaskMonitor monitor,
MessageLog log) throws CancelledException {
private void markupLocalSymbolsInfo(boolean shouldMarkup, Program program, AddressSpace space,
TaskMonitor monitor, MessageLog log) throws CancelledException {
if (!shouldMarkup) {
return;
}
monitor.setMessage("Marking up DYLD local symbols info...");
monitor.initialize(1);
try {
@ -1047,8 +1024,8 @@ public class DyldCacheHeader implements StructConverter {
monitor.setMessage("Marking up DYLD accelerator info...");
monitor.initialize(1);
try {
if (accelerateInfo != null && headerType < 9) {
Address addr = space.getAddress(accelerateInfoAddr);
if (hasAccelerateInfo() && accelerateInfo != null) {
Address addr = space.getAddress(accelerateInfoAddr_dyldInCacheMH);
DataUtilities.createData(program, addr, accelerateInfo.toDataType(), -1,
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
accelerateInfo.markup(program, addr, monitor, log);
@ -1157,11 +1134,9 @@ public class DyldCacheHeader implements StructConverter {
// this is no longer used, but if non-zero, is older format and has slide-info
return true;
}
if (headerType > 6) {
for (DyldCacheMappingAndSlideInfo info : cacheMappingAndSlideInfoList) {
if (info.getSlideInfoFileSize() != 0) {
return true;
}
for (DyldCacheMappingAndSlideInfo info : cacheMappingAndSlideInfoList) {
if (info.getSlideInfoFileSize() != 0) {
return true;
}
}
return false;
@ -1179,9 +1154,19 @@ public class DyldCacheHeader implements StructConverter {
/**
* Checks to see whether or not this is a subcache
*
* @return True if this is a subcache; otherwise, false if its a base cache
* @return True if this is a subcache; otherwise, false if it's a base cache
*/
public boolean isSubcache() {
return headerType >= 8 && subCacheArrayCount == 0 && symbolFileUUID == null;
return subCacheArrayCount != null && subCacheArrayCount == 0 && symbolFileUUID == null;
}
/**
* Checks to see whether or not the old accelerate info fields are being used
*
* @return True if the old accelerate info fields are being used; otherwise, false if the new
* dyldInCache fields are being used
*/
public boolean hasAccelerateInfo() {
return cacheSubType == null;
}
}

View File

@ -36,21 +36,19 @@ public class DyldSubcacheEntry implements StructConverter {
private long cacheVMOffset;
private byte[] cacheExtension;
private long headerType;
/**
* Create a new {@link DyldSubcacheEntry}.
*
* @param reader A {@link BinaryReader} positioned at the start of a DYLD subCache entry
* @param headerType The header type value
* @throws IOException if there was an IO-related problem creating the DYLD subCache entry
*/
public DyldSubcacheEntry(BinaryReader reader, long headerType) throws IOException {
this.headerType = headerType;
public DyldSubcacheEntry(BinaryReader reader) throws IOException {
uuid = reader.readNextByteArray(16);
cacheVMOffset = reader.readNextLong();
if (supportsCacheExtension()) {
// A bit of a hack. Is there a safer way to know if you are reading a dyld_subcache_entry
// or a dyld_subcache_entry_v1?
if (reader.readByte(reader.getPointerIndex()) == '.') {
cacheExtension = reader.readNextByteArray(32);
}
}
@ -97,20 +95,11 @@ public class DyldSubcacheEntry implements StructConverter {
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()) {
if (cacheExtension != null) {
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 headerType >= 9;
}
}