前言
在逆向和保护的过程中,总会涉及到反调试和反反调试的问题,这篇文章主要是总结一下几种常见的反调试手段以及反反调试的方法。
反调试
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
,讲到上面的ptrace
也是通过系统-调用去实现的。
在Kernel Syscalls 71 这里可以找到对应ptrace
的编号。
26\. ptrace 801e812c T
复制代码
所以如下的调用等同于调用ptrace
:
syscall(26,31,0,0,0);
复制代码
臂
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"