iOS反动态调试

逆向开发者会使用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