github代码地址https://github.com/xuebzufo/FishhookDemo.git
fishhook是什么
fishhook是facebook开源的第三方框架,顾名思义就是"钩子"的意思。在计算机里就是勾住某一个程序或者一个函数。从而扩展程序功能或者改变程序运行流程。
总所周知,c语言是静态语言,而静态语言编译后变量,函数以及参数已经确定,不能修改。但fishhook能够在程序运行时动态修改c函数(动态链接库函数).自定义的c函数是不行的。
应用场景
hook除了用于逆向攻击,如:ptrace的反调试攻破,也有很多都正向开发,如拦截用户手势进行用户行为分析,OA中拦截网络,截屏,剪贴板功能防止数据泄露。
原理
fishhook为何不能hook自定义函数呢?
自定义函数在代码段,代码段具有只读可执行权限,却不能修改。
而如NSLog函数这些外部动态库的函数是在那个段呢?
image.png
可以看到NSLog函数符号位于数据段,是可读可写的。
函数符号为何在数据段?
image.png真正的函数符号NSLog位于外部动态链接库Foundation.framework,属于外部符号,由于每次程序加载到内存,要进行ASLR动态地址重新计算一个随机值,所以地址需要重新绑定,来找到真正的NSLog。这个就是也懒加载符号了
那么如何找到对应的真正函数呢
image.png可以看到通过 他的值进行各种跳转后,最后到达了dyld_stub_binder,就是so-called桩绑定了。dyld符号重绑定。
fishhook就是通过dyld来实现方法交换
image.pngdyld动态加载器提供了获取镜像数据的接口,从而获取Mach-O中的函数符号信息
大概了解了流程我们来hook下ptrace 来破解防调试。
首先我们去github上下载fishhook源码导入工程。
fishhook的代码很简单直接上代码
//
// InjectCode.m
// FishhookDemo
//
// Created by Sem on 2020/8/31.
// Copyright © 2020 SEM. All rights reserved.
//
#import "InjectCode.h"
#import "fishhook.h"
#import <dlfcn.h>
#define PT_DENY_ATTACH 31
@implementation InjectCode
// 定义函数指针. 保存原来函数地址
int(*ptrace_ptr_t)(int _request,pid_t_pid,caddr_t_addr,int_data);
// 定义新的函数
int myPtrace (int _request, pid_t _pid, caddr_t _addr, int _data){
if(_request != PT_DENY_ATTACH){
return myPtrace(_request, _pid, _addr, _data);
}
// 如果拒绝加载, 破坏此防护
return 0;
}
static void (*orig_NSLog)(NSString *format, ...);
void(new_NSLog)(NSString *format, ...) {
va_list args;
if(format) {
va_start(args, format);
NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
orig_NSLog(@"%@🚌😁😄❤️!!!!", message);
va_end(args);
}
}
+(void)load{
struct rebinding ptrace1; //
ptrace1.name = "ptrace"; // 函数符号
ptrace1.replacement = myPtrace; // 新函数地址
ptrace1.replaced = (void *)&ptrace_ptr_t; // 原始函数地址的指针
struct rebinding ptrace2; //
ptrace2.name = "NSLog"; // 函数符号
ptrace2.replacement = new_NSLog; // 新函数地址
ptrace2.replaced = (void *)&orig_NSLog; // 原始函数地址的指针
// 创建数组
struct rebinding rebinds[]={ptrace1,ptrace2};
// 重绑定
rebind_symbols(rebinds, 2);
}
@end
部分资料来自逻辑教育公开课
网友评论