├── README.md └── sigaction.js /README.md: -------------------------------------------------------------------------------- 1 | # Frida-Sigaction-Seccomp 2 | Frida-Sigaction-Seccomp实现对Android APP系统调用的拦截 3 | 4 | ## 思路和代码来源 5 | > 6 | [[原创]基于seccomp+sigaction的Android通用svc hook方案 ](https://bbs.kanxue.com/thread-277544.htm) 7 | 8 | [[原创]SVC的TraceHook沙箱的实现&无痕Hook实现思路 ](https://bbs.kanxue.com/thread-273160.htm) 9 | 10 | [[原创]分享一个Android通用svc跟踪以及hook方案——Frida-Seccomp ](https://bbs.kanxue.com/thread-271815.htm) 11 | 12 | ## 原文 13 | * 看雪文章 14 | https://bbs.kanxue.com/thread-280343.htm 15 | 16 | * 个人博客 17 | https://blog.lleavesg.top/article/Android-Seccomp#c40e15ab4db1407f9e9e0a111631150a 18 | 19 | ## 使用说明 20 | 21 | 直接将js注入即可实现对openat的监控,需要在logcat过滤native查看结果 22 | 23 | 在实战时根据自己需求修改CModule中的`define`,其中`target_nr` 是目标系统调用号。 24 | 25 | 在拦截到系统调用后会再次进行系统调用,防止再次被拦截,就需要一个寄存器来放一个标识符`SECMAGIC` ,避免反复调用`crash`。`SECMAGIC_POS` 即为对应系统调用所不需要的第一个寄存器,比如`openat`需要三个参数,那么`SECMAGIC_POS` 填3即可,因为寄存器从`x0`开始,`args[3]`即为第四个寄存器。 26 | 27 | 然后就是在`sig_handler` 中写劫持逻辑。如果想拦截更多的系统调用,就需要重写`seccomp filter` 。 28 | 29 | 除此之外调用栈等信息,可以参考[[原创]分享一个Android通用svc跟踪以及hook方案——Frida-Seccomp ](https://bbs.kanxue.com/thread-271815.htm) 阿碧大佬的思路自己添加。 30 | ![image](https://github.com/LLeavesG/Frida-Sigaction-Seccomp/assets/57952228/77922b59-5a1a-480d-a20a-496d5589f3a8) 31 | 32 | 33 | 同理也可以实现对mincore的拦截 34 | ![image](https://github.com/LLeavesG/Frida-Sigaction-Seccomp/assets/57952228/bdeb84b3-124f-49aa-a3f1-4269178d434f) 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /sigaction.js: -------------------------------------------------------------------------------- 1 | let install_signalhandle = null; 2 | 3 | const prctl_ptr = Module.findExportByName(null, 'prctl') 4 | const sigfillset_ptr = Module.findExportByName(null, 'sigfillset') 5 | const sigaction_ptr = Module.findExportByName(null, 'sigaction') 6 | const __android_log_print_ptr = Module.findExportByName(null, '__android_log_print') 7 | const syscall_ptr = Module.findExportByName(null, 'syscall') 8 | const android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext"); 9 | 10 | function init(){ 11 | install_signalhandle = new NativeFunction(cm.install_signalhandle, "void", []) 12 | install_signalhandle(); 13 | } 14 | 15 | function hook_dlopen(){ 16 | var path = null; 17 | Interceptor.attach(android_dlopen_ext, { 18 | onEnter: function(args) { 19 | if (install_signalhandle == null) { 20 | init() 21 | } 22 | },onLeave(ret){ 23 | 24 | } 25 | }); 26 | } 27 | 28 | // CModule模块编写 29 | const cm = new CModule(` 30 | #include 31 | #include 32 | 33 | // define the target_nr 34 | #define target_nr 56 35 | 36 | // syscall again with args[SECMAGIC_POS] SEC_MAGIC avoid infinite loop 37 | #define SECMAGIC 0xdeadbeef 38 | #define SECMAGIC_POS 3 39 | 40 | // test syscall no 41 | #define __NR_openat 56 42 | #define __NR_mincore 232 43 | 44 | #define BPF_STMT(code,k) { (unsigned short) (code), 0, 0, k } 45 | #define BPF_JUMP(code,k,jt,jf) { (unsigned short) (code), jt, jf, k } 46 | #define BPF_LD 0x00 47 | #define BPF_W 0x00 48 | #define BPF_ABS 0x20 49 | #define BPF_JEQ 0x10 50 | #define BPF_JMP 0x05 51 | #define BPF_K 0x00 52 | #define BPF_RET 0x06 53 | 54 | #define PR_SET_SECCOMP 22 55 | #define PR_SET_NO_NEW_PRIVS 38 56 | #define SECCOMP_MODE_FILTER 2 57 | #define SECCOMP_RET_TRAP 0x00030000U 58 | #define SECCOMP_RET_ALLOW 0x7fff0000U 59 | 60 | #define SIGSYS 31 61 | #define SIG_UNBLOCK 2 62 | #define __user 63 | #define SI_MAX_SIZE 128 64 | #define SA_SIGINFO 0x00000004 65 | 66 | typedef unsigned char __u8; 67 | typedef unsigned short __u16; 68 | typedef unsigned int __u32; 69 | typedef unsigned long long __u64; 70 | typedef unsigned long sigset_t; 71 | typedef sigset_t sigset64_t; 72 | typedef unsigned long __kernel_size_t; 73 | 74 | extern int __android_log_print(int prio, const char* tag, const char* fmt, ...); 75 | extern void *malloc(size_t __byte_count); 76 | extern long syscall(long __number, ...); 77 | extern void on_message(const gchar *message); 78 | extern int prctl(int __option, ...); 79 | extern int sigfillset(sigset_t* __set); 80 | extern int sigaction(int __signal, const struct sigaction* __new_action, struct sigaction* __old_action); 81 | int install_filter(); 82 | #define log(...) __android_log_print(3, "native", __VA_ARGS__) 83 | 84 | // seccomp filter 85 | struct seccomp_data { 86 | int nr; 87 | __u32 arch; 88 | __u64 instruction_pointer; 89 | __u64 args[6]; 90 | }; 91 | 92 | struct sock_filter { 93 | __u16 code; 94 | __u8 jt; 95 | __u8 jf; 96 | __u32 k; 97 | }; 98 | 99 | struct sock_fprog { 100 | unsigned short len; 101 | struct sock_filter * filter; 102 | }; 103 | 104 | // sigaction 105 | union __sifields { 106 | struct { 107 | void __user * _call_addr; 108 | int _syscall; 109 | unsigned int _arch; 110 | } _sigsys; 111 | }; 112 | 113 | #define __SIGINFO struct { int si_signo; int si_errno; int si_code; union __sifields _sifields; } 114 | 115 | typedef struct siginfo { 116 | union { 117 | __SIGINFO; 118 | int _si_pad[SI_MAX_SIZE / sizeof(int)]; 119 | }; 120 | } siginfo_t; 121 | 122 | typedef void (*sighandler_t)(int); 123 | 124 | struct sigaction { 125 | int sa_flags; 126 | union { 127 | sighandler_t sa_handler; 128 | void (*sa_sigaction)(int, struct siginfo*, void*); 129 | }; 130 | sigset_t sa_mask; 131 | void (*sa_restorer)(void); 132 | }; 133 | 134 | typedef struct sigaltstack { 135 | void * ss_sp; 136 | int ss_flags; 137 | __kernel_size_t ss_size; 138 | } stack_t; 139 | 140 | 141 | struct sigcontext { 142 | __u64 fault_address; 143 | __u64 regs[31]; 144 | __u64 sp; 145 | __u64 pc; 146 | __u64 pstate; 147 | __u8 __reserved[4096] __attribute__((__aligned__(16))); 148 | }; 149 | 150 | typedef struct sigcontext mcontext_t; 151 | 152 | typedef struct ucontext { 153 | unsigned long uc_flags; 154 | struct ucontext *uc_link; 155 | stack_t uc_stack; 156 | union { 157 | sigset_t uc_sigmask; 158 | sigset64_t uc_sigmask64; 159 | }; 160 | /* The kernel adds extra padding after uc_sigmask to match glibc sigset_t on ARM64. */ 161 | char __padding[128 - sizeof(sigset_t)]; 162 | mcontext_t uc_mcontext; 163 | } ucontext_t; 164 | 165 | 166 | 167 | void sig_handler(int signo, siginfo_t *info, void *data) { 168 | int my_signo = info->si_signo; 169 | // log("my_signo: %d", my_signo); 170 | unsigned long sysno = ((ucontext_t *) data)->uc_mcontext.regs[8]; 171 | unsigned long arg0 = ((ucontext_t *) data)->uc_mcontext.regs[0]; 172 | unsigned long arg1 = ((ucontext_t *) data)->uc_mcontext.regs[1]; 173 | unsigned long arg2 = ((ucontext_t *) data)->uc_mcontext.regs[2]; 174 | 175 | int fd, mincore_ret; 176 | 177 | switch (sysno) { 178 | log("sysno: %d", sysno); 179 | case __NR_openat: 180 | // syscall with args[3] SEC_MAGIC avoid infinite loop 181 | fd = syscall(__NR_openat, arg0, arg1, arg2, SECMAGIC); 182 | log("[Openat 56] filename: %s", (char *) arg1); 183 | ((ucontext_t *) data)->uc_mcontext.regs[0] = fd; 184 | log("[Openat 56] ret fd: %d", fd); 185 | break; 186 | case __NR_mincore: 187 | mincore_ret = syscall(__NR_mincore, arg0, arg1, arg2, SECMAGIC); 188 | log("[mincore 232] args: %lx %d %lx", arg0, arg1, arg2); 189 | log("[mincore 232] orig args[2] : %lld", *(char *)arg2); 190 | *((int *)arg2 + 0) = 0x0; 191 | ((ucontext_t *) data)->uc_mcontext.regs[0] = mincore_ret; 192 | log("[mincore 232] changed args[2] : %d", *(int *)arg2); 193 | break; 194 | default: 195 | break; 196 | } 197 | } 198 | 199 | void install_signalhandle(){ 200 | struct sigaction sa; 201 | sigset_t sigset; 202 | 203 | sigfillset(&sigset); 204 | 205 | sa.sa_sigaction = sig_handler; 206 | sa.sa_mask = sigset; 207 | sa.sa_flags = SA_SIGINFO; 208 | install_filter(); 209 | if (sigaction(SIGSYS, &sa, NULL) == -1) { 210 | log("sigaction init failed.\n"); 211 | return ; 212 | } 213 | 214 | log("sigaction init success.\n"); 215 | } 216 | 217 | int install_filter() { 218 | struct sock_filter filter[] = { 219 | BPF_STMT(BPF_LD | BPF_W | BPF_ABS, 0), 220 | BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, target_nr, 0, 2), 221 | BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[SECMAGIC_POS])), 222 | BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SECMAGIC, 0, 1), 223 | BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), 224 | BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRAP) 225 | }; 226 | struct sock_fprog prog = { 227 | .len = (unsigned short) (sizeof(filter) / sizeof(filter[0])), 228 | .filter = filter, 229 | }; 230 | if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 231 | on_message("prctl(NO_NEW_PRIVS)"); 232 | return 1; 233 | } 234 | if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { 235 | on_message("prctl(PR_SET_SECCOMP)"); 236 | return 1; 237 | } 238 | return 0; 239 | } 240 | 241 | `, { 242 | prctl: prctl_ptr, 243 | __android_log_print: __android_log_print_ptr, 244 | syscall: syscall_ptr, 245 | sigfillset: sigfillset_ptr, 246 | sigaction: sigaction_ptr, 247 | on_message: new NativeCallback(messagePtr => { 248 | const message = messagePtr.readUtf8String(); 249 | console.log(message) 250 | }, 'void', ['pointer']) 251 | }); 252 | 253 | setImmediate(hook_dlopen) 254 | --------------------------------------------------------------------------------