├── kern ├── kern.h ├── Makefile ├── kern_hook.h ├── kern_func.h ├── kern_hook.c ├── kern_func.c ├── kern_offset.h ├── kern_offset.c └── xnuspy_ctl.h ├── .gitignore ├── utils ├── Makefile ├── vnode_func.h ├── helpers.h ├── vnode_func.c └── helpers.c ├── filter ├── Makefile ├── filters.h ├── caller_filter.c ├── path_filter.c └── filters.c ├── hooks ├── Makefile ├── hooks.h ├── stat_hook.h ├── ptrace_hook.h ├── getdirentries_hook.h ├── stat_hook.c ├── hooks.c ├── ptrace_hook.c ├── open1_hook.h ├── open1_hook.c └── getdirentries_hook.c ├── README.md ├── include └── darwin_hdrs.h ├── ent.xml ├── xnu_bypass.c └── Makefile /kern/kern.h: -------------------------------------------------------------------------------- 1 | extern long SYS_xnuspy_ctl; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .vscode 3 | /xnu_bypass -------------------------------------------------------------------------------- /kern/Makefile: -------------------------------------------------------------------------------- 1 | objects = *.c 2 | 3 | all : $(objects) 4 | $(CC) $(CFLAGS) $^ -c -------------------------------------------------------------------------------- /utils/Makefile: -------------------------------------------------------------------------------- 1 | objects = *.c 2 | 3 | all : $(objects) 4 | $(CC) $(CFLAGS) $^ -c -------------------------------------------------------------------------------- /filter/Makefile: -------------------------------------------------------------------------------- 1 | objects = *.c 2 | 3 | CFLAGS += -nostdlib 4 | 5 | all : $(objects) 6 | $(CC) $(CFLAGS) $^ -c -------------------------------------------------------------------------------- /hooks/Makefile: -------------------------------------------------------------------------------- 1 | objects = *.c 2 | 3 | CFLAGS += -nostdlib 4 | 5 | all : $(objects) 6 | $(CC) $(CFLAGS) $^ -c -------------------------------------------------------------------------------- /kern/kern_hook.h: -------------------------------------------------------------------------------- 1 | extern int init_xnuspy(); 2 | extern int install_hook(void *target, void *replace, void **orig); -------------------------------------------------------------------------------- /utils/vnode_func.h: -------------------------------------------------------------------------------- 1 | extern void *vnode_getfromfd(int fd); 2 | extern void *vnode_getfromfd_ctx(int fd, void *ctx); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XNUBypass 2 | 3 | Bypass jailbreak detection using xnuspy. 4 | 5 | ## Note 6 | 7 | Address are hardcoded for iPhone 8 Plus / iOS 13.5 8 | -------------------------------------------------------------------------------- /utils/helpers.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern char *log_get_caller(const char *fn, const char *param, int dolog); 4 | extern void *try_read_str(void *addr, size_t maxLen); -------------------------------------------------------------------------------- /hooks/hooks.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "open1_hook.h" 4 | #include "stat_hook.h" 5 | #include "getdirentries_hook.h" 6 | #include "ptrace_hook.h" 7 | 8 | extern int install_all_hooks(); -------------------------------------------------------------------------------- /hooks/stat_hook.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct stat_args { 4 | char *path; 5 | void *ub; 6 | }; 7 | 8 | extern int (*stat_orig)(void *p, struct stat_args *uap, int32_t *retval); 9 | 10 | extern int stat_(void *p, struct stat_args *uap, int32_t *retval); -------------------------------------------------------------------------------- /include/darwin_hdrs.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | -------------------------------------------------------------------------------- /hooks/ptrace_hook.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct ptrace_args { 4 | uint64_t req; 5 | pid_t pid; 6 | void *addr; 7 | uint8_t data; 8 | }; 9 | 10 | extern int (*ptrace_orig)(void *p, struct ptrace_args *uap, int32_t *retval); 11 | 12 | extern int ptrace_(void *p, struct ptrace_args *uap, int32_t *retval); -------------------------------------------------------------------------------- /kern/kern_func.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "kern_offset.h" 3 | 4 | #define xprintf(f_, ...) kprintf(("xnuspy: %s: " f_), __func__, __VA_ARGS__) 5 | 6 | extern uint8_t curcpu(void); 7 | extern pid_t caller_pid(void); 8 | 9 | extern int init_kern_func(); 10 | 11 | void *vfs_context_proc(void *ctx); -------------------------------------------------------------------------------- /hooks/getdirentries_hook.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern int (*getdirentries_common_orig)(int fd, void *bufp, size_t bufsize, ssize_t *bytesread, 4 | off_t *offset, int *eofflag, int flags); 5 | 6 | extern int getdirentries_common(int fd, void *bufp, size_t bufsize, ssize_t *bytesread, 7 | off_t *offset, int *eofflag, int flags); 8 | -------------------------------------------------------------------------------- /filter/filters.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define MAX_BLOCK_PATH 300 4 | #define MAX_PATH_LEN 256 5 | #define MAX_BLOCK_CALLER 100 6 | #define MAX_CALLER_LEN 50 7 | 8 | extern int check_caller(const char *p); 9 | extern int check_path(const char *p); 10 | 11 | extern void init_caller_filter(char *temp); 12 | extern void init_path_filter(char *temp); 13 | 14 | extern int init_filters(); -------------------------------------------------------------------------------- /filter/caller_filter.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "filters.h" 3 | 4 | char target_execs[MAX_BLOCK_CALLER][MAX_CALLER_LEN]; 5 | 6 | int check_caller(const char *p) { 7 | int arrsize = sizeof(target_execs) / sizeof(target_execs[0]); 8 | //xprintf("checking through %d paths\n", arrsize); 9 | for (int i = 0; i < arrsize; i++) { 10 | if (target_execs[i][0] == 0) { 11 | break; 12 | } 13 | //xprintf("checking %s vs %s\n", p, block_paths[i]); 14 | if (_strcmp(p, target_execs[i]) == 0) { 15 | return 1; 16 | } 17 | } 18 | return 0; 19 | } 20 | 21 | void init_caller_filter(char *temp) { 22 | memcpy(target_execs, temp, sizeof(target_execs)); 23 | } -------------------------------------------------------------------------------- /filter/path_filter.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "filters.h" 3 | 4 | char block_paths[MAX_BLOCK_PATH][MAX_PATH_LEN]; 5 | 6 | int check_path(const char *p) { 7 | int arrsize = sizeof(block_paths) / sizeof(block_paths[0]); 8 | //xprintf("checking through %d paths\n", arrsize); 9 | for (int i = 0; i < arrsize; i++) { 10 | if (block_paths[i][0] == 0) { 11 | break; 12 | } 13 | //xprintf("checking %s vs %s\n", p, block_paths[i]); 14 | if (_strncmp(p, block_paths[i], _strlen(block_paths[i])) == 0) { 15 | return 1; 16 | } 17 | 18 | } 19 | return 0; 20 | } 21 | 22 | void init_path_filter(char *temp) { 23 | memcpy(block_paths, temp, sizeof(block_paths)); 24 | } -------------------------------------------------------------------------------- /ent.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | com.apple.wifi_apsta.event_monitor 5 | 6 | com.apple.private.aets.user-access 7 | 8 | com.apple.developer.driverkit 9 | 10 | platform-application 11 | 12 | run-unsigned-code 13 | 14 | get-task-allow 15 | 16 | task_for_pid-allow 17 | 18 | com.apple.system-task-ports 19 | 20 | com.apple.private.security.container-required 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /xnu_bypass.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char **argv){ 7 | int ret; 8 | if ((ret = init_xnuspy())) { 9 | printf("init_xnuspy failed\n"); 10 | return 1; 11 | } 12 | printf("init_xnuspy success\n"); 13 | 14 | init_filters(); 15 | 16 | if((ret = init_kern_func())){ 17 | printf("init_kern_func failed: %s\n", strerror(errno)); 18 | return 1; 19 | } 20 | printf("init_kern_func success\n"); 21 | 22 | if((ret = install_all_hooks())){ 23 | printf("install_all_hooks failed\n"); 24 | return 1; 25 | } 26 | printf("install_all_hooks success\n"); 27 | 28 | for(;;){ 29 | sleep(1); 30 | } 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /kern/kern_hook.c: -------------------------------------------------------------------------------- 1 | #include "kern_func.h" 2 | #include "kern.h" 3 | #include "kern_hook.h" 4 | #include "xnuspy_ctl.h" 5 | 6 | long SYS_xnuspy_ctl = 0; 7 | 8 | int init_xnuspy() { 9 | size_t oldlen = sizeof(long); 10 | int ret = sysctlbyname("kern.xnuspy_ctl_callnum", &SYS_xnuspy_ctl, 11 | &oldlen, NULL, 0); 12 | 13 | if(ret == -1){ 14 | printf("sysctlbyname with kern.xnuspy_ctl_callnum failed: %s\n", 15 | strerror(errno)); 16 | return 1; 17 | } 18 | 19 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_CHECK_IF_PATCHED, 0, 0, 0); 20 | 21 | if(ret != 999){ 22 | printf("xnuspy_ctl isn't present?\n"); 23 | return 1; 24 | } 25 | 26 | return 0; 27 | } 28 | 29 | int install_hook(void *target, void *replace, void **orig) { 30 | return syscall(SYS_xnuspy_ctl, XNUSPY_INSTALL_HOOK, target, replace, orig); 31 | } -------------------------------------------------------------------------------- /hooks/stat_hook.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "stat_hook.h" 5 | 6 | /* bsd/sys/namei.h */ 7 | #define PATHBUFLEN 256 8 | 9 | int (*stat_orig)(void *p, struct stat_args *uap, int32_t *retval); 10 | 11 | int stat_(void *p, struct stat_args *uap, int32_t *retval) { 12 | char *path = NULL, *caller_name = NULL; 13 | 14 | if(!(path = try_read_str(uap->path, PATHBUFLEN))) 15 | goto orig; 16 | 17 | caller_name = log_get_caller("stat", path, 0); 18 | if(!caller_name) 19 | goto orig; 20 | 21 | if(check_caller(caller_name) && check_path(path)){ 22 | xprintf("denying stat for '%s'\n", path); 23 | unified_kfree(path); 24 | *retval = -1; 25 | return ENOENT; 26 | } 27 | 28 | orig: 29 | if(path) 30 | unified_kfree(path); 31 | if(caller_name) 32 | unified_kfree(caller_name); 33 | 34 | return stat_orig(p, uap, retval); 35 | } -------------------------------------------------------------------------------- /utils/vnode_func.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void *vnode_getfromfd(int fd) { 4 | int error = 0; 5 | void *vp, *fp; 6 | vp = fp = NULL; 7 | void *p = current_proc(); 8 | error = fp_getfvp(p, fd, &fp, &vp); 9 | if (error) { xprintf("fp_getfvp error %d\n", error); return NULL; } 10 | error = vnode_getwithref(vp); 11 | if (error) goto fail; 12 | fail: 13 | fp_drop(p, fd, fp, 0); 14 | if (error) { xprintf("getfromfd error: %d\n", error); return NULL; } 15 | return vp; 16 | } 17 | 18 | void *vnode_getfromfd_ctx(int fd, void *ctx) { 19 | int error = 0; 20 | void *vp, *fp; 21 | vp = fp = NULL; 22 | void *p = vfs_context_proc(ctx); 23 | error = fp_getfvp(p, fd, &fp, &vp); 24 | if (error) { xprintf("fp_getfvp error %d\n", error); return NULL; } 25 | error = vnode_getwithref(vp); 26 | if (error) goto fail; 27 | fail: 28 | fp_drop(p, fd, fp, 0); 29 | if (error) { xprintf("getfromfd error: %d\n", error); return NULL; } 30 | return vp; 31 | } -------------------------------------------------------------------------------- /hooks/hooks.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "hooks.h" 4 | 5 | int install_all_hooks() { 6 | #pragma clang diagnostic push 7 | #pragma clang diagnostic ignored "-Wincompatible-pointer-types" 8 | 9 | int ret = 0; 10 | if(( ret = install_hook(open1_hook_addr, open1, &open1_orig) )){ 11 | printf("Could not hook open1: %s\n", strerror(errno)); 12 | return 1; 13 | } 14 | if(( ret = install_hook(stat_hook_addr, stat_, &stat_orig) )){ 15 | printf("Could not hook stat: %s\n", strerror(errno)); 16 | return 1; 17 | } 18 | if(( ret = install_hook(getdirentries_hook_addr, getdirentries_common, &getdirentries_common_orig) )){ 19 | printf("Could not hook getdirent: %s\n", strerror(errno)); 20 | return 1; 21 | } 22 | if(( ret = install_hook(ptrace_hook_addr, ptrace_, &ptrace_orig) )){ 23 | printf("Could not hook ptrace: %s\n", strerror(errno)); 24 | return 1; 25 | } 26 | return 0; 27 | 28 | #pragma clang diagnostic pop 29 | 30 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SDK = $(shell xcrun --sdk iphoneos --show-sdk-path) 2 | CC = $(shell xcrun --sdk $(SDK) --find clang) 3 | CFLAGS = -isysroot $(SDK) -arch arm64 -Wno-string-plus-int -fno-stack-protector -Wno-deprecated-declarations 4 | CFLAGS += -Wno-shorten-64-to-32 -D_FORTIFY_SOURCE=0 5 | CFLAGS += -mllvm -align-all-functions=5 6 | 7 | mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST))) 8 | mkfile_dir := $(dir $(mkfile_path)) 9 | PROJ_DIR := $(mkfile_dir) 10 | CFLAGS += -I$(PROJ_DIR) -I$(PROJ_DIR)/include 11 | 12 | OPDUMP = $(realpath ../opdump/opdump) 13 | 14 | export CC 15 | export CFLAGS 16 | export OPDUMP 17 | export SDK 18 | 19 | TARGET_DIRS = filter hooks kern utils 20 | 21 | all : $(TARGET_DIRS) xnu_bypass 22 | 23 | .PHONY : target_dirs $(TARGET_DIRS) 24 | 25 | target_dirs : $(TARGET_DIRS) 26 | 27 | $(TARGET_DIRS) : 28 | $(MAKE) -C $@ 29 | 30 | OBJECT_FILES = $(shell find $(TARGET_DIRS) -type f -name "*.o") 31 | 32 | xnu_bypass : $(OBJECT_FILES) xnu_bypass.c 33 | $(CC) $(CFLAGS) $(LDFLAGS) $(OBJECT_FILES) xnu_bypass.c -o xnu_bypass 34 | ldid -Sent.xml xnu_bypass 35 | -------------------------------------------------------------------------------- /hooks/ptrace_hook.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "ptrace_hook.h" 5 | //#include 6 | 7 | int (*ptrace_orig)(void *p, struct ptrace_args *uap, int32_t *retval); 8 | 9 | #define PT_DENY_ATTACH 31 10 | #define PT_TRACEME 0 11 | 12 | int ptrace_(void *p, struct ptrace_args *uap, int32_t *retval) { 13 | /*if (uap->req == PT_DENY_ATTACH) { 14 | return 0; 15 | } 16 | return ptrace_orig(p, uap, retval);*/ 17 | 18 | char *caller_name = NULL; 19 | 20 | caller_name = log_get_caller("ptrace", "[unk]", 1); 21 | if(!caller_name) 22 | goto orig; 23 | 24 | if(check_caller(caller_name)){ 25 | xprintf("denying ptrace(%p, %d, %p, %p)\n", uap->req, uap->pid, uap->addr, uap->data); 26 | //if (uap->req == PT_DENY_ATTACH || uap->req == PT_TRACEME) { 27 | return 0; 28 | //} 29 | } 30 | 31 | orig: 32 | if(caller_name) 33 | unified_kfree(caller_name); 34 | 35 | return ptrace_orig(p, uap, retval); 36 | } -------------------------------------------------------------------------------- /kern/kern_func.c: -------------------------------------------------------------------------------- 1 | #include "xnuspy_ctl.h" 2 | #include "kern.h" 3 | #include "kern_func.h" 4 | 5 | int init_kern_func(void){ 6 | return init_kernel_offset(); 7 | } 8 | 9 | uint8_t curcpu(void){ 10 | uint64_t mpidr_el1; 11 | asm volatile("mrs %0, mpidr_el1" : "=r" (mpidr_el1)); 12 | return (uint8_t)(mpidr_el1 & 0xff); 13 | } 14 | 15 | pid_t caller_pid(void){ 16 | return proc_pid(current_proc()); 17 | } 18 | 19 | void *vfs_context_proc(void *ctx) { 20 | if (ctx && *(uint64_t *)ctx) { //ctx && ctx->vc_thread 21 | uint64_t proc = 0; 22 | uint64_t v17 = *(uint64_t *)(*(uint64_t *)ctx + OOO.OFFSET_TASK_BSDINFO); // th->task 23 | if (v17) { proc = *(uint64_t *)(v17 + OOO.OFFSET_TASK_BSDINFO); } // th->task->bsd_info 24 | if (proc) { 25 | if (*(uint64_t *)(proc + OOO.OFFSET_PROC_P_FD) && (*(char *)(proc + OOO.OFFSET_PROC_P_LFLAG) & 1) == 0) { // proc->p_fd && proc->p_lflag & P_LVFORK 26 | return (void *)proc; 27 | } 28 | } 29 | return current_proc(); 30 | } 31 | return NULL; 32 | } -------------------------------------------------------------------------------- /utils/helpers.c: -------------------------------------------------------------------------------- 1 | #include "helpers.h" 2 | 3 | char *log_get_caller(const char *fn, const char *param, int dolog) { 4 | uint8_t cpu = curcpu(); 5 | pid_t caller = caller_pid(); 6 | 7 | char *caller_name = unified_kalloc(MAXCOMLEN + 1); 8 | 9 | if(!caller_name) 10 | return NULL; 11 | 12 | /* proc_name doesn't bzero for some version of iOS 13 */ 13 | _bzero(caller_name, MAXCOMLEN + 1); 14 | proc_name(caller, caller_name, MAXCOMLEN + 1); 15 | if (dolog) 16 | xprintf("%s: (CPU %d): '%s' (%d) wants to call '%s' on '%s'\n", fn, cpu, 17 | caller_name, caller, fn, param); 18 | return caller_name; 19 | } 20 | 21 | void *try_read_str(void *addr, size_t maxLen) { 22 | char *path = NULL; 23 | 24 | size_t sz = maxLen; 25 | 26 | if(!(path = unified_kalloc(sz))) 27 | return NULL; 28 | 29 | _bzero(path, sz); 30 | 31 | size_t pathlen = 0; 32 | int res = copyinstr(addr, path, sz, &pathlen); 33 | 34 | if(res) 35 | return NULL; 36 | 37 | path[pathlen - 1] = '\0'; 38 | return path; 39 | } 40 | -------------------------------------------------------------------------------- /hooks/open1_hook.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* bsd/sys/uio.h */ 4 | enum uio_seg { 5 | UIO_USERSPACE = 0, /* kernel address is virtual, to/from user virtual */ 6 | UIO_SYSSPACE = 2, /* kernel address is virtual, to/from system virtual */ 7 | UIO_USERSPACE32 = 5, /* kernel address is virtual, to/from user 32-bit virtual */ 8 | UIO_USERSPACE64 = 8, /* kernel address is virtual, to/from user 64-bit virtual */ 9 | UIO_SYSSPACE32 = 11 /* deprecated */ 10 | }; 11 | 12 | #define UIO_SEG_IS_USER_SPACE( a_uio_seg ) \ 13 | ( (a_uio_seg) == UIO_USERSPACE64 || (a_uio_seg) == UIO_USERSPACE32 || \ 14 | (a_uio_seg) == UIO_USERSPACE ) 15 | 16 | /* bsd/sys/namei.h */ 17 | #define PATHBUFLEN 256 18 | 19 | struct nameidata { 20 | char * /* __user */ ni_dirp; 21 | enum uio_seg ni_segflag; 22 | /* ... */ 23 | }; 24 | 25 | extern int (*open1_orig)(void *vfsctx, struct nameidata *ndp, int uflags, 26 | void *vap, void *fp_zalloc, void *cra, int32_t *retval); 27 | 28 | extern int open1(void *vfsctx, struct nameidata *ndp, int uflags, 29 | void *vap, void *fp_zalloc, void *cra, int32_t *retval); 30 | -------------------------------------------------------------------------------- /hooks/open1_hook.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "open1_hook.h" 5 | 6 | 7 | int (*open1_orig)(void *vfsctx, struct nameidata *ndp, int uflags, 8 | void *vap, void *fp_zalloc, void *cra, int32_t *retval); 9 | 10 | int open1(void *vfsctx, struct nameidata *ndp, int uflags, 11 | void *vap, void *fp_zalloc, void *cra, int32_t *retval){ 12 | char *path = NULL, *caller_name = NULL; 13 | 14 | if(!(ndp->ni_dirp && UIO_SEG_IS_USER_SPACE(ndp->ni_segflag))) 15 | goto orig; 16 | 17 | if(!(path = try_read_str(ndp->ni_dirp, PATHBUFLEN))) 18 | goto orig; 19 | 20 | caller_name = log_get_caller("open1", path, 0); 21 | 22 | if(!caller_name) 23 | goto orig; 24 | if(check_caller(caller_name)){ 25 | //xprintf("%s opening %s with flag %x\n", caller_name, path, uflags); 26 | if (check_path(path)){ 27 | xprintf("denying open for '%s'\n", path); 28 | unified_kfree(path); 29 | unified_kfree(caller_name); 30 | *retval = -1; 31 | return ENOENT; 32 | } 33 | } 34 | 35 | orig: 36 | if(caller_name) 37 | unified_kfree(caller_name); 38 | if(path) 39 | unified_kfree(path); 40 | 41 | return open1_orig(vfsctx, ndp, uflags, vap, fp_zalloc, cra, retval); 42 | } -------------------------------------------------------------------------------- /kern/kern_offset.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | extern uint64_t kernel_slide; 6 | 7 | extern void (*_bzero)(void *p, size_t n); 8 | extern int (*copyin)(const void *user_addr, void *kernel_addr, size_t nbytes); 9 | extern int (*copyinstr)(const void *uaddr, void *kaddr, size_t len, size_t *done); 10 | extern void *(*current_proc)(void); 11 | extern void (*kprintf)(const char *, ...); 12 | extern void (*proc_name)(int pid, char *buf, int size); 13 | extern pid_t (*proc_pid)(void *); 14 | extern int (*_strcmp)(const char *s1, const char *s2); 15 | extern int (*_strncmp)(const char *s1, const char *s2, int n); 16 | extern int (*_strlen)(const char *s1); 17 | extern int (*_memcpy)(void *, const void *, int n); 18 | extern void *(*unified_kalloc)(size_t sz); 19 | extern void (*unified_kfree)(void *ptr); 20 | extern int (*fp_getfvp)(void *p, int fd, void **resultfp, void **resultvp); 21 | extern int (*vnode_getwithref)(void *vp); 22 | extern int (*vnode_put)(void *vp); 23 | extern int (*fp_drop)(void *p, int fd, void *fp, int); 24 | extern void *(*vfs_context_current)(); 25 | extern int (*build_path_with_parent)(void *first_vp, void *parent_vp, char *buff, int buflen, int *outlen, size_t *mntpt_outlen, int flags, void*ctx); 26 | extern int (*copyout)(const void *kernel_addr, void *user_addr, size_t nbytes); 27 | 28 | 29 | // find these in inlined vfs_context_proc() 30 | struct offsets { 31 | int OFFSET_THREAD_T_TASK; 32 | int OFFSET_TASK_BSDINFO; 33 | int OFFSET_PROC_P_FD; 34 | int OFFSET_PROC_P_LFLAG; 35 | }; 36 | extern struct offsets OOO; 37 | 38 | extern void *open1_hook_addr; 39 | extern void *stat_hook_addr; 40 | extern void *getdirentries_hook_addr; 41 | extern void *ptrace_hook_addr; 42 | 43 | extern int init_kernel_offset(void); -------------------------------------------------------------------------------- /filter/filters.c: -------------------------------------------------------------------------------- 1 | #include "filters.h" 2 | 3 | int init_filters() { 4 | char temp1[MAX_BLOCK_CALLER][MAX_CALLER_LEN] = { 5 | "allstars", 6 | "global", 7 | }; 8 | init_caller_filter(temp1); 9 | 10 | char temp2[MAX_BLOCK_PATH][MAX_PATH_LEN] = { 11 | "/Applications/iGameGuardian.app", 12 | "/private/var/mobile/Library/iGameGuardian", 13 | "/Library/BreakThrough", 14 | "/Library/LaunchDaemons/com.apple.gg.daemon.plist", 15 | "/private/var/db/stash", 16 | "/Library/PreferenceLoader/Preferences/LibertyPref.plist", 17 | "/Applications/Flex.app", 18 | "/Library/PreferenceLoader/Preferences/NoSubstitute.plist", 19 | "/Library/Frameworks/CydiaSubstrate.framework", 20 | "/usr/lib/TweakInject", 21 | "/usr/lib/libsubstrate.dylib", 22 | "/private/var/mobile/Library/Flex3", 23 | "/Applications/GameGemiOS.app", 24 | "/var/containers/Bundle/tweaksupport", 25 | "/private/var/containers/Bundle/tweaksupport", 26 | "/User", 27 | "/boot", 28 | "/lib", 29 | "/mnt", 30 | "/Applications/Cydia.app", 31 | "/private/var/lib", 32 | "/jb", 33 | "/private/var/mobile/Library/Caches/com.saurik.Cydia", 34 | "/var/mobile/Library/Caches/com.saurik.Cydia", 35 | "/private/etc/ssh", 36 | "/Library/MobileSubstrate", 37 | "/var/containers/Bundle/iosbinpack64", 38 | "/private/var/containers/Bundle/iosbinpack64", 39 | "/var/libexec", 40 | "/private/var/libexec", 41 | "/Applications/Sileo.app", 42 | "/private/var/mobile/Library/Caches/Snapshots/org.coolstar.SileoStore", 43 | "/private/var/mobile/Library/Preferences/org.coolstar.SileoStore.plist", 44 | "/Applications/Zebra.app", 45 | "/Library/dpkg/info/xyz.willy.zebra.list", 46 | "/private/var/mobile/Library/Preferences/xyz.willy.Zebra.plist", 47 | }; 48 | init_path_filter(temp2); 49 | return 0; 50 | } -------------------------------------------------------------------------------- /kern/kern_offset.c: -------------------------------------------------------------------------------- 1 | #include "kern_offset.h" 2 | #include "kern.h" 3 | #include "xnuspy_ctl.h" 4 | #pragma clang diagnostic push 5 | #pragma clang diagnostic ignored "-Wint-conversion" 6 | 7 | void (*_bzero)(void *p, size_t n); 8 | int (*copyin)(const void *user_addr, void *kernel_addr, size_t nbytes); 9 | int (*copyinstr)(const void *uaddr, void *kaddr, size_t len, size_t *done); 10 | int (*copyout)(const void *kernel_addr, void *user_addr, size_t nbytes) = 0xFFFFFFF007D02BF4; 11 | void *(*current_proc)(void); 12 | void (*kprintf)(const char *, ...); 13 | void (*proc_name)(int pid, char *buf, int size); 14 | pid_t (*proc_pid)(void *); 15 | int (*_strcmp)(const char *s1, const char *s2); 16 | int (*_strncmp)(const char *s1, const char *s2, int n); 17 | int (*_strlen)(const char *s1); 18 | int (*_memcpy)(void *, const void *, int n); 19 | void *(*unified_kalloc)(size_t sz); 20 | void (*unified_kfree)(void *ptr); 21 | int (*fp_getfvp)(void *p, int fd, void **resultfp, void **resultvp) = 0xFFFFFFF007FCEE24; 22 | int (*vnode_getwithref)(void *vp) = 0xFFFFFFF007D8BF88; 23 | int (*vnode_put)(void *vp) = 0xFFFFFFF007D89A90; 24 | int (*fp_drop)(void *p, int fd, void *fp, int) = 0xFFFFFFF007FC93F4; 25 | void *(*vfs_context_current)() = 0xFFFFFFF007DAFBEC; 26 | int (*build_path_with_parent)(void *first_vp, void *parent_vp, char *buff, int buflen, int *outlen, size_t *mntpt_outlen, int flags, void*ctx) = 0xFFFFFFF007D77C90; 27 | 28 | uint64_t kernel_slide; 29 | 30 | //struct offsets OOO = { -1, -1, -1, -1 }; 31 | struct offsets OOO = { 0 }; 32 | 33 | // must be UNSLID! 34 | void *open1_hook_addr = 0xFFFFFFF007D99268; 35 | void *stat_hook_addr = 0xFFFFFFF007D9E374; 36 | void *getdirentries_hook_addr = 0xFFFFFFF007DA3450; 37 | void *ptrace_hook_addr = 0xFFFFFFF00801A7A4; 38 | 39 | #pragma clang diagnostic pop 40 | 41 | int init_kernel_offset(void){ 42 | int ret; 43 | #define GET(a, b) \ 44 | do { \ 45 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_CACHE_READ, a, b, 0); \ 46 | if(ret){ \ 47 | printf("%s: failed getting %s\n", __func__, #a); \ 48 | return ret; \ 49 | } \ 50 | } while (0) 51 | 52 | GET(BZERO, &_bzero); 53 | GET(COPYIN, ©in); 54 | GET(COPYOUT, ©out); 55 | GET(COPYINSTR, ©instr); 56 | GET(CURRENT_PROC, ¤t_proc); 57 | GET(KPRINTF, &kprintf); 58 | GET(PROC_NAME, &proc_name); 59 | GET(PROC_PID, &proc_pid); 60 | GET(STRCMP, &_strcmp); 61 | GET(STRNCMP, &_strncmp); 62 | GET(UNIFIED_KALLOC, &unified_kalloc); 63 | GET(UNIFIED_KFREE, &unified_kfree); 64 | GET(STRLEN, &_strlen); 65 | GET(MEMMOVE, &_memcpy); 66 | GET(KERNEL_SLIDE, &kernel_slide); 67 | 68 | /*void *tempcopyout = NULL; 69 | GET(COPYOUT, &tempcopyout); 70 | printf("xnuspy copyout: %p, real copyout: %p", tempcopyout - kernel_slide, copyout); //unslid*/ 71 | 72 | #define SLIDE(a) \ 73 | do {\ 74 | a += kernel_slide;\ 75 | } while(0) 76 | 77 | //SLIDE(copyout); 78 | SLIDE(fp_getfvp); 79 | SLIDE(vnode_getwithref); 80 | SLIDE(vnode_put); 81 | SLIDE(fp_drop); 82 | SLIDE(vfs_context_current); 83 | SLIDE(build_path_with_parent); 84 | 85 | OOO.OFFSET_THREAD_T_TASK = 792; 86 | OOO.OFFSET_TASK_BSDINFO = 896; 87 | OOO.OFFSET_PROC_P_FD = 264; 88 | OOO.OFFSET_PROC_P_LFLAG = 329; 89 | 90 | return 0; 91 | } -------------------------------------------------------------------------------- /hooks/getdirentries_hook.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "getdirentries_hook.h" 6 | 7 | 8 | int (*getdirentries_common_orig)(int fd, void *bufp, size_t bufsize, ssize_t *bytesread, 9 | off_t *offset, int *eofflag, int flags); 10 | 11 | int getdirentries_common(int fd, void *bufp, size_t bufsize, ssize_t *bytesread, 12 | off_t *offset, int *eofflag, int flags) { 13 | // get ret value first 14 | int ret = 0; 15 | ret = getdirentries_common_orig(fd, bufp, bufsize, bytesread, offset, eofflag, flags); 16 | if (ret) return ret; 17 | 18 | // other process bypass 19 | char *caller_name = NULL; 20 | caller_name = log_get_caller("getdirent", "(unk)", 0); 21 | if(!caller_name) 22 | goto orig; 23 | if (!check_caller(caller_name)) goto orig; 24 | //goto orig; 25 | 26 | // get fd's path 27 | int retval = 0; 28 | char rootpath[1024]; _bzero(rootpath, sizeof(rootpath)); 29 | int pathlen = sizeof(rootpath); 30 | 31 | void *vp = vnode_getfromfd(fd); 32 | void *ctx = vfs_context_current(); 33 | //void *vp = vnode_getfromfd_ctx(fd, ctx); 34 | 35 | //xprintf("got vp %x\n", vp); 36 | if (!vp) goto orig; 37 | //vnode_put(vp); goto orig; 38 | #define BUILDPATH_NO_FS_ENTER 0x1 39 | ret = build_path_with_parent(vp, NULL, rootpath, pathlen, &pathlen, NULL, 0, ctx); 40 | //safe_getpath_new(vp, ) 41 | vnode_put(vp); 42 | xprintf("got getdirent ret: %d path: %s\n", ret, rootpath); 43 | if (ret) goto orig; 44 | //goto orig; 45 | 46 | // copy ret buffer 47 | //if (bufsize > 1024 * 1024 * 2) return 22; 48 | char *oribuf = unified_kalloc(*bytesread); _bzero(oribuf, sizeof(oribuf)); 49 | xprintf("got %d of %d buf\n", *bytesread, bufsize); 50 | copyin(bufp, oribuf, *bytesread); 51 | 52 | //xprintf("copied from %x to %x\n", bufp, oribuf); 53 | //unified_kfree(oribuf); goto orig; 54 | 55 | // filter directory 56 | char *newbuf = unified_kalloc(*bytesread); 57 | //xprintf("alloc newbuf!\n", 0); 58 | int curpos = 0, newpos = 0; 59 | while (curpos < *bytesread) { 60 | struct dirent *dirp = (struct dirent *)&oribuf[curpos]; 61 | curpos += dirp->d_reclen; 62 | //xprintf("handling d_name: %s\n", dirp->d_name); 63 | 64 | char curpath[sizeof(rootpath)]; _bzero(curpath, sizeof(curpath)); 65 | _memcpy(curpath, rootpath, sizeof(rootpath)); 66 | _memcpy(curpath + _strlen(rootpath), dirp->d_name, _strlen(dirp->d_name)); 67 | //xprintf("handling path: %s\n", curpath); 68 | 69 | if (!check_path(curpath)) { 70 | _memcpy(newbuf + newpos, dirp, dirp->d_reclen); 71 | newpos += dirp->d_reclen; 72 | } else { 73 | xprintf("filtering direntry: %s\n", curpath); 74 | } 75 | } 76 | 77 | // write out result 78 | unified_kfree(oribuf); 79 | //xprintf("writing out %d bytes\n", newpos); 80 | copyout(newbuf, bufp, newpos); 81 | //xprintf("copyout(%p, %p, %p)\n", newbuf,bufp,newpos); 82 | *bytesread = newpos; 83 | 84 | unified_kfree(newbuf); 85 | //xprintf("readdir hook finish\n", newpos); 86 | orig: 87 | if (caller_name) unified_kfree(caller_name); 88 | return ret; 89 | } -------------------------------------------------------------------------------- /kern/xnuspy_ctl.h: -------------------------------------------------------------------------------- 1 | #ifndef XNUSPY_CTL 2 | #define XNUSPY_CTL 3 | 4 | /* Flavors for xnuspy_ctl */ 5 | enum { 6 | XNUSPY_CHECK_IF_PATCHED = 0, 7 | XNUSPY_INSTALL_HOOK, 8 | XNUSPY_REGISTER_DEATH_CALLBACK, 9 | XNUSPY_CALL_HOOKME, 10 | XNUSPY_CACHE_READ, 11 | XNUSPY_KREAD, 12 | XNUSPY_KWRITE, 13 | XNUSPY_GET_CURRENT_THREAD, 14 | }; 15 | 16 | /* Values for XNUSPY_CACHE_READ */ 17 | enum { 18 | KERNEL_SLIDE = 0, 19 | KPRINTF, 20 | 21 | /* Use kalloc_canblock for iOS 13.x. On iOS 14.x, EINVAL will 22 | * be returned. */ 23 | KALLOC_CANBLOCK, 24 | 25 | /* Use kalloc_external for iOS 14.x. On iOS 13.x, EINVAL will 26 | * be returned. */ 27 | KALLOC_EXTERNAL, 28 | 29 | /* Use kfree_addr for iOS 13.x. On iOS 14.x, EINVAL will 30 | * be returned. */ 31 | KFREE_ADDR, 32 | 33 | /* Use kfree_ext for iOS 14.x. On iOS 13.x, EINVAL will 34 | * be returned. */ 35 | KFREE_EXT, 36 | 37 | BCOPY_PHYS, 38 | PHYSTOKV, 39 | COPYIN, 40 | COPYINSTR, 41 | COPYOUT, 42 | CURRENT_PROC, 43 | PROC_PID, 44 | KERNEL_THREAD_START, 45 | THREAD_DEALLOCATE, 46 | THREAD_TERMINATE, 47 | 48 | /* struct proclist allproc @ bsd/sys/proc_internal.h */ 49 | ALLPROC, 50 | 51 | BZERO, 52 | IPC_PORT_RELEASE_SEND, 53 | 54 | /* vm_map_t kernel_map @ osfmk/vm/vm_kern.h */ 55 | KERNEL_MAP, 56 | 57 | LCK_GRP_ALLOC_INIT, 58 | LCK_GRP_FREE, 59 | LCK_MTX_UNLOCK, 60 | LCK_RW_ALLOC_INIT, 61 | LCK_RW_DONE, 62 | LCK_RW_FREE, 63 | LCK_RW_LOCK_EXCLUSIVE, 64 | LCK_RW_LOCK_SHARED, 65 | LCK_RW_LOCK_SHARED_TO_EXCLUSIVE, 66 | MACH_MAKE_MEMORY_ENTRY_64, 67 | MACH_VM_MAP_EXTERNAL, 68 | MEMCHR, 69 | MEMCMP, 70 | MEMMEM, 71 | MEMMOVE, 72 | MEMRCHR, 73 | MEMSET, 74 | 75 | /* offsetof(struct thread, map), vm_map_t */ 76 | OFFSETOF_STRUCT_THREAD_MAP, 77 | 78 | PROC_LIST_LOCK, 79 | PROC_LIST_UNLOCK, 80 | 81 | /* lck_mtx_t *proc_list_mlock @ bsd/sys/proc_internal.h */ 82 | PROC_LIST_MLOCK, 83 | 84 | PROC_NAME, 85 | PROC_REF_LOCKED, 86 | PROC_RELE_LOCKED, 87 | PROC_UNIQUEID, 88 | SNPRINTF, 89 | STRCHR, 90 | STRRCHR, 91 | STRCMP, 92 | STRLEN, 93 | STRNCMP, 94 | STRSTR, 95 | STRNSTR, 96 | VM_DEALLOCATE, 97 | VM_MAP_UNWIRE, 98 | VM_MAP_WIRE_EXTERNAL, 99 | IOSLEEP, 100 | 101 | /* Everything below is from xnuspy, everything above is from XNU */ 102 | 103 | /* void hookme(void) 104 | * 105 | * This function is a stub for you to hook to easily gain kernel code 106 | * execution without having to hook an actual kernel function. You can 107 | * get xnuspy to call it by invoking xnuspy_ctl with the 108 | * XNUSPY_CALL_HOOKME flavor. 109 | */ 110 | HOOKME, 111 | 112 | /* void *current_map(void) 113 | * 114 | * Returns the vm_map_t for the current thread. Identical to XNU's 115 | * implementation. 116 | * 117 | * Returns: 118 | * Pointer to current thread's vm_map_t structure. 119 | */ 120 | CURRENT_MAP, 121 | 122 | /* uint64_t iOS_version 123 | * 124 | * This variable contains the major from the "Darwin Kernel Version" 125 | * string. On iOS 13.x, this is 19. On iOS 14.x, this is 20. 126 | */ 127 | IOS_VERSION, 128 | 129 | /* uint64_t kvtophys(uint64_t kaddr) 130 | * 131 | * Convert a kernel (EL1) virtual address to a physical address. 132 | * 133 | * Parameters: 134 | * kaddr: kernel virtual address. 135 | * 136 | * Returns: 137 | * Non-zero if address translation was successful, zero otherwise. 138 | */ 139 | KVTOPHYS, 140 | 141 | /* uint64_t uvtophys(uint64_t uaddr) 142 | * 143 | * Convert a user (EL0) virtual address to a physical address. 144 | * 145 | * Parameters: 146 | * uaddr: user virtual address. 147 | * 148 | * Returns: 149 | * Non-zero if address translation was successful, zero otherwise. 150 | */ 151 | UVTOPHYS, 152 | 153 | /* int kprotect(void *kaddr, uint64_t size, vm_prot_t prot) 154 | * 155 | * Change protections of kernel memory at the page table level. 156 | * 157 | * Parameters: 158 | * kaddr: kernel virtual address of target. 159 | * size: the number of bytes in the target region. 160 | * prot: protections to apply. Only VM_PROT_READ, VM_PROT_WRITE, and 161 | * VM_PROT_EXECUTE are respected. 162 | * 163 | * Returns: 164 | * Zero if successful, non-zero otherwise. 165 | */ 166 | KPROTECT, 167 | 168 | /* int uprotect(void *uaddr, uint64_t size, vm_prot_t prot) 169 | * 170 | * Change protections of user memory at the page table level. 171 | * 172 | * Parameters: 173 | * uaddr: user virtual address of target. 174 | * size: the number of bytes in the target region. 175 | * prot: protections to apply. Only VM_PROT_READ, VM_PROT_WRITE, and 176 | * VM_PROT_EXECUTE are respected. 177 | * 178 | * Returns: 179 | * Zero if successful, non-zero otherwise. 180 | */ 181 | UPROTECT, 182 | 183 | /* void kwrite_static(void *dst, void *buf, size_t sz) 184 | * 185 | * Write to static kernel memory, using bcopy_phys. 186 | * 187 | * Parameters: 188 | * dst: kernel virtual address of destination. 189 | * buf: kernel virtual address of data. 190 | * sz: how many bytes 'buf' is. 191 | */ 192 | KWRITE_STATIC, 193 | 194 | /* void kwrite_instr(uint64_t addr, uint32_t instr) 195 | * 196 | * Patch a single instruction of executable kernel code. This function 197 | * handles permissions, data cache cleaning, and instruction cache 198 | * invalidation. 199 | * 200 | * Parameters: 201 | * addr: kernel virtual address. 202 | * instr: new instruction for addr. 203 | */ 204 | KWRITE_INSTR, 205 | 206 | /* uint64_t *el0_ptep(void *uaddr) 207 | * 208 | * Given a user virtual address, this function returns a pointer to its 209 | * page table entry. 210 | * 211 | * Parameters: 212 | * uaddr: user virtual address. 213 | * 214 | * Returns: 215 | * Kernel virtual address of page table entry for uaddr. 216 | */ 217 | EL0_PTEP, 218 | 219 | /* uint64_t *el1_ptep(void *kaddr) 220 | * 221 | * Given a kernel virtual address, this function returns a pointer to its 222 | * page table entry. 223 | * 224 | * Parameters: 225 | * kaddr: kernel virtual address. 226 | * 227 | * Returns: 228 | * Kernel virtual address of page table entry for kaddr. 229 | */ 230 | EL1_PTEP, 231 | 232 | /* void tlb_flush(void) 233 | * 234 | * After modifying a page table, call this function to invalidate 235 | * the TLB. 236 | */ 237 | TLB_FLUSH, 238 | 239 | /* The next two functions abstract away the different kalloc/kfree pairs 240 | * for different iOS versions and keeps track of allocation sizes. This 241 | * creates an API like malloc/free. Pointers returned from unified_kalloc 242 | * can only be freed with unified_kfree, and pointers returned by other 243 | * memory allocation functions cannot be freed with unified_kfree. 244 | * 245 | * uint8_t *buf = unified_kalloc(0x200); 246 | * 247 | * if(!buf) 248 | * 249 | * 250 | * buf[0] = '\0'; 251 | * 252 | * unified_kfree(buf); 253 | * 254 | * ------------------------------- 255 | * 256 | * void *unified_kalloc(size_t sz) 257 | * 258 | * Parameters: 259 | * sz: allocation size. 260 | * 261 | * Returns: 262 | * Upon success, a pointer to memory. If we are on 13.x, kalloc_canblock's 263 | * canblock parameter is false. Upon failure, NULL. 264 | * 265 | * ------------------------------- 266 | * 267 | * void unified_kfree(void *ptr) 268 | * 269 | * Parameters: 270 | * ptr: a pointer returned from unified_kalloc. 271 | */ 272 | UNIFIED_KALLOC, 273 | UNIFIED_KFREE, 274 | }; 275 | 276 | #define iOS_13_x (19) 277 | #define iOS_14_x (20) 278 | 279 | #endif 280 | --------------------------------------------------------------------------------