阅读 22

MachO详解以及使用

什么是 MachO?

mach-o(Mach Object File Format)是 Mac 和 iOS 平台上可执行文件的格式,类似于 windows 平台上的exe. 常见MachO格式的文件:

  • .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)起指导作用.

(通过 MachOView 查看得到) 列举几个常用的部分

  • LC_SEGMENT_64: 定义一个Segment,加载后被映射到内存中,包括里面的节.
  • LC_MAIN: 程序的入口, dyld获取该地址,然后跳转到该处执行;
  • LC_LOAD_DYLIB: 依赖的动态库,包括动态库名称/当前版本号/兼容版本号;

Data (数据段 segment)

存放数据:代码、字符常量、类、方法等, 可以拥有多个segment,每个segment可以有零到多个section。每个段都有一段虚拟地址映射到进程的地址空间. 先来看下数据结构, LC_SEGMENT_64定义了一个 64 位的 segment. 其定义如下:

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,其结构如下图:

  • 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文件的末端是一系列链接信息。其中包含了动态加载器用来链接可执行文件或者依赖所需使用的符号表、字符串表等

能用来做什么? (代码待开源)

  • Category的方法覆盖检查
  • 包瘦身,无用代码检查
  • 代码覆盖率静态检查

参考

iOS应用逆向与安全

关注下面的标签,发现更多相似文章
评论