iOS 逆向开发 文章汇总
目录
- 一、符号表之间的关联
- 二、去符号
- 三、恢复符号
- 四、使用fishhook HOOK系统MethodSwizzle方法,以检测APP是否被HOOK
- 五、使用MonkeyDev进行重新签名和代码注入
- 六、总结
一、符号表之间的关联
懒加载符号表、间接符号表、符号表、字符串表之间的关联
懒加载符号表
和间接符号表
index一一对应
接符号表
保存了在符号表
中的index
符号表
中保存了在字符串表
中的index
上面的流程和fishhook查找符号的流程图一致:The process of looking up the name of a given entry in the lazy or non-lazy pointer tables looks like this:
二、去符号
一般情况下我们的APP会去掉所有符号(不包括间接符号)、动态库会保留全局符号供外部调用。
Xcode 默认是去掉所有符号的,但是Deployment Postprocessing 需要设置为Yes,否者只有在打包时才会去掉所有符号。
符号表中只有间接符号了,本地符号和全局符号都去掉了
添加如下代码:
运行APP后断点是不起作用的,因为去掉了所有符号。添加NSLog
符号断点可以断住,但是去掉符号后函数名会变为___lldb_unnamed_symbol2
如果调用的是OC方法可以添加符号断点并通过参数寄存器查看方法名和参数
还可以通过地址断点(ASLR+地址偏移值)、恢复符号表
等方法查看方法名
三、恢复符号
- (void)differtest {
}
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"第一次外部函数的调用!");
NSLog(@"第二次外部函数的调用!");
}
- (void)test1 {
NSLog(@"第一次外部函数的调用!");
}
- (void)test {
[self test1];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self test];
}
虽然去掉所有符号后符号表中没有符号了,但是类的方法列表中还是存在。因此通过方法列表,类名列表等信息可以恢复出相关的符号
通过restore-symbol工具恢复符号(C函数、静态函数不能恢复,只能恢复Runtime相关的)
执行代码./restore-symbol -o symbolDemo2 symbolDemo
后即可恢复符号,恢复符号的MachO还需要重新签名打包
四、使用fishhook HOOK系统MethodSwizzle方法,以检测APP是否被HOOK
目标:APP中可以MethodSwizzle方法,破解APP时直接调用MethodSwizzle方法会失败。
4.1 新建项目AntiHook模拟我们自己的APP、添加两个按钮并关联方法
代码如下:
- (IBAction)btnClick1:(id)sender {
NSLog(@"按钮1调用!");
}
- (IBAction)btnClick2:(id)sender {
NSLog(@"按钮2调用了!");
}
防护代码需要写在Framework中,因为Framework加载比主工程中的代码加载更快,别人注入的HOOK代码在Framework加载之后、在主工程之前。
添加主Framework
// AntiHookCode.m
#import "fishhook.h"
@implementation AntiHookCode
+ (void)load {
//exchange方法防护
struct rebinding exchange;
exchange.name = "method_exchangeImplementations";
exchange.replacement = my_exchange;
exchange.replaced = (void *)&exchangeP;
//set、get方法防护
//setIMP
struct rebinding setIMP;
setIMP.name = "method_setImplementation";
setIMP.replacement = my_exchange;
setIMP.replaced = (void *)&setIMP_p;
//getIMP
struct rebinding getIMP;
getIMP.name = "method_getImplementation";
getIMP.replacement = my_exchange;
getIMP.replaced = (void *)&getIMP_p;
struct rebinding bds[] = {exchange,setIMP,getIMP};
rebind_symbols(bds, 3);
}
//指针!这个可以暴露给外接!我自己的工程使用!!
void (*exchangeP)(Method _Nonnull m1, Method _Nonnull m2);
IMP _Nonnull (*setIMP_p)(Method _Nonnull m, IMP _Nonnull imp);
IMP _Nonnull (*getIMP_p)(Method _Nonnull m);
void my_exchange(Method _Nonnull m1, Method _Nonnull m2){
NSLog(@"检测到了HOOK!");
}
@end
HookMgr.h中暴露AntiHookCode.h头文件
HookMgr.h设置为Public供外界使用
ViewController.m:自己项目交换按钮2的实现
#import
- (void)viewDidLoad {
[super viewDidLoad];
//HOOK
exchangeP(class_getInstanceMethod(self.class, @selector(btnClick2:)), class_getInstanceMethod(self.class, @selector(test)));
}
- (void)test {
NSLog(@"本工程的HOOK!很顺利!!!");
}
4.2 新建项目HookDemo用来HOOK我们的APP
将编译好的AntiHook拷贝到HookDemo项目中的APP/Payload目录中(真机编译)
终端进入APP目录
zip -ry WeChat.ipa Payload (ipa的名字这里沿用之前的)
删除Payload目录
HookDemo项目编译运行到手机中
添加注入代码:模拟别人HOOK按钮1
添加脚本执行
运行项目将APP安装到手机、控制台会直接输出:检测到了HOOK!
点击按钮1也不会执行test
方法。这样就达到了HOOK APP方法失败的目的
点击按钮2会显示本工程的HOOK!很顺利!!!
五、使用MonkeyDev进行重新签名和代码注入
项目地址、安装方法
安装好后重新打开Xcode就有如下功能(安装MonkeyDev后Xcode如果打开崩溃,删除Xcode重装一次就可以了)
5.1 重签名
- 选择MonkeyApp模板创建项目MonkeyDemo并
运行安装APP
- 将需要重签名的ipa or app 拖到TargetApp目录中
- 运行项目MonkeyDemo到手机即可进行重签名
5.2 代码注入:OC方法HOOK
修改MonkeyDemoDylib.xm文件的type
HOOK APP中ViewController的BtnClick1方法
Monkey实际上使用的是MethodSwizzle 中的method_getImplementation/method_setImplementation方法
六、总结
- HOOK:钩子,改变程序的执行流程的一种技术
- MethodSwizzle
- 利用OC的运行时(Runtime) 特性修改SEL和IMP (函数指针) 对应关系。达到HOOK OC方法的目的
-
method_exchangelMP...
交换两个IMP -
class_replaceMethod
替换某个SEL的IMP (如果没有该方法,就添加。相当于替换掉这个方法) -
method_getlmplementation、method_setlmplementation
获取和设置某个方法的IMP (很多三方框架都使用)
- fishhook
- Facebook提供的一个工具,利用MachO文件的加载原理,动态修改懒加载和非懒加载两个符号表!
- Cydia Substrate
- 一个强大的框架。
- fishhook
- 可以HOOK
系统的函数
,但是无法HOOK自定义的函数
- 原理:
- 共享缓存
- iOS系统有一块特殊的位置,存放公用动态库。动态库共享缓存(dyld shared cache)
- PIC技术
- 由于外部的函数调用, 在我们编译时刻是没法确定其内存地址的。
- 苹果就采用了
PIC
技术(位置无关代码)。在MachO文件DATA段,建立两张表,懒加载和非懒加载表,里面存放执行外部函数的指针! - 首次调用懒加载函数, 会去找
桩
执行代码。首次执行会执行binder
函数!
- 共享缓存
- 通过字符找到懒加载表
- fshhook利用
stringTable
-->Symbols
-->indirect Symbols
-->懒加载符号表
之间的对应关系。通过重绑定修改指针的值达到HOOK的目的。
- fshhook利用
- 反H0OK基本防护
- 利用fishhook修改Methodswizzle 相关函数来检测是否被HOOK
- 防护代码要最先被加载,否则先HOOK就修改完毕了,防护无效。
- 原始工程编写的Framework库会优先于注入库加载。所以适合写防护代码。