iOS 反调试

作者: 77168ddcf2c6 | 来源:发表于2018-07-20 16:05 被阅读46次

    0x01

    反调试主要分为两种,第一种阻止调试器附加,第二种是检测是否有调试器存在

    0x02

    第一种方法:

    0x01 ptrace

    ptrace是系统用来对运行中的进程进行调试和跟踪的工具,通过ptrace,可以对另一个进程实现调试跟踪。但是里面提供了一个非常有用的参数,就是PT_DENY_ATTACH,const值是31,这个参数用户告诉系统阻止调试器附加。
    在main.m里面加入以下代码:

    #import <UIKit/UIKit.h>
    #import "AppDelegate.h"
    #import <dlfcn.h>
    #import <sys/types.h>
    
    typedef int  (*ptrace_ptr_t)(int _request,pid_t pid,caddr_t _addr,int _data);
    #ifndef PT_DENY_ATTACH
    #define PT_DENY_ATTACH 31
    #endif
    
    
    int main(int argc, char * argv[]) {
        @autoreleasepool {
           // ptrace(PT_DENY_ATTACH,0,0,0); //系统函数并没有暴露出此方法所以不能直接通过此方式调用
            void *handle = dlopen(0, RTLD_NOW|RTLD_GLOBAL);
            ptrace_ptr_t ptrace_ptr = (ptrace_ptr_t)dlsym(handle, "ptrace");
            ptrace_ptr(PT_DENY_ATTACH,0,0,0);
            return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
        }
    }
    

    在上面的代码中,本来是直接调用上面被注释的那一行代码就可以了,不过由于不是公开的函数所以没法直接调用。所以我们通过dlopen的方式,当path 参数为0是,他会自动查找 LD_LIBRARY_PATH,DYLD_LIBRARY_PATH, $DYLD_FALLBACK_LIBRARY_PATH 和 当前工作目录中的动态链接库,通过句柄找到对应的ptarce对应的地址,然后传入PT_DENY_ATTACH。

    0x02 syscall

    另外一种方式可以使用syscall的方式来调用ptrace,syscall是系统提供的一个系统调用函数,因为上面的调用方式会容易被反反调试,通过NSFindSymbol找到_ptrace然后hook对应的函数,所以可以最好是通过syscall来反调试
    在Kernel Syscalls里面找到ptrace对应的const。

    $ joker -u ~/Documents/projects/iOS.6.0.iPod4.kernel 
    This is an ARM binary. Applying iOS kernel signatures
    Entry point is 0x80085084....This appears to be XNU 2107.2.33
    Syscall names are @2a70f0
    Sysent offset in file/memory (for patching purposes): 0x2ef0c0/0x802f00c0
    
    Suppressing enosys (0x800b3429)  T = Thumb
    1. exit                  801d4a74 T
    2. fork                  801d7980 T
    3. read                  801eb584 T
    4. write                 801eb958 T
    5. open                  800b13a4 T
    6. close                 801ccab4 T
    7. wait4                 801d56bc T
    9. link                  800b18e8 T
    10. unlink               800b1ff0 T
    12. chdir                800b0c60 T
    13. fchdir               800b0af0 T
    14. mknod                800b14bc T
    15. chmod                800b2b40 T
    16. chown                800b2c9c T
    18. getfsstat            800b088c T
    20. getpid               801dc20c T
    23. setuid               801dc4c0 T
    24. getuid               801dc290 T
    25. geteuid              801dc2a0 T
    26. ptrace               801e812c T
    27. recvmsg              8020a8fc T
    28. sendmsg              8020a444 T
    29. recvfrom             8020a528 T
    30. accept               80209dfc T
    31. getpeername          8020abc8 T
    32. getsockname          8020ab18 T
    33. access               800b24ac T
    34. chflags              800b2928 T
    35. fchflags             800b29f0 T
    36. sync                 800b0320 T
    37. kill                 801dfdcc T
    39. getppid              801dc214 T
    41. dup                  801cab04 T
    42. pipe                 801edbe4 T
    43. getegid              801dc318 T
    46. sigaction            801deee8 T
    47. getgid               801dc308 T
    48. sigprocmask          801df42c T
    49. getlogin             801dd0e8 T
    50. setlogin             801dd160 T
    51. acct                 801c54ec T
    52. sigpending           801df5d0 T
    

    注意一下代码中的26就是ptrace的const。
    综上所述:调用syscall(26,31,0,0,0)就可以达到反调试的目的。

    0x03 sysctl

    可以通过sysctl查看内核进程状态标志位,如果一个进程在调试状态,会有一个标志位(info.kp_proc.p_flag)来标识当前是否正在调试。
    代码如下:

    BOOL existDebugger(){
        int name[4];//指定查询信息的数组
        struct kinfo_proc info;//查询的返回结果
        size_t info_size = sizeof(info);
        info.kp_proc.p_flag = 0;
        
        name[0] = CTL_KERN;
        name[1] = KERN_PROC;
        name[2] = KERN_PROC_PID;
        name[3] = getpid();
        if (sysctl(name, 4, &info, &info_size, NULL, 0) == -1) {
            NSLog(@"sysctl error ...");
            return NO;
        }
        return ((info.kp_proc.p_flag & P_TRACED) != 0);
        
    }
    
    

    可以定时执行以上代码,当检测到程序正在被调试,可以调用exit(0)来让程序奔溃或者做其他的操作

    0x04

    syscall可以通过软中断实现从用户态切换到系统内核态的转换,同时可以通过arm 汇编实现以上功能。通过asm volatile内联汇编,实际上也是调用了ptrace。
    代码如下:

    #ifdef __arm__
            asm volatile(
                         "mov r0,#31\n"
                         "mov r1,#0\n"
                         "mov r2,#0\n"
                         "mov r12,#26\n"
                         "svc #80\n"
    
                         );
    #endif
    #ifdef __arm64__
            asm volatile(
                         "mov x0,#26\n"
                         "mov x1,#31\n"
                         "mov x2,#0\n"
                         "mov x3,#0\n"
                         "mov x16,#0\n"
                         "svc #128\n"
                         );
    #endif
    
    

    相关文章

      网友评论

        本文标题:iOS 反调试

        本文链接:https://www.haomeiwen.com/subject/skrqmftx.html