HOOK原理与fishhook初探防护
1.HOOK概述
1、Method Swizzle
利用oc的runtime特性,动态改变SEL(方法编号)和IMP(方法实现)的对应关系,达到oc方法调用流程改变的目的。主要用于oc方法。
2、fishhook
它是Facebook提供的一个动态链接mach-O文件的工具。利用Macho文件加载原理,通过修改懒加载和非懒加载两个表的指针达到C函数Hook的目的
3 cydia Substrate
Cydia Substrte原名为mobile Substrte,它主要的作用是针对OC方法、C函数以及函数地址进行HOOK操作。当然它并不是仅仅针对ios而设计的,安卓也一样可以用。
下图是Method Swizzle和cydia substrte的简单原理图:
2.fishHook简单使用
1.获取facehook的源码
1.1 通过登录github 搜索fishhook 可以看到源码并且down下来。
1.2 可终端cd到想要下载的目标文件下,通过输入命令 下载,
下载后可以看到只有fishhook.h fishhook.c 2个文件,可以看到点h中·只有2个方法和一个结构体。
方法1:rebind_symbols 针对是c函数
方法2:rebind_symbols_image 主要用于image
2.fishHook简单使用
1.用自定的myNSlog 替换 系统方法NSlog
- (void)viewDidLoad {
[super viewDidLoad];
//rebinding结构体
struct rebinding nslog;
nslog.name = "NSLog";
nslog.replacement = myNslog;
nslog.replaced = (void *)&sys_nslog;
//rebinding结构体数组
struct rebinding rebs[1] = {nslog};
/**
* 存放rebinding结构体的数组
* 数组的长度
*/
rebind_symbols(rebs, 1);
}
//---------------------------------更改NSLog-----------
//函数指针
static void(*sys_nslog)(NSString * format,...);
//定义一个新的函数
void myNslog(NSString * format,...){
format = [format stringByAppendingString:@"勾上了!\n"];
//调用原始的
sys_nslog(format);
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
NSLog(@"点击了屏幕!!");
}
2.如下代码,运行后可以发现点击屏幕,new_func并未替换func方法,原因是因为fishHook只能用于替换“系统函数”,并不能替换自定义的函数,具体原理下面继续探索。
void func(const char * str){
NSLog(@"%s",str);
}
- (void)viewDidLoad {
[super viewDidLoad];
//rebinding结构体
struct rebinding nslog;
nslog.name = "func";
nslog.replacement = new_func;
nslog.replaced = (void *)&old_func;
//rebinding结构体数组
struct rebinding rebs[1] = {nslog};
/**
* 存放rebinding结构体的数组
* 数组的长度
*/
rebind_symbols(rebs, 1);
}
//---------------------------------更改NSLog-----------
//函数指针
static void(*old_func)(const char * str);
//定义一个新的函数
void new_func(const char * str){
NSLog(@"%s + 1",str);
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
func("哈哈");
// NSLog(@"哈哈!");
}
3 无法交换自定义函数,符号绑定原理
1.c 静态:系统的c函数存在着动态的部分!!
编译时确定:函数的地址!
2.oc 动态
运行时确定:函数的地址!
3.自定义函数的函数实现地址在macho的本地文件中,
而系统函数编译时系统地址不能确定,苹果用PIC技术解决,在macho的数据段中生成符号表,运行时通过dyld链接共享缓存库将真实地址绑定到符号表上符号地址,
我们可以看到nslog在macho中的偏移位置是0x4030,
我们可以看到macho在内存的起始位置是
然后我们打开电脑段的计算器,command + 3 打开科学计算器,
然后起始位置加 偏移量,得到的16进制的0x10e172030,NSlog内存中的位置,
我们将断点打到viewdidload,如图所示位置:
然后使用LLDB,读取内存的指令:memory read 0x10e172030.可以看到内存中value是 0xf7ff2081c3b5,然后使用汇编指令dis -s f7ff2081c3b5查看汇编代码,如下显示foundation模块的nslog,(我这里断点过到nslog之下了,上面走到viewdidload时候也同样使用memory read 0x10e172030,可以查看未绑定nslog符号之前,内存value是不同于此处的,同样使用dis -s 0x… 可以看到未绑定之前是我们不识别的汇编,)
同样我们过了rebing_sysbols后在断点到touch处,同样读内存,和value发现此处已经绑定为myNSlog方法了。
4 rebing_sysbols中的结构体如何通过name字符串,查找修改到nslog的交换方法的。
首先在lazy Syymbol表中可以看到NSLog,
与lazy symbol表对应的表如下,nslog都是在表中首位,看到此处data序号为0x83:
上面这张表又与下面表对应,0x83十进制是131,我们可以寻找下表中131位置,是nslog,然后data对应value是A1
与上表想对应去string表中,寻找起始位置:0x6020 + a1便找到nslog的位置了
5 初探防护
我们用fishhook交换了method_exchangeImplementations,之前使用method_exchangeImplementations进攻的代码就会可以被防护住了。
+(void)load
{
//进攻的代码!
// getIMP setIMP
Method old = class_getInstanceMethod(self, @selector(btnClick1:));
Method newMethod = class_getInstanceMethod(self, @selector(click1Hook:));
method_exchangeImplementations(old, newMethod);
//防护代码!
struct rebinding bd;
bd.name = "method_exchangeImplementations";
bd.replacement = myExchange;
bd.replaced = (void *)&exchangeP;
struct rebinding rebs[1] = {bd};
rebind_symbols(rebs, 1);
}
//防护代码
//函数指针变量
void
(*exchangeP)(Method _Nonnull m1, Method _Nonnull m2);
void myExchange(Method _Nonnull m1, Method _Nonnull m2){
NSLog(@"检测到HOOK!!");
}
-(void)click1Hook:(id)sender{
NSLog(@"HOOK成功!!");
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (IBAction)btnClick1:(id)sender {
NSLog(@"按钮1调用了!");
}
- (IBAction)btnClick2:(id)sender {
NSLog(@"按钮2调用了!");
}
上一篇: OP-TEE 环境搭建
下一篇: git的安装