现在很多iOS App都有PT_DENY_ATTACH反调试, 造成debugserver无法附加调试.
1 2 3 4 | debugserver - @( #)PROGRAM:LLDB PROJECT:lldb-1200.2.12 for arm64. Attaching to process 1468. .. Segmentation fault: 11 |
光是用Frida调动Hook进行分析难度和工作量很大,里还有很多动态跳转,静态分析难度重重.
重新打包IPA,之前hook ptrace或sysctl等方法跳过检测也已经失效,因为现在都是直接调用syscall调用内核接口.
1 2 3 4 5 6 7 8 9 10 11 | static __attribute__((always_inline)) void asm_ptrace() { #ifdef __arm64__ __asm__( "mov X0, #31\n" "mov X1, #0\n" "mov X2, #0\n" "mov X3, #0\n" "mov X16, #26\n" "svc #0x80\n" ); #endif } |
所以比较好的解决方法就是对内核进行修改.先看一下ptrace内核的源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | int ptrace(struct proc * p, struct ptrace_args * uap, int32_t * retval) { / / .... if (uap - >req = = PT_DENY_ATTACH) { / / .... proc_lock(p); if (ISSET(p - >p_lflag, P_LTRACED)) { proc_unlock(p); / / ... exit1(p, W_EXITCODE(ENOTSUP, 0 ), retval); thread_exception_return(); / * NOTREACHED * / } SET (p - >p_lflag, P_LNOATTACH); / / p_lflag | = 0x00001000 proc_unlock(p); return 0 ; } |
实现PT_DENY_ATTACH很简单,就是对相关进程proc的p_lflag加上P_LNOATTACH标识位.
那调试就是去掉P_LNOATTACH就行,那就要找到当前系统所有的进程信息,所有进程都放在了kernproc
1 2 3 4 5 | / * Components of the first process - - never freed. * / struct proc proc0 = { .p_comm = "kernel_task" , .p_name = "kernel_task" }; SECURITY_READ_ONLY_LATE(proc_t) kernproc = &proc0; proc_t XNU_PTRAUTH_SIGNED_PTR( "initproc" ) initproc; |
再找到相关进程的proc,查看proc的结构,也就是所有的内核kernproc(proc0)的子进程都放在了p_list里
1 2 3 | struct proc { LIST_ENTRY(proc) p_list; / * List of all processes. * / * * * * |
找到kernproc在内核的地址,然后通tfp0(task for pid 0)调用
mach_vm_read读取kernproc,遍历kernproc的p_list找到相当进程的proc,对p_lflag,进行修改,再mach_vm_write写回内存即可.
1 2 3 4 | if (proc - >p_pid = = pid) { proc - >p_lflag & = P_LNOATTACH; / / P_LNOATTACH = 0x1000 mach_vm_write (...&proc - >p_lflag...) } |
debugserver此时已经可以进行调试.