15、iOS逆向基础:越狱环境搭建、Cydia Substrate、Theos工具链
说到iOS逆向,很多人第一反应就是“得先越狱”。嗯,这话对,也不全对。现在确实有一些不越狱的逆向手段,比如利用开发者证书做动态调试,或者分析iTunes备份。但说实话,如果你想深入系统底层,想Hook系统服务,想分析别人的App怎么调用了私有API——那越狱环境还是绕不开的。
我个人习惯把越狱设备当作“带锁的调试器”。你想想看,一台没越狱的iPhone,就像一本只给你看封面的书。越狱之后,你才能翻开每一页,甚至用笔在上面做批注。今天我们就来聊聊怎么搭好这个环境,以及两个核心工具:Cydia Substrate和Theos。
- 越狱环境搭建:选对设备、系统版本、越狱工具
- Cydia Substrate:Hook框架的“老大哥”,理解MSHookFunction和MSHookMessageEx
- Theos工具链:从源码到deb的一站式编译环境
15.1 越狱环境搭建——别急着动手,先选对版本
我见过不少新手,买了个最新款的iPhone,系统也是最新的,然后跑来问我“怎么越狱?”——嗯,这时候我只能告诉他:等吧。越狱不是你想越就能越的,它需要漏洞。而漏洞往往需要时间被公开、被利用、被打包成工具。
所以第一步,选设备。我个人建议:
- iPhone 6s ~ iPhone X 这个区间最稳,越狱工具多,社区支持好。
- 系统版本:iOS 12.4 ~ 14.8 是目前的主流逆向区间。太老的系统(iOS 9以下)很多App已经不支持了,太新的(iOS 15+)越狱工具还不成熟。
- 越狱工具:unc0ver、Checkra1n、Taurine。我个人偏爱Checkra1n,因为它基于硬件漏洞,几乎不可能被苹果封堵。但缺点是需要一台电脑引导启动。
我曾经用一台iOS 14.3的iPhone 11,用unc0ver越狱,结果Cydia一直闪退。后来发现是越狱工具版本不对,换了个5.3.1版本就好了。所以记住:越狱工具版本和系统版本必须严格匹配,去官网查兼容性列表。
越狱完成后,第一件事是安装OpenSSH。这样你就可以从电脑上ssh到手机,不用每次都拿着手机敲命令。默认密码是alpine,记得改掉——不然你的设备就是别人的肉鸡。
15.2 Cydia Substrate——Hook界的“老大哥”
Cydia Substrate,以前叫MobileSubstrate。说白了,它是一个能让你的代码“插入”到别人进程里的框架。你写一个动态库,Substrate负责把它加载到目标App中,然后替换掉原来的函数。
它有三个核心组件:
| 组件 | 作用 | 我常用的场景 |
|---|---|---|
| MobileHooker | 负责Hook函数,替换实现 | Hook Objective-C方法,比如拦截UIAlertView的显示 |
| MobileLoader | 负责把dylib加载到目标进程 | 通过plist配置文件指定要注入的App |
| Safe Mode | 当你的Hook代码崩溃时,让App进入安全模式 | 调试时经常遇到,按一下音量减键就能退出 |
最常用的两个API:
MSHookFunction(void *function, void *replacement, void **original)—— 用于Hook C/C++函数。比如你想拦截malloc,就用这个。MSHookMessageEx(Class _class, SEL selector, IMP replacement, IMP *original)—— 用于Hook Objective-C方法。比如你想知道App什么时候调用了viewDidLoad。
假设你想拦截所有App的
NSLog输出,可以这样写:
#import <substrate.h>
void (*original_NSLog)(NSString *format, ...);
void replaced_NSLog(NSString *format, ...) {
// 在这里可以记录日志,或者修改内容
NSLog(@"[Hooked] %@", format);
original_NSLog(format);
}
%ctor {
MSHookFunction((void *)NSLog, (void *)replaced_NSLog, (void **)&original_NSLog);
}
注意:这里用了%ctor,这是Theos的语法,表示构造函数,会在dylib加载时自动执行。
你可能会问:为什么不用fishhook?嗯,fishhook只能Hook系统的动态库符号,而Substrate可以Hook任意地址,包括你自己写的函数。而且Substrate的Safe Mode机制,能让你在写错代码时不至于让整个手机白苹果——这一点我深有体会,有一次我Hook了UIApplicationDidEnterBackgroundNotification,结果死循环了,Safe Mode救了我一命。
15.3 Theos工具链——从源码到deb
Theos是一个跨平台的编译工具链。你可以在macOS上写代码,然后编译出iPhone上能跑的dylib或者deb包。它本质上是一套Makefile和模板,帮你省去了手动配置xcode项目的麻烦。
安装Theos很简单:
export THEOS=/opt/theos
git clone --recursive https://github.com/theos/theos.git $THEOS
然后你需要一个nic.pl来创建新项目。运行$THEOS/bin/nic.pl,会看到一系列模板:
- tweak —— 最常用,创建一个Substrate插件,注入到某个App。
- tool —— 创建一个命令行工具,运行在越狱设备上。
- library —— 创建一个动态库,可以被其他tweak调用。
我一般选tweak。创建完后,目录结构是这样的:
MyTweak/
├── Makefile # 编译配置
├── Tweak.x # 你的Hook代码(用Logos语法)
├── control # deb包的元信息(包名、版本、依赖)
└── plist # 指定注入的目标App的Bundle ID
Logos语法是Theos的一大特色。它让你用%hook、%log、%orig这些宏来写Hook,比直接调用MSHookMessageEx简洁得多。比如:
%hook SSViewController
- (void)viewDidLoad {
%log; // 自动打印方法调用信息
%orig; // 调用原始实现
// 在这里添加你的代码
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 50)];
label.text = @"Hooked!";
[self.view addSubview:label];
}
%end
编译命令是make,然后make package会生成deb包。最后用make install通过SSH安装到设备上。嗯,这里要注意:你的设备IP和端口需要在Makefile里配置好:
export THEOS_DEVICE_IP = 192.168.1.100
export THEOS_DEVICE_PORT = 22
千万不要在
control文件里把Depends写成firmware (>= 13.0),然后你的设备是iOS 12——安装时会直接报依赖错误。我曾经犯过这个错,折腾了半天才发现是版本号写错了。
15.4 知识体系总览
下面这张图是我自己整理的iOS逆向基础环境搭建的流程。你可以看到,越狱是地基,Substrate是桥梁,Theos是工具箱。三者缺一不可。
你看,整个流程其实很清晰:越狱拿到root权限 → Substrate提供Hook能力 → Theos帮你写代码、编译、打包。这三步走通了,你就能开始真正的逆向分析了。
刚开始别急着写复杂的Hook。先拿系统自带的App练手,比如Hook一下
MobileSafari的webView:didFinishLoadForFrame:,看看能不能在页面加载完成后弹个提示。成功之后,再挑战第三方App。一步一步来,逆向这东西,急不得。
好了,关于越狱环境、Cydia Substrate和Theos,我们就聊到这里。下一节我们会深入Logos语法的细节,以及如何调试你的tweak——嗯,到时候见。