Mach-O文件格式

Mach-O文件结构

Mach-O(Mach Object)是一种基于Mach内核的文件格式。iOS系统生成的可执行程序或者动态库文件的存储布局格式被称之为mach-o格式。Mach-O可以有一个或多个架构。多个架构的称为FAT文件。Mach-O文件结构包括

  1. Mach-O header 文件的目标基本信息,包含架构例如PPC,PPC64,IA-32或x86-64等信息
  2. Load Command 文件的逻辑结构和文件在虚拟内存中的布局。可以根据他找到相关的Section 原始数据。mach-o文件由诸多的load command组成,,每个load command所代表的是一种数据类型。每种load command都是结构体struct load_command的扩展结构体。
  3. Section 节:每个段则由多个节(Section)组成。节是内容分类的最小管理单元。每个节的描述信息是一个称之为:struct section的结构体。每个节有一个唯一的名称用来标识这个节。
image

ASLR技术

ASLR,全称是Address Spce Layout Randomization,地址空间布局随机化,是一种针对缓冲区溢出的安全保护技术,通过对堆、栈、共享库映射等线性区布局的随机化,增加了攻击者预测目的地址的难度,防止攻击者直接定位代码位置,阻止溢出攻击。这种技术会使得每个程序或者库每次运行加载到内存中时的基地址都不是固定而是随机的,这种机制会增加黑客的破解难度。

iOS中,Mach-O文件 load Commonds 中LC_DYLD_INFO或者LC_DYLD_INFO_ONLY 就是用来记录所有需要进行地址调整的位置。这样当程序被加载到内存时,加载器就会将需要调整的地址分别进行调整处理,以便转化为真实的内存地址。这个过程称之为基地址重定向(rebase)。

Header

mach-o/loader.h 。使用otool -h -v 命令查看Mach-O文件头。

$ otool -h -v  TestMachO
Mach header
      magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
MH_MAGIC_64  X86_64        ALL  0x00     EXECUTE    40       5256   NOUNDEFS DYLDLINK TWOLEVEL WEAK_DEFINES BINDS_TO_WEAK PIE

对于FAT文件。Fat文件的header,最前面时FatHeader, 接着是各架构的arch

struct fat_header {
    unsigned long   magic;      /* FAT_MAGIC */
    unsigned long   nfat_arch;  /* number of structs that follow */
};

struct fat_arch {
    cpu_type_t  cputype;    /* cpu specifier (int) */
    cpu_subtype_t   cpusubtype; /* machine specifier (int) */
    unsigned long   offset;     /* file offset to this object file */
    unsigned long   size;       /* size of this object file */
    unsigned long   align;      /* alignment as a power of 2 */
};

单架构的 Mach-O header的定义

struct mach_header_64 {
    uint32_t    magic;      /* mach magic number identifier */
    cpu_type_t  cputype;    /* cup 架构 cpu specifier */
    cpu_subtype_t   cpusubtype; /*  machine specifier */
    // 文件类型常见有的MH_OBJECT(目标文件)、MH_EXECUTABLE(可执行二进制文件)、MH_DYLIB (动态库)。
    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 */
    uint32_t    reserved;   /* reserved */
};
mach-o Header.png

Load Command

Load Command告诉操作系统应当如何加载文件中的数据,对系统内核加载器和动态链接器起指导作用。使用MachOView查看LoadCommand

mach-o load commands.png
常见的Segment
  1. LC_SEGMENT_64: 64 位segment 的映射。64-bit segment of this file to be mapped.

  2. LC_DYLD_INF0_0NLY:记录了有关链接的重要信息,包括在_LINKEDIT中动态链接相关信息的具体偏移和大小。ONLY表示这个加载指令是程序运行所必需的。

  3. LC_SYMTAB:为文件定义符号表和字符串表。在链接文件时被链接器使用,同时也用于调试器映射符号到源文件。符号表定义的本地符号仅用于调试,而已定义和未定义的 external符号被链接器使用。

  4. LC_DYSYMTAB:将符号表中给出符号的额外符号信息提供给动态链接器。

  5. LC_LOAD_DYLINKER:默认的加载器路径。

  6. LC.UUID:用于标识Mach-0文件的ID,也用于崩溃堆栈和符号文件的对应解析。

  7. LC_VERSION_MIN_IPHONEOS:系统要求的最低版本。

  8. LC.SOURCE.VERSION:构建二进制文件的源代码版本号。

  9. LC.MAIN:程序的入口。dykl获取该地址,然后跳转到该处执行。

  10. LC_ENCRYPTION_INFO_64:文件是否加密的标志,加密内容的偏移和大小。

  11. LC_LOADJDYLIB:依赖的动态库,包括动态库名称、当前版本号、兼容版本号。可以使用 “otool-Lxxx”命令查看。

$ otool -L TestMachO
SDSAD:
    /System/Library/Frameworks/Foundation.framework/Foundation (compatibility version 300.0.0, current version 1751.108.0)
    /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1292.0.0)
    ...
  1. LC_RPATH: Runpath Search Paths, @rpath
  2. LC_FUNCTION_STARTS:函数起始地址表,使调试器和其他程序能很容易地看到一个地
    址是否在函数内。
  3. LC_DATA_IN_CODE:定义在代码段内的非指令的表。 • LC_CODE_SIGNATURE:代码签名信息。
LC_Segment_64

segment 的结构定义:

struct segment_command_64 { /* for 64-bit architectures */
    uint32_t    cmd;        /* LoadCommand类型 */
    uint32_t    cmdsize;    /* LoadCommand结构的大小  */
    char        segname[16];    /* segment name */
    uint64_t    vmaddr;     /* 对应section的起始地址 。映射到虚拟地址的偏移 */
    uint64_t    vmsize;     /* 映射到虚拟地址的大小 */
    uint64_t    fileoff;    /* 对应于当前架构文件的偏移(注意:是当前架构文件,不是整个FAT文件) */
    uint64_t    filesize;   /* 文件的大小 */
    vm_prot_t   maxprot;    /* 段页面的最高内存保护 */
    vm_prot_t   initprot;   /* 初始内存保护。 */
    uint32_t    nsects;     /* 包含section 的个数 */
    uint32_t    flags;      /* flags 页面标志 */
};

系统将fileoff偏移处filesize大小的内容加载到虚拟内存的vmaddr处,大小为vmsize,Segment页面的权限由initprot进行初始化。它的权限可以动态改变,但是不能超过maxprot的值,例如 _TEXT初始化和最大权限都是可读/可执行/不可写。
Segment 的分类

  • _PAGEZERO:空指针陷阱段,映射到虚拟内存空间的第1页,用于捕捉对 的引用。
  • _TEXT:代码段/只读数据段。
  • _DATA_CONST:常量数据的段
  • _DATA:读取和写入数据的段。
  • _LINKEDIT:动态链接器需要使用的信息,包括重定位信息、绑定信息、懒加载信息等。

每一个 Segment 对应着0到多个Section 的数据。LC_Senment_64 的后面位置则存储着 Section64 数据(找到对应的section 原始数据的偏移,大小等)。

Section64

struct section_64 { /* for 64-bit architectures */
    char        sectname[16];   /* name of this section */
    char        segname[16];    /* 对应Segment 的名称 */
    uint64_t    addr;       /* 映射到虚拟地址的偏移 */
    uint64_t    size;       /* size in bytes of this section */
    uint32_t    offset;     /* file offset of this section */
    uint32_t    align;      /* 字节对其大小 (power of 2) */
    uint32_t    reloff;     /* file offset of relocation entries */
    uint32_t    nreloc;     /*  重定位入口的个数。 */
    uint32_t    flags;      /* flags (section type and attributes)*/
    uint32_t    reserved1;  /* 保留位 (for offset or index) */
    uint32_t    reserved2;  /* reserved (for count or sizeof) */
    uint32_t    reserved3;  /* reserved */
};
Segment _TEXT
  • 程序可执行的代码区域。
  • __stubs:间接符号存根,跳转到懒加载指针表。
  • __stub_helper:帮助解决懒加载符号加载的辅助函数。
  • __objc一methname:方法名。
  • __objc_classname:类名。
  • __objc_methtype:方法签名。
  • __cstring:只读的C风格字符串,包含0C的部分字符串和属性名。
Segment _DATA
  • __nl_symboLptr:非懒加载指针表,在dyld加载时会立即绑定值。
  • _la_symbol_ptr:懒加载指针表,第1次调用时才会绑定值。
  • __got:非懒加载全局指针表。
  • __objc_classrefs:被引用的类列表。
  • __mod一 init一 func: constructor函数
  • __mod_term_func: destructor函数。
  • __cfstring: 0C字符串。
  • __objc_classlist:程序中类的列表。
  • __objc_nlclslist:程序中自己实现了+load方法的类。
  • __objc_protolist:协议的列表。
用于分析Mach-O的工具
  • /usr/bin/lipo :可以创建和分析包含用于多个体系结构的映像的二进制文件。这种二进制文件的一个示例是通用二进制文件。通用二进制文件可以在基于PowerPC和基于Intel的Macintosh计算机中使用。另一个示例是PPC / PPC64二进制文件,可以在基于32位PowerPC和基于64位PowerPC的Macintosh计算机中使用。
  • /usr/bin/file:显示文件的类型。对于多体系结构文件,它显示构成档案的每个图像的类型。
  • /usr/bin/otool:可以列出了Mach-O文件中特定节和段的内容。它包括每种受支持体系结构的符号反汇编程序,并且知道如何格式化许多常见节类型的内容。
  • /usr/bin/pagestuff:显示组成图像的每个逻辑页面上的信息,包括各部分的名称和每个页面中包含的符号。该工具不适用于包含多个架构的图像的二进制文件。
  • /usr/bin/nm:可以查看目标文件的符号表的内容。
  • MachoView:可以查看mach-o文件内容
// 通过file命令查看文件信息
$ file TestMachO
SDSAD: Mach-O 64-bit executable x86_64

相关链接

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