> For the complete documentation index, see [llms.txt](https://ryukiedev.gitbook.io/wiki/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ryukiedev.gitbook.io/wiki/ni-xiang/06.macho-wen-jian.md).

# 06.MachO文件

## 一、基础概念

* Mach-O文件其实是MachObject文件格式的缩写。是Mac以及iOS上客户性文件的格式。
* 属于MachO格式的常见文件：
  * 目标文件.o
  * 库文件
    * .a
    * .dylib
    * Framework
  * 可执行文件
  * dyld
  * .dsym
* `file`指令可以产看文件类型

## 二、我们通过一个简单的例子来看下MachO是怎么生成的

Test.c

```c
# include <stdio.h>

int main() {
    printf("Hello world");
    return 1;
}
```

Test2.c

```c
# include <stdio.h>

int main2() {
    printf("Hello money");
    return 1;
}
```

### 2.1 源文件编译为.o文件（中间对象文件）

执行命令`clang -c Test.c Test2.c`

![](/files/-MZrrBtOryHeJLdrgbsd)

看到编译出了两个对应的`.o`文件

> 可以直接 -o 一步到位

### 2.2 将.o文件生成可执行文件

执行命名`clang -o TestEx Test.o Test2.o`

生成`TestEx`的可执行文件，通过`file`指令确认一下，这里可以发现生成的就是`MachO`文件了

```
file TestEx
TestEx: Mach-O 64-bit executable x86_64
```

### 2.3 链接顺序对MachO文件的影响

我们看下当前生成TestEx文件的MD5

```
md5 TestEx
MD5 (TestEx) = 3db04e90a4e078438a03f7cb9d8bf8c8
```

再执行命名`clang -o TestEx2 Test2.o Test.o`，调整.o文件顺序。

```
➜  Create md5 TestEx2
MD5 (TestEx2) = b32bbfd76c8784f8a517249f5f7c4bec
```

#### 通过objdump查看MachO文件数据

```
➜  Create objdump --macho -d TestEx
TestEx:
(__TEXT,__text) section
_main:
100003f20:    55    pushq    %rbp
100003f21:    48 89 e5    movq    %rsp, %rbp
100003f24:    48 83 ec 10    subq    $16, %rsp
100003f28:    c7 45 fc 00 00 00 00    movl    $0, -4(%rbp)
100003f2f:    48 8d 3d 60 00 00 00    leaq    96(%rip), %rdi ## literal pool for: "Hello world"
100003f36:    b0 00    movb    $0, %al
100003f38:    e8 39 00 00 00    callq    0x100003f76 ## symbol stub for: _printf
100003f3d:    b9 01 00 00 00    movl    $1, %ecx
100003f42:    89 45 f8    movl    %eax, -8(%rbp)
100003f45:    89 c8    movl    %ecx, %eax
100003f47:    48 83 c4 10    addq    $16, %rsp
100003f4b:    5d    popq    %rbp
100003f4c:    c3    retq
100003f4d:    90    nop
100003f4e:    90    nop
100003f4f:    90    nop
_main2:
100003f50:    55    pushq    %rbp
100003f51:    48 89 e5    movq    %rsp, %rbp
100003f54:    48 83 ec 10    subq    $16, %rsp
100003f58:    48 8d 3d 43 00 00 00    leaq    67(%rip), %rdi ## literal pool for: "Hello money"
100003f5f:    b0 00    movb    $0, %al
100003f61:    e8 10 00 00 00    callq    0x100003f76 ## symbol stub for: _printf
100003f66:    b9 01 00 00 00    movl    $1, %ecx
100003f6b:    89 45 fc    movl    %eax, -4(%rbp)
100003f6e:    89 c8    movl    %ecx, %eax
100003f70:    48 83 c4 10    addq    $16, %rsp
100003f74:    5d    popq    %rbp
100003f75:    c3    retq
```

```
➜  Create objdump --macho -d TestEx2
TestEx2:
(__TEXT,__text) section
_main2:
100003f20:    55    pushq    %rbp
100003f21:    48 89 e5    movq    %rsp, %rbp
100003f24:    48 83 ec 10    subq    $16, %rsp
100003f28:    48 8d 3d 6f 00 00 00    leaq    111(%rip), %rdi ## literal pool for: "Hello money"
100003f2f:    b0 00    movb    $0, %al
100003f31:    e8 48 00 00 00    callq    0x100003f7e ## symbol stub for: _printf
100003f36:    b9 01 00 00 00    movl    $1, %ecx
100003f3b:    89 45 fc    movl    %eax, -4(%rbp)
100003f3e:    89 c8    movl    %ecx, %eax
100003f40:    48 83 c4 10    addq    $16, %rsp
100003f44:    5d    popq    %rbp
100003f45:    c3    retq
100003f46:    90    nop
100003f47:    90    nop
100003f48:    90    nop
100003f49:    90    nop
100003f4a:    90    nop
100003f4b:    90    nop
100003f4c:    90    nop
100003f4d:    90    nop
100003f4e:    90    nop
100003f4f:    90    nop
_main:
100003f50:    55    pushq    %rbp
100003f51:    48 89 e5    movq    %rsp, %rbp
100003f54:    48 83 ec 10    subq    $16, %rsp
100003f58:    c7 45 fc 00 00 00 00    movl    $0, -4(%rbp)
100003f5f:    48 8d 3d 44 00 00 00    leaq    68(%rip), %rdi ## literal pool for: "Hello world"
100003f66:    b0 00    movb    $0, %al
100003f68:    e8 11 00 00 00    callq    0x100003f7e ## symbol stub for: _printf
100003f6d:    b9 01 00 00 00    movl    $1, %ecx
100003f72:    89 45 f8    movl    %eax, -8(%rbp)
100003f75:    89 c8    movl    %ecx, %eax
100003f77:    48 83 c4 10    addq    $16, %rsp
100003f7b:    5d    popq    %rbp
100003f7c:    c3    retq
```

可以确定生成的MachO文件不同了。

> MachO是一系列.o文件的集合

## 三：MachO文件结构

### 3.1 Header

* 包含了二进制文件的一般信息
  * 字节顺序、架构类型、加载指令的数量等
  * 使得一些信息可以快速确认
    * 比如当前文件是用于32位还是64位，对应的处理器是什么、文件类型是什么

#### Header数据结构

> 可以再Xcode中快速打开文件 `Loader.h`查看，这个文件时学习MachO非常好的一个入口！

```swift
/*
 * The 64-bit mach header appears at the very beginning of object files for
 * 64-bit architectures.
 */
struct mach_header_64 {
    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 */
    uint32_t    reserved;    /* reserved */
};
```

`magic` 快速定位是64位还是32位 `cputype` CPU类型，比如ARM `cpusubtype` CPU具体类型，比如：arm64/armv7 `filetype` 文件类型，比如：可执行文件 `ncmds` LoadCommands条数 `sizeofcmds` LoadCommands大小 `flags` 标志位，标识二进制文件支持的功能。主要是和系统加载、链接有关。

#### 使用`otool`查看`Header`内容

```
➜  Create otool -v -h TestEx2
TestEx2:
Mach header
      magic  cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
MH_MAGIC_64   X86_64        ALL  0x00     EXECUTE    16       1368   NOUNDEFS DYLDLINK TWOLEVEL PIE
```

### 3.2 Load commands

* 内容包括区域的位置、符号表、动态符号表等

#### Rebase info offset

MachO文件在加载到内存中后（虚拟内存），会被分配一个随机的偏移值`ASLR`。 我们使用静态分析工具看到的并不是真实的内存地址。

#### 查看当前ASLR

![Img](/files/-MZrrBtR7HrH5zAsWi_q)

命令`image list -o -f | grep 当前MachO文件名`

```
(lldb) image list -o -f | grep WeChat
[  0] 0x0000000000118000 /Users/RyukieW/Library/Developer/Xcode/DerivedData/WeChat-ajurlvyhlazpsbhatmdivvridyee/Build/Products/Debug-iphoneos/WeChat.app/WeChat
```

ASLR `0x0000000000118000` （随机的每次都不一样） 真实地址 `0x10011e640`

#### 用工具查看地址

![Img](/files/-MZrrBtSY3CCjzDer_Rq) `0x0000000100006640`

#### 计算真实地址

* `ASLR` + `工具显示的地址`
* 使用编程计算器验证成功！

#### 使用`otool`查看`Load commands`内容

```
➜  Create otool -v -l TestEx2
...
```

### 3.3 Data

* 通常是文件中最大的部分
* 包含Segement的具体数据

[戴铭-Apple 操作系统可执行文件 Mach-O](https://ming1016.github.io/2020/03/29/apple-system-executable-file-macho/) [iOS逆向工程（九）：ASLR](https://www.jianshu.com/p/94f67bb84c93)
