信息安全逆向工程iOS开发之常用技术点

iOS 反调试

2018-07-20  本文已影响46人  77168ddcf2c6

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

上一篇下一篇

猜你喜欢

热点阅读