SVC的TraceHook沙箱的实现 无痕Hook实现思路

来源:岁月联盟 编辑:猪蛋儿 时间:2022-07-04

前言

二年前因为工作需要,自己尝试开发过一套沙盒,普通的Linux IO 函数可以通过Hook Libc 去实现,比如Hook openat 等。大部分文件都可以进行处理(比如VA的IO处理)。但是一直有个心病困扰我半年之久,就是如何处理系统调用/内联SVC指令的拦截和处理。

大厂基本为了程序的安全,会使用大量内联SVC去调用系统函数,以此来保护程序的安全。以防被Hook。

如何实现SVC指令的IO重定向,成为最大的问题。尝试在国内查找这块资料,发现基本很少,大部分都是介绍基础而不是去讲如何进行Hook和修改,还有的就是通过刷机改源码的方式,但是大部分大厂都是有自己的真机库,基本谷歌系列,很容易就被认定为危险设备。

如果通过修改型号等方式去mock成国内的型号也可以,但是这种方式有弊端,如果有的App调用三方服务,比如小米会自带一些系统服务,这些是没办法进行mock的。很容导致app崩溃 。

通过不断去Google去查阅大量文章,问了很多老外,看代码后来发现一套比较成熟的方案就是ptrace+seccomp,两者缺一不可。

前奏知识

什么是SVC指令?什么是Syscall?根据我个人的理解,在Linux里面内存主要分为Linux用户态,内核态。

当用户自定义运行的函数在用户态。内核态是当Linux需要处理文件,或者进行中断IO等操作的时候就会进入内核态。

syscall 就是这个内核态的入口。而syscall函数里面的实现就是一段汇编(具体实现参考如下),汇编里面便是调用了svc的这条指令。

当arm系列cpu发现svc指令的时候,就会陷入中断,简称0x80中断。开始执行内核态逻辑,这个时候程序会进入暂停状态。

优先去执行内核的逻辑。以此保证程序的安全性。(当我们自己去设计系统的时候,肯定也不希望在系统执行的时候被程序去干扰,导致系统崩溃)

Linux内核本身提供很多函数,比如常见的文件函数,openat,execve都是Linux内核提供的。这些函数都可以通过svc指令的方式去调用,只是实现的sysnum不一样。传入的参数不一样而已。

通过svc执行的函数无法进行inlinehook Hook ,所以会提升程序的安全度。

总结:

svc是一条arm指令,Syscall函数是libc函数,实现底层使用了svc指令。

syscall 32&64位具体实现如下。

32位:

raw_syscall:        MOV             R12, SP        STMFD           SP!, {R4-R7}        MOV             R7, R0        MOV             R0, R1        MOV             R1, R2        MOV             R2, R3        LDMIA           R12, {R3-R6}        SVC             0        LDMFD           SP!, {R4-R7}        mov             pc, lr

64位:

raw_syscall:        MOV             X8, X0        MOV             X0, X1        MOV             X1, X2        MOV             X2, X3        MOV             X3, X4        MOV             X4, X5        MOV             X5, X6        SVC             0        RET

什么是Ptrace&Seccomp ?

Ptrace:

ptrace是linux 提供的调试函数,很多好用的工具,IDA ,LLDB等调试器都是通过ptrace去实现的。

这个函数里面有很多action 每个action都包含一个功能,比如注入进程,暂停,修改寄存器等常用功能。

ptrace当注入当前进程的时候是不需要root。如果注入非自己的进程是需要root才可以。调用注入的时候选择一个pid即可。

ptrace可以在任何内存地方下断点,修改对应位置的数据。ptrace的权限非常高。ptrace还可以调试内核态。所以也可以用来处理svc的参数和返回值。

ptrace具体API说明官方文档如下:

https://man7.org/linux/man-pages/man2/ptrace.2.html

Seccomp:

Seccomp是Linux的一种安全机制,android 8.1以上使用了Seccomp。

主要功能是限制接通过syscall去调用某些系统函数,当开启了Seccomp的进程在此调用的时候会变走异常的回调。

之前B佬的文章里面便采用了frida+seccomp的方式去做的svc拦截。也是很好的思路,帖子地址如下。

https://bbs.pediy.com/thread-271815.htm

Seccomp的过滤模式有两种(strict&filter)。

strict

strict模式如果开启以后,只支持四个函数的系统调用。(read,write,exit,rt_sigreturn)

如果一旦使用了其他的syscall 则会收到SIGKILL信号。

#include #include #include #include #include #include  int main(int argc, char **argv){int output = open(“output.txt”, O_WRONLY);const char *val = “test”;//通过prctl函数设置seccomp的模式为strictprintf(“Calling prctl() to set seccomp strict mode…”); prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT); printf(“Writing to an already open file…”);//尝试写入write(output, val, strlen(val)+1);printf(“Trying to open file for reading…”); //设置完毕seccomp以后再次尝试open (因为设置了secomp的模式是strict,所以这行代码直接sign -9 信号)int input = open(“output.txt”, O_RDONLY);printf(“You will not see this message