iOS 逆向

class-dump 与 Hopper 实战:从界面布局还原业务逻辑

2025-06-30 wangjun 15 min read
0x

静态分析三板斧

拿到一个砸壳后的 IPA,先别急着上调试器。静态分析能在几分钟内勾勒出 App 的"地图":

# 1. 字符串:直接暴露线索
$ strings App | grep -iE "api|token|secret|login"

# 2. 类结构:还原全部 OC 类与接口
$ class-dump App -H -o ./headers

# 3. 符号:函数与全局符号一览
$ nm -nm App | grep -iE "login|encrypt"

class-dump:把二进制还原成头文件

Objective-C 的运行时特性(类名、方法名、协议都以字符串存在)决定了它"藏不住秘密"。class-dump 直接输出近似源码的头文件:

// 还原出的头文件示例
@interface PaymentService : NSObject
{
  NSString *_token;
}
- (void)startPayWithOrderId:(NSString *)orderId
                   amount:(double)amount
                    sign:(NSString *)sign;
- (NSString *)generateSignWithParams:(NSDictionary *)params;
@end

看到 generateSignWithParams: 就基本锁定了签名算法的位置 -- 这就是突破口。

Hopper:从汇编到伪代码

class-dump 只能看到接口,实现细节要靠反汇编。Hopper 的伪代码模式能把 arm64 汇编还原成类 C 代码,大幅降低阅读门槛:

// Hopper 伪代码示例(还原 sign 算法)
NSString *generateSignWithParams(self, _cmd, params) {
    NSMutableString *sorted = [params sortedKeysJoined:@""];
    NSString *pre = [sorted stringByAppendingString:SECRET_KEY];
    return [pre md5Upper];  // 参数排序拼接 + 密钥 + MD5
}

Hopper 使用技巧

  • 重命名:把 sub_1000045A8 改名为 generateSign,整个分析过程可读性大增
  • 类型修复:手动把 void* 标成 NSString *,伪代码质量立刻提升
  • 交叉引用:对字符串/方法按 X 查看谁引用了它,快速定位调用链
  • 书签与注释:边分析边记录,防止走回头路

LLDB:静态结论的动态验证

静态分析可能误判,重要结论必须动态验证。把 LLDB 附加到进程,在可疑函数下断点:

(lldb) breakpoint set --name "-[PaymentService generateSignWithParams:]"
(lldb) run
(lldb) po $arg2    # 打印参数(self 是 $arg0)
(lldb) finish     # 运行到函数返回
(lldb) po $x0     # 打印返回值,确认签名结果

配合 Frida 可以更灵活:直接调用目标方法、篡改参数、打印调用栈。

完整分析流程

  1. strings 快速浏览,记录敏感关键词
  2. class-dump 还原类结构,定位"入口方法"
  3. Hopper 打开关键方法,还原伪代码与调用链
  4. LLDB / Frida 动态验证,确认数据流与控制流
  5. 整理成文档:类图、时序、算法还原
静态分析回答"它有什么",动态分析回答"它做了什么" -- 两者结合,黑盒才能变白盒。