sysctl、反HOOK
1. 反调试sysctl
系统函数 监测应用是否被调试
#import "ViewController.h"
#import <sys/sysctl.h>
@interface ViewController ()
@end
static dispatch_source_t timer;
@implementation ViewController
void debugCheck(){
timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 0.0 * NSEC_PER_SEC);
dispatch_source_set_event_handler(timer, ^{
if (isDebugger()) {
NSLog(@"检测到了!!");
}else{
NSLog(@"正常!!");
}
});
dispatch_resume(timer);
}
//检测是否被调试
BOOL isDebugger(){
//控制码
int name[4];//里面放字节码.查询信息
name[0] = CTL_KERN;//内核查看
name[1] = KERN_PROC;//查询进程
name[2] = KERN_PROC_PID;//传递的参数是进程的ID(PID)
name[3] = getpid();//PID的值告诉
struct kinfo_proc info;//接受进程查询结果信息的结构体
size_t info_size = sizeof(info);//结构体的大小
int error = sysctl(name, sizeof(name)/sizeof(*name), &info, &info_size, 0, 0);
assert(error == 0);//0就是没有错误,其他就是错误码
//p_flag 有很多二进制信息
//例如:1011 1000 1010 1010 1101 0101 1101 0101
//&
//0000 0000 0000 1000 0000 0000 0000 0000
// 第32位 == 0 ? 没有 有!!
return ((info.kp_proc.p_flag & P_TRACED) != 0);
}
- (void)viewDidLoad {
[super viewDidLoad];
debugCheck();
}
2.破解sysctl - fishHook
#import "injectCode.h"
#import "fishhook.h"
#import <sys/sysctl.h>
@implementation injectCode
//原始函数的地址
int (*sysctl_p)(int *, u_int, void *, size_t *, void *, size_t);
//自定义函数
int mySysctl(int *name, u_int namelen, void *info, size_t *infosize, void *newinfo, size_t newinfosize){
if (namelen == 4
//检查内核
&& name[0] == CTL_KERN
//检查内核的进程
&& name[1] == KERN_PROC
//传递的参数是PID
&& name[2] == KERN_PROC_PID
&& info
&& (int)*infosize == sizeof(struct kinfo_proc))
{
int err = sysctl_p(name, namelen, info, infosize, newinfo, newinfosize);
//拿出info做判断
struct kinfo_proc * myInfo = (struct kinfo_proc *)info;
if((myInfo->kp_proc.p_flag & P_TRACED) != 0){
//使用异或取反
myInfo->kp_proc.p_flag ^= P_TRACED;
}
return err;
}
return sysctl_p(name, namelen, info, infosize, newinfo, newinfosize);
}
+(void)load
{
//交换
rebind_symbols((struct rebinding[1])sysctl, 1);
}
@end
3. ptrace&sysctl提前执行
- 新建的动态库放到最前面执行
- 在load里面判断
#import "antiDebugCode.h"
#import "fishhook.h"
#import "MyPtraceHeader.h"
#import <sys/sysctl.h>
static dispatch_source_t timer;
@implementation antiDebugCode
void debugCheck(){
timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 0.0 * NSEC_PER_SEC);
dispatch_source_set_event_handler(timer, ^{
if (isDebugger()) {
NSLog(@"检测到了!!");
}else{
NSLog(@"正常!!");
}
});
dispatch_resume(timer);
}
//检测是否被调试
BOOL isDebugger(){
//控制码
int name[4];//里面放字节码.查询信息
name[0] = CTL_KERN;//内核查看
name[1] = KERN_PROC;//查询进程
name[2] = KERN_PROC_PID;//传递的参数是进程的ID(PID)
name[3] = getpid();//PID的值告诉
struct kinfo_proc info;//接受进程查询结果信息的结构体
size_t info_size = sizeof(info);//结构体的大小
int error = sysctl(name, sizeof(name)/sizeof(*name), &info, &info_size, 0, 0);
assert(error == 0);//0就是没有错误,其他就是错误码
//1011 1000 1010 1010 1101 0101 1101 0101
//&
//0000 0000 0000 1000 0000 0000 0000 0000
// == 0 ? 没有 有!!
return ((info.kp_proc.p_flag & P_TRACED) != 0);
}
void debugerCheck(){
if (isDebugger()) {
NSLog(@"进程被调试!!");
}
//开启反调试
ptrace(PT_DENY_ATTACH, getpid(), 0, 0);
}
+(void)load
{
debugerCheck();
}
@end
4. 攻防博弈!找到你就赢
- loadCommand段前移…
- 直接修改二进制,改变代码
- 直接闪退,两种
- exit
- ptrace
- 下一个符号断点
//只要调用就可以断住
ptrace
//bt查看函数真实。相对于动态库偏移地址。指令地址,pc寄存器永远指向下一条
//image list 找到动态库地址
//偏移地址减去动态库地址,拿到指令地址
//hopper查看,指令地址的上一条即为调用地址
//寄存器前三句(保护寄存器)直接跳到后三句(恢复寄存器)。不执行中间option+A修改
//导出file/Produce New Executable
//替换Macho
5. 破解悬疑已久的反HOOK
- hopper查找 method_setImplementation
- 直接修改地址~~~
//拿到的地址
bt
//查看汇编
dis -s 地址