前言
在逆向和保护的过程中,总会涉及到反调试和反反调试的问题,这篇文章主要是总结一下几种常见的反调试手段以及反反调试的方法。
反调试
ptrace
为了方便应用软件的开发和调试,从Unix的早期版本开始就提供了一种对运行中的进程进行跟踪和控制的手段,那就是系统调用ptrace()。
通过ptrace可以对另一个进程实现调试跟踪,同时ptrace还提供了一个非常有用的参数那就是PT_DENY_ATTACH,这个参数用来告诉系统,阻止调试器依附。
所以最常用的反调试方案就是通过调用ptrace来实现反调试。
#ifndef PT_DENY_ATTACH #define PT_DENY_ATTACH 31 #endif typedef int (*ptrace_ptr_t)(int _request, pid_t _pid, caddr_t _addr, int _data); ptrace(PT_DENY_ATTACH, 0, 0, 0); void *handle = dlopen(0, RTLD_GLOBAL | RTLD_NOW); ptrace_ptr_t ptrace_ptr = (ptrace_ptr_t)dlsym(handle, "ptrace"); ptrace_ptr(PT_DENY_ATTACH, 0, 0, 0);
sysctl
当一个进程被调试的时候,该进程会有一个标记来标记自己正在被调试,所以可以通过sysctl去查看当前进程的信息,看有没有这个标记位即可检查当前调试状态。
BOOL isDebuggerPresent(){ 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); }
检测到调试器就退出,或者制造崩溃,或者隐藏工程啥的,当然也可以定时去查看有没有这个标记。
syscall
为从实现从用户态切换到内核态,系统提供了一个系统调用函数syscall,上面讲到的ptrace也是通过系统调用去实现的。
在Kernel Syscalls这里可以找到ptrace对应的编号。
1
26. ptrace 801e812c T
所以如下的调用等同于调用ptrace:
1
syscall(26,31,0,0,0);
arm
syscall是通过软中断来实现从用户态到内核态,也可以通过汇编svc调用来实现。
#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
下面几种可能在实际中用到的比较少,不过也可以尝试一下。
SIGSTOP
通过捕获系统SIGSTOP信号来判断。
dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGSTOP, 0, dispatch_get_main_queue()); dispatch_source_set_event_handler(source, ^{ NSLog(@"SIGSTOP!!!"); exit(0); } ); dispatch_resume(source);
task_get_exception_ports
获取异常端口:
struct macosx_exception_info{ exception_mask_t masks[EXC_TYPES_COUNT]; mach_port_t ports[EXC_TYPES_COUNT]; exception_behavior_t behaviors[EXC_TYPES_COUNT]; thread_state_flavor_t flavors[EXC_TYPES_COUNT]; mach_msg_type_number_t cout; } ; struct macosx_exception_info *info = malloc(sizeof(struct macosx_exception_info)); task_get_exception_ports(mach_task_self(),EXC_MASK_ALL,info->masks,&info->cout,info->ports,info->behaviors,info->flavors); for(uint32_t i = 0; i < info->cout; i ++){ if(info->ports[i] != 0 || info->flavors[i] == THREAD_STATE_NONE){ NSLog(@"debugger detected via exception ports (null port)!\n"); } }
isatty
if (isatty(1)) {
NSLog(@"Being Debugged isatty");
}
ioctl
if (!ioctl(1, TIOCGWINSZ)) {
NSLog(@"Being Debugged ioctl");
}
反反调试(Tweak)
了解了几种不同的反调试的方法,那么就可以根据几种常用的反调试方法来反反调试。
这里主要针对ptrace、sysctl、syscall来反反调试,做法就很简单了,hook函数,判断参数,返回结果。
#import <substrate.h> #import <sys/sysctl.h> static int (*orig_ptrace) (int request, pid_t pid, caddr_t addr, int data); static int my_ptrace (int request, pid_t pid, caddr_t addr, int data){ if(request == 31){ NSLog(@"[AntiAntiDebug] - ptrace request is PT_DENY_ATTACH"); return 0; } return orig_ptrace(request,pid,addr,data); } static void* (*orig_dlsym)(void* handle, const char* symbol); static void* my_dlsym(void* handle, const char* symbol){ if(strcmp(symbol, "ptrace") == 0){ NSLog(@"[AntiAntiDebug] - dlsym get ptrace symbol"); return (void*)my_ptrace; } return orig_dlsym(handle, symbol); } static int (*orig_sysctl)(int * name, u_int namelen, void * info, size_t * infosize, void * newinfo, size_t newinfosize); static int my_sysctl(int * name, u_int namelen, void * info, size_t * infosize, void * newinfo, size_t newinfosize){ int ret = orig_sysctl(name,namelen,info,infosize,newinfo,newinfosize); if(namelen == 4 && name[0] == 1 && name[1] == 14 && name[2] == 1){ struct kinfo_proc *info_ptr = (struct kinfo_proc *)info; if(info_ptr && (info_ptr->kp_proc.p_flag & P_TRACED) != 0){ NSLog(@"[AntiAntiDebug] - sysctl query trace status."); info_ptr->kp_proc.p_flag ^= P_TRACED; if((info_ptr->kp_proc.p_flag & P_TRACED) == 0){ NSLog(@"[AntiAntiDebug] trace status reomve success!"); } } } return ret; } static void* (*orig_syscall)(int code, va_list args); static void* my_syscall(int code, va_list args){ int request; va_list newArgs; va_copy(newArgs, args); if(code == 26){ request = (long)args; if(request == 31){ NSLog(@"[AntiAntiDebug] - syscall call ptrace, and request is PT_DENY_ATTACH"); return nil; } } return (void*)orig_syscall(code, newArgs); } %ctor{ MSHookFunction((void *)MSFindSymbol(NULL,"_ptrace"),(void*)my_ptrace,(void**)&orig_ptrace); MSHookFunction((void *)dlsym,(void*)my_dlsym,(void**)&orig_dlsym); MSHookFunction((void *)sysctl,(void*)my_sysctl,(void**)&orig_sysctl); MSHookFunction((void *)syscall,(void*)my_syscall,(void**)&orig_syscall); NSLog(@"[AntiAntiDebug] Module loaded!!!"); }