iOS瘦身之__Text段移动

3,425 阅读2分钟

之前看过头条的一篇文章,移动__Text段来瘦身,主要的原理是因为苹果会对APP加壳,加壳的话会是加到__Text段,将数据从__Text段,移动到我们所创建的段,并赋予可读可写权限,那么就可以达到瘦身的效果。

iOS 7 之前,二进制文件中所有的 __TEXT 段总和不得超过 80 MB

iOS 7.X 至 iOS 8.X ,二进制文件中,每个特定架构中的 __TEXT 段不得超过 60 MB

iOS 9.0 之后,二进制文件中所有的 __TEXT 段总和不得超过 500 MB

  • Data 部分中有 5 个 Segment,依次是:

    • __PAGEZERO
    • __TEXT
    • __DATA_CONST
    • __DATA
    • __LINKEDIT
  • 除 __PAGEZERO 和 __LINKEDIT外,每个段中有多个 Section

注意:Data 与 __DATA 是不同的两个概念。Data 是 Mach-O 文件中的一部分,包含多个段。__DATA 只是 Data 中的一个段。

__PAGEZERO 的大小是 4 GB,但并不是它在 Mach-O 文件中的真实大小。这 4 GB 是 Mach-O 加载进内存后, __PAGEZERO 在内存中占中的大小,它不可读,不可写,主要用来捕捉 NULL 指针的引用。如果访问 __PAGEZERO 段,会引起 EXC_BAD_ACCESS 错误。__PAGEZERO 在 Mach-O 中实际上并不占用 Data 部分的空间。

  • __TEXT、__DATA_CONST、__DATA 用于保存程序的代码指令和数据。

  • __LINKEDIT 包含启动 App 需要的信息,比如 bind & rebase 的地址,代码签名,符号表等。

核心但是就是在Build SettingsOther Linker Flags中添加

-Wl,-rename_section,__TEXT,__text,__BD_TEXT,__text
-Wl,-segprot,__BD_TEXT,rx,rx

其中 -Wl 的作用是告诉 Xcode 它后面的参数是添加给Ld链接器的,这些参数将在链接阶段生效

第一行参数会新创建一个 BD_TEXT段,并把TEXT移动到BD_TEXT

第二行参数是给 __BD_TEXT 赋予可读和可执行权限。

可以看到  TEXT 已经被移动到了 __BD_TEXT 中去了 它的地址也由起始的 0x100005e5c 变为了 0x100010000

此时程序仍可以正常的运行,这是因为操作系统只关心段的读/写/执行权限,并不关心段或节的名称。即便是使用了 -rename_p 移动 Segment/Section,各符号的地址也会由链接器修正好,因此段移动后程序也可以正常运行。

注意点:

  1. dyld在启动阶段会检查 unwind_infoeh_frame 这两个 Section如果移动这两个 Section ,在启动后程序就会 Crash

  2. Swift 相关的 Section 不能移动,否则会引起 Crash

  3. 自己在代码中指明要读取的 Section

我们打开MachO查看两个包可以看到

image.png

新增加了Section64(__BD_TEXT,__text)

打开__Text我们来看一下,发现__text段的确被移动了 image.png