mirror of
https://github.com/blacktop/ipsw.git
synced 2026-05-08 12:22:26 +00:00
1072 lines
35 KiB
Plaintext
1072 lines
35 KiB
Plaintext
//------------------------------------------------
|
|
//--- 010 Editor v3.2.2 Binary Template
|
|
//
|
|
// File: MachO.bt
|
|
// Authors: Tim "diff" Strazzere
|
|
// E-mail: diff@lookout.com, strazz@gmail.com
|
|
// Version: 1.7
|
|
// Purpose: Quick template for parsing Mach-o binaries,
|
|
// including Mac OS X executables, .o and .dylib files.
|
|
// Category: Executable
|
|
// File Mask: *,*.o,*.dylib
|
|
// ID Bytes: CF FA ED FE, CE FA ED FE, BE BA FE CA, CA FE BA BE
|
|
// History:
|
|
// 1.7 2019-03-05 D.Miller: Fixed ARM64, Added CpuType enum, Changed Load Handling to MAIN, MAIN|DYLD
|
|
// - Changed load command handling to always seek to orig offset + command size after switch
|
|
// 1.6 2019-02-19 nathan@lanza.io: LC_MAIN is 0x28 | REQ_DYLD - adjust this template accordingly and implement in switch
|
|
// 1.5 2018-11-09 swigger at gmail.com: support LC_BUILD_VERSION load command.
|
|
// 1.4 2017-03-17 swigger at gmail.com: enable encryption segment 64.
|
|
// 1.3 2016-06-08 N Moinvaziri: Fixed definition of section_64. Offset should have been uint64 and reserved3 missing.
|
|
// 1.2 2016-02-12 SweetScape Software: Updated header for repository submission.
|
|
// 1.1 T Strazzere: - Minimum version load command now properly outputs the format for better readability
|
|
// - Added a readvalue function for the header, helps understand headers at a glance
|
|
// 1.0 T Strazzere: - Correctly parses FAT headers and will continue to parse the rest of the combined
|
|
// binary
|
|
// - Added many todo's to make the output more pretty
|
|
// - Fixed some broken LoadCommands (64bit ones mainly), will gracefully fail if unknown
|
|
// LoadCommand is hit
|
|
// - Found some bugs in 010Editor and added fixes to try to avoid those
|
|
// 1.0 T Strazzere: - First stab it this, lots of issues - FAT binaries don't work at all
|
|
//
|
|
// Known issues:
|
|
// - Needs optimized structures otherwise anything of a decent size will kill it
|
|
// (Related to an 010Editor template bug)
|
|
//------------------------------------------------
|
|
|
|
// 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,
|
|
MACH_FILESET = 0xC,
|
|
} 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)
|
|
#define REQ_SEP (0x8000000)
|
|
|
|
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_LINKER_OPTION = 0x2d,
|
|
LC_LINKER_OPTIMIZATION_HINT = 0x2e,
|
|
LC_VERSION_MIN_TVOS = 0x2f,
|
|
LC_VERSION_MIN_WATCHOS = 0x30,
|
|
LC_NOTE = 0x31,
|
|
LC_BUILD_VERSION = 0x32,
|
|
LC_DYLD_EXPORTS_TRIE = 0x33 | REQ_DYLD,
|
|
LC_DYLD_CHAINED_FIXUPS = 0x34 | REQ_DYLD,
|
|
LC_FILESET_ENTRY = 0x35 | REQ_DYLD,
|
|
LC_ATOM_INFO = 0x36,
|
|
LC_FUNCTION_VARIANTS = 0x37,
|
|
LC_FUNCTION_VARIANT_FIXUPS = 0x38,
|
|
LC_TARGET_TRIPLE = 0x39,
|
|
LC_SEP_CACHE_SLIDE = 0x1 | REQ_SEP,
|
|
LC_SEP_UNKNOWN2 = 0x2 | REQ_SEP,
|
|
LC_SEP_UNKNOWN3 = 0x3 | REQ_SEP,
|
|
} 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_LINKER_OPTION:
|
|
return "LC_LINKER_OPTION";
|
|
case LC_LINKER_OPTIMIZATION_HINT:
|
|
return "LC_LINKER_OPTIMIZATION_HINT";
|
|
case LC_VERSION_MIN_TVOS:
|
|
return "LC_VERSION_MIN_TVOS";
|
|
case LC_VERSION_MIN_WATCHOS:
|
|
return "LC_VERSION_MIN_WATCHOS";
|
|
case LC_NOTE:
|
|
return "LC_NOTE";
|
|
case LC_BUILD_VERSION:
|
|
return "LC_BUILD_VERSION";
|
|
case LC_DYLD_EXPORTS_TRIE:
|
|
return "LC_DYLD_EXPORTS_TRIE";
|
|
case LC_DYLD_CHAINED_FIXUPS:
|
|
return "LC_DYLD_CHAINED_FIXUPS";
|
|
case LC_FILESET_ENTRY:
|
|
return "LC_FILESET_ENTRY";
|
|
case LC_ATOM_INFO:
|
|
return "LC_ATOM_INFO";
|
|
case LC_FUNCTION_VARIANTS:
|
|
return "LC_FUNCTION_VARIANTS";
|
|
case LC_FUNCTION_VARIANT_FIXUPS:
|
|
return "LC_FUNCTION_VARIANT_FIXUPS";
|
|
case LC_TARGET_TRIPLE:
|
|
return "LC_TARGET_TRIPLE";
|
|
case LC_SEP_CACHE_SLIDE:
|
|
return "LC_SEP_CACHE_SLIDE";
|
|
case LC_SEP_UNKNOWN2:
|
|
return "LC_SEP_UNKNOWN2";
|
|
case LC_SEP_UNKNOWN3:
|
|
return "LC_SEP_UNKNOWN3";
|
|
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=UuidRead, format=hex>;
|
|
|
|
// TODO : Clean this ugly thing up
|
|
string UuidRead(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;
|
|
}
|
|
|
|
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
|
|
{
|
|
uint32 tool; // enum for the tool
|
|
Version version; // version of the tool
|
|
}build_tool_version;
|
|
|
|
typedef enum <uint32> {
|
|
MAGIC_REQUIREMENT = 0xfade0c00, // single Requirement blob
|
|
MAGIC_REQUIREMENTS = 0xfade0c01, // Requirements vector (internal requirements)
|
|
MAGIC_CODEDIRECTORY = 0xfade0c02, // CodeDirectory blob
|
|
MAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0, // embedded form of signature data
|
|
MAGIC_EMBEDDED_SIGNATURE_OLD = 0xfade0b02, /* XXX */
|
|
MAGIC_LIBRARY_DEPENDENCY_BLOB = 0xfade0c05,
|
|
MAGIC_EMBEDDED_ENTITLEMENTS = 0xfade7171, /* embedded entitlements */
|
|
MAGIC_EMBEDDED_ENTITLEMENTS_DER = 0xfade7172, /* embedded entitlements */
|
|
MAGIC_DETACHED_SIGNATURE = 0xfade0cc1, // multi-arch collection of embedded signatures
|
|
MAGIC_BLOBWRAPPER = 0xfade0b01, // used for the cms blob
|
|
} SbMagic;
|
|
|
|
typedef enum <uint32> {
|
|
CSSLOT_CODEDIRECTORY = 0,
|
|
CSSLOT_INFOSLOT = 1, // Info.plist
|
|
CSSLOT_REQUIREMENTS = 2, // internal requirements
|
|
CSSLOT_RESOURCEDIR = 3, // resource directory
|
|
CSSLOT_APPLICATION = 4, // Application specific slot/Top-level directory list
|
|
CSSLOT_ENTITLEMENTS = 5, // embedded entitlement configuration
|
|
CSSLOT_REP_SPECIFIC = 6, // for use by disk images
|
|
CSSLOT_ENTITLEMENTS_DER = 7, // DER representation of entitlements plist
|
|
CSSLOT_ALTERNATE_CODEDIRECTORIES = 0x1000, // Used for expressing a code directory using an alternate digest type.
|
|
CSSLOT_ALTERNATE_CODEDIRECTORIES1 = 0x1001, // Used for expressing a code directory using an alternate digest type.
|
|
CSSLOT_ALTERNATE_CODEDIRECTORIES2 = 0x1002, // Used for expressing a code directory using an alternate digest type.
|
|
CSSLOT_ALTERNATE_CODEDIRECTORIES3 = 0x1003, // Used for expressing a code directory using an alternate digest type.
|
|
CSSLOT_ALTERNATE_CODEDIRECTORIES4 = 0x1004, // Used for expressing a code directory using an alternate digest type.
|
|
CSSLOT_CMS_SIGNATURE = 0x10000, // CMS signature
|
|
CSSLOT_IDENTIFICATIONSLOT = 0x10001, // identification blob; used for detached signature
|
|
CSSLOT_TICKETSLOT = 0x10002, // Notarization ticket
|
|
} SlotType;
|
|
|
|
typedef enum <uint32> {
|
|
EARLIEST_VERSION = 0x20001,
|
|
SUPPORTS_SCATTER = 0x20100,
|
|
SUPPORTS_TEAMID = 0x20200,
|
|
SUPPORTS_CODELIMIT64 = 0x20300,
|
|
SUPPORTS_EXECSEG = 0x20400,
|
|
SUPPORTS_RUNTIME = 0x20500,
|
|
SUPPORTS_LINKAGE = 0x20600,
|
|
COMPATIBILITY_LIMIT = 0x2F000, // "version 3 with wiggle room"
|
|
} CdVersion;
|
|
|
|
typedef enum <ubyte> {
|
|
HASHTYPE_NOHASH = 0,
|
|
HASHTYPE_SHA1 = 1,
|
|
HASHTYPE_SHA256 = 2,
|
|
HASHTYPE_SHA256_TRUNCATED = 3,
|
|
HASHTYPE_SHA384 = 4,
|
|
HASHTYPE_SHA512 = 5,
|
|
} HashType;
|
|
|
|
typedef struct {
|
|
SlotType type;
|
|
uint32 offset;
|
|
} CSBlobIndex;
|
|
|
|
typedef struct {
|
|
CdVersion version; // compatibility version
|
|
uint32 flags; // setup and mode flags
|
|
uint32 hashOffset; // offset of hash slot element at index zero
|
|
uint32 identOffset; // offset of identifier string
|
|
uint32 nSpecialSlots; // number of special hash slots
|
|
uint32 nCodeSlots<format=decimal>; // number of ordinary (code) hash slots
|
|
uint32 codeLimit; // limit to main image signature range
|
|
ubyte hashSize; // size of each hash in bytes
|
|
HashType hashType; // type of hash (cdHashType* constants)
|
|
ubyte platform; // platform identifier zero if not platform binary
|
|
ubyte pageSize; // log2(page size in bytes) 0 => infinite
|
|
uint32 pad; // unused (must be zero)
|
|
if(version >= SUPPORTS_SCATTER) {
|
|
uint32 ScatterOffset;
|
|
}
|
|
if(version >= SUPPORTS_TEAMID) {
|
|
uint32 TeamOffset;
|
|
}
|
|
if(version >= SUPPORTS_CODELIMIT64) {
|
|
uint32 pad;
|
|
uint64 CodeLimit64;
|
|
}
|
|
if(version >= SUPPORTS_EXECSEG) {
|
|
uint64 ExecSegBase;
|
|
uint64 ExecSegLimit;
|
|
uint64 ExecSegFlags;
|
|
}
|
|
if(version >= SUPPORTS_RUNTIME) {
|
|
Version Runtime;
|
|
uint32 PreEncryptOffset;
|
|
}
|
|
if(version >= SUPPORTS_LINKAGE) {
|
|
ubyte LinkageHashType;
|
|
ubyte LinkageTruncated;
|
|
uint16 pad;
|
|
uint32 LinkageOffset;
|
|
uint32 LinkageSize;
|
|
}
|
|
} CodeDirectoryType;
|
|
|
|
typedef struct {
|
|
ubyte hash[codeDirectory.hashSize];
|
|
} Slot;
|
|
|
|
typedef struct {
|
|
SbMagic magic;
|
|
uint32 length;
|
|
if (magic == MAGIC_CODEDIRECTORY) {
|
|
// local int64 cdPos = FTell();
|
|
CodeDirectoryType codeDirectory <comment="CodeDirectory">;
|
|
// FSeek(cdPos + codeDirectory.identOffset);
|
|
string ident;
|
|
// FSeek(cdPos + codeDirectory.hashOffset);
|
|
Slot specialSlots[codeDirectory.nSpecialSlots]<optimize=false>;
|
|
Slot codeSlots[codeDirectory.nCodeSlots]<optimize=false>;
|
|
} else {
|
|
if ((length - 8) > 0) {
|
|
ubyte data[length - 8];
|
|
}
|
|
}
|
|
} CSBlob;
|
|
|
|
typedef struct {
|
|
SbMagic magic;
|
|
uint32 length;
|
|
uint32 count;
|
|
CSBlobIndex indices[count];
|
|
CSBlob blobs[count]<optimize=false>;
|
|
} CSSuperBlob;
|
|
|
|
typedef struct {
|
|
uint32 data_offset;
|
|
uint32 data_size;
|
|
|
|
BigEndian();
|
|
|
|
local int64 pos = FTell();
|
|
FSeek(data_offset);
|
|
|
|
CSSuperBlob super_blob <comment="CodeSignature">;
|
|
|
|
FSeek(pos);
|
|
LittleEndian();
|
|
} CodeSignature;
|
|
|
|
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 CODE_SIGNATURE :
|
|
CodeSignature codeSignature;
|
|
break;
|
|
case LC_DYLD_EXPORTS_TRIE :
|
|
case LC_DYLD_CHAINED_FIXUPS :
|
|
case FUNCTION_STARTS :
|
|
case SEGMENT_SPLIT_INFO:
|
|
case DATA_IN_CODE:
|
|
case LC_ATOM_INFO:
|
|
case LC_FUNCTION_VARIANTS:
|
|
case LC_FUNCTION_VARIANT_FIXUPS:
|
|
uint32 data_offset;
|
|
uint32 data_size;
|
|
break;
|
|
case LC_TARGET_TRIPLE:
|
|
LoadCommandString target_triple <comment="Target triple string">;
|
|
break;
|
|
case LC_FILESET_ENTRY:
|
|
uint64 addr; // memory address of the entry
|
|
uint64 offset; // file offset of the entry
|
|
uint32 entryID; // contained entry id
|
|
uint32 reserved; // reserved
|
|
string name;
|
|
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_NOTE:
|
|
char data_owner[16];
|
|
uint64 offset;
|
|
uint64 size;
|
|
break;
|
|
case LC_BUILD_VERSION:
|
|
uint32 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;
|
|
case LC_SEP_CACHE_SLIDE:
|
|
case LC_SEP_UNKNOWN2:
|
|
case LC_SEP_UNKNOWN3:
|
|
uint32 data_offset;
|
|
uint32 data_size;
|
|
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) + "]";
|
|
}
|
|
|
|
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];
|
|
}
|
|
} |