逆向开发者会使用LLDB对应用进行调试,LLDB是Xcode中的动态调试工具。
反调试也就是屏蔽调试器挂载
使用 ptrace 函数
typedef int (*ptrace_ptr_t)(int _request, pid_t _pid, caddr_t _addr, int _data);
#if !defined(PT_DENY_ATTACH)
#define PT_DENY_ATTACH 31
#endif // !defined(PT_DENY_ATTACH)
void disable_gdb() {
void *handle = dlopen(0, RTLD_GLOBAL | RTLD_NOW);
ptrace_ptr_t ptrace_ptr = dlsym(handle, "ptrace");
ptrace_ptr(PT_DENY_ATTACH, 0, 0, 0);
dlclose(handle);
}
disable_gdb 去阻止调试器,但是通过这种方法很容易被修改。运行时断点ptrace直接 return,就破解了。
用汇编去调用ptrace,这样就无法通过函数替换来实现反调试了,必须通过修改二进制文件中的汇编代码才能反调试。攻击者可以使用nop来移除掉命令svc #0x80,但是这种破解难度就比前面的要高很多。
static __attribute__((always_inline)) void debug()
{
#ifdef __arm64__
__asm__("mov X0, #31 \t\n"
"mov X1, #0 \t\n"
"mov X2, #0 \t\n"
"mov X3, #0 \t\n"
"mov w16, #26 \t\n" // ip1 指针。
"svc #0x80"
);
#elif __arm__
__asm__(
"mov r0, #31 \t\n"
"mov r1, #0 \t\n"
"mov r2, #0 \t\n"
"mov r3, #0 \t\n"
"mov ip, #26 \t\n"
"svc #0x80"
);
#endif
return;
}
使用的时候直接调用debug(),同时可以在多出调用debug(),增加破解难度。
sysctl 检测到调试器后使用 exit(-1) 强制退出程序,这样就无法继续
static int is_debugged(){
int name[4] = {CTL_KERN,KERN_PROC,KERN_PROC_PID,getpid()};
struct kinfo_proc Kproc;
size_t kproc_size = sizeof(Kproc);
memset((void*)&Kproc, 0, kproc_size);
if (sysctl(name, 4, &Kproc, &kproc_size, NULL, 0) == -1) {
perror("sysctl error \n ");
exit(-1);
}
return (Kproc.kp_proc.p_flag & P_TRACED) ? 1 : 0;
}
if (is_debugged() == YES) {
NSLog(@"is_debugged ");
exit(-1);
}else{
NSLog(@"not is_debugged");
}
以上两种方法基本可以防止一般hacker动态调试app,具体深入研究可以参考http://bbs.iosre.com
参考资料:http://www.jianshu.com/p/122f9e4db055 http://bbs.iosre.com/t/7-2-0-ios/770/14