Files
ipsw/hack/extras/Dyld.bt

1428 lines
45 KiB
Plaintext

//------------------------------------------------
//--- 010 Editor v10.0 Binary Template
//
// File: Dyld.bt
// Authors: blacktop
// Version: 1.0
// Purpose:
// Category: Executable
// File Mask: dyld_shared_cache*
// ID Bytes: 64 79 6C 64
// History:
//------------------------------------------------
#define MH_MAGIC_64 0xfeedfacf /* the 64-bit mach magic number */
#define MH_CIGAM_64 0xcffaedfe /* NXSwapInt(MH_MAGIC_64) */
#define MH_MAGIC 0xfeedface /* the mach magic number */
#define MH_CIGAM 0xcefaedfe /* NXSwapInt(MH_MAGIC) */
typedef ubyte Uuid[16]<read = readUUID, format = hex>;
typedef struct
{
union
{
char n_name[4]; /* for use when in-core */
uint32 n_strx; /* index into the string table */
} n_un;
uchar n_type; /* type flag, see below */
uchar n_sect; /* section number or NO_SECT */
int16 n_desc; /* see <mach-o/stab.h> */
uint32 n_value; /* value of this symbol (or stab offset) */
} nlist;
/*
* This is the symbol table entry structure for 64-bit architectures.
*/
typedef struct
{
union
{
uint32 n_strx; /* index into the string table */
} n_un;
uchar n_type; /* type flag, see below */
uchar n_sect; /* section number or NO_SECT */
uint16 n_desc; /* see <mach-o/stab.h> */
uint64 n_value; /* value of this symbol (or stab offset) */
} nlist_64;
typedef enum<uint>
{
unknown = 0,
macOS = 1, // PLATFORM_MACOS
iOS = 2, // PLATFORM_IOS
tvOS = 3, // PLATFORM_TVOS
watchOS = 4, // PLATFORM_WATCHOS
bridgeOS = 5, // PLATFORM_BRIDGEOS
iOSMac = 6, // PLATFORM_MACCATALYST
iOS_simulator = 7, // PLATFORM_IOSSIMULATOR
tvOS_simulator = 8, // PLATFORM_TVOSSIMULATOR
watchOS_simulator = 9, // PLATFORM_WATCHOSSIMULATOR
driverKit = 10, // PLATFORM_DRIVERKIT
} Platform<format = hex>;
typedef enum<uint>
{
kDyldSharedCacheTypeDevelopment = 0,
kDyldSharedCacheTypeProduction = 1,
kDyldSharedCacheTypeUniversal = 2,
} CacheType<format = decimal>;
typedef struct
{
uint32 version;
} Version<read = VersionRead>;
string VersionRead(Version &version)
{
local string version_string;
if (version.version & 0xFF == 0)
{
SPrintf(version_string, "%u.%u", version.version >> 16, (version.version >> 8) & 0xFF);
}
else
{
SPrintf(version_string, "%u.%u.%u", version.version >> 16, (version.version >> 8) & 0xFF, version.version & 0xFF);
}
return version_string;
}
typedef struct
{
char magic[16]<bgcolor = cLtBlue>; // e.g. "dyld_v0 i386"
uint mappingOffset; // file offset to first dyld_cache_mapping_info
uint mappingCount; // number of dyld_cache_mapping_info entries
uint32 imagesOffsetOld; // UNUSED: moved to imagesOffset to prevent older dsc_extarctors from crashing
uint32 imagesCountOld; // UNUSED: moved to imagesCount to prevent older dsc_extarctors from crashing
uint64 dyldBaseAddress; // base address of dyld when cache was built
uint64 codeSignatureOffset; // file offset of code signature blob
uint64 codeSignatureSize; // size of code signature blob (zero means to end of file)
uint64 slideInfoOffset; // file offset of kernel slid info
uint64 slideInfoSize; // size of kernel slid info
uint64 localSymbolsOffset; // file offset of where local symbols are stored
uint64 localSymbolsSize; // size of local symbols information
Uuid uuid; // unique value for each shared cache file
uint64 cacheType; // 0 for development, 1 for production, 2 for multi-cache
uint branchPoolsOffset; // file offset to table of uint64 pool addresses
uint branchPoolsCount; // number of uint64 entries
uint64 dyldInCacheMH; // (unslid) address of mach_header of dyld in cache
uint64 dyldInCacheEntry; // (unslid) address of entry point (_dyld_start) of dyld in cache
uint64 imagesTextOffset; // file offset to first dyld_cache_image_text_info
uint64 imagesTextCount; // number of dyld_cache_image_text_info entries
uint64 patchInfoAddr; // (unslid) address of dyld_cache_patch_info
uint64 patchInfoSize; // Size of all of the patch information pointed to via the dyld_cache_patch_info
uint64 otherImageGroupAddrUnused; // unused
uint64 otherImageGroupSizeUnused; // unused
uint64 progClosuresAddr; // (unslid) address of list of program launch closures
uint64 progClosuresSize; // size of list of program launch closures
uint64 progClosuresTrieAddr; // (unslid) address of trie of indexes into program launch closures
uint64 progClosuresTrieSize; // size of trie of indexes into program launch closures
uint platform; // platform number (macOS=1, etc)
uint formatVersion : 8; // dyld3::closure::kFormatVersion
uint dylibsExpectedOnDisk : 1; // dyld should expect the dylib exists on disk and to compare inode/mtime to see if cache is valid
uint simulator : 1; // for simulator of specified platform
uint locallyBuiltCache : 1; // 0 for B&I built cache, 1 for locally built cache
uint builtFromChainedFixups : 1; // some dylib in cache was built using chained fixups, so patch tables must be used for overrides
uint newFormatTLVs : 1; // TLVs have been set by cache builder as new format (not needing runtime side table)
uint padding : 19; // TBD
uint64 sharedRegionStart; // base load address of cache if not slid
uint64 sharedRegionSize; // overall size of region cache can be mapped into
uint64 maxSlide<format = hex>; // runtime slide of cache can be between zero and this value
uint64 dylibsImageArrayAddr; // (unslid) address of ImageArray for dylibs in this cache
uint64 dylibsImageArraySize; // size of ImageArray for dylibs in this cache
uint64 dylibsTrieAddr; // (unslid) address of trie of indexes of all cached dylibs
uint64 dylibsTrieSize; // size of trie of cached dylib paths
uint64 otherImageArrayAddr; // (unslid) address of ImageArray for dylibs and bundles with dlopen closures
uint64 otherImageArraySize; // size of ImageArray for dylibs and bundles with dlopen closures
uint64 otherTrieAddr; // (unslid) address of trie of indexes of all dylibs and bundles with dlopen closures
uint64 otherTrieSize; // size of trie of dylibs and bundles with dlopen closures
uint32 mappingWithSlideOffset; // file offset to first dyld_cache_mapping_and_slide_info
uint32 mappingWithSlideCount; // number of dyld_cache_mapping_and_slide_info entries
uint64 dylibsPBLStateArrayAddrUnused; // unused
uint64 dylibsPBLSetAddr; // (unslid) address of PrebuiltLoaderSet of all cached dylibs
uint64 programsPBLSetPoolAddr; // (unslid) address of pool of PrebuiltLoaderSet for each program
uint64 programsPBLSetPoolSize; // size of pool of PrebuiltLoaderSet for each program
uint64 programTrieAddr; // (unslid) address of trie mapping program path to PrebuiltLoaderSet
uint32 programTrieSize;
Version osVersion; // OS Version of dylibs in this cache for the main platform
Platform altPlatform; // e.g. iOSMac on macOS
Version altOsVersion; // e.g. 14.0 for iOSMac
uint64 swiftOptsOffset; // file offset to Swift optimizations header
uint64 swiftOptsSize; // size of Swift optimizations header
uint32 subCacheArrayOffset; // file offset to first dyld_subcache_entry
uint32 subCacheArrayCount; // number of subCache entries
Uuid symbolFileUUID; // unique value for the shared cache file containing unmapped local symbols
uint64 rosettaReadOnlyAddr; // (unslid) address of the start of where Rosetta can add read-only/executable data
uint64 rosettaReadOnlySize; // maximum size of the Rosetta read-only/executable region
uint64 rosettaReadWriteAddr; // (unslid) address of the start of where Rosetta can add read-write data
uint64 rosettaReadWriteSize; // maximum size of the Rosetta read-write region
uint32 imagesOffset; // file offset to first dyld_cache_image_info
uint32 imagesCount; // number of dyld_cache_image_info entries
uint32 cacheSubType; // 0 for development, 1 for production, when cacheType is multi-cache(2)
uint32 padding;
uint64 objcOptsOffset; // VM offset from cache_header* to ObjC optimizations header
uint64 objcOptsSize; // size of ObjC optimizations header
uint64 cacheAtlasOffset; // VM offset from cache_header* to embedded cache atlas for process introspection
uint64 cacheAtlasSize; // size of embedded cache atlas
uint64 dynamicDataOffset; // VM offset from cache_header* to the location of dyld_cache_dynamic_data_header
uint64 dynamicDataMaxSize; // maximum size of space reserved from dynamic dataz
uint32 tProMappingOffset; // file offset to first dyld_cache_tpro_mapping_info
uint32 tProMappingCount; // number of dyld_cache_tpro_mapping_info entries
uint64 functionVariantInfoAddr;// (unslid) address of dyld_cache_function_variant_info
uint64 functionVariantInfoSize;// Size of all of the variant information pointed to via the dyld_cache_function_variant_info
uint64 prewarmingDataOffset; // file offset to dyld_prewarming_header
uint64 prewarmingDataSize; // byte size of prewarming data
} dyld_cache_header;
typedef struct
{
uint64 address;
uint64 size;
uint64 fileOffset;
uint32 maxProt;
uint32 initProt;
} dyld_cache_mapping_info<bgcolor = cBlue>;
typedef struct
{
uint64 address;
uint64 size;
uint64 fileOffset;
uint64 slideInfoFileOffset;
uint64 slideInfoFileSize;
uint64 flags;
uint32 maxProt;
uint32 initProt;
} dyld_cache_mapping_and_slide_info<bgcolor = cBlue>;
typedef struct
{
uint64 address;
uint64 modTime;
uint64 inode;
uint32 pathFileOffset;
uint32 pad;
} dyld_cache_image_info<read = readimagename, bgcolor = cLtGreen>;
string readimagename(dyld_cache_image_info &info)
{
return ReadString(info.pathFileOffset);
}
typedef struct
{
uint64 exportsTrieAddr; // address of trie in unslid cache
uint64 weakBindingsAddr;
uint32 exportsTrieSize;
uint32 weakBindingsSize;
uint32 dependentsStartArrayIndex;
uint32 reExportsStartArrayIndex;
} dyld_cache_image_info_extra;
typedef struct
{
uint32 version; // currently 1
uint32 imageExtrasCount; // does not include aliases
uint32 imagesExtrasOffset; // offset into this chunk of first dyld_cache_image_info_extra
uint32 bottomUpListOffset; // offset into this chunk to start of 16-bit array of sorted image indexes
uint32 dylibTrieOffset; // offset into this chunk to start of trie containing all dylib paths
uint32 dylibTrieSize; // size of trie containing all dylib paths
uint32 initializersOffset; // offset into this chunk to start of initializers list
uint32 initializersCount; // size of initializers list
uint32 dofSectionsOffset; // offset into this chunk to start of DOF sections list
uint32 dofSectionsCount; // size of initializers list
uint32 reExportListOffset; // offset into this chunk to start of 16-bit array of re-exports
uint32 reExportCount; // size of re-exports
uint32 depListOffset; // offset into this chunk to start of 16-bit array of dependencies (0x8000 bit set if upward)
uint32 depListCount; // size of dependencies
uint32 rangeTableOffset; // offset into this chunk to start of ss
uint32 rangeTableCount; // size of dependencies
uint64 dyldSectionAddr; // address of libdyld's __dyld section in unslid cache
} dyld_cache_accelerator_info;
typedef struct
{
uint32 functionOffset; // address offset from start of cache mapping
uint32 imageIndex;
} dyld_cache_accelerator_initializer;
typedef struct
{
uint64 startAddress; // unslid address of start of region
uint32 size;
uint32 imageIndex;
} dyld_cache_range_entry;
typedef struct
{
uint64 sectionAddress; // unslid address of start of region
uint32 sectionSize;
uint32 imageIndex;
} dyld_cache_accelerator_dof;
typedef struct
{
Uuid uuid;
uint64 loadAddress; // unslid address of start of __TEXT
uint32 textSegmentSize;
uint32 pathOffset; // offset from start of cache file
} dyld_cache_image_text_info<read = readimagetextname, bgcolor = cGreen>;
string readimagetextname(dyld_cache_image_text_info &tinfo)
{
return ReadString(tinfo.pathOffset);
}
// typedef struct
// {
// local uint64 base = FTell();
// uint32 version; // currently 1
// uint32 toc_offset<format = hex>;
// uint32 toc_count;
// uint32 entries_offset<format = hex>;
// uint32 entries_count;
// uint32 entries_size; // currently 128
// FSeek(base + toc_offset);
// uint16 toc[toc_count];
// FSeek(base + entries_offset);
// uchar entries[entries_count * entries_size];
// } dyld_cache_slide_info;
// void get_dyld_cache_slide_info(uint64 totalsize)
// {
// dyld_cache_slide_info slideinfo;
// }
char[] showstring64(nlist_64 &list)
{
return ReadString(strtableoff + list.n_un.n_strx);
}
char[] showstring(nlist &list)
{
return ReadString(strtableoff + list.n_un.n_strx);
}
void readliststring()
{
if (isbit64)
{
nlist_64 nlists<read = showstring64>;
}
else
{
nlist nlists<read = showstring>;
}
}
typedef struct
{
uint32 dylibOffset; // offset in cache file of start of dylib
uint32 nlistStartIndex; // start index of locals for this dylib
uint32 nlistCount; // number of local symbols for this dylib
} dyld_cache_local_symbols_entry;
typedef struct
{
uint64 dylibOffset; // offset in cache file of start of dylib
uint32 nlistStartIndex; // start index of locals for this dylib
uint32 nlistCount; // number of local symbols for this dylib
} dyld4_cache_local_symbols_entry;
typedef struct(uint count)
{
for (i = 0; i < count; i++)
{
readliststring();
}
}
allnlist;
struct dyld_cache_slide_info2
{
uint32 version; // currently 2
uint32 page_size; // currently 4096 (may also be 16384)
uint32 page_starts_offset;
uint32 page_starts_count;
uint32 page_extras_offset;
uint32 page_extras_count;
uint64 delta_mask; // which (contiguous) set of bits contains the delta to the next rebase location
uint64 value_add;
uint16 page_starts[page_starts_count];
uint16 page_extras[page_extras_count];
};
#define DYLD_CACHE_SLIDE_PAGE_ATTRS 0xC000 // high bits of uint16_t are flags
#define DYLD_CACHE_SLIDE_PAGE_ATTR_EXTRA 0x8000 // index is into extras array (not starts array)
#define DYLD_CACHE_SLIDE_PAGE_ATTR_NO_REBASE 0x4000 // page has no rebasing
#define DYLD_CACHE_SLIDE_PAGE_ATTR_END 0x8000 // last chain entry for page
typedef struct
{
local uint64 base = FTell();
local uint i;
uint32 nlistOffset; // offset into this chunk of nlist entries
uint32 nlistCount; // count of nlist entries
uint32 stringsOffset; // offset into this chunk of string pool
uint32 stringsSize; // byte count of string pool
uint32 entriesOffset; // offset into this chunk of array of dyld_cache_local_symbols_entry
uint32 entriesCount; // number of elements in dyld_cache_local_symbols_entry array
FSeek(base + nlistOffset);
strtableoff = base + stringsOffset;
// allnlist lists(nlistCount);
FSeek(base + entriesOffset);
if (header.imagesOffsetOld > 0)
{
dyld_cache_local_symbols_entry nlistentry[entriesCount];
}
else
{
dyld4_cache_local_symbols_entry nlistentry[entriesCount];
}
} dyld_cache_local_symbols_info;
typedef struct
{
uint32 version;
uint32 padding;
uint64 typeConformanceHashTableCacheOffset;
uint64 metadataConformanceHashTableCacheOffset;
uint64 foreignTypeConformanceHashTableCacheOffset;
} SwiftOptimizationHeader<bgcolor = cPurple>;
typedef struct
{
uint32 capacity;
uint32 occupied;
uint32 shift;
uint32 mask;
uint32 sentinelTarget;
uint32 roundedTabSize;
uint64 salt;
uint32 scramble[256];
uchar tab0; /* tab[mask+1] (always power-of-2). Rounded up to roundedTabSize */
} SwiftHashTable<bgcolor = cLtPurple>;
void get_dyld_cache_local_symbols_info(uint64 totalsize)
{
dyld_cache_local_symbols_info symbolinfo;
}
void get_dyld_cache_local_symbols_entry(uint64 totalsize)
{
}
LittleEndian();
local int isbit64 = 0;
local uint32 i;
local uint32 sig;
local uint64 strtableoff;
dyld_cache_header header;
FSeek(header.mappingOffset);
dyld_cache_mapping_info mapinfo[header.mappingCount];
FSeek(header.mappingWithSlideOffset);
dyld_cache_mapping_and_slide_info mapWithSlideInfo[header.mappingWithSlideCount];
for (i = 0; i < header.mappingCount; i++)
{
sig = ReadUInt(mapinfo[i].fileOffset);
if (sig == MH_MAGIC_64 || sig == MH_CIGAM_64)
{
isbit64 = 1;
}
}
if (header.imagesOffsetOld > 0)
{
FSeek(header.imagesOffsetOld);
dyld_cache_image_info imageinfo[header.imagesCountOld];
}
else if (header.imagesOffset > 0)
{
FSeek(header.imagesOffset);
dyld_cache_image_info imageinfo[header.imagesCount];
}
// FSeek(header.imagesTextOffset);
// dyld_cache_image_text_info imagetext[header.imagesTextCount];
// FIXME: this is wrong for iOS16 caches
// if (header.imagesOffsetOld == 0 && header.swiftOptsOffset > 0)
// {
// FSeek(header.swiftOptsOffset);
// SwiftOptimizationHeader swiftOpt;
// FSeek(swiftOpt.typeConformanceHashTableCacheOffset);
// SwiftHashTable typeConformance;
// FSeek(swiftOpt.metadataConformanceHashTableCacheOffset);
// SwiftHashTable metadataConformance;
// FSeek(swiftOpt.foreignTypeConformanceHashTableCacheOffset);
// SwiftHashTable foreignTypeConformance;
// }
typedef struct
{
Uuid uuid; // UUID of subcache
uint64 cacheVMOffset<format = hex>; // The offset of this subcache from the main cache base address
} dyld_subcache_entry<bgcolor = cLtPurple>;
typedef struct
{
Uuid uuid; // UUID of subcache
uint64 cacheVMOffset<format = hex>; // The offset of this subcache from the main cache base address
char extension[32];
} dyld_subcache_entry_pagein_link<bgcolor = cLtPurple>;
if (header.subCacheArrayOffset > 0 && header.subCacheArrayCount > 0)
{
if (header.mappingOffset >= 0x200)
{
FSeek(header.subCacheArrayOffset);
dyld_subcache_entry_pagein_link info[header.subCacheArrayCount];
}
else
{
FSeek(header.subCacheArrayOffset);
dyld_subcache_entry info[header.subCacheArrayCount];
}
}
typedef struct
{
uint64 address;
uint64 size;
} tpro_mapping<bgcolor = cLtBlue>;
if (header.mappingOffset >= 0x208)
{
FSeek(header.tProMappingOffset);
tpro_mapping tproMappings[header.tProMappingCount];
}
// FSeek(header.codeSignatureOffset);
// if (header.codeSignatureSize > 0)
// {
// uchar sign[header.codeSignatureSize];
// }
// if (header.slideInfoOffset > 0)
// {
// FSeek(header.slideInfoOffset);
// get_dyld_cache_slide_info(header.slideInfoSize);
// }
if (header.localSymbolsOffset > 0)
{
FSeek(header.localSymbolsOffset);
get_dyld_cache_local_symbols_info(header.localSymbolsSize);
}
// ---------------------------------- macho header ---------------------------------------
// Mach-o's should be Little Endian only -- except for the fat_header/fat_arch
LittleEndian();
typedef enum<uint>
{
MACHO_32 = 0xFEEDFACE, // 32-bit mach object file
MACHO_64 = 0xFEEDFACF, // 64-bit mach object file
MACHO_FAT = 0xCAFEBABE, // Universal object file / FAT_MAGIC
MACHO_FAT_CIGAM = 0xBEBAFECA
} Magic<format = hex>;
#define CPU_ARCH_MASK 0xff000000
#define CPU_ARCH_ABI64 0x01000000
// Changed to enum, more info and handles constant | macro fine //
//
typedef enum<uint>
{
CPU_TYPE_X86 = 0x07,
CPU_TYPE_X64 = 0x07 | CPU_ARCH_ABI64,
CPU_TYPE_ARM = 0x0C,
CPU_TYPE_ARM64 = 0x0C | CPU_ARCH_ABI64,
CPU_TYPE_PPC = 0x12,
CPU_TYPE_PPC64 = 0x12 | CPU_ARCH_ABI64,
CPU_TYPE_I386 = CPU_TYPE_X86,
CPU_TYPE_X86_64 = CPU_TYPE_X64,
CPU_TYPE_POWERPC = CPU_TYPE_PPC,
CPU_TYPE_POWERPC64 = CPU_TYPE_PPC64,
} CpuType<format = hex>;
typedef enum<uint>
{
MACH_OBJECT = 0x1,
MACH_EXECUTE = 0x2,
MACH_FVMLIB = 0x3,
MACH_CORE = 0x4,
MACH_PRELOAD = 0x5,
MACH_DYLIB = 0x6,
MACH_DYLINKER = 0x7,
MACH_BUNDLE = 0x8,
MACH_DYLIB_STUB = 0x9,
MACH_DSYM = 0xA,
MACH_KEXT_BUNDLE = 0xB,
} FileType;
typedef enum<uint>
{
i386_THREAD_STATE = 0x1,
i386_FLOAT_STATE = 0x2,
i386_EXCEPTION_STATE = 0x3
} i386ThreadFlavor<format = hex>;
typedef struct
{
uint32 eax<format = hex>;
uint32 ebx<format = hex>;
uint32 ecx<format = hex>;
uint32 edx<format = hex>;
uint32 edi<format = hex>;
uint32 esi<format = hex>;
uint32 ebp<format = hex>;
uint32 esp<format = hex>;
uint32 ss<format = hex>;
uint32 eflags<format = hex>;
uint32 eip<format = hex>;
uint32 cs<format = hex>;
uint32 ds<format = hex>;
uint32 es<format = hex>;
uint32 fs<format = hex>;
uint32 gs<format = hex>;
} i386ThreadState;
typedef enum<uint>
{
x86_THREAD_STATE32 = 0x1,
x86_FLOAT_STATE32 = 0x2,
x86_EXCEPTION_STATE32 = 0x3,
x86_THREAD_STATE64 = 0x4,
x86_FLOAT_STATE64 = 0x5,
x86_EXCEPTION_STATE64 = 0x6,
x86_THREAD_STATE = 0x7,
x86_FLOAT_STATE = 0x8,
x86_EXCEPTION_STATE = 0x9,
x86_DEBUG_STATE32 = 0xA,
x86_DEBUG_STATE64 = 0xB,
x86_DEBUG_STATE = 0xC,
THREAD_STATE_NONE = 0xD
} x86ThreadFlavor<format = hex>;
typedef struct
{
uint64 rax<format = hex>;
uint64 rbx<format = hex>;
uint64 rcx<format = hex>;
uint64 rdx<format = hex>;
uint64 rdi<format = hex>;
uint64 rsi<format = hex>;
uint64 rbp<format = hex>;
uint64 rsp<format = hex>;
uint64 r8<format = hex>;
uint64 r9<format = hex>;
uint64 r10<format = hex>;
uint64 r11<format = hex>;
uint64 r12<format = hex>;
uint64 r13<format = hex>;
uint64 r14<format = hex>;
uint64 r15<format = hex>;
uint64 rip<format = hex>;
uint64 rflags<format = hex>;
uint64 cs<format = hex>;
uint64 fs<format = hex>;
uint64 gs<format = hex>;
} x86ThreadState;
typedef enum<uint>
{
PPC_THREAD_STATE = 0x1,
PPC_FLOAT_STATE = 0x2,
PPC_EXCEPTION_STATE = 0x3,
PPC_VECTOR_STATE = 0x4,
PPC_THREAD_STATE64 = 0x5,
PPC_EXCEPTION_STATE64 = 0x6
} PPCThreadFlavor<format = hex>;
typedef struct
{
uint32 r0<format = hex>;
uint32 r1<format = hex>;
uint32 r2<format = hex>;
uint32 r3<format = hex>;
uint32 r4<format = hex>;
uint32 r5<format = hex>;
uint32 r6<format = hex>;
uint32 r7<format = hex>;
uint32 r8<format = hex>;
uint32 r9<format = hex>;
uint32 r10<format = hex>;
uint32 r11<format = hex>;
uint32 r12<format = hex>;
uint32 r13<format = hex>;
uint32 r14<format = hex>;
uint32 r15<format = hex>;
uint32 r16<format = hex>;
} ARMThreadState;
typedef struct
{
uint32 __srr0<comment = "Instruction address register (PC)">;
uint32 __srr1<comment = "Machine state register (supervisor)">;
uint32 __r0;
uint32 __r1;
uint32 __r2;
uint32 __r3;
uint32 __r4;
uint32 __r5;
uint32 __r6;
uint32 __r7;
uint32 __r8;
uint32 __r9;
uint32 __r10;
uint32 __r11;
uint32 __r12;
uint32 __r13;
uint32 __r14;
uint32 __r15;
uint32 __r16;
uint32 __r17;
uint32 __r18;
uint32 __r19;
uint32 __r20;
uint32 __r21;
uint32 __r22;
uint32 __r23;
uint32 __r24;
uint32 __r25;
uint32 __r26;
uint32 __r27;
uint32 __r28;
uint32 __r29;
uint32 __r30;
uint32 __r31;
uint32 __cr<comment = "Condition register">;
uint32 __xer<comment = "User's integer exception register">;
uint32 __lr<comment = "Link register">;
uint32 __ctr<comment = "Count register">;
uint32 __mq<comment = "MQ Register (601 only)">;
uint32 __vrsave<comment = "Vector save register">;
} PPCThreadState;
typedef enum<uint>
{
MACH_NOUNDEFS = 0x1,
MACH_INCRLINK = 0x2,
MACH_DYLDLINK = 0x4,
MACH_BINDATLOAD = 0x8,
MACH_PREBOUND = 0x10,
MACH_SPLIT_SEGS = 0x20,
MACH_LAZY_INIT = 0x40,
MACH_TWOLEVEL = 0x80,
MACH_FORCE_FLAT = 0x100,
MACH_NOMULTIDEFS = 0x200,
MACH_NOFIXPREBINDING = 0x400,
MACH_PREBINDABLE = 0x800,
MACH_ALLMODSBOUND = 0x1000,
MACH_SUBSECTIONS_VIA_SYMBOLS = 0x2000,
MACH_CANONICAL = 0x4000,
MACH_WEAK_DEFINES = 0x8000,
MACH_BINDS_TO_WEAK = 0x10000,
MACH_ALLOW_STACK_EXECUTION = 0x20000,
MACH_ROOT_SAFE = 0x40000,
MACH_SETUID_SAFE = 0x80000,
MACH_NO_REEXPORTED_DYLIBS = 0x100000,
MACH_PIE = 0x200000,
MACH_DEAD_STRIPPABLE_DYLIB = 0x400000,
MACH_HAS_TLV_DESCRIPTORS = 0x800000,
MACH_NO_HEAP_EXECUTION = 0x1000000
} Flags;
typedef struct
{
// TODO : Extract out capabilities here
CpuType cpu_type<comment = "CPU specifier", format = hex>;
uint32 cpu_sub_type<comment = "Machine specifier", format = hex>;
uint32 file_offset<comment = "Offset of header in file">;
uint32 size<comment = "Size of object file">;
uint32 align<comment = "alignment as a power of two">;
} Fat_Arch;
typedef struct
{
Magic magic<comment = "Magic bytes for the file">;
if (magic == MACHO_FAT || magic == MACHO_FAT_CIGAM)
{
// Need to switch to BigEndian!
BigEndian();
uint32 fat_arch_size<comment = "Number of fat_arch structs">;
Fat_Arch fat_arch[fat_arch_size];
// Switch back to LittleEndian for rest of parsing
LittleEndian();
}
else
{
CpuType cpu_type<comment = "CPU specifier", format = hex>;
uint32 cpu_sub_type<comment = "Machine specifier", format = hex>;
FileType file_type;
uint32 num_load_commands;
uint32 size_of_load_commands;
Flags flags;
}
if (magic == MACHO_64)
{
uint32 reserved;
}
} Header<read = HeaderRead>;
string HeaderRead(Header &header)
{
local string header_string;
switch (header.magic)
{
case MACHO_FAT:
case MACHO_FAT_CIGAM:
header_string = "FAT header";
break;
case MACHO_32:
header_string = "32bit Mach-O header";
break;
case MACHO_64:
header_string = "64bit Mach-O header";
break;
default:
header_string = "Unknown header!";
}
return header_string;
}
#define REQ_DYLD (0x80000000)
typedef enum<uint>
{
SEGMENT = 0x1,
SYM_TAB = 0x2,
SYM_SEG = 0x3,
THREAD = 0x4,
UNIX_THREAD = 0x5,
LOAD_FVM_LIB = 0x6,
ID_FVM_LIB = 0x7,
IDENT = 0x8,
FVM_FILE = 0x9,
PREPAGE = 0xA,
DY_SYM_TAB = 0xB,
LOAD_DYLIB = 0xC,
ID_DYLIB = 0xD,
LOAD_DYLINKER = 0xE,
ID_DYLINKER = 0xF,
PREBOUND_DYLIB = 0x10,
ROUTINES = 0x11,
SUB_FRAMEWORK = 0x12,
SUB_UMBRELLA = 0x13,
SUB_CLIENT = 0x14,
SUB_LIBRARY = 0x15,
TWOLEVEL_HINTS = 0x16,
PREBIND_CKSUM = 0x17,
LOAD_WEAK_DYLIB = 0x18 | REQ_DYLD,
SEGMENT_64 = 0x19,
ROUTINES_64 = 0x1A,
UUID = 0x1B,
RPATH = 0x1C | REQ_DYLD,
CODE_SIGNATURE = 0x1D,
SEGMENT_SPLIT_INFO = 0x1E,
REEXPORT_DYLIB = 0x1F | REQ_DYLD,
LAZY_LOAD_DYLIB = 0x20,
ENCRYPTION_INFO = 0x21,
DYLD_INFO = 0x22,
DYLD_INFO_ONLY = 0x22 | REQ_DYLD,
LOAD_UPWARD_DYLIB = 0x23 | REQ_DYLD,
VERSION_MIN_MAC_OSX = 0x24,
VERSION_MIN_IPHONE_OS = 0x25,
FUNCTION_STARTS = 0x26,
DYLD_ENVIRONMENT = 0x27,
MAIN = 0x28,
MAIN_DYLIB = 0x28 | REQ_DYLD, // Idk, ios app in arm64 uses
DATA_IN_CODE = 0x29,
SOURCE_VERSION = 0x2A,
DYLIB_CODE_SIGN_DRS = 0x2B,
ENCRYPTION_INFO_64 = 0x2c,
LC_BUILD_VERSION = 0x32,
} LoadCommandType<read = LoadCommandTypeRead>;
string LoadCommandTypeRead(LoadCommandType &loadCommandType)
{
switch (loadCommandType)
{
case SEGMENT:
return "SEGMENT";
case SYM_TAB:
return "SYM_TAB";
case SYM_SEG:
return "SYM_SEG";
case THREAD:
return "THREAD";
case UNIX_THREAD:
return "UNIX_THREAD";
case LOAD_FVM_LIB:
return "LOAD_FVM_LIB";
case ID_FVM_LIB:
return "ID_FVM_LIB";
case IDENT:
return "IDENT";
case FVM_FILE:
return "FVM_FILE";
case PREPAGE:
return "PREPAGE";
case DY_SYM_TAB:
return "DY_SYM_TAB";
case LOAD_DYLIB:
return "LOAD_DYLIB";
case ID_DYLIB:
return "ID_DYLIB";
case LOAD_DYLINKER:
return "LOAD_DYLINKER";
case ID_DYLINKER:
return "ID_DYLINKER";
case PREBOUND_DYLIB:
return "PREBOUND_DYLIB";
case ROUTINES:
return "ROUTINES";
case SUB_FRAMEWORK:
return "SUB_FRAMEWORK";
case SUB_UMBRELLA:
return "SUB_UMBRELLA";
case SUB_CLIENT:
return "SUB_CLIENT";
case SUB_LIBRARY:
return "SUB_LIBRARY";
case TWOLEVEL_HINTS:
return "TWOLEVEL_HINTS";
case PREBIND_CKSUM:
return "PREBIND_CKSUM";
case LOAD_WEAK_DYLIB:
return "LOAD_WEAK_DYLIB";
case SEGMENT_64:
return "SEGMENT_64";
case ROUTINES_64:
return "ROUTINES_64";
case UUID:
return "UUID";
case RPATH:
return "RPATH";
case CODE_SIGNATURE:
return "CODE_SIGNATURE";
case SEGMENT_SPLIT_INFO:
return "SEGMENT_SPLIT_INFO";
case REEXPORT_DYLIB:
return "REEXPORT_DYLIB";
case LAZY_LOAD_DYLIB:
return "LAZY_LOAD_DYLIB";
case ENCRYPTION_INFO:
return "ENCRYPTION_INFO";
case DYLD_INFO:
return "DYLD_INFO";
case DYLD_INFO_ONLY:
return "DYLD_INFO_ONLY";
case LOAD_UPWARD_DYLIB:
return "LOAD_UPWARD_DYLIB";
case VERSION_MIN_MAC_OSX:
return "VERSION_MIN_MAC_OSX";
case VERSION_MIN_IPHONE_OS:
return "VERSION_MIN_IPHONE_OS";
case FUNCTION_STARTS:
return "FUNCTION_STARTS";
case DYLD_ENVIRONMENT:
return "DYLD_ENVIRONMENT";
case MAIN:
return "MAIN";
case MAIN_DYLIB:
return "MAIN_DYLIB";
case DATA_IN_CODE:
return "DATA_IN_CODE";
case SOURCE_VERSION:
return "SOURCE_VERSION";
case DYLIB_CODE_SIGN_DRS:
return "DYLIB_CODE_SIGN_DRS";
case ENCRYPTION_INFO_64:
return "ENCRYPTION_INFO_64";
case LC_BUILD_VERSION:
return "LC_BUILD_VERSION";
default:
return "Error";
}
}
typedef struct
{
char section_name[16];
char segment_name[16];
uint32 address<format = hex>;
uint32 size<format = hex>;
uint32 offset;
uint32 section_alignment;
uint32 relocation_entry_offset;
uint32 number_of_relocation_entries;
uint32 flags<format = hex>;
uint32 reserved1;
uint32 reserved2;
} Section<optimize = false>;
typedef struct
{
char section_name[16];
char segment_name[16];
uint64 address<format = hex>;
uint64 size<format = hex>;
uint32 offset;
uint32 section_alignment;
uint32 relocation_entry_offset;
uint32 number_of_relocation_entries;
uint32 flags<format = hex>;
uint32 reserved1;
uint32 reserved2;
uint32 reserved3;
} Section64<optimize = false>;
typedef uint vm_proc;
typedef enum<uint>
{
HIGH_VM = 0x1,
FVM_LIB = 0x2,
NO_RELOC = 0x4,
PROTECTION_VERSION_1 = 0x8
} SegmentFlags<format = hex>;
typedef struct
{
uint32 load_command_string_offset<comment = "Offset in respect to the start of load command to string data">;
local int64 pos = FTell();
// We need to goto beginning of LoadCommand, then goto the offset
FSeek(FTell() - (sizeof(uint32) * 3) + load_command_string_offset);
string string_data<comment = "Load command string">;
FSeek(pos);
} LoadCommandString<read = LoadCommandStringRead>;
string LoadCommandStringRead(LoadCommandString &loadCommandString)
{
return loadCommandString.string_data;
};
typedef ubyte Uuid[16]<read = readUUID, format = hex>;
// TODO : Clean this ugly thing up
string readUUID(Uuid uuid)
{
local string ret, tmp;
local int i;
for (i = 0; i < 4; i++)
{
SPrintf(tmp, "%.2X", uuid[i]);
ret += tmp;
}
ret += "-";
for (i = 0; i < 2; i++)
{
SPrintf(tmp, "%.2X", uuid[i + 4]);
ret += tmp;
}
ret += "-";
for (i = 0; i < 2; i++)
{
SPrintf(tmp, "%.2X", uuid[i + 6]);
ret += tmp;
}
ret += "-";
for (i = 0; i < 2; i++)
{
SPrintf(tmp, "%.2X", uuid[i + 8]);
ret += tmp;
}
ret += "-";
for (i = 0; i < 6; i++)
{
SPrintf(tmp, "%.2X", uuid[i + 10]);
ret += tmp;
}
return ret;
}
string readUUID2(ubyte uuid[16])
{
local string ret, tmp;
local int i;
for (i = 0; i < 4; i++)
{
SPrintf(tmp, "%.2X", uuid[i]);
ret += tmp;
}
ret += "-";
for (i = 0; i < 2; i++)
{
SPrintf(tmp, "%.2X", uuid[i + 4]);
ret += tmp;
}
ret += "-";
for (i = 0; i < 2; i++)
{
SPrintf(tmp, "%.2X", uuid[i + 6]);
ret += tmp;
}
ret += "-";
for (i = 0; i < 2; i++)
{
SPrintf(tmp, "%.2X", uuid[i + 8]);
ret += tmp;
}
ret += "-";
for (i = 0; i < 6; i++)
{
SPrintf(tmp, "%.2X", uuid[i + 10]);
ret += tmp;
}
return ret;
}
typedef struct
{
uint32 tool; // enum for the tool
Version version; // version of the tool
} build_tool_version;
typedef struct
{
local uint64 o_pos = FTell();
// LoadCommandHead loadCommandHead <comment="Load command type and size">;
LoadCommandType command;
uint command_size;
// Process rest of load command based on command type
switch (command)
{
case ID_DYLIB:
case LOAD_DYLIB:
case LOAD_WEAK_DYLIB:
case REEXPORT_DYLIB:
LoadCommandString name;
// TODO : Pretty print this
uint32 timestamp;
// TODO : Pretty print this
uint32 current_version;
// TODO : Pretty print this
uint32 compatibility_version;
break;
case SYM_TAB:
uint32 symbol_table_offset<format = hex, comment = "Symbol table offsett address">;
uint32 number_of_symbol_table_entries<comment = "Number of symbol table entries">;
uint32 string_table_offset<format = hex, comment = "String table offset">;
uint32 string_table_size<comment = "String table size in bytes">;
break;
case DYLD_INFO:
case DYLD_INFO_ONLY:
uint32 rebase_offset;
uint32 rebase_size;
uint32 bind_offset;
uint32 bind_size;
uint32 weak_bind_offset;
uint32 weak_bind_size;
uint32 lazy_bind_offset;
uint32 lazy_bind_size;
uint32 export_offset;
uint32 export_size;
break;
case DY_SYM_TAB:
uint32 index_local_symbols;
uint32 local_symbols_size;
uint32 index_externally_defined_symbols;
uint32 externally_defined_symbols_size;
uint32 index_undefined_symbols;
uint32 undefined_symbols_size;
uint32 table_contents_offset;
uint32 enteries_toc_size;
uint32 file_offset_module_table;
uint32 module_table_entries_size;
uint32 external_references_symbol_table_offset;
uint32 external_references_symbol_table_size;
uint32 indirect_symbol_table_offset;
uint32 indirect_symbol_table_size;
uint32 external_relocation_entries_offset;
uint32 external_relocation_entries_size;
uint32 local_relocation_entries_offset;
uint32 local_relocation_entries_size;
break;
case UUID:
Uuid uuid;
break;
case VERSION_MIN_MAC_OSX:
case VERSION_MIN_IPHONE_OS:
// TODO : Pretty print this
Version version;
uint32 reserved<comment = "Should be zero">;
break;
case FUNCTION_STARTS:
case CODE_SIGNATURE:
case SEGMENT_SPLIT_INFO:
case DATA_IN_CODE:
uint32 data_offset;
uint32 data_size;
break;
case UNIX_THREAD:
case THREAD:
switch (cpu_typer)
{
case CPU_TYPE_X86:
case CPU_TYPE_I386:
i386ThreadFlavor flavor;
// TODO : Pretty print this
uint32 count;
switch (flavor)
{
case i386_THREAD_STATE:
i386ThreadState threadState;
// TODO : Flesh these guys out
case i386_FLOAT_STATE:
case i386_EXCEPTION_STATE:
}
break;
case CPU_TYPE_X86_64:
x86ThreadFlavor flavor;
// TODO : Pretty print this
uint32 count;
switch (flavor)
{
case x86_THREAD_STATE64:
x86ThreadState threadState;
break;
// TODO : Flesh these guys out
case x86_FLOAT_STATE64:
case x86_EXCEPTION_STATE64:
case x86_DEBUG_STATE64:
}
break;
case CPU_TYPE_POWERPC:
case CPU_TYPE_POWERPC64:
PPCThreadFlavor flavor;
// TODO : Pretty print this
uint32 count;
switch (flavor)
{
case PPC_THREAD_STATE:
PPCThreadState threadState;
break;
// TODO : Flesh these guys out
case PPC_FLOAT_STATE:
case PPC_EXCEPTION_STATE:
case PPC_VECTOR_STATE:
case PPC_THREAD_STATE64:
case PPC_EXCEPTION_STATE64:
}
break;
case CPU_TYPE_ARM:
// TODO: Unsure if this is correct ?
// uint32 flavor;
// uint32 count;
ARMThreadState threadState;
break;
}
break;
case FVM_LIB:
case ID_FVM_LIB:
LoadCommandString name<comment = "Fixed virtual memory library's target path name">;
uint32 minor_version<comment = "Library's minor version number">;
uint32 header_address<comment = "Library's header address">;
break;
case SUB_FRAMEWORK:
LoadCommandString umbrella<comment = "Umbrella framework name">;
break;
case SUB_CLIENT:
LoadCommandString client<comment = "Client name">;
break;
case SUB_UMBRELLA:
LoadCommandString sub_umbrella<comment = "Sub umbrella framework name">;
break;
case SUB_LIBRARY:
LoadCommandString sub_library<comment = "Sub library name">;
break;
case PREBOUND_DYLIB:
LoadCommandString name<comment = "Library's path name">;
uint32 modules_size<comment = "Number of modules inside library">;
LoadCommandString linked_modules<comment = "Bit vector of linked modules">;
break;
case ID_DYLINKER:
case LOAD_DYLINKER:
LoadCommandString name<comment = "Dynamic linker's path name">;
break;
case ROUTINES_64:
uint64 init_address<comment = "Address of initialization routine">;
uint64 init_module<comment = "Index into module table that init routine is defined">;
uint32 reversed_1;
uint32 reversed_2;
uint32 reversed_3;
uint32 reversed_4;
uint32 reversed_5;
uint32 reversed_6;
break;
case ROUTINES:
uint32 init_address<comment = "Address of initialization routine">;
uint32 init_module<comment = "Index into module table that init routine is defined">;
uint32 reversed_1;
uint32 reversed_2;
uint32 reversed_3;
uint32 reversed_4;
uint32 reversed_5;
uint32 reversed_6;
break;
case TWOLEVEL_HINTS:
uint32 offset<comment = "Offset into the hint table">;
uint32 hints_size<comment = "Number of hints inside the hints table">;
break;
case PREBIND_CKSUM:
uint32 cksum<comment = "Checksum or zero">;
break;
case RPATH:
LoadCommandString path<comment = "Path to add to run path">;
break;
case ENCRYPTION_INFO:
uint32 crypt_offset<comment = "File offset of encrypted range">;
uint32 crypt_size<comment = "File size of the encrypted range">;
uint32 crypt_id<comment = "Which encryption system, 0 means not-encrypted yet">;
break;
case IDENT:
break;
case FVM_FILE:
LoadCommandString name<comment = "File's pathname">;
uint32 header_address<comment = "File's virtual address">;
break;
case SEGMENT_64:
char segment_name[16];
uint64 vm_address<format = hex>;
uint64 vm_size<format = hex>;
uint64 file_off;
uint64 file_size;
vm_proc maximum_protection<format = hex>;
vm_proc initial_protection<format = hex>;
uint32 number_of_sections;
// TODO : Fix this enum
SegmentFlags flags;
// Having this if statement will prevent warnings in 010Editor
if (number_of_sections > 0)
{
Section64 section[number_of_sections];
}
break;
case SEGMENT:
char segment_name[16];
uint32 vm_address<format = hex>;
uint32 vm_size<format = hex>;
uint32 file_off;
uint32 file_size;
vm_proc maximum_protection<format = hex>;
vm_proc initial_protection<format = hex>;
uint32 number_of_sections;
// TODO : Fix this enum
SegmentFlags flags;
// Having this if statement will prevent warnings in 010Editor
if (number_of_sections > 0)
{
Section section[number_of_sections];
}
break;
case SOURCE_VERSION:
uint32 unka;
uint32 unkb;
break;
case ENCRYPTION_INFO_64:
uint32 cryptoff<format = hex>; /* file offset of encrypted range */
uint32 cryptsize<format = hex>; /* file size of encrypted range */
uint32 cryptid; /* which enryption system, 0 means not-encrypted yet */
uint32 pad; /* padding to make this struct's size a multiple of 8 */
break;
case LC_BUILD_VERSION:
Platform platform; // platform
Version minos; // X.Y.Z is encoded in nibbles xxxx.yy.zz
Version sdk; // X.Y.Z is encoded in nibbles xxxx.yy.zz
uint32 ntools;
if (ntools > 0)
{
build_tool_version tools[ntools];
}
break;
case MAIN:
case MAIN_DYLIB:
uint64 entryoff<format = hex>;
uint64 stacksize<format = hex>;
break;
default:
Warning("Hit an unknown or unsupported load command : [%d]", command);
break; // Exit(-1);
}
FSeek(o_pos + command_size); // AIO solution, fixes default case, need for unk/pad, and all of the LoadCommandString + Seeks all over //
} LoadCommand<read = LoadCommandReader, optimize = false>;
string LoadCommandReader(LoadCommand &loadCommand)
{
return "load_command[" + LoadCommandTypeRead(loadCommand.command) + "]";
}
// parse each macho
typedef struct(uint64 offset)
{
local uint64 endpos = FTell();
FSeek(offset);
Header header<comment = "Mach-o header information">;
local uint32 cpu_typer;
if (header.magic == MACHO_32 || header.magic == MACHO_64)
{
cpu_typer = header.cpu_type;
// If we didn't find a FAT header, then just process the load commands
LoadCommand loadCommand[header.num_load_commands];
}
else
{
// Otherwise we need to grab the new headers again
local int i;
for (i = 0; i < header.fat_arch_size; i++)
{
FSeek(header.fat_arch[i].file_offset);
Header machHeader;
cpu_typer = machHeader.cpu_type;
LoadCommand loadCommand[machHeader.num_load_commands];
}
}
FSeek(endpos);
}
machoParser;
if (header.localSymbolsOffset > 0)
{
for (i = 0; i < symbolinfo.entriesCount; i++)
{
machoParser parser(symbolinfo.nlistentry[i].dylibOffset);
}
}