Skip to content

第一阶段:基础准备

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版本选择:不同版本支持不同工具

越狱步骤

  1. 备份数据:通过iTunes或iCloud完整备份
  2. 下载越狱工具:从官方渠道下载
  3. 连接设备:用数据线连接Mac和iPhone
  4. 运行越狱工具:按照工具提示操作
  5. 等待完成:设备会自动重启
  6. 验证越狱:查看Cydia或Sileo是否安装成功

越狱后的变化

  • Root权限:获得最高系统权限
  • 文件系统访问:可以访问全部系统文件
  • 系统修改:可以修改系统设置和文件
  • 安装插件:可以安装各种Tweak插件

4. 配置逆向环境

安装包管理器

  • Cydia:传统的越狱商店(checkra1n默认安装)
  • Sileo:现代化的包管理器(Taurine默认)
  • Zebra:轻量级的包管理器
  • 添加源:添加逆向工具源

安装必要工具

OpenSSH

  • 作用:让Mac可以SSH连接到iPhone
  • 安装:在Cydia搜索OpenSSH并安装
  • 默认密码:alpine(必须修改!
  • 修改密码:SSH登录后执行passwdpasswd mobile

Cycript

  • 作用:运行时分析和调试工具
  • 安装:Cydia搜索Cycript
  • 功能:注入进程、执行代码、查看对象

Frida

  • 作用:强大的动态插桩工具
  • 安装:在设备上通过Cydia安装frida-server
  • Mac端安装pip install frida-tools
  • 功能:Hook函数、追踪调用、修改行为

AppSync Unified

  • 作用:允许安装未签名或自签名应用
  • 安装:添加源后从Cydia安装
  • 必要性:重签名后的应用需要此插件

配置SSH连接

WiFi方式

  1. 确保Mac和iPhone在同一WiFi网络
  2. 查看iPhone的IP地址:设置→WiFi→点击已连接网络
  3. Mac终端执行:ssh root@iPhone的IP
  4. 输入密码:alpine(首次)或修改后的密码

USB方式(更稳定)

  1. 安装usbmuxd:brew install usbmuxd
  2. 端口转发:iproxy 2222 22
  3. 新终端窗口: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段的可执行代码
  • 目的:防止盗版和逆向分析

检测应用是否加密

bash
# 使用otool查看加密信息
otool -l /path/to/app | grep -A 4 LC_ENCRYPTION_INFO
# cryptid 1表示已加密,0表示未加密

砸壳工具

dumpdecrypted

  • 原理:应用运行时,系统会解密到内存,从内存dump出来
  • 使用步骤
    1. 编译dumpdecrypted.dylib
    2. 拷贝到iPhone的/usr/lib
    3. 启动目标应用
    4. 注入dylib:DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /path/to/app

frida-ios-dump

  • 优势:自动化程度高,操作简单

  • 准备工作

    1. iPhone安装frida-server
    2. Mac安装frida和frida-ios-dump
  • 使用方法

    bash
    python dump.py 应用名称或Bundle ID
  • 输出:解密后的IPA文件

Clutch

  • 特点:命令行工具,支持批量砸壳

  • 安装:从GitHub下载编译好的版本

  • 使用

    bash
    Clutch -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

bash
unzip App.ipa -d App_extracted
cd App_extracted/Payload/App.app

查看Info.plist

bash
# 转换为可读格式
plutil -convert xml1 Info.plist
# 或使用Xcode打开
open -a Xcode Info.plist

重要字段

  • CFBundleIdentifier:Bundle ID
  • CFBundleExecutable:可执行文件名
  • MinimumOSVersion:最低系统版本
  • UIRequiredDeviceCapabilities:设备要求
  • NSAppTransportSecurity:网络安全设置

使用class-dump导出头文件

安装class-dump

bash
brew install class-dump

导出头文件

bash
class-dump -H /path/to/App -o ./Headers

分析头文件

  • 类名:了解应用的类结构
  • 方法名:找到关键功能的方法
  • 属性:查看数据模型
  • 协议:了解接口定义

Mach-O文件分析

Mach-O结构

  • Header:架构、文件类型、加载命令数量
  • Load Commands:段信息、动态库依赖、代码签名
  • Data:实际的代码和数据

使用otool分析

bash
# 查看架构
lipo -info App

# 查看Load Commands
otool -l App

# 查看依赖的动态库
otool -L App

# 查看代码段
otool -t App

使用MachOView

  • 图形化工具:可视化查看Mach-O结构
  • 下载地址:GitHub搜索MachOView
  • 功能:查看各个段、节、符号表

反汇编工具

Hopper Disassembler

  • 功能:反汇编、反编译、生成伪代码
  • 使用方法
    1. 打开Mach-O文件
    2. 等待分析完成
    3. 搜索关键类和方法
    4. 查看汇编代码和伪代码

IDA Pro

  • 专业工具:功能最强大的反汇编工具
  • 优势:支持调试、脚本、插件
  • 学习曲线:较陡峭,但值得投入

Ghidra

  • 免费开源:NSA开源的逆向工具
  • 功能:反汇编、反编译、脚本分析
  • 跨平台:支持多种架构

7. 寻找关键代码

UI定位代码

Cycript定位

  1. SSH连接到iPhone
  2. 启动目标应用
  3. 获取应用进程ID:ps -e | grep App
  4. 注入Cycript:cycript -p 进程ID
  5. 获取当前视图控制器:
jsx
UIApp.keyWindow.rootViewController
  1. 查看视图层次:
jsx
UIApp.keyWindow.recursiveDescription().toString()

Reveal/Lookin定位

  • 安装Reveal:Mac端和iOS端都需安装
  • 功能:实时查看视图层次结构
  • 定位步骤
    1. 选中UI元素
    2. 查看对应的视图控制器类名
    3. 查看响应的Target-Action

FLEX工具

  • 安装:Cydia搜索FLEX 3
  • 使用:应用内长按状态栏激活
  • 功能
    • 查看视图层次
    • 查看网络请求
    • 修改属性值
    • 调用方法

分析业务逻辑

网络请求分析

  • Charles抓包
    1. Mac安装Charles
    2. iPhone配置代理
    3. 安装Charles证书
    4. 查看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配置

  1. 从Mac拷贝debugserver到iPhone

    bash
    # debugserver位置(Xcode内)
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/版本号/DeveloperDiskImage.dmg
  2. 重签名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>

    签名命令:

    bash
    codesign -s - --entitlements entitlements.xml -f debugserver
  3. 拷贝到iPhone/usr/bin/debugserver

使用LLDB调试

iPhone端启动debugserver

bash
debugserver *:1234 -a "App名称"
# 或附加到运行中的进程
debugserver *:1234 -a 进程ID

Mac端连接

bash
lldb
(lldb) process connect connect://iPhone的IP:1234

常用LLDB命令

bash
# 查看镜像(加载的库)
image list

# 在方法上下断点
b -[ClassName methodName:]

# 在地址下断点
b 0x100004000

# 继续执行
c

# 单步执行
n  # next(跨过)
s  # step(进入)

# 查看寄存器
register read

# 查看内存
memory read 0x地址

# 打印对象
po $x0  # ARM64中x0通常是self

# 修改返回值
thread return 1

Cycript运行时调试

注入应用

bash
cycript -p 应用名称或进程ID

常用Cycript命令

jsx
// 获取应用实例
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端:

bash
frida-server &

查看进程

Mac端:

bash
frida-ps -U  # USB连接
frida-ps -R  # 远程连接

基础Hook示例

jsx
// 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);
        }
    });
}

运行脚本:

bash
frida -U -f com.app.bundleid -l hook.js --no-pause

Frida进阶技巧

jsx
// 枚举所有类
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实现

objectivec
#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被调用了");
}

@end

Logos语法

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

bash
# 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项目

bash
$THEOS/bin/nic.pl
# 选择:iphone/tweak
# 输入项目名称
# 输入Bundle ID(要Hook的应用)
# 输入作者名

项目结构

MyTweak/
├── Makefile              # 编译配置
├── MyTweak.plist        # 注入配置(指定Bundle ID)
├── Tweak.x              # Hook代码(Logos语法)
└── control              # deb包信息

Makefile配置

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

编译与安装

bash
# 编译
make

# 打包deb
make package

# 安装到设备(需配置THEOS_DEVICE_IP)
export THEOS_DEVICE_IP=iPhone的IP
export THEOS_DEVICE_PORT=22
make install

# 重启SpringBoard
killall -9 SpringBoard

Hook实战示例

示例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. 文件检测

objectivec
// 应用检测这些文件是否存在
@[
    @"/Applications/Cydia.app",
    @"/Library/MobileSubstrate/MobileSubstrate.dylib",
    @"/bin/bash",
    @"/usr/sbin/sshd",
    @"/etc/apt"
]

2. 沙盒检测

objectivec
// 尝试写文件到非沙盒目录
NSString *path = @"/private/test.txt";
[@"test" writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];

3. 系统调用检测

objectivec
// 调用fork函数(越狱后可以成功)
int result = fork();
if (result >= 0) {
    // 设备已越狱
}

4. 动态库检测

objectivec
// 检测是否加载了越狱相关的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系统函数

c
// 使用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脚本绕过

jsx
// Frida动态Hook
Interceptor.attach(Module.findExportByName(null, 'fork'), {
    onLeave: function(retval) {
        retval.replace(-1);  // fork失败
    }
});

绕过SSL Pinning

什么是SSL Pinning

  • 证书锁定:应用内置服务器证书或公钥
  • 目的:防止中间人攻击和抓包分析
  • 校验时机:建立HTTPS连接时

SSL Pinning实现方式

1. AFNetworking

objectivec
AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
manager.securityPolicy = policy;

2. NSURLSession

objectivec
- (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:使用现成工具

处理代码混淆

常见混淆技术

  • 符号混淆:类名、方法名替换为无意义字符
  • 控制流平坦化:打乱代码执行流程
  • 字符串加密:加密字符串常量
  • 指令替换:用复杂指令替换简单指令

反混淆方法

  • 动态分析:运行时对象的类名是真实的
  • 符号恢复:通过上下文推测真实名称
  • IDA脚本:自动化分析混淆模式
  • Frida追踪:追踪方法调用链

反反调试技术

常见反调试方法

1. sysctl检测

c
// 检测是否被调试器附加
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自我保护

c
// 调用ptrace(PT_DENY_ATTACH, 0, 0, 0)防止被附加

3. 时间检测

c
// 检测代码执行时间,如果太慢可能是在调试
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

c
// 使用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. 实现构造函数

objectivec
__attribute__((constructor)) static void initialize() {
    NSLog(@"Dylib loaded!");
    // 执行Hook代码
}

3. 编译dylib

bash
xcodebuild -project MyHook.xcodeproj -scheme MyHook -configuration Release

注入dylib到IPA

使用insert_dylib工具

bash
# 安装
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/

修改应用资源

修改图片资源

修改字符串

  • 本地化文件:修改.lproj目录下的.strings文件
  • 二进制字符串:用Hex编辑器修改(需保持长度)

修改Info.plist

bash
# 修改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. 创建开发者证书

2. 创建Provisioning Profile

  • Profiles → Create Profile
  • 选择iOS App Development
  • 添加设备UDID
  • 下载.mobileprovision文件

签名步骤

1. 删除原签名

bash
rm -rf App.app/_CodeSignature
rm App.app/embedded.mobileprovision

2. 签名Frameworks

bash
for framework in App.app/Frameworks/*.dylib App.app/Frameworks/*.framework; do
    codesign -fs "iPhone Developer: Your Name (XXXXXXXXXX)" "$framework"
done

3. 拷贝Provisioning Profile

bash
cp YourApp.mobileprovision App.app/embedded.mobileprovision

4. 生成entitlements.plist

bash
security cms -D -i App.app/embedded.mobileprovision > temp.plist
/usr/libexec/PlistBuddy -x -c 'Print :Entitlements' temp.plist > entitlements.plist

5. 签名应用

bash
codesign -fs "iPhone Developer: Your Name (XXXXXXXXXX)" --entitlements entitlements.plist App.app

6. 打包IPA

bash
mkdir Payload
cp -r App.app Payload/
zip -r App-resigned.ipa Payload
rm -rf Payload

使用自动化工具

iOS App Signer

iResign

  • 开源签名工具
  • 命令行或GUI都支持
  • 支持批量签名

安装修改后的应用

通过Xcode安装

bash
# 使用ideviceinstaller
brew install ideviceinstaller
ideviceinstaller -i App-resigned.ipa

通过工具安装

  • Cydia Impactor:拖拽IPA安装
  • AltStore:本地签名并安装
  • Sideloadly:免费签名工具

越狱设备直接安装

bash
# 通过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方法打印计算过程

步骤

  1. 下载一个简单的计算器应用
  2. 使用Cycript查看视图层次
  3. 定位按钮的Target-Action
  4. 编写Tweak Hook点击事件
  5. 重签名安装测试

收获

  • 熟悉基本的UI分析流程
  • 掌握Cycript的使用
  • 学会简单的Hook技术

项目2:TODO应用数据读取

目标

  • 找到应用的数据存储位置
  • 读取SQLite数据库
  • 修改数据并观察界面变化

步骤

  1. 下载TODO类应用
  2. SSH连接到iPhone
  3. 找到应用的沙盒目录
  4. 定位数据库文件
  5. 使用sqlite3命令查看和修改数据
  6. 重启应用验证

收获

  • 了解iOS文件系统结构
  • 掌握数据存储位置
  • 学会SQLite操作

中级项目:网络应用分析

项目3:天气应用API分析

目标

  • 抓取应用的网络请求
  • 分析API接口和参数
  • 模拟请求获取数据

步骤

  1. 下载天气类应用
  2. 配置Charles代理
  3. 安装SSL证书
  4. 观察API请求
  5. 分析请求参数和响应格式
  6. 使用Postman模拟请求
  7. Hook网络请求打印数据

收获

  • 掌握网络抓包技术
  • 了解HTTPS和证书
  • 学会API逆向分析

项目4:社交应用消息解密

目标

  • 找到消息的加密算法
  • 定位加密/解密函数
  • Hook函数查看明文

步骤

  1. 选择一个有加密的社交应用
  2. 抓包观察加密的消息
  3. 使用class-dump导出头文件
  4. 搜索encrypt、decrypt等关键字
  5. 使用Frida Hook相关方法
  6. 打印加密前和解密后的数据
  7. 分析加密算法(AES、RSA等)

收获

  • 学会定位加密相关代码
  • 了解常见加密算法
  • 掌握动态分析技巧

高级项目:游戏修改

项目5:单机游戏数值修改

目标

  • 修改游戏内的金币、等级等数值
  • 绕过数值校验
  • 实现自动化修改

步骤

  1. 选择一个单机游戏
  2. 使用内存搜索工具(如GameGem)定位数值地址
  3. 分析数值的存储方式(明文/加密)
  4. 找到数值校验的代码
  5. Hook校验函数绕过
  6. 编写Tweak自动修改数值
  7. 处理可能的反作弊机制

收获

  • 掌握内存搜索技术
  • 了解游戏数据存储
  • 学会绕过校验

项目6:网络游戏协议分析

目标

  • 分析游戏的网络协议
  • 解密通信数据
  • 模拟客户端请求

步骤

  1. 选择网络游戏
  2. 抓包分析协议格式
  3. 定位协议的序列化/反序列化代码
  4. Hook相关方法查看原始数据
  5. 分析协议字段含义
  6. 编写脚本模拟请求
  7. 注意反作弊和封号风险

收获

  • 掌握协议逆向技术
  • 了解网络游戏架构
  • 学会高级Hook技巧

进阶项目:安全研究

项目7:支付流程安全分析

目标

  • 分析应用的支付流程
  • 查找潜在的安全漏洞
  • 提交安全报告(负责任披露)

步骤

  1. 选择有支付功能的应用(测试环境)
  2. 抓包分析支付请求
  3. 查看订单验证逻辑
  4. 测试能否绕过支付
  5. 分析客户端签名算法
  6. 检查是否有服务端验证
  7. 整理漏洞报告

注意

  • 仅在测试环境进行
  • 不要用于非法获利
  • 负责任地披露漏洞

项目8:VIP功能破解与防护

目标

  • 分析VIP验证机制
  • 实现VIP功能破解
  • 思考如何防护

步骤

  1. 选择有VIP功能的应用
  2. 定位VIP检测代码
  3. 分析验证流程(本地/服务器)
  4. Hook验证方法返回VIP状态
  5. 测试VIP功能是否可用
  6. 分析服务器端验证
  7. 总结防护建议

收获

  • 全面理解iOS逆向流程
  • 学会攻防思维
  • 了解安全最佳实践

实战建议

学习路径

  1. 从简单开始:不要一上来就挑战复杂应用
  2. 循序渐进:先做初级项目,再做高级项目
  3. 举一反三:同类应用的分析方法相似
  4. 记录总结:每个项目都写分析报告

工具组合

  • 静态分析:class-dump + Hopper/IDA
  • 动态分析:Frida + LLDB
  • 网络分析:Charles + Burp Suite
  • 开发工具:Theos + Xcode

法律与道德

⚠️ 重要提醒

  • 仅限学习:逆向技术仅用于学习和研究
  • 遵守法律:不要破解商业软件用于非法目的
  • 尊重版权:不要分发破解应用
  • 负责披露:发现安全漏洞应负责任地报告
  • 自我约束:技术无罪,关键在于使用者的态度

学习资源

推荐书籍

  • 《iOS应用逆向工程》:沙梓社、吴航著
  • 《macOS and iOS Internals》:Jonathan Levin著
  • 《The Mac Hacker's Handbook》

在线资源

社区论坛

  • Reddit r/jailbreakdevelopers
  • 看雪论坛
  • 52pojie论坛(需谨慎,注意法律边界)

视频教程

  • YouTube搜索:iOS Reverse Engineering
  • B站搜索:iOS逆向

总结

iOS逆向是一个需要多方面知识的领域,包括:

  • 编程基础:Swift、Objective-C、C语言
  • 操作系统:iOS架构、安全机制
  • 汇编语言:ARM64汇编基础
  • 网络知识:HTTP/HTTPS协议
  • 密码学:常见加密算法

循序渐进,持之以恒,相信你能掌握iOS逆向技术!

记住:

✅ 合法学习,提升技能

✅ 发现漏洞,负责披露

✅ 尊重版权,遵守法律

❌ 破解牟利,违法犯罪

❌ 恶意攻击,损害他人

评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v3.7.1