ptrace
反调试的原理是进程只能被一个进程附加。
当一个应用使用了 ptrace
反调试的时候,以 objection
为例,附加时候会出现这种现象:
查看进程 /proc/self/status
目录,会看到 TracerPid
不为0,其值为附加它的父进程 pid
,这里是 zygote
进程。
它的原理也很,加上 ptrace(PTRACE_TRACEME);
就行。
过掉它的方法很多,下面介绍使用 ptrace
怎么过掉 ptrace
:
1、使用 ptrace
附加 zygote
进程。
2、拦截 zygote
的 fork
调用,在 fork
子进程时候获取当前子进程名称,判断是不是我们想要的那个应用,如果是,就保存子进程 pid
3、获取到子进程 pid
后,再拦截子进程的系统调用,判断此系统调用是不是 ptrace
,并且参数是 PTRACE_TRACEME
4、拦截到指定系统调用后,修改调用参数,让 ptrace(PTRACE_TRACEME);
执行失败。
// 拦截 zygote 进程的 fork
if (ptrace(PTRACE_SETOPTIONS, pid, (void *)1, (void *)(PTRACE_O_TRACEFORK))) {
printf("FATAL ERROR: ptrace(PTRACE_SETOPTIONS, ...)");
return -1;
}
ptrace(PTRACE_CONT, pid, (void *)1, 0);
int t;
int stat;
int child_pid = 0;
for (;;) {
t = waitpid(-1, &stat, __WALL | WUNTRACED);
// 判断当前 fork 程序是不是我们指定的应用
if (t != 0 && t == child_pid) {
if (debug > 1)
printf(".");
char fname[256];
sprintf(fname, "/proc/%d/cmdline", child_pid);
int fp = open(fname, O_RDONLY);
if (fp < 0) {
ptrace(PTRACE_SYSCALL, child_pid, 0, 0);
continue;
}
read(fp, fname, sizeof(fname));
close(fp);
if (strcmp(fname, appname) == 0) {
if (debug)
printf("zygote -> %s\n", fname);
// detach from zygote
ptrace(PTRACE_DETACH, pid, 0, (void *)SIGCONT);
// now perform on new process
pid = child_pid;
break;
} else {
ptrace(PTRACE_SYSCALL, child_pid, 0, 0);
continue;
}
}
if (zygote) {
// 获取到指定进程pid后,拦截它的system_call
ptrace(PTRACE_SYSCALL, pid, 0, 0);
while (1) {
waitpid(pid, NULL, 0);
//系统调用前修改调用参数
hookSysCallBefore(pid);
ptrace(PTRACE_SYSCALL, pid, 0, 0);
waitpid(pid, NULL, 0);
// 修改系统调用结果
hookSysCallAfter(pid);
ptrace(PTRACE_SYSCALL, pid, 0, 0);
}
}
void hookSysCallBefore(pid_t pid) {
struct pt_regs regs;
int sysCallNo = 0;
ptrace(PTRACE_GETREGS, pid, NULL, ®s);
sysCallNo = getSysCallNo(pid, ®s);
if (sysCallNo == __NR_ptrace) {
regs.ARM_r0 = 0; // 伪造一个成功的返回值
ptrace(PTRACE_SETREGS, pid, NULL, regs);
printf("__NR_ptrace: %d\n", regs.ARM_r0);
}
}
void hookSysCallAfter(pid_t pid) {
struct pt_regs regs;
int sysCallNo = 0;
ptrace(PTRACE_GETREGS, pid, NULL, ®s);
sysCallNo = getSysCallNo(pid, ®s);
if (sysCallNo == __NR_ptrace) {
regs.ARM_r0 = PTRACE_PEEKTEXT;
ptrace(PTRACE_SETREGS, pid, NULL, regs);
printf("__NR_ptrace: %ld\n", regs.ARM_r0);
}
}
最后效果如下,可以看到 TracerPid = 0 了
参考:https://bbs.pediy.com/thread-212404.htm
阿里云助力开发者!2核2G 3M带宽不限流量!6.18限时价,开
发者可享99元/年,续费同价!