美文网首页IOS个人开发
Mach-O文件初了解

Mach-O文件初了解

作者: Claire_wu | 来源:发表于2019-03-25 15:05 被阅读62次

1 什么是Mach-O

Mach-O其实是Mach Object文件格式的缩写,是mac以及iOS上可执行文件的格式, 类似于windows上的PE格式 (Portable Executable ), linux上的elf格式 (Executable and Linking Format)。
如果我们想对 Mach -O 文件有所了解,可以将我们打包好的 ipa 文件后缀改成 .zip,然后解压生成 Payload 文件,在其中就可以找到 exec 文件。或者找一个动态库的 framework 在其中也可以找到 exec 文件。

常见的MachO文件:

  • 目标文件:.o
  • 库文件:.a .dylib Framework
  • 可执行文件:dyld .dsym

如何查看文件格式

file [文件路径/文件名]
image.png

2 MachOView

官网直接下载的MachOView.app打开后不停闪退,因此最好是直接去下载源码然后编译出来使用。
MachOView GitHub地址
下载后记得修改源码:

image.png

3 MachO文件结构

使用MachOView打开两个Xcode编译后生成的app可执行文件,文件结构分别如下:


x86_64.png armv7 and arm64.png

根据图可以看出,同时支持多种指令集的MachO文件会针对每个指令集生成一个Executable,每一个Executable里的文件结构又是一样的。下面我们针对Executable文件来分析,先看一张官网的MachO文件结构图,可看出MachO文件主要由三部分组成:

  • Header
  • Load Commons
  • Data


    image.png

3.1 Mach Header

选取了Mach64 Header来分析,图中未红字表明的flags表示的是标示位,主要与系统的加载、链接相关:


image.png

3.2 Load Commands

Load commands是一张包含很多内容的表,内容包括区域的位置、符号表、动态符号表等。这里就是二进制文件加载进内存要执行的一些指令。这里的指令主要在负责我们 APP 对应进程的创建和基本设置(分配虚拟内存,创建主线程,处理代码签名/加密的工作),然后对动态链接库(.dylib 系统库和我们自己创建的动态库)进行库加载和符号解析的工作。

字段名称及意义分别如下:

名称 含义
LC_SEGMENT_64 将文件中(32位或64位)的段映射到进程地址空间中
LC_DYLD_INFO_ONLY 动态链接相关信息
LC_SYMTAB 符号地址
LC_DYSYMTAB 动态符号表地址
LC_LOAD_DYLINKER 使用谁加载,我们使用dyld
LC_UUID 文件的UUID
LC_VERSION_MIN_MACOSX 支持最低的操作系统版本
LC_SOURCE_VERSION 源代码版本
LC_MAIN 设置程序主线程的入口地址和栈大小
LC_LOAD_DYLIB 依赖库的路径,包含三方库
LC_FUNCTION_STARTS 函数起始地址表
LC_CODE_SIGNATURE 代码签名

首先看下Load Commands目录结构:

image.png
从上图可知 Load Commands 主要包含了有多个 Segment 段,每个中又包含了多个 Section 段。每一部分都是系统执行指令。其中 LC_SEGMENT 包含空指针陷阱
__TEXT段主要包含程序代码和只读的常量,这个段的内容如果是系统动态库的内容那么所有进程公用
__DATA 段主要包含全局变量和静态变量,这个段的内容每个进程单独进行维护
__LINKEDIT 主要包含链接器使用的符号和其他的表(比如函数名称、地址等) 这个段的内容也是可以多进程公用的。

此外还需介绍下和 SEGMENT 并列的一些比较重要的指令:

  • LC_LOAD_DYLINKER 该字段标明我们的MachO是被谁加载进去的。
    可以理解为LC_LOAD_DYLINKER指向的地址是微信APP加载小程序的引擎,而我们的MachO是小程序。在上图中可以看到我们的Demo1的LC_LOAD_DYLINKER指向的地址就是dylddyld确实是用来加载我们app的。

  • LC_LOAD_DYLIB
    该字段标记了所有动态库的地址,只有在LC_LOAD_DYLIB中有标记,我们MachO外部的动态库(如:Framework)才能被dyld正确的引用,否则dyld不会主动加载。(因此很多通过这个知识点来做代码注入

  • LC_MAIN 是在所有的库都加载完成后,有其中的指令启动程序的主线程。我们的程序也是在这个函数之后才开始执行 main() 函数的。

  • LC_CODE_SIGNATURE 我想每个 iOSer 都知道代码签名的机制,其实代码签名的校验也是在这个指令下进行。实际上指令会把整个文件进行 hash 化处理并签名,在运行时去验证签名的正确性。

3.3 Data

Data 通常是对象文件中最大的部分,包含Segement的具体数据,如静态C字符串,带参数/不带参数的OC方法,带参数/不带参数的C函数。

可以看到,全局静态C字符,方法里面的字符串都被保存在data段的cstring里了,哪怕是%d,%s等等这样的参数类型字符串也被保存在内,但所有同样的字符串只会被保存一次:


cstring.png

同样所有的OC方法都被保存在methname里了:


methname.png

4 结语

暂时通过MachOView初步窥探了一下MachO文件的结构,理解MachO文件结构是对后续学习MachO文件加载、dyld等建立知识基础。好多知识对于自己目前的知识水平感觉真的是看着像都懂了,但一问细节却又什么都不懂,书读百遍其义自见吧。
参考文章:
iOS逆向(5)-不知MachO怎敢说自己懂DYLD
理解 Mach-O 并提高程序启动速度

相关文章

网友评论

    本文标题:Mach-O文件初了解

    本文链接:https://www.haomeiwen.com/subject/cecvvqtx.html