//------------------------------------------------ //--- 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 { 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 ; #define CPU_ARCH_MASK 0xff000000 #define CPU_ARCH_ABI64 0x01000000 // Changed to enum, more info and handles constant | macro fine // // typedef enum { 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 ; typedef enum { 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 { i386_THREAD_STATE = 0x1, i386_FLOAT_STATE = 0x2, i386_EXCEPTION_STATE = 0x3 } i386ThreadFlavor ; typedef struct { uint32 eax ; uint32 ebx ; uint32 ecx ; uint32 edx ; uint32 edi ; uint32 esi ; uint32 ebp ; uint32 esp ; uint32 ss ; uint32 eflags ; uint32 eip ; uint32 cs ; uint32 ds ; uint32 es ; uint32 fs ; uint32 gs ; } i386ThreadState; typedef enum { 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 ; typedef struct { uint64 rax ; uint64 rbx ; uint64 rcx ; uint64 rdx ; uint64 rdi ; uint64 rsi ; uint64 rbp ; uint64 rsp ; uint64 r8 ; uint64 r9 ; uint64 r10 ; uint64 r11 ; uint64 r12 ; uint64 r13 ; uint64 r14 ; uint64 r15 ; uint64 rip ; uint64 rflags ; uint64 cs ; uint64 fs ; uint64 gs ; } x86ThreadState; typedef enum { 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 ; typedef struct { 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 ; } ARMThreadState; typedef struct { uint32 __srr0 ; uint32 __srr1 ; 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 ; uint32 __xer ; uint32 __lr ; uint32 __ctr ; uint32 __mq ; uint32 __vrsave ; } PPCThreadState; typedef enum { 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 ; uint32 cpu_sub_type ; uint32 file_offset ; uint32 size ; uint32 align ; } Fat_Arch; typedef struct { Magic magic ; if(magic == MACHO_FAT || magic == MACHO_FAT_CIGAM) { // Need to switch to BigEndian! BigEndian(); uint32 fat_arch_size ; Fat_Arch fat_arch[fat_arch_size]; // Switch back to LittleEndian for rest of parsing LittleEndian(); } else { CpuType cpu_type ; uint32 cpu_sub_type ; FileType file_type; uint32 num_load_commands; uint32 size_of_load_commands; Flags flags; } if(magic == MACHO_64) { uint32 reserved; } } Header ; 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 { 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 ; 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 ; uint32 size ; uint32 offset; uint32 section_alignment; uint32 relocation_entry_offset; uint32 number_of_relocation_entries; uint32 flags ; uint32 reserved1; uint32 reserved2; } Section ; typedef struct { char section_name[16]; char segment_name[16]; uint64 address ; uint64 size ; uint32 offset; uint32 section_alignment; uint32 relocation_entry_offset; uint32 number_of_relocation_entries; uint32 flags ; uint32 reserved1; uint32 reserved2; uint32 reserved3; } Section64 ; typedef uint vm_proc; typedef enum { HIGH_VM = 0x1, FVM_LIB = 0x2, NO_RELOC = 0x4, PROTECTION_VERSION_1 = 0x8 } SegmentFlags ; typedef struct { uint32 load_command_string_offset ; 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 ; FSeek(pos); } LoadCommandString ; string LoadCommandStringRead(LoadCommandString &loadCommandString) { return loadCommandString.string_data; }; typedef ubyte Uuid[16] ; // 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 ; 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 { 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 { 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 { 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 { 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; // 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 ; // FSeek(cdPos + codeDirectory.identOffset); string ident; // FSeek(cdPos + codeDirectory.hashOffset); Slot specialSlots[codeDirectory.nSpecialSlots]; Slot codeSlots[codeDirectory.nCodeSlots]; } else { if ((length - 8) > 0) { ubyte data[length - 8]; } } } CSBlob; typedef struct { SbMagic magic; uint32 length; uint32 count; CSBlobIndex indices[count]; CSBlob blobs[count]; } CSSuperBlob; typedef struct { uint32 data_offset; uint32 data_size; BigEndian(); local int64 pos = FTell(); FSeek(data_offset); CSSuperBlob super_blob ; FSeek(pos); LittleEndian(); } CodeSignature; typedef struct { local uint64 o_pos = FTell(); //LoadCommandHead loadCommandHead ; 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 ; uint32 number_of_symbol_table_entries ; uint32 string_table_offset ; uint32 string_table_size ; 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 ; 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 ; 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 ; uint32 minor_version ; uint32 header_address ; break; case SUB_FRAMEWORK : LoadCommandString umbrella ; break; case SUB_CLIENT : LoadCommandString client ; break; case SUB_UMBRELLA : LoadCommandString sub_umbrella ; break; case SUB_LIBRARY : LoadCommandString sub_library ; break; case PREBOUND_DYLIB : LoadCommandString name ; uint32 modules_size ; LoadCommandString linked_modules ; break; case ID_DYLINKER : case LOAD_DYLINKER : LoadCommandString name ; break; case ROUTINES_64 : uint64 init_address ; uint64 init_module ; uint32 reversed_1; uint32 reversed_2; uint32 reversed_3; uint32 reversed_4; uint32 reversed_5; uint32 reversed_6; break; case ROUTINES : uint32 init_address ; uint32 init_module ; uint32 reversed_1; uint32 reversed_2; uint32 reversed_3; uint32 reversed_4; uint32 reversed_5; uint32 reversed_6; break; case TWOLEVEL_HINTS : uint32 offset ; uint32 hints_size ; break; case PREBIND_CKSUM : uint32 cksum ; break; case RPATH: LoadCommandString path ; break; case ENCRYPTION_INFO : uint32 crypt_offset ; uint32 crypt_size ; uint32 crypt_id ; break; case IDENT : break; case FVM_FILE : LoadCommandString name ; uint32 header_address ; break; case SEGMENT_64 : char segment_name[16]; uint64 vm_address ; uint64 vm_size ; uint64 file_off; uint64 file_size; vm_proc maximum_protection ; vm_proc initial_protection ; 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 ; uint32 vm_size ; uint32 file_off; uint32 file_size; vm_proc maximum_protection ; vm_proc initial_protection ; 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 ; /* file offset of encrypted range */ uint32 cryptsize ; /* 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 ; uint64 stacksize ; 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 ; string LoadCommandReader(LoadCommand &loadCommand) { return "load_command[" + LoadCommandTypeRead(loadCommand.command) + "]"; } Header header ; 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]; } }