iOS 逆向
class-dump 与 Hopper 实战:从界面布局还原业务逻辑
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 可以更灵活:直接调用目标方法、篡改参数、打印调用栈。
完整分析流程
strings快速浏览,记录敏感关键词class-dump还原类结构,定位"入口方法"- Hopper 打开关键方法,还原伪代码与调用链
- LLDB / Frida 动态验证,确认数据流与控制流
- 整理成文档:类图、时序、算法还原
静态分析回答"它有什么",动态分析回答"它做了什么" -- 两者结合,黑盒才能变白盒。