diff --git a/loader/src/injector/clear.c b/loader/src/injector/clear.c new file mode 100644 index 0000000..fde5fa4 --- /dev/null +++ b/loader/src/injector/clear.c @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "logging.h" + +static bool seccomp_filters_visible() { + FILE *status_file = fopen("/proc/self/status", "r"); + if (!status_file) { + return true; + } + + const char *needle = "Seccomp_filters:"; + char line[256]; + + while (fgets(line, sizeof(line), status_file)) { + if (strncmp(line, needle, strlen(needle)) == 0) { + fclose(status_file); + return true; + } + } + + fclose(status_file); + return false; +} + +void send_seccomp_event() { + if (seccomp_filters_visible()) { + return; + } + + __u32 args[4] = {0}; + + int rnd_fd = open("/dev/urandom", O_RDONLY); + if (rnd_fd == -1) { + PLOGE("send_seccomp_event: open(/dev/urandom)"); + return; + } + + if (read(rnd_fd, &args, sizeof(args)) != sizeof(args)) { + PLOGE("send_seccomp_event: read(rnd_fd)"); + close(rnd_fd); + return; + } + + close(rnd_fd); + + args[0] |= 0x10000; + + struct sock_filter filter[] = { + /* INFO: Check syscall number */ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, nr)), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_exit_group, 0, 9), + + /* INFO: Load and check arg0 (lower 32 bits) */ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, args[0], 0, 7), + + /* INFO: Load and check arg1 (lower 32 bits) */ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[1])), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, args[1], 0, 5), + + /* INFO: Load and check arg2 (lower 32 bits) */ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[2])), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, args[2], 0, 3), + + /* INFO: Load and check arg3 (lower 32 bits) */ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[3])), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, args[3], 0, 1), + + /* INFO: All match: return TRACE => will trigger PTRACE_EVENT_SECCOMP */ + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRACE), + + /* INFO: Default: allow */ + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + }; + + struct sock_fprog prog = { + .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])), + .filter = filter, + }; + + if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { + PLOGE("send_seccomp_event: prctl(SECCOMP)"); + return; + } + + /* INFO: This will trigger a ptrace event, syscall will not execute due to tracee_skip_syscall */ + syscall(__NR_exit_group, args[0], args[1], args[2], args[3]); +} diff --git a/loader/src/injector/entry.cpp b/loader/src/injector/entry.cpp index c2e008e..295db9f 100644 --- a/loader/src/injector/entry.cpp +++ b/loader/src/injector/entry.cpp @@ -25,4 +25,5 @@ void entry(void* addr, size_t size, const char* path) { void *module_addrs[1] = { addr }; clean_trace(path, module_addrs, 1, 1, 0, false); + send_seccomp_event(); } diff --git a/loader/src/injector/zygisk.hpp b/loader/src/injector/zygisk.hpp index 8051de6..4b82768 100644 --- a/loader/src/injector/zygisk.hpp +++ b/loader/src/injector/zygisk.hpp @@ -8,3 +8,5 @@ extern size_t block_size; void hook_functions(); void clean_trace(const char *path, void **module_addrs, size_t module_addrs_length, size_t load, size_t unload, bool spoof_maps); + +extern "C" void send_seccomp_event(); diff --git a/loader/src/ptracer/ptracer.c b/loader/src/ptracer/ptracer.c index 71d6c63..03dd1d9 100644 --- a/loader/src/ptracer/ptracer.c +++ b/loader/src/ptracer/ptracer.c @@ -403,7 +403,7 @@ bool trace_zygote(int pid) { int status; - if (ptrace(PTRACE_SEIZE, pid, 0, PTRACE_O_EXITKILL) == -1) { + if (ptrace(PTRACE_SEIZE, pid, 0, PTRACE_O_EXITKILL | PTRACE_O_TRACESECCOMP) == -1) { PLOGE("seize"); return false; diff --git a/loader/src/ptracer/utils.c b/loader/src/ptracer/utils.c index 76aae16..dc56f6e 100644 --- a/loader/src/ptracer/utils.c +++ b/loader/src/ptracer/utils.c @@ -522,6 +522,32 @@ int fork_dont_care() { return pid; } +void tracee_skip_syscall(int pid) { + struct user_regs_struct regs; + if (!get_regs(pid, ®s)) { + LOGE("failed to get seccomp regs"); + exit(1); + } + regs.REG_SYSNR = -1; + if (!set_regs(pid, ®s)) { + LOGE("failed to set seccomp regs"); + exit(1); + } + + /* INFO: It might not work, don't check for error */ +#if defined(__aarch64__) + int sysnr = -1; + struct iovec iov = { + .iov_base = &sysnr, + .iov_len = sizeof (int), + }; + ptrace(PTRACE_SETREGSET, pid, NT_ARM_SYSTEM_CALL, &iov); +#elif defined(__arm__) + ptrace(PTRACE_SET_SYSCALL, pid, 0, (void*) -1); +#endif + +} + void wait_for_trace(int pid, int *status, int flags) { while (1) { pid_t result = waitpid(pid, status, flags); @@ -532,7 +558,13 @@ void wait_for_trace(int pid, int *status, int flags) { exit(1); } - if (!WIFSTOPPED(*status)) { + if (*status >> 8 == (SIGTRAP | (PTRACE_EVENT_SECCOMP << 8))) { + tracee_skip_syscall(pid); + + ptrace(PTRACE_CONT, pid, 0, 0); + + continue; + } else if (!WIFSTOPPED(*status)) { char status_str[64]; parse_status(*status, status_str, sizeof(status_str)); diff --git a/loader/src/ptracer/utils.h b/loader/src/ptracer/utils.h index 4d469ac..4a80e40 100644 --- a/loader/src/ptracer/utils.h +++ b/loader/src/ptracer/utils.h @@ -37,18 +37,22 @@ void free_maps(struct maps *maps); #define REG_SP rsp #define REG_IP rip #define REG_RET rax + #define REG_SYSNR orig_rax #elif defined(__i386__) #define REG_SP esp #define REG_IP eip #define REG_RET eax + #define REG_SYSNR orig_eax #elif defined(__aarch64__) #define REG_SP sp #define REG_IP pc #define REG_RET regs[0] + #define REG_SYSNR regs[8] #elif defined(__arm__) #define REG_SP uregs[13] #define REG_IP uregs[15] #define REG_RET uregs[0] + #define REG_SYSNR uregs[7] #define user_regs_struct user_regs #endif