什么是 MachO?
mach-o(Mach Object File Format)是 Mac 和 iOS 平台上可执行文件的格式,相似于 windows 平台上的exe. 常见MachO格式的文件:windows
- .o
- .a .dylib .framework
- 二进制可执行文件
- .dsym
加载与执行
首先了解下什么是进程,进程是一个程序的执行实体. 那 App 的启动就能够分为两步:安全
- 内核建立一个进程,分配空间,加载 dyld
- dyld 加载根据mach-o的格式将可执行文件加载到内存. 以后系统经过
解析文件
、创建依赖
、初始化运行环境
、执行进程
这几步来真正的运行App.
MachO的结构
结构图数据结构
从图上能够看出 Mach-O 文件的结构,包括 Mach-O的头部,Load Command, Data.架构
Header
Header: 在<mach-o/loader.h>中定义了 Header 的数据结构:函数
上图代码是 64 位的 Header 数据结构,跟 32 位基本没有差异,mach_header_64多了一个额外的预留字段
uint32_t reserved
.
- magic: 魔数, FAT文件(包含多个架构)为
0xcafebabe
, armV7 是0xfeedface
, arm64是0xfeedfacf
.
- cputype: CPU 架构以及子版本
- filetype: 文件类型,常见的有MH_OBJECT(目标文件),MH_EXECUTABLE(二进制文件),MH_DYLIB(动态库)
- ncmds: 加载命名的数量
- sizeofcmds: 全部加载命名的大小
- flags: dyld 加载须要的一些标记
- reserved: 64位预留字段
LoadCommands
用于告诉loader如何设置并加载二进制数据,对系统内核加载器和动态连接器(dyld)起指导做用.ui
(经过 MachOView 查看获得) 列举几个经常使用的部分
- LC_SEGMENT_64: 定义一个Segment,加载后被映射到内存中,包括里面的节.
- LC_MAIN: 程序的入口, dyld获取该地址,而后跳转到该处执行;
- LC_LOAD_DYLIB: 依赖的动态库,包括动态库名称/当前版本号/兼容版本号;
Data (数据段 segment)
存放数据:代码、字符常量、类、方法等, 能够拥有多个segment,每一个segment能够有零到多个section。每一个段都有一段虚拟地址映射到进程的地址空间. 先来看下数据结构, LC_SEGMENT_64
定义了一个 64 位的 segment. 其定义以下:ssr
dyld 将 fileoff(基于当前架构的文件偏移量)处 fileSize 大小的内容加载到虚拟内存的 vmaddr处,其大小为 vmsize,segment 的权限由 initprot 进行初始化.
LC_SEGMENT_64
包括了一下 4 种:
- _PAGEZERO: 空指针陷阱段,用与捕捉对 iNULL指针的引用;
- _TEXT: 代码段/只读数据段;
- _DATA: 读取/写入数据的段;
- _LINKEDIT: dyld 须要的信息;
这里重点说下_TEXT字段,对于还要适配 iOS 8的 App, 可用的_TEXT段只有60M,这致使不少大团队对包大小异常敏感,也搞出来了不少trick的办法来解决.
Section
在Segment 里面会包含不一样的 section,其结构以下图:3d
- sectname: section 的名字
- segname: segment 的名字
- addr: 映射到虚拟地址的偏移
- size: section 的大小
- offset: section 在当前架构中的偏移
- align: section的字节对齐大小 n
- reloff: 重定位入口的文件偏移
- nreloc: 重定位入口的个数
- flags: section的类型与属性:
- reserved: 保留位
__TEXT Segment的 Section:指针
- __text: 可执行文件的代码区域
- __objc_methname: 方法名
- __objc_classname: 类名
- __objc_methtype: 方法签名
- __cstring: 类C 风格的字符串. __DATA Segment 的 Section:
- __nl_symbol_ptr: 非懒加载指针表,dyld 加载会当即绑定
- __ls_symbol_ptr: 懒加载指针表
- __mod_init_func: constructor 函数
- __mod_term_func: destructor 函数
- __objc_classlist: 类列表
- __objc_nlclslist: 实现了 load 方法的类
- __objc_protolist: protocol的列表
- __objc_classrefs: 被引用的类列表
- __objc _catlist: Category列表
Loader Info (连接信息)
一个完整的用户级MachO文件的末端是一系列连接信息。其中包含了动态加载器用来连接可执行文件或者依赖所需使用的符号表、字符串表等code
能用来作什么? (代码待开源)
- Category的方法覆盖检查
- 包瘦身,无用代码检查
- 代码覆盖率静态检查
参考
iOS应用逆向与安全