保护调试
防止App被重签名调试
代码:
#import <sys/sysctl.h>
- (void)done{
if([self isDebug]){
NSLog(@"存在调试器");
//存在工具调试操作直接退出
exit(0);
}else{
NSLog(@"不存在调试器");
}
}
- (BOOL)isDebug{
int name[4];//里面存放字节码
name[0] = CTL_KERN;//内核查询
name[1] = KERN_PROC;//查询进程
name[2] = KERN_PROC_PID;//传递的参数是进程ID
name[3] = getpid();//PID 进程ID
struct kinfo_proc info;//查询到的结果放到此结构体
size_t info_size = sizeof(info);
//调试信息
sysctl(name, sizeof(name)/sizeof(*name), &info, &info_size, 0, 0);
//info.kp_proc.p_flag 第12位若为1则存在调试
return ((info.kp_proc.p_flag & P_TRACED) !=0);
}
攻击保护调试
步骤(hook方式)
1.重签名应用进行调试
2.增加symbolic Breakpoint断点并筛选方法名关键字,例如:(exit)
3.进入断点后,输出(lldb)bt 指令,查看函数调用栈,找到根方法的内存地址
4.进入断点后,输出(lldb)image list 镜像(可执行)文件列表指令,找到文件首地址(第一条 )
5.用内存地址减去文件首地址计算出偏移量
6.找到可执行文件(exec)使用反汇编工具(hopper diaassembler v4)进行分析,并用计算出的偏移量进行查询
7.由于寄存器的原因需减掉4字节,所以真实调用的为查询结果的上一条
8.选择汇编代码,点击空格查看调用流程(保护调试方式为sysctl)
9.建立framework使用脚本进行fishHook注入,方法交换
代码:
#import "fishhook.h"
//原是函数指针
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 && name[2] == KERN_PROC_PID && info) {
//暂时保留
int error = 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 error;
}
return sysctl_p(name,namelen,info,infoSize,newInfo,newInfoSize);
}
+(void)load{
//方法交换
rebind_symblos((struct rebinding[1]{{"sysctl",mySysctl,(void *)&sysctl_p}},1);
}