03-什么是Mach-O文件?

App从开发到安装到手机上的过程


想要了解Mach-O文件,首先要了解从编写代码,开发App到App打包并安装到手机上的整个过程

首先代码经过编译、链接、签名获得一个“xxx.app”包,app包里面就装着nib文件、资源文件以及可执行文件(Mach-O文件),我们编写的代码其实就放在这个Mach-O文件里面
03-什么是Mach-O文件?_第1张图片03-什么是Mach-O文件?_第2张图片
然后经过zip压缩,将app包转成ipa包,而ipa包就可通过以下几个途径可以装到手机里

  • 上传至App Store,自行下载
  • 通过Xcode、爱思助手、iFunBox等工具安装

逆向App的思路


主要是以下四个步骤:
1、界面分析,通过Cycript、Reveal等工具窥探UI界面
2、 代码分析,用MachOView、class-dump、Hopper Disassembler、ida等对Mach-O文件静态分析
3、 动态调试、用debugserver、LLDB对运行中的App进行代码调试
4、代码编写,注入代码到App中,必要时还需要重新签名、打包ipa

代码分析工具


接下来介绍几个Mach-O的静态分析工具

class-dump(下载地址)

class-dump的作用就是把Mach-O文件的class信息给导出来(把类信息导出来),生成对应的.h头文件,下载完成需要将其中的class-dump可执行文件复制到Mac上的/usr/local/bin目录中,终端就能识别class-dump命令

在Mac中,终端执行的所有指令都会去/usr/bin目录和/usr/local/bin目录下寻找,但是在Mac OS 10.11之后,usr/bin/目录下是不可写的,因此只能放到/usr/local/bin目录下

class-dump的常用命令如下:

class-dump -H Mach-O文件路径 -o 头文件存放目录
Hopper Disassmbler

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

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


如果想分析一下类似UIKit等系统框架的Mach-O文件,那么如何找到该文件呢?

其实从iOS3.1开始,为了提高性能,绝大部分的系统动态库文件都打包存放到了一个缓存文件中(dyld shared cache),缓存路径为/System/Library/Caches/com.apple.dyld/dyld_shared_cache_armX(X代表ARM处理器指令集的架构),其用处多个App共享一份内存,可以节省内存

ARM指令集有以下几种:

ARM指令集 支持的设备
armv6 iPhone、iPhone3G
iPod Touch、iPod Touch2
armv6 iPhone3GS、iPhone4、iPhone4S
iPad、iPad2、iPad3(The New iPad)、iPad mini
iPod、Touch3G、iPod Touch4、iPod Touch5
armv6 iPhone5、iPhone5C、iPad4
armv6 iPhone5S、iPhone6、iPhone6 Plus、iPhone6S、iPhone6S Plus
iPhoneSE、iPhone7、iPhone7Plus、iPhone8、iPhone8 Plus、iPhoneX
iPad5、iPad Air、iPad Air2、iPad Pro、iPad Pro2
iPad mini with Retina display、iPad mini3、iPad mini4
iPod Touch6

然而由于动态库共享缓存太大,想要分析单个动态库,就需要从动态库共享缓存中抽取对应的动态库。在Mac/iOS中,是使用了/usr/lib/dyld程序来加载动态库,dyld程序名称为dynamic link editor(动态链接编辑器)或dynamic loader(动态加载器),其源码地址在这里

提取步骤为:

  • 找到launch-cache/dsc_extractor.cpp文件
  • 去掉前面的#if 0和后面的#endif
  • 编译dsc_extractor.cpp文件
clang++ -o dsc_extractor dsc_extractor.cpp
  • 使用dsc_extractor抽取
./dsc_extractor 动态库共享缓存文件的路径 用于存放抽取结果的目录

03-什么是Mach-O文件?_第3张图片
此时动态库就被抽取出来,然后使用Hopper Disassmbler打开动态库,就可以看到动态库中的源码信息了

Mach-O文件


接下来从几个方面介绍Mach-O文件,Mach-O是Mach object的缩写,是Mac\iOS上用来存储程序、库的标准格式

Mach-O文件类型

在xnu源码(点击下载源码)中,可以查看到Mach-O格式的详细定义,具体代码在EXTERNAL_HEADERS/mach-o/loader.h 文件中
03-什么是Mach-O文件?_第4张图片
常见的Mach-O文件文件类有:

  • MH_OBJECT
    目标文件(.o):代码编译后的目标文件,如clang -c xxx.c 生成xxx.o目标文件
    静态库文件(.a)
  • MH_EXECUTE
    可执行文件:如.app包中的可执行文件
  • MH_DYLIB
    动态库文件(.dylib):在/usr/lib/目录下就有很多类似文件
  • MH_DYLINKER
    动态链接编辑器:在设备的/usr/lib/dyld文件
  • MH_DSYM
    二进制文件符号信息:App在release环境下编译后生成的文件,用来分析App
    的崩溃信息

想要查看某个具体的Mach-O文件类型,在终端中输入指令:

# 需要在文件所属目录下
file 文件名
dyld和Mach-O的关系

dyld是iOS中用来加载可执行文件、动态库的工具,其实它本身也是一个Mach-O文件,其类型为MH_DYLINKER,可以用来加载以下三种类型的Mach-O文件

  • MH_EXECUTE
  • MH_DYLIB
  • MH_BUNDLE

以下就是dyld的源码加载文件时的类型校验
03-什么是Mach-O文件?_第5张图片

Universal Binary(通用二进制文件)

通用二进制文件适用于多种架构,包含了多种不同架构的独立的二进制文件,有如下特点:

  • 因为需要存储多种架构的代码,所以通用二进制文件要比单架构二进制文件要大
  • 因为两种种架构之间可以共用一些资源,所以两种架构的通用二进制文件大小不会达到单一架构版本的两倍
  • 运行过程中只会调用其中的部分代码,所以运行起来不会占用额外的内存
  • 通用二进制文件通常也被称为“胖二进制文件(Fat binary)

可以用如下指令来处理多架构Mach-O文件:

#查看架构信息
lipo -info 文件路径
#导出某种类型的架构
lipo 文件路径 -thin 架构类型 -output 输出文件路径
#合并多种架构类型
lipo 文件路径1 文件路径2 -output 输出文件路径
Mach-O的基本结构

一个Mach-O文件包含三个主要区域:

  • Header:存放文件类型、目标架构类型等
  • Load commands:描述文件在虚拟内存中的逻辑结构和布局,可以理解成Raw segment data的索引目录
  • Raw segment data:在Load commands中定义的Segment的原始数据
    03-什么是Mach-O文件?_第6张图片
窥探Mach-O的结构

想要查看Mach-O文件的结构,可以使用otool命令和MachOView工具

  • otool
#查看Mach-O文件的header信息
otool -h 文件路径
#查看Mach-O文件的load commands信息
otool -l 文件路径
#更多用法直接输入
otool
  • MachOView
    一个可以直接查看Mach-O文件结构的GUI工具,点击这里下载

你可能感兴趣的:(iOS,逆向,ios,swift,objective-c)