iOS逆向(二):Hopper/IDA for iOS、静态分析Objective-C/Swift

好,咱们接着聊iOS逆向。上一章我们把环境搭好了,工具也装上了。这一章,咱们要真刀真枪地干活了——用Hopper和IDA去分析一个iOS的Mach-O文件。

说实话,我第一次用Hopper反编译一个Objective-C的App时,整个人是懵的。满屏的objc_msgSend,各种奇怪的selector,根本不知道从哪下手。后来摸爬滚打了一段时间,才慢慢理清了门道。今天我就把这些经验掰开揉碎了讲给你听。

为什么是Hopper和IDA?

这两个工具,说白了就是逆向工程师的“显微镜”。

  • Hopper:macOS原生,轻量级,对Objective-C和Swift的支持非常好。我个人习惯用它做快速分析。
  • IDA Pro:重型武器,插件生态丰富,反编译能力更强。遇到加壳或者混淆严重的App,我会上IDA。

你可能会问:“我该学哪个?”我的建议是:两个都装。Hopper用来日常分析,IDA用来攻坚克难。

静态分析的核心:看懂Mach-O

iOS的App打包后是一个.ipa文件,解压后里面是Payload文件夹,里面就是Mach-O可执行文件。静态分析,就是直接分析这个二进制文件,不运行它。

嗯,这里要注意:Mach-O的结构和PE(Windows)或者ELF(Linux)不太一样。它有几个关键部分:

部分 说明
Header 文件头,标识架构、类型等
Load Commands 加载命令,告诉dyld如何加载这个文件
__TEXT 代码段,只读,包含可执行指令
__DATA 数据段,可读写,包含全局变量、Objective-C的类信息等
__LINKEDIT 链接信息,符号表、字符串表等

我在项目中遇到过一个问题:一个App在iOS 14上运行正常,iOS 15上就闪退。用Hopper一看,发现它调用了私有API,而iOS 15把这个API移到了__TEXT段之外。这就是静态分析的价值——不用跑代码,就能发现问题。

Hopper实战:分析Objective-C代码

咱们拿一个简单的Objective-C方法举例。假设我们反编译后看到这样的伪代码:

// Hopper 反编译结果
int -[ViewController loginWithUsername:password:] {
    var_20 = arg2;  // username
    var_18 = arg3;  // password
    r0 = objc_retain(arg2);
    r0 = objc_retain(arg3);
    
    // 检查用户名和密码是否为空
    if (var_20 == 0x0) {
        r0 = objc_msgSend(*(_objc_class *)(self + 0x10), @selector(showAlert:));
        return 0x0;
    }
    
    // 调用网络请求
    r0 = objc_msgSend(*(_objc_class *)(self + 0x18), @selector(postRequest:url:));
    return r0;
}

你看,Objective-C的方法调用在二进制层面就是objc_msgSend。第一个参数是self,第二个参数是selector。selector是一个字符串,在__DATA段的objc_selrefs区域可以找到。

我个人习惯的做法是:先找到所有objc_msgSend的调用,然后提取出selector字符串。这样就能快速了解这个App有哪些功能。

关键技巧:在Hopper中,按Shift + M可以快速跳转到objc_msgSend的调用点。按Ctrl + X可以查看交叉引用。

IDA Pro:处理Swift的利器

Swift的二进制比Objective-C复杂得多。因为Swift的类名和方法名会被mangling(名字改编),比如:

// Swift 源码
class UserManager {
    func login(username: String, password: String) -> Bool {
        // ...
    }
}

// 编译后的符号名
_$s11MyAppModule12UserManagerC5login8username8passwordSbSS_SStF

这个符号名看着就头疼。但IDA Pro有Swift demangler插件,可以把它还原成可读的形式。

我曾经分析过一个用Swift写的金融App。它的核心逻辑都在一个叫TransactionService的类里。IDA反编译后,我看到了这样的伪代码:

// IDA 反编译结果(已demangle)
bool TransactionService.validateTransaction(amount: Double, currency: String) {
    if (amount <= 0.0) {
        return false;
    }
    
    // 检查金额是否超过限额
    if (amount > 10000.0) {
        // 调用风控接口
        RiskControl.check(amount, currency);
        return false;
    }
    
    // 正常交易
    return true;
}

你看,虽然Swift的二进制很乱,但反编译后逻辑还是很清晰的。关键是要找到正确的入口点。

提示:在IDA中,按Alt + T可以搜索字符串。Swift的字符串通常以_Tt开头,后面跟着模块名和类名。

静态分析的通用流程

不管用Hopper还是IDA,我一般按这个流程走:

  1. 查看字符串表:先看所有硬编码的字符串,比如URL、API Key、错误提示等。这能快速了解App的功能。
  2. 定位关键类:搜索AppDelegateViewControllerManager等关键词。
  3. 分析objc_msgSend:提取所有selector,建立方法调用关系图。
  4. 追踪数据流:从输入点(比如按钮点击)开始,跟踪数据流向。
  5. 识别加密/混淆:查找常见的加密函数(如AES、RSA)或者混淆特征(如花指令)。

说白了,静态分析就是“读代码”。只不过读的不是源码,是二进制。你需要把机器码还原成逻辑。

避坑指南

我曾经踩过的坑

  • 不要完全相信反编译结果:Hopper和IDA的反编译不是100%准确的。尤其是优化过的代码,可能会丢失一些变量名和逻辑分支。
  • 注意ARC的影响:Objective-C的ARC会在二进制中插入大量的retain/release调用。这些调用会干扰你的分析,要学会忽略它们。
  • Swift的协议方法:Swift的协议方法在二进制中可能没有直接的调用点,而是通过虚函数表(vtable)调用的。这时候需要分析vtable的结构。

知识体系图

下面这张图总结了本章的核心知识结构:

iOS逆向静态分析知识体系 Mach-O 可执行文件 分析工具 Hopper IDA Pro 目标语言 Objective-C Swift 分析内容 字符串表 objc_msgSend Mach-O 关键段 __TEXT __DATA __LINKEDIT Load Commands

这张图把静态分析的几个维度串起来了。你分析的时候,就按这个框架来,不会乱。

写在最后

静态分析是逆向的基础功。说白了,就是“读代码”的能力。你读得越多,就越熟练。我刚开始的时候,一个简单的登录功能要分析半天。现在,十分钟就能摸清一个App的大致结构。

嗯,这一章的内容就到这里。记住:工具只是辅助,真正的功夫在于你对二进制和语言特性的理解。多练,多看,慢慢就有感觉了。


公众号:蓝海资料掘金营,微信deep3321