Mach-O

iOS | Mach-O | Objective-C

1.APP从开发到安装到手机的过程

APP从开发到安装到手机_1

APP从开发到安装到手机_2

2.逆向APP的思路

  • 界面分析
    Cycript、Reveal

  • 代码分析
    1> 对Mach-O文件的静态分析
    2> MachOView、class-dump、Hopper Disassembler、ida等

  • 动态调试
    1> 对运行中的APP进行代码调试
    2> debugserver、LLDB

  • 代码编写
    1> 注入代码到APP中
    2> 必要时还可能需要重新签名、打包ipa

3.class-dump

  • 顾名思义,它的作用就是把Mach-O文件的class信息给dump出来(把类信息给导出来),生成对应的.h头文件

  • 官方地址:http://stevenygard.com/projects/class-dump/
    class-dump

  • 下载完工具包后将class-dump文件复制到Mac的/usr/local/bin目录,这样在终端就能识别class-dump命令了

  • 常用格式
    1> class-dump -H Mach-O文件路径 -o 头文件存放目录
    2> -H表示要生成头文件
    3> -o用于制定头文件的存放目录

4.代码的编译过程

代码编译过程_1

不同的OC代码,编译出来的汇编代码可能是一样的:
代码编译过程_2

5.Hopper Disassmbler

  • Hopper Disassmbler能够将Mach-O文件的机器语言代码反编译成汇编代码、OC伪代码或者Swift伪代码

  • 常用快捷键
    找出哪里引用了这个方法:Shift + Option + X

6.动态库共享缓存(dyld shared cache)

  • 从iOS3.1开始,为了提高性能,绝大部分的系统动态库文件都打包存放到了一个缓存文件中(dyld shared cache)
    缓存文件路径:/System/Library/Caches/com.apple.dyld/dyld_shared_cache_armX

  • dyld_shared_cache_armXX代表ARM处理器指令集架构

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    v6
    iPhone、iPhone3G
    iPod Touch、iPod Touch2

    v7
    iPhone3GS、iPhone4、iPhone4S
    iPad、iPad2、iPad3(The New iPad)
    iPad mini
    iPod Touch3G、iPod Touch4、iPod Touch5

    v7s
    iPhone5、iPhone5C
    iPad4

    arm64
    iPhone5S、iPhone6、iPhone6 Plus、iPhone6S、iPhone6S Plus
    iPhoneSE、iPhone7、iPhone7 Plus、iPhone8、iPhone8 Plus、iPhoneX、iPhoneXR、iPhoneXS
    iPad5、iPad Air、iPad Air2、iPad Pro、iPad Pro2
    iPad mini with Retina display、iPad mini3、iPad mini4
    iPod Touch6
  • 所有指令集原则上都是向下兼容的

  • 动态库共享缓存一个非常明显的好处是节省内存
  • 现在的ida、Hopper反编译工具都可以识别动态库共享缓存

动态库共享缓存

7.动态库的加载

8.从动态库共享缓存抽取动态库

  • 可以使用 dyld 源码中的 launch-cache/dsc_extractor.cpp
    1> 将#if 0前面的代码删除(包括#if 0),把最后面的#endif也删掉
    2> 编译dsc_extractor.cpp
    clang++ -o dsc_extractor dsc_extractor.cpp
    3> 使用dsc_extractor
    ./dsc_extractor 动态库共享缓存文件的路径 用于存放抽取结果的文件夹

9.Mach-O

  • Mach-O是Mach object的缩写,是Mac\iOS上用于存储程序、库的标准格式

  • 属于Mach-O格式的文件类型有
    Mach-O_Type

  • 可以在xnu源码中,查看到Mach-O格式的详细定义: https://opensource.apple.com/tarballs/xnu/
    1> EXTERNAL_HEADERS/mach-o/fat.h
    2> EXTERNAL_HEADERS/mach-o/loader.h


常见的Mach-O文件类型:

  • MH_OBJECT
    1> 目标文件(.o)
    2> 静态库文件(.a),静态库其实就是N个.o合并在一起

  • MH_EXECUTE:可执行文件
    .app/xx

  • MH_DYLIB:动态库文件
    1> .dylib
    2> .framework/xx

  • MH_DYLINKER:动态链接编辑器
    /usr/lib/dyld

  • MH_DSYM:存储着二进制文件符号信息的文件
    .dSYM/Contents/Resources/DWARF/xx(常用于分析APP的崩溃信息)

10.Mach-O的基本结构

Mach-O结构

11.窥探Mach-O的结构

命令行工具:

  • file:查看Mach-O的文件类型
    file 文件路径
  • otool:查看Mach-O特定部分和段的内容
  • lipo:常用于多架构Mach-O文件的处理
    1> 查看架构信息:lipo -info 文件路径
    2> 导出某种特定架构:lipo 文件路径 -thin 架构类型 -output 输出文件路径
    3> 合并多种架构:lipo 文件路径1 文件路径2 -output 输出文件路径

GUI工具
MachOView: https://github.com/gdbinit/MachOView

12.Universal Binary(通用二进制文件)

  • 通用二进制文件
    1> 同时适用于多种架构的二进制文件
    2> 包含了多种不同架构的独立的二进制文件

  • 因为需要储存多种架构的代码,通用二进制文件通常比单一平台二进制的程序要大

  • 由于两种架构有共同的一些资源,所以并不会达到单一版本的两倍之多

  • 由于执行过程中,只调用一部分代码,运行起来也不需要额外的内存

  • 因为文件比原来的要大,也被称为“胖二进制文件”(Fat Binary)

13.dyld和Mach-O

  • dyld用于加载以下类型的Mach-O文件
    1> MH_EXECUTE
    2> MH_DYLIB
    3> MH_BUNDLE

  • APP的可执行文件、动态库都是由dyld负责加载的