Mach-o格式头部结构

Mach-o格式,是Mach操作系统内核(Mac、iOS系统的内核)主要支持的可执行文件格式。

用otool工具可以查看Mach-o的头部,并参考Xcode自带的关于Mach-o的头文件仔细分析了一下,关于Mach-o的头文件在/Applications/Xcode.app/Contents/Developer/Platforms/

iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/mach-o下面。

Note:下面的宏定义以MH_开头,应该是mach_header的缩写。

下面是Mach-o文件头部的标注。

➜  ~ otool -h Hello

Mach header

      magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags

 0xfeedfacf 16777223          3  0x80           2    18       1616 0x00200085

  从十六进制下面查看下(在VI下面执行 :%!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。

在下面的结构体声明

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 格式的标识符 */

    cpu_type_t  cputype;    /* cpu区分符 */

    cpu_subtype_t   cpusubtype; /* machine区分符 */

    uint32_t    filetype;   /* 文件类型 */

    uint32_t    ncmds;      /* 加载命令的个数 */

    uint32_t    sizeofcmds; /* 加载命令的字节数 */

    uint32_t    flags;      /* 程序的标识位 */

    uint32_t    reserved;   /* 保留字段 */

};

#define MH_MAGIC_64 0xfeedfacf /* the 64-bit mach magic number */

#define MH_CIGAM_64 0xcffaedfe /* NXSwapInt(MH_MAGIC_64) */

  64位的头部结构体和32位的相比只多了一个reserved字段,然而这个字段是保留字段,目前还是0x0。等于说现在头的结构都是一样的。

第一个字段magic

magic字段就是个特征数值,没有什么好说的,取自于下面的宏定义。

疑惑点note: 为什么是4个宏定义?查找资料并仔细观察发现:CIGAM是MAGIC反过来的拼写,写反的意思是在大端序(big endian mode)(不了解大端序,请点击wiki https://en.wikipedia.org/wiki/Endianness)环境下面使用。

第二&&三个字段CPU type 和 CPU subtype

  定义了Mach-o所能支持的所有CPU类型,这两个位置的标记表明了运行程序的平台是啥,太长了就只把 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),可重定位文件,编译器的中间产物之一,静态库(后缀名是.a)就是这类文件的集合*/

#defineMH_EXECUTE0x2

/* demand paged executable file */

/* 示例中看到的可执行文件,最基础的类型 */

#defineMH_FVMLIB0x3

/* fixed VM shared library file */

/* 后续补上,不知道在哪里见过 */

#defineMH_CORE0x4

/* core file */

/* 程序Crash之后产生的Core文件,现在默认的core dumps都是关闭的,可以通过 XXX 打开,一个Crash就生成了700多M的一个文件,我截取了他的前1600字节数据,收集起来。 */

#defineMH_PRELOAD0x5

/* preloaded executable file */

/* */

#defineMH_DYLIB0x6

/* dynamically bound shared library */

/* 一般后缀名为(.dylib),动态链接库,很常见*/

#defineMH_DYLINKER0x7

/* dynamic link editor */

/* 动态库的连接器,就这个文件/usr/lib/dyld ,Fat文件就用lipo提取一下,下面会讲到*/

#defineMH_BUNDLE0x8

/* dynamically bound bundle file */

/* Xcode里面可以创建bundle的Target,编译之后在bundle后缀名的文件夹下面可以找到*/

#defineMH_DYLIB_STUB0x9

/* shared library stub for static */

/* linking only, no section contents */

/* 后续补上,不知道在哪里见过 */

#defineMH_DSYM0xa

/* companion file with only debug */

/* sections */

/* 这个也很常见,Xcode->Product->Archive打包之后,里面就会生成一个叫DSYM后缀名的文件夹,查看包内容就可以找到它*/

#defineMH_KEXT_BUNDLE0xb

/* x86_64 kexts */

/* 内核功能扩展文件,常见与 /System/Library/Extensions 下面,这个自己可以打开瞅瞅*/

第五和六个字段 ncmds、sizeofcmds

ncmds 指的是加载命令(load commands)的数量

sizeofcmds 所有加载命令的大小。如果没有设置的话,没有办法知道加载命令从什么时候结束啦。

第七个字段 flags

  dyld加载时的标志位

#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 */

/* 动态连接器(dyld)的输入文件,无法被再次静态链接 */

#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. */

/* 当这个位被设置了之后,所有在任务中的栈被赋予栈内可执行的权限。仅在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 */

/* 当这个位被设置了之后,程序声明它对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. */

/* 当这个位被设置了之后,系统加载主可执行程序在随机的地址空间,仅在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. */

/* 当这个位被设置了之后,,仅在filetype是MH_EXECUTE的时候使用 */

#define MH_APP_EXTENSION_SAFE 0x02000000

/* The code was linked for use in an application extension. */

关于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结构,这一种是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文件就是一个包装盒,里面填了若干个针对不同架构的指令集,第一个参数magic就是Fat的标识,第二个参数就是里面包含了几个架构的指令集。

在中对指令集包装的申明

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: 看完之后,应该明白了mach-o文件共有

8种magic number {(32位/64位) * (大端序/小端序) * (是否是Fat文件)},

11种filetype

26中flag

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容