[原创]bypass svc 0 PTRACE_TRACEME
最近在研究一个crackme,已经获取到了check的地址,本想IDA附加单步分析,不过它在壳代码里面调用了PTRACE_TRACEME,首先想到的是hook ptrace,过滤掉PTRACE_TRACEME,不过ptrace似乎从来没有调用过,所以判定有可能是svc的方式调用了PTRACE_TRACEME。尝试过IDA单步壳代码,不过花指令太多,始终跟不到目标位置。最后通过ptrace解决:(好吧,对付ptrace还得靠它自己)
首先必须在壳代码运行之前attach,我的方法是注入zygote,然后用PTRACE_O_TRACEFORK,在zygote fork的时候,会自动attach到子进程,然后用PTRACE_GETEVENTMSG获取子进程pid ,最后detach zygote。参考了adbi的hijack里面的代码。
for (;;) {
ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
waitpid(pid, NULL, 0);
ptrace(PTRACE_GETREGS, pid, NULL, ®s);
if (regs.ARM_ip != 0) { // 此时syscall还处于syscall-exit-stop,再执行一次syscall到syscall-enter-stop
ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
waitpid(pid, NULL, 0);
ptrace(PTRACE_GETREGS, pid, NULL, ®s);
}
if (regs.ARM_r0 == PTRACE_TRACEME && regs.ARM_r7 == __NR_ptrace) { // PTRACE_TRACEME
// 把request改为PTRACE_PEEKTEXT,原因是就算PTRACE_PEEKTEXT失败,也没有任何影响
// 改为其他request应该也可以,或者直接改调用号
regs.ARM_r0 = PTRACE_PEEKTEXT;
ptrace(PTRACE_SETREGS, pid, NULL, ®s);
ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
waitpid(pid, NULL, 0);
ptrace(PTRACE_GETREGS, pid, NULL, ®s);
regs.ARM_r0 = 0; // 伪造一个成功的返回值
ptrace(PTRACE_SETREGS, pid, NULL, ®s);
break;
}
ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
waitpid(pid, NULL, 0);
}最后detach,这时查看status,TracerPid的值已经为0了。
crackme.apk
