项目地址: https://github.com/chroblert/JC-AntiPtrace
环境:kali2020,ndkr17c,arm64,pixel2,android8.1
一、适用场景
描述:zygote通过fork()系统调用,fork出一个app
app内通过ptrace(PTRACE_TRACEME,0,0,0);将父进程zygote做为自己的tracer
这样其他进程就无法ptrace()到app进程了
二、创建反调试app Demodemo版app放在GitHub中,app-debug.apk
app运行后查看/proc//status中的TracerPid
使用frida进行调试,可以看到显示报错如下:
注:对于这种很简单的反调试,frida可以用-f进行绕过。
三、绕过ptrace反调试
(一)、思路(这里主要来自看雪论坛https://bbs.pediy.com/thread-260731.htm)使用ptrace附加zygote进程
拦截zygote的fork调用,在fork子进程时候获取当前进程名称,判断是不是我们想要的那个应用,若是则保存子进程pid
获取到子进程pid后,再拦截子进程的系统调用,判断此系统调用是不是ptrace,并且参数是PTRACE_TRACEME
拦截到指定系统调用后,修改调用参数,让ptrace(PTRACE_TRACEME);执行失败
(二)、差异:
由于ptrace对底层架构的依赖很高,同一份代码不适用于所有架构的手机,因而原作者给出的代码不适用于我的需求,我这里的是android 8.1,pixel2,arm64。有些代码需要做一些变换,如下:ARM32 (AARCH32)ARM64 (AARCH64)
PTRACE_GETREGSPTRACE_GETREGSET
pidpid
NULLNT_PRSTATUS
struct pt_regs *{ struct user_pt_regs *ubf, size_t len }
GETREGSNT_PRSTATUS
PTRACE_SETREGSPTRACE_SETREGSET有些结构体在arm64中的头文件中的声明不一样,也需要重新define,如下:#define pt_regs user_pt_regs
#define uregs regs
#define ARM_r0 regs[0]
#define ARM_r7 regs[7]
#define ARM_1r regs[30]
#define ARM_sp sp
#define ARM_pc pc
#define ARM_cpsr pstate
#define NT_PRSTATUS 1
#define NT_foo 1关于传参和返回值用的寄存器也有些差异,如下:archsyscall NRreturnarg0arg1arg2arg3arg4arg5
armr7r0r0r1r2r3r4r5
arm64x8x0x0x1x2x3x4x5
x86eaxeaxebxecxedxesiediebp
x86_64raxraxrdirsirdxr10r8r9
(三)、实现
代码在GitHub仓库中:[https://github.com/chroblert/JC-AntiPtrace](https://github.com/chroblert/JC-AntiPtrace)
(四)、使用查看zygote64的pid
我这里的手机是arm64的,所有用zygote64的pid4979
执行编译后的JC-AntiPtrace-v1-arm64-1214.o程序./JC-AntiPtrace-v1-arm64-1214.o -p 4979 -t com.zer0ne_sec.ptrace.jnitest -n 117 -r1 -e
执行frida附加
效果如下:
成功拦截并修改ptrace()系统调用的结果,frida成功hook
(五)、使用说明JC-AntiPtrace-v1-arm64.o [-v] -p -t [-n ] [-r [-e]]
options:
-v : verbose
-p : pid of zygote or zygote64
-t : application name of to hook
-n : syscalll number to hook(十进制)
117:ptrace
220:clone
260:wait
-r : update return value of the syscallno
-h : show helper
-e : detach when updated return value
(1)、用于监控系统调用JC-AntiPtrace-v1-arm64.o [-v] -p -t [-n ]
-v: 表示显示详细输出,包含有每个系统调用的参数值与返回值
-p: 表示zygote进程的pid
-t: 要监控的app的名称
-n:表示监控某一个特定的系统调用
(2)、用于绕过ptrace反调试JC-AntiPtrace-v1-arm64.o [-v] -p -t [-n 117] [-r0 [-e]]
-v: 表示显示详细输出,包含有每个系统调用的参数值与返回值
-p: 表示zygote进程的pid
-t: 要监控的app的名称
-n:表示监控某一个特定的系统调用
-r: 表示要修改返回值为某个值。-r后面紧跟数值
-e: 表示修改返回值后就detach
四、总结
本篇文章及代码只是对简单ptrace反调试的一种绕过,仅供研究。之后会继续研究其他ptrace反调试的场景,
参考资料:[使用ptrace过ptrace反调试](https://bbs.pediy.com/thread-260731.htm)
参考资料:[一种绕过ptrace反调试的方法]()
参考资料:[ptrace.h](https://sites.uclouvain.be/SystInfo/usr/include/sys/ptrace.h.html)
参考资料:[在Android操作系统中设置永久环境变量]()
参考资料:[Shared Library Injection on Android 8.0](https://fadeevab.com/shared-library-injection-on-android-8/)
参考资料:[NT_PRSTATUS](https://www.man7.org/linux/man-pages/man2/ptrace.2.html)
参考资料:[arm64 vs arm32](https://undo.io/resources/arm64-vs-arm32-whats-different-linux-programmers/)
参考资料:[linux沙箱之ptrace](https://blog.betamao.me/2019/02/02/Linux%E6%B2%99%E7%AE%B1%E4%B9%8Bptrace/)
参考资料:[arm64: ptrace: reload a syscall number after ptrace operations](https://patchwork.kernel.org/project/linux-arm-kernel/patch/1406020499-5537-2-git-send-email-takahiro.akashi@linaro.org/)
参考资料:[ptrace change syscall number arm64](https://stackoverflow.com/questions/63620203/ptrace-change-syscall-number-arm64)
参考资料:[linux system call table](https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md)