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