IOS逆向学习-Mach-o
1. 动态库
1.1 动态库的缓存
-
从IOS3.1开始,为了提高性能,绝大部分的系统动态库文件都打包存放到一个缓存文件夹中(
dyld shared cache) -
缓存文件的路径:
/System/Library/Caches/com.apple.dyld/dyld_share_cache_armX(X: 代表ARM处理器指令集架构)

-
所有的框架的可执行文件(
Mach-o)文件都不在/System/Library/Frameworks/xxxx.framework中,改路径下存放都的都是各个各个framework的一些资源配置文件,可执行文件都合并到一个caches中,这样做的好处是:节省内存
1.2 动态库的加载
- 在Mac\IOS中,是使用了
/usr/lib/dyld程序来加载动态库 dyld:dynamic link editor: 动态链接编辑器dynamic loader: 动态加载器
- dyld源码
- 苹果开源代码地址
- dyld源码查看过程截图


1.3 拆分dyld_share_cache_armX(动态库)文件
- 网上有些工具可以拆分,但是我们可以使用苹果官方拆分方法
- 下载dyld的源码 ,然后找到
dsc_extractor.cpp文件,该文件所在路径(源码823.73版本)dyld/shared_cache文件加下dsc_extractor.cpp类 - 进入当前文件所在目录,然后在终端使用命令编译该文件(本次编译会报错):

- 如果编译报错, 我们把该文件的一些代码删除只保留如下部分,然后再编译:

// test program
#include <stdio.h>
#include <stddef.h>
#include <dlfcn.h>
typedef int (*extractor_proc)(const char* shared_cache_file_path, const char* extraction_root_path,
void (^progress)(unsigned current, unsigned total));
int main(int argc, const char* argv[])
{
if ( argc != 3 ) {
fprintf(stderr, "usage: dsc_extractor <path-to-cache-file> <path-to-device-dir>\n");
return 1;
}
//void* handle = dlopen("/Volumes/my/src/dyld/build/Debug/dsc_extractor.bundle", RTLD_LAZY);
void* handle = dlopen("/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/usr/lib/dsc_extractor.bundle", RTLD_LAZY);
if ( handle == NULL ) {
fprintf(stderr, "dsc_extractor.bundle could not be loaded\n");
return 1;
}
extractor_proc proc = (extractor_proc)dlsym(handle, "dyld_shared_cache_extract_dylibs_progress");
if ( proc == NULL ) {
fprintf(stderr, "dsc_extractor.bundle did not have dyld_shared_cache_extract_dylibs_progress symbol\n");
return 1;
}
int result = (*proc)(argv[1], argv[2], ^(unsigned c, unsigned total) { printf("%d/%d\n", c, total); } );
fprintf(stderr, "dyld_shared_cache_extract_dylibs_progress() => %d\n", result);
return 0;
}
-
变成该文件之后,我们需要在终端执行该文件, 那么你在执行这个文件的时候需要指明路径,然后开始拆分库:
./dsc.extractor(可执行键) dyld_shared_cachexx(缓存文件路径) 拆分文件路径:/dsc_extractor dyld_shared_cache_arm64 arm64,最后拆分:
-
拆解完成之后,你可以使用
hopper disassemble来分析你想分析的框架
2. Mach-O
2.1 查看Mach-O的文件类型
-
Mach-O是Mach object的缩写,是Mac\iO上用于储存程序、库的标准格式
-
Mach-O格式的文件类型有:

-
可以在xnu源码中,查看到Mach-O格式的详细定义源码地址
-
xnu: Mac系统的一些内核源码,先下载xnu的源码(xnu-7195.81.3版本),然后把整个源码拖拽到sublineText工具中,根据下面路径可以查看Mach-o类包含的文件类型- EXTEENAL_HEADERS/mach-o/loader.h

- EXTEENAL_HEADERS/mach-o/loader.h
2.2 常见的Mach-O文件类型
我们在在终端,输入命令file xxx查看某个文件的类型
.o文件被称为目标文件:.c 文件 ---(编译)---> .o文件(目标文件)-----(链接)----> 可执行文件(文件的编译过程)
-
MH_OBJECT: 目标文件(.o)、静态库文件(.a),静态库其实就是N个.o合并在一起- 示例:我们可以生成一个.文件,然后编译生成.o文件,然后查看文件类型:

- 由上面过程我们可以看出
.o文件其实是Mach-O文件类型,可以通过同样的方式查看.a文件的类型
- 示例:我们可以生成一个.文件,然后编译生成.o文件,然后查看文件类型:
-
MH_EXECUTE:可执行文件
-
MH_DYLIB:动态库文件 ;.dyld、.framework/xx -
MH_DYLINKER:动态链接编辑器;/usr/lib/dyld -
MH_DSYM:存储这二进制文件符号信息的文件,.dSYM.Content/Resources/DWAFR/xx常用于分析APP的崩溃信息 -
find . -name "*.a": 在当前路径下查找后缀名为.a的文件 (. 代表当前路径)

-
在Xcode中查看target的Mach-O类型:

2.3 Universal Binary(通用二进制文件)
-
通用二进制文件 :
- 同时适用于多种架构的二进制文件
- 包含了多种不同架构的独立二进制文件
-
因为需要储存多种代码的结构,通用二进制文件通常比单一平台的二进制文件的程序要大
-
由于两种架构的有共同的一些资源,所以并不会达到单一版本的两倍之多
-
由于执行过程中,只调用一部分代码,运行起来也不需要额外的内存
-
因为文件比原来的大,也被称为
胖二进制文件(Fat Binary)

-
$(ARCHS_STANDARD): Xcode内置的环境变量,不同版本的Xcode的值不一样,通过的一些架构值- Xcode9中的
$(ARCHS_STANDARD)值可能是arm64、armv7 - Xcode4中的
$(ARCHS_STANDARD)值可能是armv7
- Xcode9中的
-
Xcode打包出的二进制(Mach-O类型)文件包含的架构是这两个变量的交集,也就是说两个变量同时支持的架构,打包出来的文件才会支持这个架构 -
在开发中我们一般不会去修改两个参数,但是比如在开发静态库的时候, 你可以通过设置这两个参数,来设置静态库支持什么架构
-
如何拆分和合并多个架构的二进制文件:



2.4窥探Mach-O的结构
2.4.1 查看Mach-o文件常用命令
- 命令行工具:file:查看Mach-O的文件类型
file 文件路径 - otools:
查看Mach-O特定部分和段的内容,苹果自带的工具 - lipo :常用与查看多架构Mach-O文件的处理
- 查看架构信息:
lipo -info 文件路径 - 导出某种特定架构:
lipo 文件路径 -thin 架构类型(如:arm64) -output 输出文件路径 - 合并多种架构:
lipo -create 文件路径1 文件路劲2 -output 输出文件路径
- 查看架构信息:
- GUI工具:MachOView
2.4.2 Mach-O结构
- 内存是分段管理的,常见代码段、数据段
- 一个Mach-O文件主要包括3个主要区域
Header: 文件类型、目标架构类型,等Load commands:描述文件在虚拟内存中的逻辑结构、布局(有点类似指针的作用,告诉原始数据存放的一些位置信息)Raw segement data: 在Load commands中定义的Segement的原始数据

我么只有了解了Mach-O文件的结构,你才可能往里面注入自己的代码,达到修改app的效果
-
我们可以通过苹果自带的命令 来查看
Mach-O的文件的结构信息:

-
除了苹果自带的
otools命令,我们还可以通过MachOView工具来查看,可以按照上面下载地址下载源码然后运行项目,如果运行项目报SDK错误,我们要修改工程中的SDK版本,选择最新版本,在运行即可:

2.4.3 Mach-o和dyld
dyld:也是Mach-O类型的文件,属于MH_DYLINKER类型(动态连接器),dyld可以加载三种类型的Mach-O类型的文件:MH_EXECUTE: 可执行文件MH_DYLIB:动态库MH_BUNDLE: bundle类型的文件
- APP的可执行文件、动态库都是由
dyld负责加载的,下面我们从源码中查看dyld支持加载的Mach-O类型的文件:
本文介绍iOS系统中Mach-O文件格式及动态库的管理方式,包括动态库缓存、加载机制,以及如何拆分dyld缓存文件进行逆向分析。
914

被折叠的 条评论
为什么被折叠?



