Mach-o格式,是Mach操作系統(tǒng)內(nèi)核(Mac、iOS系統(tǒng)的內(nèi)核)主要支持的可執(zhí)行文件格式霞掺。
用otool工具可以查看Mach-o的頭部,并參考Xcode自帶的關(guān)于Mach-o的頭文件仔細分析了一下传于,關(guān)于Mach-o的頭文件在/Applications/Xcode.app/Contents/Developer/Platforms/
iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/mach-o下面囱挑。
Note:下面的宏定義以MH_開頭,應(yīng)該是mach_header的縮寫沼溜。
下面是Mach-o文件頭部的標(biāo)注平挑。
?? ~ otool -h Hello
Mach header
??????magic cputype cpusubtype? caps??? filetype ncmds sizeofcmds????? flags
?0xfeedfacf 16777223????????? 3? 0x80?????????? 2??? 18?????? 1616 0x00200085
從十六進制下面查看下(在VI下面執(zhí)行 :%!xxd 命令 或者 用任何其他十六進制編輯器)
00000000: cffa edfe 0700 0001 0300 0080 0200 0000? ................
00000010: 1200 0000 5006 0000 8500 2000 0000 0000? ....P..... .....
疑惑點note: otool打印出來的cputype怎么是16777223呢?想了一下系草,明白是十進制表示的通熄,0x10000070==16777223。
在下面的結(jié)構(gòu)體聲明
struct mach_header {
????uint32_t??? magic;????? /* mach magic number identifier */
????cpu_type_t? cputype;??? /* cpu specifier */
????cpu_subtype_t?? cpusubtype; /* machine specifier */
????uint32_t??? filetype;?? /* type of file */
????uint32_t??? ncmds;????? /* number of load commands */
????uint32_t??? sizeofcmds; /* the size of all the load commands */
????uint32_t??? flags;????? /* flags */
};
#define MH_MAGIC??? 0xfeedface? /* the mach magic number */
#define MH_CIGAM??? 0xcefaedfe? /* NXSwapInt(MH_MAGIC) */
structmach_header_64 {
????uint32_t??? magic;????? /* mach-o 格式的標(biāo)識符 */
????cpu_type_t? cputype;??? /* cpu區(qū)分符 */
????cpu_subtype_t?? cpusubtype; /* machine區(qū)分符 */
????uint32_t??? filetype;?? /* 文件類型 */
????uint32_t??? ncmds;????? /* 加載命令的個數(shù) */
????uint32_t??? sizeofcmds; /* 加載命令的字節(jié)數(shù) */
????uint32_t??? flags;????? /* 程序的標(biāo)識位 */
????uint32_t??? reserved;?? /* 保留字段 */
};
#define MH_MAGIC_64 0xfeedfacf /* the 64-bit mach magic number */
#define MH_CIGAM_64 0xcffaedfe /* NXSwapInt(MH_MAGIC_64) */
64位的頭部結(jié)構(gòu)體和32位的相比只多了一個reserved字段找都,然而這個字段是保留字段唇辨,目前還是0x0。等于說現(xiàn)在頭的結(jié)構(gòu)都是一樣的檐嚣。
第一個字段magic
magic字段就是個特征數(shù)值助泽,沒有什么好說的,取自于下面的宏定義嚎京。
疑惑點note: 為什么是4個宏定義嗡贺?查找資料并仔細觀察發(fā)現(xiàn):CIGAM是MAGIC反過來的拼寫,寫反的意思是在大端序(big endian mode)(不了解大端序鞍帝,請點擊wiki https://en.wikipedia.org/wiki/Endianness)環(huán)境下面使用诫睬。
第二&&三個字段CPU type 和 CPU subtype
定義了Mach-o所能支持的所有CPU類型,這兩個位置的標(biāo)記表明了運行程序的平臺是啥帕涌,太長了就只把 x86和arm的copy出來記一下摄凡。示例中的就是CPU_TYPE_X86_64這個類型。
#define CPU_ARCH_ABI64? 0x01000000????? /* 64 bit ABI */
#define CPU_TYPE_X86??????? ((cpu_type_t) 7)
#define CPU_TYPE_I386?????? CPU_TYPE_X86???
#define CPU_TYPE_X86_64???? (CPU_TYPE_X86 | CPU_ARCH_ABI64)
#define CPU_TYPE_ARM??????? ((cpu_type_t) 12)
#define CPU_TYPE_ARM64????????? (CPU_TYPE_ARM | CPU_ARCH_ABI64)
第四個字段 filetype
表明Mach-o的文件類型蚓曼,下面列出了所有的文件類型亲澡。每一種我在Github上面有收集的每一種filetype
#defineMH_OBJECT0x1
/* relocatable object file */
/* 一般后綴名為(.o),可重定位文件纫版,編譯器的中間產(chǎn)物之一床绪,靜態(tài)庫(后綴名是.a)就是這類文件的集合*/
#defineMH_EXECUTE0x2
/* demand paged executable file */
/* 示例中看到的可執(zhí)行文件,最基礎(chǔ)的類型 */
#defineMH_FVMLIB0x3
/* fixed VM shared library file */
/* 后續(xù)補上,不知道在哪里見過 */
#defineMH_CORE0x4
/* core file */
/* 程序Crash之后產(chǎn)生的Core文件其弊,現(xiàn)在默認的core dumps都是關(guān)閉的癞己,可以通過 XXX 打開,一個Crash就生成了700多M的一個文件梭伐,我截取了他的前1600字節(jié)數(shù)據(jù)痹雅,收集起來。 */
#defineMH_PRELOAD0x5
/* preloaded executable file */
/* */
#defineMH_DYLIB0x6
/* dynamically bound shared library */
/* 一般后綴名為(.dylib)糊识,動態(tài)鏈接庫绩社,很常見*/
#defineMH_DYLINKER0x7
/* dynamic link editor */
/* 動態(tài)庫的連接器摔蓝,就這個文件/usr/lib/dyld ,F(xiàn)at文件就用lipo提取一下愉耙,下面會講到*/
#defineMH_BUNDLE0x8
/* dynamically bound bundle file */
/* Xcode里面可以創(chuàng)建bundle的Target项鬼,編譯之后在bundle后綴名的文件夾下面可以找到*/
#defineMH_DYLIB_STUB0x9
/* shared library stub for static */
/* linking only, no section contents */
/* 后續(xù)補上,不知道在哪里見過 */
#defineMH_DSYM0xa
/* companion file with only debug */
/* sections */
/* 這個也很常見,Xcode->Product->Archive打包之后劲阎,里面就會生成一個叫DSYM后綴名的文件夾,查看包內(nèi)容就可以找到它*/
#defineMH_KEXT_BUNDLE0xb
/* x86_64 kexts */
/* 內(nèi)核功能擴展文件鸠真,常見與 /System/Library/Extensions 下面悯仙,這個自己可以打開瞅瞅*/
第五和六個字段 ncmds、sizeofcmds
ncmds 指的是加載命令(load commands)的數(shù)量
sizeofcmds 所有加載命令的大小吠卷。如果沒有設(shè)置的話锡垄,沒有辦法知道加載命令從什么時候結(jié)束啦。
第七個字段 flags
dyld加載時的標(biāo)志位
#defineMH_NOUNDEFS0x1
/* the object file has no undefined references */
/* 目前沒有未定義的符號祭隔,不存在鏈接依賴*/
#defineMH_INCRLINK0x2
/* the object file is the output of an incremental link against a base file and can’t be link edited again */
/* 一個對基本文件的一個增量鏈接的輸出文件货岭,無法被再次鏈接*/
#define MH_DYLDLINK0x4
/* the object file is input for the dynamic linker and can’t be staticly link edited again */
/* 動態(tài)連接器(dyld)的輸入文件,無法被再次靜態(tài)鏈接 */
#define MH_BINDATLOAD0x8
/* the object file’s undefined references are bound by the dynamic linker when loaded. */
#define MH_PREBOUND0x10
/* the file has its dynamic undefined references prebound. */
#define MH_SPLIT_SEGS0x20
/* the file has its read-only and read-write segments split */
#define MH_LAZY_INIT0x40
/* the shared library init routine is to be run lazily via catching memory faults to its writeable segments (obsolete) */
#define MH_TWOLEVEL0x80
/* the image is using two-level name space bindings */
/* 這個鏡像使用的是兩級名稱空間綁定*/
#define MH_FORCE_FLAT0x100
/* the executable is forcing all images to use flat name space bindings */
#define MH_NOMULTIDEFS0x200
/* this umbrella guarantees no multiple defintions of symbols in its sub-images so the two-level namespace hints can always be used. */
#define MH_NOFIXPREBINDING 0x400
/* do not have dyld notify the prebinding agent about this executable */
#define MH_PREBINDABLE 0x800
/* the binary is not prebound but can have its prebinding redone. only used when MH_PREBOUND is not set. */
#define MH_ALLMODSBOUND 0x1000
/* indicates that this binary binds to all two-level namespace modules of its dependent libraries. only used when MH_PREBINDABLE and MH_TWOLEVEL are both set. */?
#define MH_SUBSECTIONS_VIA_SYMBOLS 0x2000
/* safe to divide up the sections into sub-sections via symbols for dead code stripping */
#define MH_CANONICAL 0x4000
/* the binary has been canonicalized via the unprebind operation */
#define MH_WEAK_DEFINES0x8000
/* the final linked image contains external weak symbols */
#define MH_BINDS_TO_WEAK 0x10000
/* the final linked image uses weak symbols */
#define MH_ALLOW_STACK_EXECUTION 0x20000
/* When this bit is set, all stacks in the task will be given stack execution privilege. Only used in MH_EXECUTE filetypes. */
/* 當(dāng)這個位被設(shè)置了之后疾渴,所有在任務(wù)中的棧被賦予棧內(nèi)可執(zhí)行的權(quán)限千贯。僅在filetype是MH_EXECUTE的時候使用*/
#define MH_ROOT_SAFE 0x40000
/* When this bit is set, the binary declares it is safe for use in processes with uid zero */
/* 當(dāng)這個位被設(shè)置了之后,程序聲明它對root(進程UID是0的用戶)是安全的 */
#define MH_SETUID_SAFE 0x80000
/* When this bit is set, the binary declares it is safe for use in processes when issetugid() is true */
#define MH_NO_REEXPORTED_DYLIBS 0x100000
/* When this bit is set on a dylib, the static linker does not need to examine dependent dylibs to see if any are re-exported */
#defineMH_PIE 0x200000
/* When this bit is set, the OS will load the main executable at a random address. Only used in MH_EXECUTE filetypes. */
/* 當(dāng)這個位被設(shè)置了之后搞坝,系統(tǒng)加載主可執(zhí)行程序在隨機的地址空間搔谴,僅在filetype是MH_EXECUTE的時候使用 */
#defineMH_DEAD_STRIPPABLE_DYLIB 0x400000
/* Only for use on dylibs. When linking against a dylib that has this bit set, the static linker will automatically not create a LC_LOAD_DYLIB load command to the dylib if no symbols are being referenced from the dylib. */
#define MH_HAS_TLV_DESCRIPTORS 0x800000
/* Contains a section of type S_THREAD_LOCAL_VARIABLES */
#define MH_NO_HEAP_EXECUTION 0x1000000
/* When this bit is set, the OS will run the main executable with a non-executable heap even on platforms (e.g. i386) that don’t require it. Only used in MH_EXECUTE filetypes. */
/* 當(dāng)這個位被設(shè)置了之后,桩撮,僅在filetype是MH_EXECUTE的時候使用 */
#define MH_APP_EXTENSION_SAFE 0x02000000
/* The code was linked for use in an application extension. */
關(guān)于Fat文件
有時候使用下面命令會看到顯示兩個Mach頭部敦第,如下面:
?? ~ otool -h AlipayWallet
Mach header
??????magic cputype cpusubtype? caps??? filetype ncmds sizeofcmds????? flags
?0xfeedface????? 12????????? 9? 0x00?????????? 2??? 72?????? 7280 0x00210085
Mach header
??????magic cputype cpusubtype? caps??? filetype ncmds sizeofcmds????? flags
?0xfeedfacf 16777228????????? 0? 0x00?????????? 2??? 72?????? 8088 0x00210085
上面介紹的是單一的Arch結(jié)構(gòu),這一種是Fat的店量,可以通過 lipo 進行拆解開芜果,使用下面命令
1lipo AlipayWallet -thin armv7 -output AlipayWallet_v7
在中的Fat頭部聲明
#define FAT_MAGIC?? 0xcafebabe
#define FAT_CIGAM?? 0xbebafeca? /* NXSwapLong(FAT_MAGIC) */
structfat_header {
????uint32_t??? magic;????? /* FAT_MAGIC or FAT_MAGIC_64 */
????uint32_t??? nfat_arch;? /* number of structs that follow */
};
#define FAT_MAGIC_64??? 0xcafebabf
#define FAT_CIGAM_64??? 0xbfbafeca? /* NXSwapLong(FAT_MAGIC_64) */
Fat文件就是一個包裝盒,里面填了若干個針對不同架構(gòu)的指令集融师,第一個參數(shù)magic就是Fat的標(biāo)識右钾,第二個參數(shù)就是里面包含了幾個架構(gòu)的指令集。
在中對指令集包裝的申明
struct fat_arch {
????cpu_type_t? cputype;???
????cpu_subtype_t?? cpusubtype;
????uint32_t??? offset;???? /* 指令集在文件中的偏移量诬滩,也就是從哪點開始 */
????uint32_t??? size;?????? /* 指令集的大小 */
????uint32_t??? align;????? /* 必須是2的n次方 */
};
struct fat_arch_64 {
????cpu_type_t? cputype;??? /* cpu specifier (int) */
????cpu_subtype_t?? cpusubtype; /* machine specifier (int) */
????uint64_t??? offset;???? /* file offset to this object file */
????uint64_t??? size;?????? /* size of this object file */
????uint32_t??? align;????? /* alignment as a power of 2 */
????uint32_t??? reserved;?? /* reserved */
};
Note: 看完之后霹粥,應(yīng)該明白了mach-o文件共有
8種magic number {(32位/64位) * (大端序/小端序) * (是否是Fat文件)},
11種filetype
26中flag