第一阶段:基础准备
1. 学习iOS开发基础
Xcode安装与配置
- 打开Mac上的App Store应用
- 搜索Xcode并下载安装(约10GB,需要时间)
- 首次打开Xcode,同意许可协议
- 安装额外的命令行工具:
xcode-select --install - 熟悉Xcode界面:导航器、编辑器、调试区、工具栏
Swift编程语言
- 基础语法:变量、常量、数据类型、运算符
- 控制流:if-else、switch、for-in、while循环
- 函数与闭包:函数定义、参数传递、闭包表达式
- 面向对象:类、结构体、枚举、属性、方法
- 协议与扩展:协议定义、协议继承、扩展功能
- 可选类型:Optional处理、可选绑定、可选链
- 错误处理:throws、do-catch、try语句
Objective-C基础
- 为什么要学OC:很多老应用和系统框架用OC编写,逆向时经常遇到
- 基础语法:消息传递机制、方法调用语法
- 内存管理:ARC、引用计数、strong/weak
- 常用类:NSString、NSArray、NSDictionary、NSObject
- Runtime机制:消息转发、方法交换(重要!)
iOS应用结构
- 应用生命周期:启动、前台、后台、挂起、终止
- 视图控制器:UIViewController、视图层次结构
- MVC设计模式:Model-View-Controller架构
- Storyboard与XIB:界面设计工具
- 应用构建过程:编译、链接、打包、签名
核心框架
- UIKit:UI组件、视图、控制器
- Foundation:基础数据类型、集合、文件系统
- CoreFoundation:C语言级别的框架
- CoreGraphics:图形绘制
2. 了解iOS系统架构
iOS文件系统
- /Applications:系统应用目录
- /var/mobile/Containers/Bundle/Application:第三方应用安装目录
- /var/mobile/Containers/Data/Application:应用数据目录
- /System/Library:系统库文件
- /usr/lib:系统动态库
应用沙盒机制
- 什么是沙盒:每个应用只能访问自己的目录,无法访问其他应用
- 沙盒目录结构:
- Documents:用户数据,会被iTunes备份
- Library/Caches:缓存文件,不会被备份
- Library/Preferences:偏好设置
- tmp:临时文件
- 沙盒限制:文件访问、网络访问、系统资源访问
- 越狱后的变化:可以突破沙盒限制
代码签名机制
- 什么是代码签名:确保应用来源可信、未被篡改
- 签名流程:开发者证书、Provisioning Profile、Entitlements
- 签名验证:系统安装和启动时验证签名
- 越狱后的影响:可以使用自签名证书
iOS安全保护机制
- ASLR(地址空间布局随机化):防止内存攻击
- DEP(数据执行保护):防止代码注入
- App Store加密:对二进制文件加密
- 完整性校验:防止应用被修改
- 越狱检测:应用检测设备是否越狱
第二阶段:越狱与环境配置
3. 准备越狱设备
选择合适的设备
- 建议使用备用机:避免影响日常使用
- 设备要求:iPhone 6或更新机型
- 系统版本:查看当前可越狱的iOS版本
- 注意事项:越狱可能失去保修,谨慎操作
越狱工具选择
- checkra1n:支持iOS 12-14.8,基于硬件漏洞
- unc0ver:支持iOS 11-14.8
- Taurine:支持iOS 14-14.3
- Dopamine:支持iOS 15-15.4.1
- 根据iOS版本选择:不同版本支持不同工具
越狱步骤
- 备份数据:通过iTunes或iCloud完整备份
- 下载越狱工具:从官方渠道下载
- 连接设备:用数据线连接Mac和iPhone
- 运行越狱工具:按照工具提示操作
- 等待完成:设备会自动重启
- 验证越狱:查看Cydia或Sileo是否安装成功
越狱后的变化
- Root权限:获得最高系统权限
- 文件系统访问:可以访问全部系统文件
- 系统修改:可以修改系统设置和文件
- 安装插件:可以安装各种Tweak插件
4. 配置逆向环境
安装包管理器
- Cydia:传统的越狱商店(checkra1n默认安装)
- Sileo:现代化的包管理器(Taurine默认)
- Zebra:轻量级的包管理器
- 添加源:添加逆向工具源
安装必要工具
OpenSSH
- 作用:让Mac可以SSH连接到iPhone
- 安装:在Cydia搜索OpenSSH并安装
- 默认密码:alpine(必须修改!)
- 修改密码:SSH登录后执行
passwd和passwd mobile
Cycript
- 作用:运行时分析和调试工具
- 安装:Cydia搜索Cycript
- 功能:注入进程、执行代码、查看对象
Frida
- 作用:强大的动态插桩工具
- 安装:在设备上通过Cydia安装frida-server
- Mac端安装:
pip install frida-tools - 功能:Hook函数、追踪调用、修改行为
AppSync Unified
- 作用:允许安装未签名或自签名应用
- 安装:添加源后从Cydia安装
- 必要性:重签名后的应用需要此插件
配置SSH连接
WiFi方式
- 确保Mac和iPhone在同一WiFi网络
- 查看iPhone的IP地址:设置→WiFi→点击已连接网络
- Mac终端执行:
ssh root@iPhone的IP - 输入密码:alpine(首次)或修改后的密码
USB方式(更稳定)
- 安装usbmuxd:
brew install usbmuxd - 端口转发:
iproxy 2222 22 - 新终端窗口:
ssh [root@localhost](mailto:root@localhost) -p 2222
安装调试工具
- LLDB:底层调试器
- debugserver:iOS上的调试服务器
- class-dump:导出头文件工具
- otool:查看Mach-O文件信息
- install_name_tool:修改动态库路径
第三阶段:静态分析
5. 砸壳(解密)
为什么需要砸壳
- App Store加密:苹果会对上传的应用进行加密
- 加密算法:使用FairPlay DRM加密
- 加密段:只加密__TEXT段的可执行代码
- 目的:防止盗版和逆向分析
检测应用是否加密
# 使用otool查看加密信息
otool -l /path/to/app | grep -A 4 LC_ENCRYPTION_INFO
# cryptid 1表示已加密,0表示未加密砸壳工具
dumpdecrypted
- 原理:应用运行时,系统会解密到内存,从内存dump出来
- 使用步骤:
- 编译dumpdecrypted.dylib
- 拷贝到iPhone的/usr/lib
- 启动目标应用
- 注入dylib:
DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /path/to/app
frida-ios-dump
优势:自动化程度高,操作简单
准备工作:
- iPhone安装frida-server
- Mac安装frida和frida-ios-dump
使用方法:
bashpython dump.py 应用名称或Bundle ID输出:解密后的IPA文件
Clutch
特点:命令行工具,支持批量砸壳
安装:从GitHub下载编译好的版本
使用:
bashClutch -i # 列出已安装应用 Clutch -d 应用编号 # 砸壳
砸壳后的处理
- 获取IPA:砸壳工具会生成IPA文件
- 验证解密:再次用otool检查cryptid是否为0
- 备份保存:妥善保存解密后的文件
6. 分析应用结构
IPA文件结构
App.ipa(实际是ZIP文件)
└── Payload/
└── App.app/
├── App(Mach-O可执行文件)
├── Info.plist(应用配置信息)
├── PkgInfo
├── embedded.mobileprovision(签名配置)
├── _CodeSignature/(代码签名)
├── Assets.car(图片资源)
├── Frameworks/(动态库)
├── PlugIns/(扩展插件)
└── Base.lproj/(本地化资源)解压IPA
unzip App.ipa -d App_extracted
cd App_extracted/Payload/App.app查看Info.plist
# 转换为可读格式
plutil -convert xml1 Info.plist
# 或使用Xcode打开
open -a Xcode Info.plist重要字段:
- CFBundleIdentifier:Bundle ID
- CFBundleExecutable:可执行文件名
- MinimumOSVersion:最低系统版本
- UIRequiredDeviceCapabilities:设备要求
- NSAppTransportSecurity:网络安全设置
使用class-dump导出头文件
安装class-dump
brew install class-dump导出头文件
class-dump -H /path/to/App -o ./Headers分析头文件
- 类名:了解应用的类结构
- 方法名:找到关键功能的方法
- 属性:查看数据模型
- 协议:了解接口定义
Mach-O文件分析
Mach-O结构
- Header:架构、文件类型、加载命令数量
- Load Commands:段信息、动态库依赖、代码签名
- Data:实际的代码和数据
使用otool分析
# 查看架构
lipo -info App
# 查看Load Commands
otool -l App
# 查看依赖的动态库
otool -L App
# 查看代码段
otool -t App使用MachOView
- 图形化工具:可视化查看Mach-O结构
- 下载地址:GitHub搜索MachOView
- 功能:查看各个段、节、符号表
反汇编工具
Hopper Disassembler
- 功能:反汇编、反编译、生成伪代码
- 使用方法:
- 打开Mach-O文件
- 等待分析完成
- 搜索关键类和方法
- 查看汇编代码和伪代码
IDA Pro
- 专业工具:功能最强大的反汇编工具
- 优势:支持调试、脚本、插件
- 学习曲线:较陡峭,但值得投入
Ghidra
- 免费开源:NSA开源的逆向工具
- 功能:反汇编、反编译、脚本分析
- 跨平台:支持多种架构
7. 寻找关键代码
UI定位代码
Cycript定位
- SSH连接到iPhone
- 启动目标应用
- 获取应用进程ID:
ps -e | grep App - 注入Cycript:
cycript -p 进程ID - 获取当前视图控制器:
UIApp.keyWindow.rootViewController- 查看视图层次:
UIApp.keyWindow.recursiveDescription().toString()Reveal/Lookin定位
- 安装Reveal:Mac端和iOS端都需安装
- 功能:实时查看视图层次结构
- 定位步骤:
- 选中UI元素
- 查看对应的视图控制器类名
- 查看响应的Target-Action
FLEX工具
- 安装:Cydia搜索FLEX 3
- 使用:应用内长按状态栏激活
- 功能:
- 查看视图层次
- 查看网络请求
- 修改属性值
- 调用方法
分析业务逻辑
网络请求分析
- Charles抓包:
- Mac安装Charles
- iPhone配置代理
- 安装Charles证书
- 查看HTTPS请求
- 关键信息:API接口、请求参数、加密算法
数据存储分析
- 沙盒目录:查看应用数据目录
- SQLite数据库:使用DB Browser查看
- Plist文件:偏好设置和配置
- Keychain:敏感信息存储
关键字搜索
- 在头文件中搜索:
- 登录:Login、SignIn、Auth
- 支付:Pay、Purchase、Order
- 加密:Encrypt、Decrypt、AES、RSA
- 在汇编代码中搜索:
- 字符串常量
- 错误提示
- 接口地址
控制流分析
- 入口函数:main、application:didFinishLaunchingWithOptions:
- 关键方法:从UI操作追踪到业务代码
- 调用链:理解方法之间的调用关系
- 判断逻辑:找到关键的if判断和返回值
第四阶段:动态分析
8. 动态调试
LLDB调试器
debugserver配置
从Mac拷贝debugserver到iPhone:
bash# debugserver位置(Xcode内) /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/版本号/DeveloperDiskImage.dmg重签名debugserver(赋予调试权限):
创建entitlements.xml:
xml<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>com.apple.springboard.debugapplications</key> <true/> <key>get-task-allow</key> <true/> <key>task_for_pid-allow</key> <true/> <key>run-unsigned-code</key> <true/> </dict> </plist>签名命令:
bashcodesign -s - --entitlements entitlements.xml -f debugserver拷贝到iPhone:
/usr/bin/debugserver
使用LLDB调试
iPhone端启动debugserver:
debugserver *:1234 -a "App名称"
# 或附加到运行中的进程
debugserver *:1234 -a 进程IDMac端连接:
lldb
(lldb) process connect connect://iPhone的IP:1234常用LLDB命令:
# 查看镜像(加载的库)
image list
# 在方法上下断点
b -[ClassName methodName:]
# 在地址下断点
b 0x100004000
# 继续执行
c
# 单步执行
n # next(跨过)
s # step(进入)
# 查看寄存器
register read
# 查看内存
memory read 0x地址
# 打印对象
po $x0 # ARM64中x0通常是self
# 修改返回值
thread return 1Cycript运行时调试
注入应用
cycript -p 应用名称或进程ID常用Cycript命令
// 获取应用实例
var app = [UIApplication sharedApplication]
// 获取根视图控制器
var rootVC = app.keyWindow.rootViewController
// 查看类的所有方法
function methods(className) {
var count = new new Type("I");
var methods = class_copyMethodList(objc_getClass(className), count);
var methodsArray = [];
for(var i = 0; i < *count; i++) {
var method = methods[i];
methodsArray.push({selector:method_getName(method), implementation:method_getImplementation(method)});
}
free(methods);
return methodsArray;
}
// 调用方法
[对象 方法名:参数]
// 修改属性
对象.属性名 = 新值Frida动态插桩
启动frida-server
iPhone端:
frida-server &查看进程
Mac端:
frida-ps -U # USB连接
frida-ps -R # 远程连接基础Hook示例
// hook.js
if (ObjC.available) {
// Hook Objective-C方法
var className = "ViewController";
var methodName = "- buttonTapped:";
var hook = ObjC.classes[className][methodName];
Interceptor.attach(hook.implementation, {
onEnter: function(args) {
console.log("[*] Calling " + methodName);
console.log("[*] self: " + new ObjC.Object(args[0]).toString());
console.log("[*] _cmd: " + ObjC.selectorAsString(args[1]));
},
onLeave: function(retval) {
console.log("[*] Return value: " + retval);
}
});
}运行脚本:
frida -U -f com.app.bundleid -l hook.js --no-pauseFrida进阶技巧
// 枚举所有类
for (var className in ObjC.classes) {
console.log(className);
}
// 枚举类的所有方法
var methods = ObjC.classes.ClassName.$ownMethods;
console.log(methods);
// 修改返回值
Interceptor.attach(方法地址, {
onLeave: function(retval) {
retval.replace(1); // 修改返回值为1
}
});
// Hook C函数
Interceptor.attach(Module.findExportByName(null, 'open'), {
onEnter: function(args) {
console.log('open("' + Memory.readUtf8String(args[0]) + '")');
}
});9. Hook技术
Method Swizzling原理
Runtime消息机制
- 消息发送:
[object method]实际是objc_msgSend(object, @selector(method)) - 方法查找:通过SEL在方法列表中查找IMP
- 方法交换:交换两个方法的IMP指针
Method Swizzling实现
#import <objc/runtime.h>
@implementation UIViewController (Swizzle)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
SEL originalSelector = @selector(viewDidLoad);
SEL swizzledSelector = @selector(swizzled_viewDidLoad);
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL didAddMethod = class_addMethod(class,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
});
}
- (void)swizzled_viewDidLoad {
[self swizzled_viewDidLoad]; // 实际调用原始viewDidLoad
NSLog(@"viewDidLoad被调用了");
}
@endLogos语法
Logos是Theos提供的预处理器,简化Hook代码编写。
基础语法
// Hook类
%hook ClassName
// Hook实例方法
- (返回类型)methodName:(参数类型)参数 {
NSLog(@"方法被调用");
%orig; // 调用原始实现
return 返回值;
}
// Hook类方法
+ (返回类型)classMethod {
return %orig; // 调用原始实现并返回
}
// 新增方法
%new
- (void)newMethod {
NSLog(@"新增的方法");
}
// 访问成员变量
- (void)someMethod {
NSString *ivar = MSHookIvar<NSString *>(self, "_privateIvar");
}
%end
// 条件编译
%hook iOS13ViewController
%end
// 初始化函数
%ctor {
NSLog(@"Tweak loaded");
}
// 析构函数
%dtor {
NSLog(@"Tweak unloaded");
}Theos开发工具链
安装Theos
# Mac端安装
sudo git clone --recursive https://github.com/theos/theos.git /opt/theos
export THEOS=/opt/theos
export PATH=$THEOS/bin:$PATH
# 安装ldid(签名工具)
brew install ldid创建Tweak项目
$THEOS/bin/nic.pl
# 选择:iphone/tweak
# 输入项目名称
# 输入Bundle ID(要Hook的应用)
# 输入作者名项目结构
MyTweak/
├── Makefile # 编译配置
├── MyTweak.plist # 注入配置(指定Bundle ID)
├── Tweak.x # Hook代码(Logos语法)
└── control # deb包信息Makefile配置
TARGET := iphone:clang:latest:12.0
ARCHS = arm64 arm64e
include $(THEOS)/makefiles/common.mk
TWEAK_NAME = MyTweak
MyTweak_FILES = Tweak.x
MyTweak_CFLAGS = -fobjc-arc
include $(THEOS_MAKE_PATH)/tweak.mk编译与安装
# 编译
make
# 打包deb
make package
# 安装到设备(需配置THEOS_DEVICE_IP)
export THEOS_DEVICE_IP=iPhone的IP
export THEOS_DEVICE_PORT=22
make install
# 重启SpringBoard
killall -9 SpringBoardHook实战示例
示例1:绕过登录验证
%hook LoginViewController
- (void)loginButtonTapped:(id)sender {
// 不调用原始方法,直接跳转到主页
UIViewController *mainVC = [[NSClassFromString(@"MainViewController") alloc] init];
[self.navigationController pushViewController:mainVC animated:YES];
}
%end示例2:修改返回值
%hook VIPManager
- (BOOL)isVIP {
return YES; // 始终返回YES
}
- (NSInteger)vipLevel {
return 10; // 返回最高等级
}
%end示例3:打印网络请求
%hook NSURLSession
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler {
NSLog(@"[URL] %@", request.URL);
NSLog(@"[Method] %@", request.HTTPMethod);
NSLog(@"[Headers] %@", request.allHTTPHeaderFields);
return %orig;
}
%end第五阶段:进阶技术
10. 绕过安全检测
绕过越狱检测
常见检测方法
1. 文件检测
// 应用检测这些文件是否存在
@[
@"/Applications/Cydia.app",
@"/Library/MobileSubstrate/MobileSubstrate.dylib",
@"/bin/bash",
@"/usr/sbin/sshd",
@"/etc/apt"
]2. 沙盒检测
// 尝试写文件到非沙盒目录
NSString *path = @"/private/test.txt";
[@"test" writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];3. 系统调用检测
// 调用fork函数(越狱后可以成功)
int result = fork();
if (result >= 0) {
// 设备已越狱
}4. 动态库检测
// 检测是否加载了越狱相关的dylib
char *env = getenv("DYLD_INSERT_LIBRARIES");绕过方法
方法1:Hook文件检测
%hook NSFileManager
- (BOOL)fileExistsAtPath:(NSString *)path {
// 越狱相关路径返回NO
if ([path containsString:@"Cydia"] ||
[path containsString:@"MobileSubstrate"]) {
return NO;
}
return %orig;
}
%end方法2:Hook系统函数
// 使用fishhook Hook C函数
static int (*orig_stat)(const char *, struct stat *);
int my_stat(const char *path, struct stat *buf) {
NSString *pathStr = [NSString stringWithUTF8String:path];
if ([pathStr containsString:@"Cydia"]) {
return -1; // 返回文件不存在
}
return orig_stat(path, buf);
}
// 在初始化时进行rebind
rebind_symbols((struct rebinding[1])"stat", my_stat, (void *)&orig_stat, 1);方法3:Frida脚本绕过
// Frida动态Hook
Interceptor.attach(Module.findExportByName(null, 'fork'), {
onLeave: function(retval) {
retval.replace(-1); // fork失败
}
});绕过SSL Pinning
什么是SSL Pinning
- 证书锁定:应用内置服务器证书或公钥
- 目的:防止中间人攻击和抓包分析
- 校验时机:建立HTTPS连接时
SSL Pinning实现方式
1. AFNetworking
AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
manager.securityPolicy = policy;2. NSURLSession
- (void)URLSession:(NSURLSession *)session
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler {
// 自定义证书验证逻辑
}绕过方法
方法1:Hook AFNetworking
%hook AFSecurityPolicy
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain {
return YES; // 始终通过验证
}
%end方法2:Hook NSURLSession
%hook NSURLSession
- (void)URLSession:(NSURLSession *)session
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler {
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
} else {
%orig;
}
}
%end方法3:使用现成工具
- SSL Kill Switch 2:Cydia插件,一键禁用SSL Pinning
- 安装:添加源 https://julioverne.github.io/
- 使用:安装后在设置中启用
处理代码混淆
常见混淆技术
- 符号混淆:类名、方法名替换为无意义字符
- 控制流平坦化:打乱代码执行流程
- 字符串加密:加密字符串常量
- 指令替换:用复杂指令替换简单指令
反混淆方法
- 动态分析:运行时对象的类名是真实的
- 符号恢复:通过上下文推测真实名称
- IDA脚本:自动化分析混淆模式
- Frida追踪:追踪方法调用链
反反调试技术
常见反调试方法
1. sysctl检测
// 检测是否被调试器附加
struct kinfo_proc info;
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()};
size_t size = sizeof(info);
sysctl(mib, 4, &info, &size, NULL, 0);
if (info.kp_proc.p_flag & P_TRACED) {
// 正在被调试
exit(0);
}2. ptrace自我保护
// 调用ptrace(PT_DENY_ATTACH, 0, 0, 0)防止被附加3. 时间检测
// 检测代码执行时间,如果太慢可能是在调试
uint64_t start = mach_absolute_time();
// ... 一些代码 ...
uint64_t end = mach_absolute_time();
if (end - start > threshold) {
// 可能在调试
}绕过反调试
方法1:Hook sysctl
%hookf(int, sysctl, int *name, u_int namelen, void *info, size_t *infosize, void *newinfo, size_t newinfosize) {
int ret = %orig;
if (namelen == 4 && name[0] == CTL_KERN && name[1] == KERN_PROC && name[2] == KERN_PROC_PID) {
struct kinfo_proc *p = (struct kinfo_proc *)info;
p->kp_proc.p_flag &= ~P_TRACED; // 清除调试标志
}
return ret;
}
%end方法2:Hook ptrace
// 使用fishhook
static int (*orig_ptrace)(int request, pid_t pid, caddr_t addr, int data);
int my_ptrace(int request, pid_t pid, caddr_t addr, int data) {
if (request == PT_DENY_ATTACH) {
return 0; // 不执行拒绝附加
}
return orig_ptrace(request, pid, addr, data);
}
rebind_symbols((struct rebinding[1])"ptrace", my_ptrace, (void *)&orig_ptrace, 1);11. 代码注入与重签名
注入dylib动态库
创建dylib
1. Xcode创建动态库项目
- New Project → Framework & Library → Library
- 选择Dynamic Library
- 编写Hook代码
2. 实现构造函数
__attribute__((constructor)) static void initialize() {
NSLog(@"Dylib loaded!");
// 执行Hook代码
}3. 编译dylib
xcodebuild -project MyHook.xcodeproj -scheme MyHook -configuration Release注入dylib到IPA
使用insert_dylib工具
# 安装
git clone https://github.com/Tyilo/insert_dylib.git
cd insert_dylib && ./build.sh
# 注入dylib
insert_dylib @executable_path/MyHook.dylib App原始二进制文件 --output App新二进制文件 --weak
# 替换原文件
cp App新二进制文件 App.app/App
# 拷贝dylib到应用包
cp MyHook.dylib App.app/修改应用资源
修改图片资源
- 解包Assets.car:使用CartTool或Asset Catalog Tinkerer
- 替换图片:替换为自定义图片
- 重新打包:生成新的Assets.car
修改字符串
- 本地化文件:修改.lproj目录下的.strings文件
- 二进制字符串:用Hex编辑器修改(需保持长度)
修改Info.plist
# 修改Bundle ID
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.new.bundleid" Info.plist
# 修改版本号
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString 2.0.0" Info.plist重新签名
准备签名证书
1. 创建开发者证书
- 登录 https://developer.apple.com
- Certificates → Create Certificate
- 选择iOS App Development
- 下载并安装证书
2. 创建Provisioning Profile
- Profiles → Create Profile
- 选择iOS App Development
- 添加设备UDID
- 下载.mobileprovision文件
签名步骤
1. 删除原签名
rm -rf App.app/_CodeSignature
rm App.app/embedded.mobileprovision2. 签名Frameworks
for framework in App.app/Frameworks/*.dylib App.app/Frameworks/*.framework; do
codesign -fs "iPhone Developer: Your Name (XXXXXXXXXX)" "$framework"
done3. 拷贝Provisioning Profile
cp YourApp.mobileprovision App.app/embedded.mobileprovision4. 生成entitlements.plist
security cms -D -i App.app/embedded.mobileprovision > temp.plist
/usr/libexec/PlistBuddy -x -c 'Print :Entitlements' temp.plist > entitlements.plist5. 签名应用
codesign -fs "iPhone Developer: Your Name (XXXXXXXXXX)" --entitlements entitlements.plist App.app6. 打包IPA
mkdir Payload
cp -r App.app Payload/
zip -r App-resigned.ipa Payload
rm -rf Payload使用自动化工具
iOS App Signer
- 图形化签名工具
- 下载:https://dantheman827.github.io/ios-app-signer/
- 使用:拖入IPA,选择证书,点击Start
iResign
- 开源签名工具
- 命令行或GUI都支持
- 支持批量签名
安装修改后的应用
通过Xcode安装
# 使用ideviceinstaller
brew install ideviceinstaller
ideviceinstaller -i App-resigned.ipa通过工具安装
- Cydia Impactor:拖拽IPA安装
- AltStore:本地签名并安装
- Sideloadly:免费签名工具
越狱设备直接安装
# 通过SSH传输
scp App-resigned.ipa root@iPhone的IP:/var/mobile/
# iPhone上解压安装
ssh root@iPhone的IP
cd /var/mobile
unzip App-resigned.ipa
cp -r Payload/App.app /Applications/
uicache # 刷新桌面图标第六阶段:实战项目
12. 实战练习
初级项目:简单应用分析
项目1:计算器应用逆向
目标:
- 分析计算器的UI结构
- 找到按钮点击事件的处理方法
- Hook方法打印计算过程
步骤:
- 下载一个简单的计算器应用
- 使用Cycript查看视图层次
- 定位按钮的Target-Action
- 编写Tweak Hook点击事件
- 重签名安装测试
收获:
- 熟悉基本的UI分析流程
- 掌握Cycript的使用
- 学会简单的Hook技术
项目2:TODO应用数据读取
目标:
- 找到应用的数据存储位置
- 读取SQLite数据库
- 修改数据并观察界面变化
步骤:
- 下载TODO类应用
- SSH连接到iPhone
- 找到应用的沙盒目录
- 定位数据库文件
- 使用sqlite3命令查看和修改数据
- 重启应用验证
收获:
- 了解iOS文件系统结构
- 掌握数据存储位置
- 学会SQLite操作
中级项目:网络应用分析
项目3:天气应用API分析
目标:
- 抓取应用的网络请求
- 分析API接口和参数
- 模拟请求获取数据
步骤:
- 下载天气类应用
- 配置Charles代理
- 安装SSL证书
- 观察API请求
- 分析请求参数和响应格式
- 使用Postman模拟请求
- Hook网络请求打印数据
收获:
- 掌握网络抓包技术
- 了解HTTPS和证书
- 学会API逆向分析
项目4:社交应用消息解密
目标:
- 找到消息的加密算法
- 定位加密/解密函数
- Hook函数查看明文
步骤:
- 选择一个有加密的社交应用
- 抓包观察加密的消息
- 使用class-dump导出头文件
- 搜索encrypt、decrypt等关键字
- 使用Frida Hook相关方法
- 打印加密前和解密后的数据
- 分析加密算法(AES、RSA等)
收获:
- 学会定位加密相关代码
- 了解常见加密算法
- 掌握动态分析技巧
高级项目:游戏修改
项目5:单机游戏数值修改
目标:
- 修改游戏内的金币、等级等数值
- 绕过数值校验
- 实现自动化修改
步骤:
- 选择一个单机游戏
- 使用内存搜索工具(如GameGem)定位数值地址
- 分析数值的存储方式(明文/加密)
- 找到数值校验的代码
- Hook校验函数绕过
- 编写Tweak自动修改数值
- 处理可能的反作弊机制
收获:
- 掌握内存搜索技术
- 了解游戏数据存储
- 学会绕过校验
项目6:网络游戏协议分析
目标:
- 分析游戏的网络协议
- 解密通信数据
- 模拟客户端请求
步骤:
- 选择网络游戏
- 抓包分析协议格式
- 定位协议的序列化/反序列化代码
- Hook相关方法查看原始数据
- 分析协议字段含义
- 编写脚本模拟请求
- 注意反作弊和封号风险
收获:
- 掌握协议逆向技术
- 了解网络游戏架构
- 学会高级Hook技巧
进阶项目:安全研究
项目7:支付流程安全分析
目标:
- 分析应用的支付流程
- 查找潜在的安全漏洞
- 提交安全报告(负责任披露)
步骤:
- 选择有支付功能的应用(测试环境)
- 抓包分析支付请求
- 查看订单验证逻辑
- 测试能否绕过支付
- 分析客户端签名算法
- 检查是否有服务端验证
- 整理漏洞报告
注意:
- 仅在测试环境进行
- 不要用于非法获利
- 负责任地披露漏洞
项目8:VIP功能破解与防护
目标:
- 分析VIP验证机制
- 实现VIP功能破解
- 思考如何防护
步骤:
- 选择有VIP功能的应用
- 定位VIP检测代码
- 分析验证流程(本地/服务器)
- Hook验证方法返回VIP状态
- 测试VIP功能是否可用
- 分析服务器端验证
- 总结防护建议
收获:
- 全面理解iOS逆向流程
- 学会攻防思维
- 了解安全最佳实践
实战建议
学习路径
- 从简单开始:不要一上来就挑战复杂应用
- 循序渐进:先做初级项目,再做高级项目
- 举一反三:同类应用的分析方法相似
- 记录总结:每个项目都写分析报告
工具组合
- 静态分析:class-dump + Hopper/IDA
- 动态分析:Frida + LLDB
- 网络分析:Charles + Burp Suite
- 开发工具:Theos + Xcode
法律与道德
⚠️ 重要提醒
- 仅限学习:逆向技术仅用于学习和研究
- 遵守法律:不要破解商业软件用于非法目的
- 尊重版权:不要分发破解应用
- 负责披露:发现安全漏洞应负责任地报告
- 自我约束:技术无罪,关键在于使用者的态度
学习资源
推荐书籍
- 《iOS应用逆向工程》:沙梓社、吴航著
- 《macOS and iOS Internals》:Jonathan Levin著
- 《The Mac Hacker's Handbook》
在线资源
- iPhoneDevWiki:https://iphonedev.wiki
- Theos文档:https://theos.dev
- Frida官方文档:https://frida.re/docs/
社区论坛
- Reddit r/jailbreakdevelopers
- 看雪论坛
- 52pojie论坛(需谨慎,注意法律边界)
视频教程
- YouTube搜索:iOS Reverse Engineering
- B站搜索:iOS逆向
总结
iOS逆向是一个需要多方面知识的领域,包括:
- 编程基础:Swift、Objective-C、C语言
- 操作系统:iOS架构、安全机制
- 汇编语言:ARM64汇编基础
- 网络知识:HTTP/HTTPS协议
- 密码学:常见加密算法
循序渐进,持之以恒,相信你能掌握iOS逆向技术!
记住:
✅ 合法学习,提升技能
✅ 发现漏洞,负责披露
✅ 尊重版权,遵守法律
❌ 破解牟利,违法犯罪
❌ 恶意攻击,损害他人