├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── ent.xml
├── example
├── Makefile
├── README.md
├── kaddr_of_port.c
├── kernel_thread.c
├── open1_hook.c
├── shmem.c
└── user_client_monitor.c
├── include
├── asm
│ ├── asm.h
│ └── asm_support.h
├── common
│ ├── common.h
│ └── preboot_hook.h
├── pf
│ ├── 13
│ │ └── pf.h
│ ├── 14
│ │ └── pf.h
│ ├── 15
│ │ └── pf.h
│ ├── offsets.h
│ ├── pf_common.h
│ └── pfs.h
├── pongo.h
└── xnuspy
│ ├── el1
│ ├── debug.h
│ ├── externs.h
│ ├── libc.h
│ ├── mem.h
│ ├── pte.h
│ ├── tramp.h
│ ├── utils.h
│ └── wrappers.h
│ ├── el3
│ └── kpp.h
│ ├── xnuspy_cache.h
│ ├── xnuspy_ctl.h
│ └── xnuspy_structs.h
├── klog
├── Makefile
├── README.md
└── klog.c
├── loader
├── Makefile
└── loader.c
├── module
├── Makefile
├── README.md
├── common
│ ├── Makefile
│ ├── asm.c
│ └── common.c
├── el1
│ ├── Makefile
│ ├── hook_system_check_sysctlbyname_hook.h
│ ├── hook_system_check_sysctlbyname_hook.s
│ ├── xnuspy_ctl
│ │ ├── Makefile
│ │ ├── debug.c
│ │ ├── libc.c
│ │ ├── mem.c
│ │ ├── pte.c
│ │ ├── tramp.c
│ │ ├── utils.c
│ │ ├── wrappers.c
│ │ └── xnuspy_ctl.c
│ ├── xnuspy_ctl_tramp.h
│ └── xnuspy_ctl_tramp.s
├── el3
│ ├── Makefile
│ ├── kpp.c
│ └── kpp.s
├── pf
│ ├── 13
│ │ ├── Makefile
│ │ └── pf.c
│ ├── 14
│ │ ├── Makefile
│ │ └── pf.c
│ ├── 15
│ │ ├── Makefile
│ │ └── pf.c
│ ├── Makefile
│ └── README.md
├── preboot_hook.c
└── xnuspy.c
├── opdump
├── Makefile
└── opdump.c
└── open1_hook.png
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | *.ld
4 | *.o
5 | *.dSYM
6 |
7 | # Auto-generated header files containing byte arrays
8 | *_instrs.h
9 | include/xnuspy/el3/kpp_patches.h
10 |
11 | # Binaries generated at build-time (probably not the best way of doing this)
12 | example/user_client_monitor
13 | loader/loader
14 | module/el1/hook_system_check_sysctlbyname_hook
15 | module/el1/xnuspy_ctl/xnuspy_ctl
16 | module/el1/xnuspy_ctl_tramp
17 | module/el3/kpp
18 | module/xnuspy
19 | opdump/opdump
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Justin Sherman
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | RP = $(realpath $(shell pwd))
2 |
3 | export RP
4 |
5 | TARGET_DIRS = loader opdump module klog example
6 |
7 | all : $(TARGET_DIRS)
8 |
9 | .PHONY: all $(TARGET_DIRS)
10 |
11 | $(TARGET_DIRS) :
12 | $(MAKE) -C $@
13 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/example/Makefile:
--------------------------------------------------------------------------------
1 | SDK = $(shell xcrun --sdk iphoneos --show-sdk-path)
2 | CC = $(shell xcrun --sdk $(SDK) --find clang)
3 | CFLAGS = -isysroot $(SDK) -arch arm64 -fno-stack-protector -D_FORTIFY_SOURCE=0
4 | CFLAGS += -Wno-deprecated-declarations
5 |
6 | # If user invokes make in this directory, $(RP) will not be defined
7 | ifndef RP
8 | CFLAGS += -I../include
9 | else
10 | CFLAGS += -I$(RP)/include
11 | endif
12 |
13 | XNUSPY_HEADER = ../include/xnuspy/xnuspy_ctl.h
14 |
15 | all : open1_hook user_client_monitor kernel_thread kaddr_of_port shmem
16 |
17 | .PHONY : upload
18 |
19 | upload : open1_hook user_client_monitor kernel_thread kaddr_of_port shmem
20 | rsync -sz -e 'ssh -p 2222' open1_hook root@localhost:/var/root
21 | rsync -sz -e 'ssh -p 2222' user_client_monitor root@localhost:/var/root
22 | rsync -sz -e 'ssh -p 2222' kernel_thread root@localhost:/var/root
23 | rsync -sz -e 'ssh -p 2222' kaddr_of_port root@localhost:/var/root
24 | rsync -sz -e 'ssh -p 2222' shmem root@localhost:/var/root
25 |
26 | open1_hook : open1_hook.c $(XNUSPY_HEADER)
27 | $(CC) $(CFLAGS) open1_hook.c -o open1_hook
28 | ldid -S../ent.xml ./open1_hook
29 |
30 | user_client_monitor : user_client_monitor.c $(XNUSPY_HEADER)
31 | $(CC) $(CFLAGS) user_client_monitor.c -o user_client_monitor
32 | ldid -S../ent.xml ./user_client_monitor
33 |
34 | kernel_thread : kernel_thread.c $(XNUSPY_HEADER)
35 | $(CC) $(CFLAGS) kernel_thread.c -o kernel_thread
36 | ldid -S../ent.xml ./kernel_thread
37 |
38 | kaddr_of_port : kaddr_of_port.c $(XNUSPY_HEADER)
39 | $(CC) $(CFLAGS) kaddr_of_port.c -o kaddr_of_port
40 | ldid -S../ent.xml ./kaddr_of_port
41 |
42 | shmem : shmem.c $(XNUSPY_HEADER)
43 | $(CC) $(CFLAGS) shmem.c -o shmem
44 | ldid -S../ent.xml ./shmem
45 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # Examples
2 | Porting these to other kernels is just a matter of swapping out offsets.
3 |
4 | Run `make` in this directory to build all of them. `make upload` will
5 | upload them to your device, but you may have to swap out the port number.
6 |
7 | ### open1_hook
8 | This hooks `open1` and logs a message about the file a process just tried
9 | to open, while at the same time preventing everyone from `open`'ing
10 | `/var/mobile/testfile.txt`.
11 |
12 | Some offsets I already have for `open1`:
13 |
14 | ```
15 | iPhone X 13.3.1: 0xfffffff007d70534
16 | iPhone X 15.0: 0xfffffff007d574f4
17 | iPhone 8 13.6.1: 0xfffffff007d99c1c
18 | iPhone 8 14.6: 0xfffffff007c4c8c4
19 | iPhone 8 14.8: 0xfffffff007c4c930
20 | iPhone 7 14.1: 0xfffffff00730aa64
21 | iPhone 7 14.5: 0xfffffff00733b960
22 | iPhone 7 15.0: 0xfffffff00736addc
23 | iPhone SE (2016) 14.3: 0xfffffff0072da190
24 | iPhone SE (2016) 14.5: 0xfffffff0072fd3dc
25 | ```
26 |
27 | ### user_client_monitor
28 | This hooks `is_io_service_open_extended` and logs a descriptive message every
29 | time any process opens a new IOKit user client.
30 |
31 | Some offsets I already have for this:
32 |
33 | ```
34 | iPhone X 13.3.1:
35 | getClassName: 0xfffffff0080bf600
36 | is_io_service_open_extended: 0xfffffff008168d28
37 |
38 | iPhone X 15.0:
39 | getClassName: 0xfffffff0080e8ba0
40 | is_io_service_open_extended: 0xfffffff0081c1580
41 |
42 | iPhone 8 13.6.1:
43 | getClassName: 0xfffffff0080ec9a8
44 | is_io_service_open_extended: 0xfffffff0081994dc
45 |
46 | iPhone 8 14.6:
47 | getClassName: 0xfffffff007fbd108
48 | is_io_service_open_extended: 0xfffffff008085dd0
49 |
50 | iPhone 8 14.8:
51 | getClassName: 0xfffffff007fbd400
52 | is_io_service_open_extended: 0xfffffff0080861a0
53 |
54 | iPhone 7 14.1:
55 | getClassName: 0xfffffff00765be54
56 | is_io_service_open_extended: 0xfffffff00770d114
57 |
58 | iPhone 7 14.5:
59 | getClassName: 0xfffffff00769130c
60 | is_io_service_open_extended: 0xfffffff0077473a8
61 |
62 | iPhone 7 15.0:
63 | getClassName: 0xfffffff0076dcac4
64 | is_io_service_open_extended: 0xfffffff0077a1f2c
65 |
66 | iPhone SE (2016) 14.3:
67 | getClassName: 0xfffffff00762e3e4
68 | is_io_service_open_extended: 0xfffffff0076e3104
69 |
70 | iPhone SE (2016) 14.5:
71 | getClassName: 0xfffffff007652c80
72 | is_io_service_open_extended: 0xfffffff007708dac
73 | ```
74 |
75 | ### kernel_thread
76 | This hooks `hookme`, invokes `xnuspy_ctl` to call it, starts up a kernel
77 | thread, and registers a death callback.
78 |
79 | ### kaddr_of_port
80 | This uses `XNUSPY_KREAD` to determine the kernel addres of a userspace
81 | Mach port handle.
82 |
83 | Some offsets I already have for `offsetof(struct task, itk_space)`:
84 |
85 | ```
86 | iPhone 8 13.6.1: 0x320
87 | iPhone X 13.3.1: 0x320
88 | iPhone 7 14.1: 0x330
89 | ```
90 |
91 | ### shmem
92 | Demonstrates kernel-user shared data synchronization with shared memory
93 | returned by `mkshmem_ktou`.
94 |
--------------------------------------------------------------------------------
/example/kaddr_of_port.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | #include
12 |
13 | static long SYS_xnuspy_ctl = 0;
14 |
15 | /* https://gist.github.com/ccbrown/9722406 */
16 | void kdump(const void *kaddr, size_t size) {
17 | char *data = malloc(size);
18 | if(syscall(SYS_xnuspy_ctl, XNUSPY_KREAD, kaddr, data, size)){
19 | printf("%s: kread failed: %s\n", __func__, strerror(errno));
20 | return;
21 | }
22 | char ascii[17];
23 | size_t i, j;
24 | ascii[16] = '\0';
25 | for (i = 0; i < size; ++i) {
26 | printf("%02X ", ((unsigned char*)data)[i]);
27 | if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') {
28 | ascii[i % 16] = ((unsigned char*)data)[i];
29 | } else {
30 | ascii[i % 16] = '.';
31 | }
32 | if ((i+1) % 8 == 0 || i+1 == size) {
33 | printf(" ");
34 | if ((i+1) % 16 == 0) {
35 | printf("| %s \n", ascii);
36 | } else if (i+1 == size) {
37 | ascii[(i+1) % 16] = '\0';
38 | if ((i+1) % 16 <= 8) {
39 | printf(" ");
40 | }
41 | for (j = (i+1) % 16; j < 16; ++j) {
42 | printf(" ");
43 | }
44 | printf("| %s \n", ascii);
45 | }
46 | }
47 | }
48 | free(data);
49 | }
50 |
51 | struct ipc_entry {
52 | uint64_t ie_object;
53 | uint32_t ie_bits;
54 | uint32_t ie_dist : 12;
55 | uint32_t ie_index : 20;
56 | union {
57 | uint32_t next;
58 | uint32_t request;
59 | } index;
60 | };
61 |
62 | struct ipc_space {
63 | struct {
64 | uint64_t data;
65 | uint32_t type;
66 | uint32_t pad;
67 | } is_lock_data;
68 | uint32_t is_bits;
69 | uint32_t is_table_size;
70 | uint32_t is_table_hashed;
71 | uint32_t is_table_free;
72 | struct ipc_entry *is_table;
73 | uint64_t is_task;
74 | uint64_t is_table_next;
75 | uint32_t is_low_mod;
76 | uint32_t is_high_mod;
77 |
78 | /* other stuff that isn't needed */
79 | };
80 |
81 | static uint64_t kaddr_of_port(mach_port_t p){
82 | uint64_t tp;
83 | int ret = syscall(SYS_xnuspy_ctl, XNUSPY_GET_CURRENT_THREAD, &tp, 0, 0);
84 |
85 | if(ret){
86 | printf("%s: XNUSPY_GET_CURRENT_THREAD failed: %s\n", __func__,
87 | strerror(errno));
88 | return 0;
89 | }
90 |
91 | uint64_t offsetof_map;
92 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_CACHE_READ, OFFSETOF_STRUCT_THREAD_MAP,
93 | &offsetof_map, 0);
94 |
95 | if(ret){
96 | printf("%s: getting map offset failed: %s\n", __func__,
97 | strerror(errno));
98 | return 0;
99 | }
100 |
101 | /* task pointer is conveniently right before map pointer for all
102 | * my phones */
103 | uint64_t task;
104 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_KREAD, tp + (offsetof_map - 8), &task,
105 | sizeof(task));
106 |
107 | if(ret){
108 | printf("%s: kread failed for task: %s\n", __func__, strerror(errno));
109 | return 0;
110 | }
111 |
112 | if(!task){
113 | printf("%s: task NULL?\n", __func__);
114 | return 0;
115 | }
116 |
117 | /* Offsets:
118 | * iPhone 8 13.6.1: 0x320
119 | * iPhone X 13.3.1: 0x320
120 | * iPhone 7 14.1: 0x330
121 | */
122 | uint64_t itk_space;
123 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_KREAD, task + 0x320, &itk_space,
124 | sizeof(itk_space));
125 |
126 | if(ret){
127 | printf("%s: kread failed for itk_space: %s\n", __func__,
128 | strerror(errno));
129 | return 0;
130 | }
131 |
132 | struct ipc_entry *is_tablep = NULL;
133 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_KREAD,
134 | itk_space + __builtin_offsetof(struct ipc_space, is_table),
135 | &is_tablep, sizeof(is_tablep));
136 |
137 | if(ret){
138 | printf("%s: kread for is_table failed: %s\n", __func__,
139 | strerror(errno));
140 | return 0;
141 | }
142 |
143 | uint64_t kaddr;
144 | struct ipc_entry *entryp = is_tablep + (p >> 8);
145 |
146 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_KREAD, entryp, &kaddr, sizeof(kaddr));
147 |
148 | if(ret){
149 | printf("%s: kread for ie_object failed: %s\n", __func__,
150 | strerror(errno));
151 | return 0;
152 | }
153 |
154 | return kaddr;
155 | }
156 |
157 | int main(int argc, char **argv){
158 | size_t oldlen = sizeof(long);
159 | int ret = sysctlbyname("kern.xnuspy_ctl_callnum", &SYS_xnuspy_ctl,
160 | &oldlen, NULL, 0);
161 |
162 | if(ret == -1){
163 | printf("sysctlbyname with kern.xnuspy_ctl_callnum failed: %s\n",
164 | strerror(errno));
165 | return 1;
166 | }
167 |
168 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_CHECK_IF_PATCHED, 0, 0, 0);
169 |
170 | if(ret != 999){
171 | printf("xnuspy_ctl isn't present?\n");
172 | return 1;
173 | }
174 |
175 | uint64_t taskport_kaddr = kaddr_of_port(mach_task_self());
176 |
177 | if(!taskport_kaddr)
178 | return 1;
179 |
180 | printf("mach_task_self() @ %#llx\n", taskport_kaddr);
181 |
182 | kdump((void *)taskport_kaddr, 0xa8);
183 |
184 | return 0;
185 | }
186 |
--------------------------------------------------------------------------------
/example/kernel_thread.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | #include
12 |
13 | __attribute__ ((naked)) static void *current_thread(void){
14 | asm(""
15 | "mrs x0, tpidr_el1\n"
16 | "ret\n"
17 | );
18 | }
19 |
20 | typedef void (*thread_continue_t)(void *param, int wait_result);
21 |
22 | static void (*IOSleep)(unsigned int millis);
23 | static kern_return_t (*kernel_thread_start)(thread_continue_t cont, void *param,
24 | void **thread);
25 | static void (*kprintf)(const char *fmt, ...);
26 | static void (*thread_deallocate)(void *thread);
27 | static void (*_thread_terminate)(void *thread);
28 |
29 | static uint64_t kernel_slide, hookme_addr;
30 |
31 | static int time_to_die = 0;
32 |
33 | static void kernel_thread_fxn(void *param, int wait_result){
34 | while(!time_to_die){
35 | kprintf("%s: alive, but at what cost?\n", __func__);
36 | IOSleep(1000);
37 | }
38 |
39 | kprintf("%s: goodbye\n", __func__);
40 |
41 | _thread_terminate(current_thread());
42 |
43 | /* We shouldn't reach here */
44 |
45 | kprintf("%s: we are still alive?\n", __func__);
46 | }
47 |
48 | static void death_callback(void){
49 | kprintf("%s: called\n", __func__);
50 | time_to_die = 1;
51 | }
52 |
53 | static int kernel_thread_made = 0;
54 |
55 | static void hookme_hook(void *arg){
56 | kprintf("%s: we were called!\n", __func__);
57 |
58 | if(kernel_thread_made)
59 | return;
60 |
61 | void *thread;
62 | kern_return_t kret = kernel_thread_start(kernel_thread_fxn, NULL, &thread);
63 |
64 | if(kret)
65 | kprintf("%s: could not make kernel thread: %#x\n", __func__, kret);
66 | else{
67 | /* Throw away the reference from kernel_thread_start */
68 | thread_deallocate(thread);
69 | kernel_thread_made = 1;
70 | kprintf("%s: created kernel thread\n", __func__);
71 | }
72 | }
73 |
74 | static long SYS_xnuspy_ctl = 0;
75 |
76 | static int gather_kernel_offsets(void){
77 | int ret;
78 |
79 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_CACHE_READ, IOSLEEP, &IOSleep, 0);
80 |
81 | if(ret){
82 | printf("Failed getting IOSleep\n");
83 | return ret;
84 | }
85 |
86 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_CACHE_READ, KERNEL_THREAD_START,
87 | &kernel_thread_start, 0);
88 |
89 | if(ret){
90 | printf("Failed getting kernel_thread_start\n");
91 | return ret;
92 | }
93 |
94 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_CACHE_READ, THREAD_DEALLOCATE,
95 | &thread_deallocate, 0);
96 |
97 | if(ret){
98 | printf("Failed getting thread_deallocate\n");
99 | return ret;
100 | }
101 |
102 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_CACHE_READ, THREAD_TERMINATE,
103 | &_thread_terminate, 0);
104 |
105 | if(ret){
106 | printf("Failed getting thread_terminate\n");
107 | return ret;
108 | }
109 |
110 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_CACHE_READ, KPRINTF, &kprintf, 0);
111 |
112 | if(ret){
113 | printf("Failed getting kprintf\n");
114 | return ret;
115 | }
116 |
117 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_CACHE_READ, KERNEL_SLIDE,
118 | &kernel_slide, 0);
119 |
120 | if(ret){
121 | printf("Failed getting kernel slide\n");
122 | return ret;
123 | }
124 |
125 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_CACHE_READ, HOOKME, &hookme_addr, 0);
126 |
127 | if(ret){
128 | printf("Failed getting hookme\n");
129 | return ret;
130 | }
131 |
132 | return 0;
133 | }
134 |
135 | int main(int argc, char **argv){
136 | size_t oldlen = sizeof(long);
137 | int ret = sysctlbyname("kern.xnuspy_ctl_callnum", &SYS_xnuspy_ctl,
138 | &oldlen, NULL, 0);
139 |
140 | if(ret == -1){
141 | printf("sysctlbyname with kern.xnuspy_ctl_callnum failed: %s\n",
142 | strerror(errno));
143 | return 1;
144 | }
145 |
146 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_CHECK_IF_PATCHED, 0, 0, 0);
147 |
148 | if(ret != 999){
149 | printf("xnuspy_ctl isn't present?\n");
150 | return 1;
151 | }
152 |
153 | ret = gather_kernel_offsets();
154 |
155 | if(ret){
156 | printf("something failed: %s\n", strerror(errno));
157 | return 1;
158 | }
159 |
160 | /* xnuspy does not operate on slid addresses */
161 | hookme_addr -= kernel_slide;
162 |
163 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_INSTALL_HOOK, hookme_addr,
164 | hookme_hook, NULL);
165 |
166 | if(ret){
167 | printf("Could not hook hookme: %s\n", strerror(errno));
168 | return 1;
169 | }
170 |
171 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_REGISTER_DEATH_CALLBACK,
172 | death_callback, 0, 0);
173 |
174 | if(ret){
175 | printf("Could not register death callback: %s\n", strerror(errno));
176 | return 1;
177 | }
178 |
179 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_CALL_HOOKME, 0, 0, 0);
180 |
181 | if(ret){
182 | printf("Calling hookme not supported\n");
183 | return 1;
184 | }
185 |
186 | printf("Ctrl C or enter to quit and invoke death callback\n");
187 | getchar();
188 |
189 | return 0;
190 | }
191 |
--------------------------------------------------------------------------------
/example/open1_hook.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | #include
12 |
13 | static void (*_bzero)(void *p, size_t n);
14 | static int (*copyinstr)(const void *uaddr, void *kaddr, size_t len, size_t *done);
15 | static void *(*current_proc)(void);
16 | static void (*kprintf)(const char *, ...);
17 | static void (*proc_name)(int pid, char *buf, int size);
18 | static pid_t (*proc_pid)(void *);
19 | static int (*_strcmp)(const char *s1, const char *s2);
20 | static void *(*unified_kalloc)(size_t sz);
21 | static void (*unified_kfree)(void *ptr);
22 |
23 | static uint64_t kernel_slide;
24 |
25 | static uint8_t curcpu(void){
26 | uint64_t mpidr_el1;
27 | asm volatile("mrs %0, mpidr_el1" : "=r" (mpidr_el1));
28 | return (uint8_t)(mpidr_el1 & 0xff);
29 | }
30 |
31 | static pid_t caller_pid(void){
32 | return proc_pid(current_proc());
33 | }
34 |
35 | /* bsd/sys/uio.h */
36 | enum uio_seg {
37 | UIO_USERSPACE = 0, /* kernel address is virtual, to/from user virtual */
38 | UIO_SYSSPACE = 2, /* kernel address is virtual, to/from system virtual */
39 | UIO_USERSPACE32 = 5, /* kernel address is virtual, to/from user 32-bit virtual */
40 | UIO_USERSPACE64 = 8, /* kernel address is virtual, to/from user 64-bit virtual */
41 | UIO_SYSSPACE32 = 11 /* deprecated */
42 | };
43 |
44 | #define UIO_SEG_IS_USER_SPACE( a_uio_seg ) \
45 | ( (a_uio_seg) == UIO_USERSPACE64 || (a_uio_seg) == UIO_USERSPACE32 || \
46 | (a_uio_seg) == UIO_USERSPACE )
47 |
48 | /* bsd/sys/namei.h */
49 | #define PATHBUFLEN 256
50 |
51 | struct nameidata {
52 | char * /* __user */ ni_dirp;
53 | enum uio_seg ni_segflag;
54 | /* ... */
55 | };
56 |
57 | #define BLOCKED_FILE "/var/mobile/testfile.txt"
58 |
59 | static int (*open1_orig)(void *vfsctx, struct nameidata *ndp, int uflags,
60 | void *vap, void *fp_zalloc, void *cra, int32_t *retval);
61 |
62 | static int open1(void *vfsctx, struct nameidata *ndp, int uflags,
63 | void *vap, void *fp_zalloc, void *cra, int32_t *retval){
64 | char *path = NULL;
65 |
66 | if(!(ndp->ni_dirp && UIO_SEG_IS_USER_SPACE(ndp->ni_segflag)))
67 | goto orig;
68 |
69 | size_t sz = PATHBUFLEN;
70 |
71 | if(!(path = unified_kalloc(sz)))
72 | goto orig;
73 |
74 | _bzero(path, sz);
75 |
76 | size_t pathlen = 0;
77 | int res = copyinstr(ndp->ni_dirp, path, sz, &pathlen);
78 |
79 | if(res)
80 | goto orig;
81 |
82 | path[pathlen - 1] = '\0';
83 |
84 | uint8_t cpu = curcpu();
85 | pid_t caller = caller_pid();
86 |
87 | char *caller_name = unified_kalloc(MAXCOMLEN + 1);
88 |
89 | if(!caller_name)
90 | goto orig;
91 |
92 | /* proc_name doesn't bzero for some version of iOS 13 */
93 | _bzero(caller_name, MAXCOMLEN + 1);
94 | proc_name(caller, caller_name, MAXCOMLEN + 1);
95 |
96 | kprintf("%s: (CPU %d): '%s' (%d) wants to open '%s'\n", __func__, cpu,
97 | caller_name, caller, path);
98 |
99 | unified_kfree(caller_name);
100 |
101 | if(_strcmp(path, BLOCKED_FILE) == 0){
102 | kprintf("%s: denying open for '%s'\n", __func__, path);
103 | unified_kfree(path);
104 | *retval = -1;
105 | return ENOENT;
106 | }
107 |
108 | orig:;
109 | if(path)
110 | unified_kfree(path);
111 |
112 | return open1_orig(vfsctx, ndp, uflags, vap, fp_zalloc, cra, retval);
113 | }
114 |
115 | static long SYS_xnuspy_ctl = 0;
116 |
117 | static int gather_kernel_offsets(void){
118 | int ret;
119 | #define GET(a, b) \
120 | do { \
121 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_CACHE_READ, a, b, 0); \
122 | if(ret){ \
123 | printf("%s: failed getting %s\n", __func__, #a); \
124 | return ret; \
125 | } \
126 | } while (0)
127 |
128 | GET(BZERO, &_bzero);
129 | GET(COPYINSTR, ©instr);
130 | GET(CURRENT_PROC, ¤t_proc);
131 | GET(KPRINTF, &kprintf);
132 | GET(PROC_NAME, &proc_name);
133 | GET(PROC_PID, &proc_pid);
134 | GET(STRCMP, &_strcmp);
135 | GET(UNIFIED_KALLOC, &unified_kalloc);
136 | GET(UNIFIED_KFREE, &unified_kfree);
137 |
138 | return 0;
139 | }
140 |
141 | int main(int argc, char **argv){
142 | size_t oldlen = sizeof(long);
143 | int ret = sysctlbyname("kern.xnuspy_ctl_callnum", &SYS_xnuspy_ctl,
144 | &oldlen, NULL, 0);
145 |
146 | if(ret == -1){
147 | printf("sysctlbyname with kern.xnuspy_ctl_callnum failed: %s\n",
148 | strerror(errno));
149 | return 1;
150 | }
151 |
152 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_CHECK_IF_PATCHED, 0, 0, 0);
153 |
154 | if(ret != 999){
155 | printf("xnuspy_ctl isn't present?\n");
156 | return 1;
157 | }
158 |
159 | ret = gather_kernel_offsets();
160 |
161 | if(ret){
162 | printf("something failed: %s\n", strerror(errno));
163 | return 1;
164 | }
165 |
166 | /* iPhone X 15.0 */
167 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_INSTALL_HOOK, 0xfffffff007d574f4,
168 | open1, &open1_orig);
169 |
170 | if(ret){
171 | printf("Could not hook open1: %s\n", strerror(errno));
172 | return 1;
173 | }
174 |
175 | for(;;){
176 | int fd = open(BLOCKED_FILE, O_CREAT);
177 |
178 | if(fd == -1)
179 | printf("open failed: %s\n", strerror(errno));
180 | else{
181 | printf("Got valid fd? %d\n", fd);
182 | close(fd);
183 | }
184 |
185 | sleep(1);
186 | }
187 |
188 | return 0;
189 | }
190 |
--------------------------------------------------------------------------------
/example/shmem.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #include
13 |
14 | static kuslck_t g_kuslck = KUSLCK_INITIALIZER;
15 |
16 | static bool g_dead = false;
17 | static bool g_go = false;
18 | static bool g_made = false;
19 | static bool g_kernel_racer_finished = false;
20 |
21 | static uint64_t *g_kernel_valp = NULL;
22 | static struct xnuspy_shmem g_kernel_valp_shmem;
23 |
24 | __attribute__ ((naked)) static void *current_thread(void){
25 | asm(""
26 | "mrs x0, tpidr_el1\n"
27 | "ret\n"
28 | );
29 | }
30 |
31 | static uint64_t kernel_slide, hookme_addr;
32 | static long SYS_xnuspy_ctl = 0;
33 | static void *kernel_map;
34 |
35 | typedef void (*thread_continue_t)(void *param, int wait_result);
36 |
37 | static void (*IOSleep)(unsigned int millis);
38 | static kern_return_t (*kernel_thread_start)(thread_continue_t cont, void *param,
39 | void **thread);
40 | static void (*kprintf)(const char *fmt, ...);
41 | static void (*thread_deallocate)(void *thread);
42 | static void (*_thread_terminate)(void *thread);
43 |
44 | static int (*mkshmem_ktou)(uint64_t kaddr, uint64_t sz, vm_prot_t prot,
45 | struct xnuspy_shmem *shmemp);
46 | static int (*mkshmem_utok)(uint64_t uaddr, uint64_t sz, vm_prot_t prot,
47 | struct xnuspy_shmem *shmemp);
48 | static int (*mkshmem_raw)(uint64_t addr, uint64_t sz, vm_prot_t prot,
49 | void *from, void *to, struct xnuspy_shmem *shmemp);
50 | static int (*shmem_destroy)(struct xnuspy_shmem *);
51 |
52 | static kern_return_t (*vm_allocate_external)(void *map, uint64_t *address,
53 | uint64_t size, int flags);
54 |
55 | static void kernel_racer(void *param, int wait_result){
56 | while(!g_go){
57 | if(g_dead)
58 | break;
59 | }
60 |
61 | for(int i=0; i<500; i++){
62 | kuslck_lock(g_kuslck);
63 | (*g_kernel_valp)++;
64 | kuslck_unlock(g_kuslck);
65 | }
66 |
67 | g_kernel_racer_finished = true;
68 |
69 | _thread_terminate(current_thread());
70 | }
71 |
72 | static void death_callback(void){
73 | kprintf("%s: called\n", __func__);
74 | shmem_destroy(&g_kernel_valp_shmem);
75 | g_dead = true;
76 | }
77 |
78 | static void hookme_hook(void *arg){
79 | if(g_made)
80 | return;
81 |
82 | void *thread;
83 | kern_return_t kret = kernel_thread_start(kernel_racer, NULL, &thread);
84 |
85 | if(kret){
86 | kprintf("%s: kernel_thread_start returned %#x\n", __func__, kret);
87 | return;
88 | }
89 |
90 | thread_deallocate(thread);
91 |
92 | kret = vm_allocate_external(kernel_map, (uint64_t *)&g_kernel_valp,
93 | 0x4000, VM_FLAGS_ANYWHERE);
94 |
95 | if(kret){
96 | kprintf("%s: mach_vm_allocate_external: %#x\n", __func__, kret);
97 | return;
98 | }
99 |
100 | int res = mkshmem_ktou((uint64_t)g_kernel_valp, 0x4000, VM_PROT_READ |
101 | VM_PROT_WRITE, &g_kernel_valp_shmem);
102 |
103 | if(res){
104 | kprintf("%s: mkshmem_ktou failed: %d\n", __func__, res);
105 | return;
106 | }
107 |
108 | kprintf("%s: returned shmem: %p\n", __func__,
109 | g_kernel_valp_shmem.shm_base);
110 |
111 | g_made = true;
112 | }
113 |
114 | static int gather_kernel_offsets(void){
115 | int ret;
116 | #define GET(a, b) \
117 | do { \
118 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_CACHE_READ, a, b, 0); \
119 | if(ret){ \
120 | printf("%s: failed getting %s\n", __func__, #a); \
121 | return ret; \
122 | } \
123 | } while (0)
124 |
125 | GET(KERNEL_THREAD_START, &kernel_thread_start);
126 | GET(KPRINTF, &kprintf);
127 | GET(THREAD_DEALLOCATE, &thread_deallocate);
128 | GET(THREAD_TERMINATE, &_thread_terminate);
129 | GET(KERNEL_SLIDE, &kernel_slide);
130 | GET(HOOKME, &hookme_addr);
131 | GET(MKSHMEM_KTOU, &mkshmem_ktou);
132 | GET(MKSHMEM_UTOK, &mkshmem_utok);
133 | GET(MKSHMEM_RAW, &mkshmem_raw);
134 | GET(SHMEM_DESTROY, &shmem_destroy);
135 | GET(KERNEL_MAP, &kernel_map);
136 | GET(VM_ALLOCATE_EXTERNAL, &vm_allocate_external);
137 |
138 | hookme_addr -= kernel_slide;
139 |
140 | return 0;
141 | }
142 |
143 | static void *userspace_racer(void *arg){
144 | while(!g_go){}
145 |
146 | uint64_t *user_valp = g_kernel_valp_shmem.shm_base;
147 |
148 | for(int i=0; i<500; i++){
149 | kuslck_lock(g_kuslck);
150 | (*user_valp)++;
151 | kuslck_unlock(g_kuslck);
152 | }
153 |
154 | return NULL;
155 | }
156 |
157 | int main(int argc, char **argv){
158 | size_t oldlen = sizeof(long);
159 | int ret = sysctlbyname("kern.xnuspy_ctl_callnum", &SYS_xnuspy_ctl,
160 | &oldlen, NULL, 0);
161 |
162 | if(ret == -1){
163 | printf("sysctlbyname with kern.xnuspy_ctl_callnum failed: %s\n",
164 | strerror(errno));
165 | return 1;
166 | }
167 |
168 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_CHECK_IF_PATCHED, 0, 0, 0);
169 |
170 | if(ret != 999){
171 | printf("xnuspy_ctl isn't present?\n");
172 | return 1;
173 | }
174 |
175 | ret = gather_kernel_offsets();
176 |
177 | if(ret){
178 | printf("something failed: %s\n", strerror(errno));
179 | return 1;
180 | }
181 |
182 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_INSTALL_HOOK, hookme_addr,
183 | hookme_hook, NULL);
184 |
185 | if(ret){
186 | printf("Could not hook hookme: %s\n", strerror(errno));
187 | return 1;
188 | }
189 |
190 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_REGISTER_DEATH_CALLBACK,
191 | death_callback, 0, 0);
192 |
193 | if(ret){
194 | printf("Could not register death callback: %s\n", strerror(errno));
195 | return 1;
196 | }
197 |
198 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_CALL_HOOKME, 0, 0, 0);
199 |
200 | if(ret){
201 | printf("Calling hookme not supported\n");
202 | return 1;
203 | }
204 |
205 | sleep(1);
206 |
207 | pthread_t pt;
208 | pthread_create(&pt, NULL, userspace_racer, NULL);
209 |
210 | g_go = true;
211 |
212 | while(!g_kernel_racer_finished){}
213 |
214 | sleep(2);
215 |
216 | uint64_t result = *(uint64_t *)g_kernel_valp_shmem.shm_base;
217 |
218 | if(result != 1000)
219 | printf("Got unexpected result %lld\n", result);
220 | else
221 | printf("Correct result! %lld\n", result);
222 |
223 | return 0;
224 | }
225 |
--------------------------------------------------------------------------------
/example/user_client_monitor.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | #include
12 |
13 | static void *(*current_proc)(void);
14 | static void (*kprintf)(const char *, ...);
15 | static pid_t (*proc_pid)(void *);
16 |
17 | static uint64_t kernel_slide;
18 |
19 | static uint8_t curcpu(void){
20 | uint64_t mpidr_el1;
21 | asm volatile("mrs %0, mpidr_el1" : "=r" (mpidr_el1));
22 | return (uint8_t)(mpidr_el1 & 0xff);
23 | }
24 |
25 | static pid_t caller_pid(void){
26 | return proc_pid(current_proc());
27 | }
28 |
29 | static const char *(*getClassName)(const void *OSObject);
30 |
31 | struct IOUserClient_vtab {
32 | uint8_t pad0[0x118];
33 | void *(*getProperty)(void *this, const char *key);
34 | uint8_t pad120[0x370 - 0x120];
35 | void *(*getProvider)(void *this);
36 | };
37 |
38 | struct IOUserClient {
39 | struct IOUserClient_vtab *vt;
40 | };
41 |
42 | static kern_return_t (*is_io_service_open_extended_orig)(void *_service,
43 | void *owning_task, uint32_t connect_type, NDR_record_t ndr,
44 | char *properties, mach_msg_type_number_t properties_cnt,
45 | kern_return_t *result, struct IOUserClient **connection);
46 |
47 | static kern_return_t is_io_service_open_extended(void *_service,
48 | void *owning_task, uint32_t connect_type, NDR_record_t ndr,
49 | char *properties, mach_msg_type_number_t properties_cnt,
50 | kern_return_t *result, struct IOUserClient **connection){
51 | uint8_t cpu = curcpu();
52 | pid_t cpid = caller_pid();
53 | uint64_t caller = (uint64_t)__builtin_return_address(0);
54 |
55 | kern_return_t kret = is_io_service_open_extended_orig(_service, owning_task,
56 | connect_type, ndr, properties, properties_cnt, result,
57 | connection);
58 |
59 | kprintf("user_client_monitor: (CPU %d, unslid caller %#llx, pid %d): connect "
60 | "type %#x: ", cpu, caller - kernel_slide, cpid, connect_type);
61 |
62 | if(*result != KERN_SUCCESS){
63 | kprintf("failed. Returned %#x, result = %#x\n", kret, *result);
64 | return kret;
65 | }
66 |
67 | struct IOUserClient *client = *connection;
68 |
69 | kprintf("opened user client = %#llx ", client);
70 |
71 | if(!client){
72 | kprintf("\n");
73 | return kret;
74 | }
75 |
76 | const char *class_name = getClassName(client);
77 |
78 | if(!class_name){
79 | kprintf("getClassName failed.\n");
80 | return kret;
81 | }
82 |
83 | kprintf("class: '%s'", class_name);
84 |
85 | /* IOService */
86 | void *provider = client->vt->getProvider(client);
87 |
88 | if(!provider)
89 | kprintf(" unknown provider");
90 | else{
91 | const char *provider_class_name = getClassName(provider);
92 |
93 | if(provider_class_name)
94 | kprintf(" provider: '%s'", provider_class_name);
95 | }
96 |
97 | /* OSString */
98 | void *creator_name_prop = client->vt->getProperty(client, "IOUserClientCreator");
99 |
100 | if(!creator_name_prop){
101 | kprintf(" unknown creator\n");
102 | return kret;
103 | }
104 |
105 | const char *creator_name = *(const char **)((uint8_t *)creator_name_prop + 0x10);
106 |
107 | if(!creator_name){
108 | kprintf(" unknown creator\n");
109 | return kret;
110 | }
111 |
112 | kprintf(" creator: '%s'\n", creator_name);
113 |
114 | return kret;
115 | }
116 |
117 | static kern_return_t (*is_io_connect_method)(struct IOUserClient *,
118 | uint32_t selector, uint64_t *scalar_input,
119 | uint32_t scalar_input_sz, uint8_t *struct_input,
120 | uint32_t struct_input_sz, uint64_t ool_input, uint64_t ool_input_sz,
121 | uint8_t *struct_output, uint32_t *struct_output_szp,
122 | uint64_t *scalar_output, uint64_t *scalar_output_szp,
123 | uint64_t ool_output, uint64_t *ool_output_szp);
124 |
125 | static kern_return_t _is_io_connect_method(struct IOUserClient *uc,
126 | uint32_t selector, uint64_t *scalar_input,
127 | uint32_t scalar_input_sz, uint8_t *struct_input,
128 | uint32_t struct_input_sz, uint64_t ool_input, uint64_t ool_input_sz,
129 | uint8_t *struct_output, uint32_t *struct_output_szp,
130 | uint64_t *scalar_output, uint64_t *scalar_output_szp,
131 | uint64_t ool_output, uint64_t *ool_output_szp){
132 | kern_return_t kret = is_io_connect_method(uc, selector, scalar_input,
133 | scalar_input_sz, struct_input, struct_input_sz, ool_input,
134 | ool_input_sz, struct_output, struct_output_szp, scalar_output,
135 | scalar_output_szp, ool_output, ool_output_szp);
136 |
137 | const char *class_name = getClassName(uc);
138 |
139 | if(!class_name)
140 | return kret;
141 |
142 | kprintf("user_client_monitor: '%s' invoked external method %d\n",
143 | class_name, selector);
144 |
145 | return kret;
146 | }
147 |
148 | static long SYS_xnuspy_ctl = 0;
149 |
150 | static int gather_kernel_offsets(void){
151 | int ret;
152 |
153 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_CACHE_READ, CURRENT_PROC,
154 | ¤t_proc, 0);
155 |
156 | if(ret){
157 | printf("Failed getting current_proc\n");
158 | return ret;
159 | }
160 |
161 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_CACHE_READ, KPRINTF, &kprintf, 0);
162 | if(ret){
163 | printf("Failed getting kprintf\n");
164 | return ret;
165 | }
166 |
167 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_CACHE_READ, PROC_PID, &proc_pid, 0);
168 |
169 | if(ret){
170 | printf("Failed getting proc_pid\n");
171 | return ret;
172 | }
173 |
174 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_CACHE_READ, KERNEL_SLIDE, &kernel_slide, 0);
175 |
176 | if(ret){
177 | printf("Failed getting kernel slide\n");
178 | return ret;
179 | }
180 |
181 | return 0;
182 | }
183 |
184 | int main(int argc, char **argv){
185 | size_t oldlen = sizeof(long);
186 | int ret = sysctlbyname("kern.xnuspy_ctl_callnum", &SYS_xnuspy_ctl,
187 | &oldlen, NULL, 0);
188 |
189 | if(ret == -1){
190 | printf("sysctlbyname with kern.xnuspy_ctl_callnum failed: %s\n",
191 | strerror(errno));
192 | return 1;
193 | }
194 |
195 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_CHECK_IF_PATCHED, 0, 0, 0);
196 |
197 | if(ret != 999){
198 | printf("xnuspy_ctl isn't present?\n");
199 | return 1;
200 | }
201 |
202 | ret = gather_kernel_offsets();
203 |
204 | if(ret){
205 | printf("something failed: %s\n", strerror(errno));
206 | return 1;
207 | }
208 |
209 | /* iPhone X 15.0 */
210 | getClassName = (const char *(*)(const void *))(0xfffffff0080e8ba0 + kernel_slide);
211 |
212 | printf("kernel slide: %#llx\n", kernel_slide);
213 | printf("current_proc @ %#llx\n", (uint64_t)current_proc);
214 | printf("getClassName @ %#llx\n", (uint64_t)getClassName);
215 | printf("kprintf @ %#llx\n", (uint64_t)kprintf);
216 | printf("proc_pid @ %#llx\n", (uint64_t)proc_pid);
217 |
218 | ret = syscall(SYS_xnuspy_ctl, XNUSPY_INSTALL_HOOK, 0xfffffff0081c1580,
219 | is_io_service_open_extended, &is_io_service_open_extended_orig);
220 |
221 | if(ret){
222 | printf("Could not hook is_io_service_open_extended: %s\n",
223 | strerror(errno));
224 | return 1;
225 | }
226 |
227 | /* XXX Optional */
228 | /* ret = syscall(SYS_xnuspy_ctl, XNUSPY_INSTALL_HOOK, 0xfffffff0081c68ec, */
229 | /* _is_io_connect_method, &is_io_connect_method); */
230 |
231 | /* if(ret){ */
232 | /* printf("Could not hook is_io_connect_method: %s\n", */
233 | /* strerror(errno)); */
234 | /* return 1; */
235 | /* } */
236 |
237 | printf("Hit enter to quit\n");
238 | getchar();
239 |
240 | return 0;
241 | }
242 |
--------------------------------------------------------------------------------
/include/asm/asm.h:
--------------------------------------------------------------------------------
1 | #ifndef ASM
2 | #define ASM
3 |
4 | #include
5 |
6 | uint64_t sign_extend(uint64_t, uint32_t);
7 |
8 | uint32_t assemble_adrp(uint64_t, uint64_t, uint32_t);
9 | uint32_t assemble_b(uint64_t, uint64_t);
10 | uint32_t assemble_bl(uint64_t, uint64_t);
11 | uint32_t assemble_csel(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
12 | uint32_t assemble_mov(uint32_t, uint32_t, uint32_t);
13 | uint32_t assemble_immediate_add(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
14 | uint32_t assemble_immediate_cmp(uint32_t, uint32_t, uint32_t, uint32_t);
15 | uint32_t assemble_immediate_ldr(uint32_t, uint32_t, uint32_t);
16 | uint32_t assemble_immediate_prfm(uint32_t, uint32_t);
17 | uint32_t assemble_ldrsw(uint32_t, uint32_t);
18 | uint32_t assemble_simd_fp_ldr(uint32_t, uint32_t, uint32_t, uint32_t);
19 |
20 | uint32_t bits(uint64_t, uint64_t, uint64_t);
21 |
22 | uint64_t get_add_imm(uint32_t);
23 |
24 | uint64_t get_adr_target(uint32_t *);
25 | uint64_t get_adrp_target(uint32_t *);
26 | uint64_t get_adrp_add_target(uint32_t *);
27 | uint64_t get_adrp_ldr_target(uint32_t *);
28 | uint64_t get_pc_rel_target(uint32_t *);
29 |
30 | uint64_t get_branch_dst(uint32_t, uint32_t *);
31 | uint32_t *get_branch_dst_ptr(uint32_t *);
32 | uint64_t get_compare_and_branch_dst(uint32_t, uint32_t *);
33 | uint64_t get_cond_branch_dst(uint32_t, uint32_t *);
34 | uint64_t get_test_and_branch_dst(uint32_t, uint32_t *);
35 |
36 | void write_blr(uint32_t, uint32_t *, uint64_t);
37 |
38 | #endif
39 |
--------------------------------------------------------------------------------
/include/asm/asm_support.h:
--------------------------------------------------------------------------------
1 | #ifndef ASM_SUPPORT
2 | #define ASM_SUPPORT
3 |
4 | #define OPCODE_PLACEHOLDER_BYTE (0x41)
5 | #define OPCODE_PLACEHOLDER (0x41414141)
6 | #define QWORD_PLACEHOLDER (0x4142434445464748)
7 |
8 | #endif
9 |
--------------------------------------------------------------------------------
/include/common/common.h:
--------------------------------------------------------------------------------
1 | #ifndef COMMON
2 | #define COMMON
3 |
4 | #include
5 | #include
6 |
7 | bool is_15_x__pongo(void);
8 | bool is_14_5_and_above__pongo(void);
9 | bool is_14_x_and_above__pongo(void);
10 | bool is_14_x_and_below__pongo(void);
11 | bool is_14_x__pongo(void);
12 | bool is_13_x__pongo(void);
13 |
14 | int atoi(const char *);
15 | int isdigit(int);
16 |
17 | char *strcpy(char *, const char *);
18 | char *strstr(const char *, const char *);
19 |
20 | __attribute__ ((noreturn)) void xnuspy_fatal_error(void);
21 |
22 | extern struct mach_header_64 *mh_execute_header;
23 | extern uint64_t kernel_slide;
24 |
25 | extern void (*next_preboot_hook)(void);
26 |
27 | #define iOS_13_x (19)
28 | #define iOS_14_x (20)
29 | #define iOS_15_x (21)
30 |
31 | #define VERSION_BIAS iOS_13_x
32 |
33 | #endif
34 |
--------------------------------------------------------------------------------
/include/common/preboot_hook.h:
--------------------------------------------------------------------------------
1 | #ifndef PREBOOT_HOOK
2 | #define PREBOOT_HOOK
3 |
4 | void xnuspy_preboot_hook(void);
5 |
6 | #endif
7 |
--------------------------------------------------------------------------------
/include/pf/13/pf.h:
--------------------------------------------------------------------------------
1 | #ifndef PF_13
2 | #define PF_13
3 |
4 | #include
5 |
6 | typedef struct xnu_pf_patch xnu_pf_patch_t;
7 |
8 | bool sysent_finder_13(xnu_pf_patch_t *, void *);
9 | bool kalloc_canblock_finder_13(xnu_pf_patch_t *, void *);
10 | bool kfree_addr_finder_13(xnu_pf_patch_t *, void *);
11 | bool ExceptionVectorsBase_finder_13(xnu_pf_patch_t *, void *);
12 | bool sysctl__kern_children_finder_13(xnu_pf_patch_t *, void *);
13 | bool sysctl_register_oid_finder_13(xnu_pf_patch_t *, void *);
14 | bool sysctl_handle_long_finder_13(xnu_pf_patch_t *, void *);
15 | bool name2oid_and_its_dependencies_finder_13(xnu_pf_patch_t *, void *);
16 | bool hook_system_check_sysctlbyname_finder_13(xnu_pf_patch_t *, void *);
17 | bool lck_grp_alloc_init_finder_13(xnu_pf_patch_t *, void *);
18 | bool lck_rw_alloc_init_finder_13(xnu_pf_patch_t *, void *);
19 | bool bcopy_phys_finder_13(xnu_pf_patch_t *, void *);
20 | bool phystokv_finder_13(xnu_pf_patch_t *, void *);
21 | bool ktrr_lockdown_patcher_13(xnu_pf_patch_t *, void *);
22 | bool amcc_lockdown_patcher_13(xnu_pf_patch_t *, void *);
23 | bool copyin_finder_13(xnu_pf_patch_t *, void *);
24 | bool copyout_finder_13(xnu_pf_patch_t *, void *);
25 | bool IOSleep_finder_13(xnu_pf_patch_t *, void *);
26 | bool kprintf_finder_13(xnu_pf_patch_t *, void *);
27 | bool kernel_map_vm_deallocate_vm_map_unwire_finder_13(xnu_pf_patch_t *, void *);
28 | bool kernel_thread_start_thread_deallocate_finder_13(xnu_pf_patch_t *, void *);
29 | bool mach_make_memory_entry_64_finder_13(xnu_pf_patch_t *, void *);
30 | bool offsetof_struct_thread_map_finder_13(xnu_pf_patch_t *, void *);
31 | bool proc_stuff0_finder_13(xnu_pf_patch_t *, void *);
32 | bool proc_stuff1_finder_13(xnu_pf_patch_t *, void *);
33 | bool allproc_finder_13(xnu_pf_patch_t *, void *);
34 | bool misc_lck_stuff_finder_13(xnu_pf_patch_t *, void *);
35 | bool vm_map_wire_external_finder_13(xnu_pf_patch_t *, void *);
36 | bool mach_vm_map_external_finder_13(xnu_pf_patch_t *, void *);
37 | bool ipc_port_release_send_finder_13(xnu_pf_patch_t *, void *);
38 | bool lck_rw_free_finder_13(xnu_pf_patch_t *, void *);
39 | bool lck_grp_free_finder_13(xnu_pf_patch_t *, void *);
40 | bool doprnt_hide_pointers_patcher_13(xnu_pf_patch_t *, void *);
41 | bool copyinstr_finder_13(xnu_pf_patch_t *, void *);
42 | bool thread_terminate_finder_13(xnu_pf_patch_t *, void *);
43 | bool pinst_set_tcr_patcher_13(xnu_pf_patch_t *, void *);
44 | bool msr_tcr_el1_x18_patcher_13(xnu_pf_patch_t *, void *);
45 | bool proc_name_snprintf_strlen_finder_13(xnu_pf_patch_t *, void *);
46 | bool strncmp_finder_13(xnu_pf_patch_t *, void *);
47 | bool memset_finder_13(xnu_pf_patch_t *, void *);
48 | bool memmove_finder_13(xnu_pf_patch_t *, void *);
49 | bool panic_finder_13(xnu_pf_patch_t *, void *);
50 | bool mach_to_bsd_errno_finder_13(xnu_pf_patch_t *, void *);
51 | bool vm_allocate_external_finder_13(xnu_pf_patch_t *, void *);
52 | bool vm_map_deallocate_offsetof_vm_map_refcnt_finder_13(xnu_pf_patch_t *, void *);
53 | bool IOLog_finder_13(xnu_pf_patch_t *, void *);
54 | bool lck_mtx_lock_finder_13(xnu_pf_patch_t *, void *);
55 |
56 | #endif
57 |
--------------------------------------------------------------------------------
/include/pf/14/pf.h:
--------------------------------------------------------------------------------
1 | #ifndef PF_14
2 | #define PF_14
3 |
4 | #include
5 |
6 | typedef struct xnu_pf_patch xnu_pf_patch_t;
7 |
8 | bool kalloc_external_finder_14(xnu_pf_patch_t *, void *);
9 | bool kfree_ext_finder_14(xnu_pf_patch_t *, void *);
10 | bool ExceptionVectorsBase_finder_14(xnu_pf_patch_t *, void *);
11 | bool sysctl__kern_children_and_register_oid_finder_14(xnu_pf_patch_t *, void *);
12 | bool lck_grp_alloc_init_finder_14(xnu_pf_patch_t *, void *);
13 | bool lck_rw_alloc_init_finder_14(xnu_pf_patch_t *, void *);
14 | bool ktrr_lockdown_patcher_14(xnu_pf_patch_t *, void *);
15 | bool amcc_ctrr_lockdown_patcher_14(xnu_pf_patch_t *, void *);
16 | bool name2oid_and_its_dependencies_finder_14(xnu_pf_patch_t *, void *);
17 |
18 | #endif
19 |
--------------------------------------------------------------------------------
/include/pf/15/pf.h:
--------------------------------------------------------------------------------
1 | #ifndef PF_15
2 | #define PF_15
3 |
4 | #include
5 |
6 | typedef struct xnu_pf_patch xnu_pf_patch_t;
7 |
8 | bool ipc_port_release_send_finder_15(xnu_pf_patch_t *, void *);
9 | bool proc_name_snprintf_strlen_finder_15(xnu_pf_patch_t *, void *);
10 | bool current_proc_finder_15(xnu_pf_patch_t *, void *);
11 | bool vm_map_unwire_nested_finder_15(xnu_pf_patch_t *, void *);
12 | bool kernel_map_finder_15(xnu_pf_patch_t *, void *);
13 | bool vm_deallocate_finder_15(xnu_pf_patch_t *, void *);
14 | bool proc_list_mlock_lck_mtx_lock_unlock_finder_15(xnu_pf_patch_t *, void *);
15 | bool lck_grp_free_finder_15(xnu_pf_patch_t *, void *);
16 | bool proc_ref_rele_finder_15(xnu_pf_patch_t *, void *);
17 | bool lck_rw_alloc_init_finder_15(xnu_pf_patch_t *, void *);
18 |
19 | #endif
20 |
--------------------------------------------------------------------------------
/include/pf/offsets.h:
--------------------------------------------------------------------------------
1 | #ifndef OFFSETS
2 | #define OFFSETS
3 |
4 | #include
5 |
6 | extern uint64_t *xnuspy_cache_base;
7 |
8 | /* This file contains offsets which will be written to the xnuspy cache
9 | * as well as offsets needed before XNU boots. */
10 |
11 | /* NOT a kernel virtual address */
12 | extern uint64_t g_sysent_addr;
13 |
14 | /* iOS 13.x: kalloc_canblock
15 | * iOS 14.x and iOS 15.x: kalloc_external */
16 | extern uint64_t g_kalloc_canblock_addr;
17 | extern uint64_t g_kalloc_external_addr;
18 |
19 | /* iOS 13.x: kfree_addr
20 | * iOS 14.x and iOS 15.x: kfree_ext */
21 | extern uint64_t g_kfree_addr_addr;
22 | extern uint64_t g_kfree_ext_addr;
23 |
24 | extern uint64_t g_sysctl__kern_children_addr;
25 | extern uint64_t g_sysctl_register_oid_addr;
26 | extern uint64_t g_sysctl_handle_long_addr;
27 | extern uint64_t g_name2oid_addr;
28 | extern uint64_t g_sysctl_geometry_lock_addr;
29 | extern uint64_t g_lck_rw_done_addr;
30 | extern uint64_t g_h_s_c_sbn_branch_addr;
31 | extern uint64_t g_h_s_c_sbn_epilogue_addr;
32 | extern uint64_t g_lck_grp_alloc_init_addr;
33 | extern uint64_t g_lck_rw_alloc_init_addr;
34 | extern uint64_t g_exec_scratch_space_addr;
35 | extern uint64_t g_exec_scratch_space_size;
36 | extern uint32_t *g_ExceptionVectorsBase_stream;
37 | extern uint64_t g_bcopy_phys_addr;
38 | extern uint64_t g_phystokv_addr;
39 | extern uint64_t g_copyin_addr;
40 | extern uint64_t g_copyout_addr;
41 | extern uint64_t g_IOSleep_addr;
42 | extern uint64_t g_kprintf_addr;
43 | extern uint64_t g_vm_map_unwire_addr;
44 | extern uint64_t g_vm_map_unwire_nested_addr;
45 | extern uint64_t g_vm_deallocate_addr;
46 | extern uint64_t g_kernel_map_addr;
47 | extern uint64_t g_kernel_thread_start_addr;
48 | extern uint64_t g_thread_deallocate_addr;
49 | extern uint64_t g_mach_make_memory_entry_64_addr;
50 | extern uint64_t g_offsetof_struct_thread_map;
51 | extern uint64_t g_current_proc_addr;
52 | extern uint64_t g_proc_list_lock_addr;
53 | extern uint64_t g_proc_ref_locked_addr;
54 | extern uint64_t g_proc_list_mlock_addr;
55 | extern uint64_t g_lck_mtx_lock_addr;
56 | extern uint64_t g_lck_mtx_unlock_addr;
57 | extern uint64_t g_proc_rele_locked_addr;
58 | extern uint64_t g_proc_uniqueid_addr;
59 | extern uint64_t g_proc_pid_addr;
60 | extern uint64_t g_allproc_addr;
61 | extern uint64_t g_lck_rw_lock_shared_addr;
62 | extern uint64_t g_lck_rw_lock_shared_to_exclusive_addr;
63 | extern uint64_t g_lck_rw_lock_exclusive_addr;
64 | extern uint64_t g_vm_map_wire_external_addr;
65 | extern uint64_t g_mach_vm_map_external_addr;
66 |
67 | /* Only for <14.5 */
68 | extern uint64_t g_ipc_port_release_send_addr;
69 |
70 | /* Only for >=14.5 */
71 | extern uint64_t g_ipc_port_release_send_and_unlock_addr;
72 |
73 | extern uint64_t g_lck_rw_free_addr;
74 | extern uint64_t g_lck_grp_free_addr;
75 | extern int g_patched_doprnt_hide_pointers;
76 | extern uint64_t g_copyinstr_addr;
77 | extern uint64_t g_thread_terminate_addr;
78 | extern int g_patched_pinst_set_tcr;
79 | extern int g_patched_all_msr_tcr_el1_x18;
80 | extern uint64_t g_snprintf_addr;
81 | extern uint64_t g_strlen_addr;
82 | extern uint64_t g_proc_name_addr;
83 | extern uint64_t g_strncmp_addr;
84 | extern uint64_t g_memset_addr;
85 | extern uint64_t g_memmove_addr;
86 | extern uint64_t g_panic_addr;
87 | extern uint64_t g_mach_to_bsd_errno_addr;
88 | extern uint64_t g_xnuspy_sysctl_mib_ptr;
89 | extern uint64_t g_xnuspy_sysctl_mib_count_ptr;
90 | extern uint64_t g_xnuspy_ctl_callnum;
91 | extern uint64_t g_kern_version_major;
92 | extern uint64_t g_kern_version_minor;
93 |
94 | /* Only for >=14.5 && <15.0 */
95 | extern uint64_t g_io_lock_addr;
96 |
97 | /* Only for >=15.0 */
98 | extern uint64_t g_ipc_object_lock_addr;
99 |
100 | extern uint64_t g_vm_allocate_external_addr;
101 | extern uint64_t g_vm_map_deallocate_addr;
102 | extern uint64_t g_offsetof_struct_vm_map_refcnt;
103 | extern uint64_t g_IOLog_addr;
104 |
105 | /* Following two are only valid on iOS 15+ */
106 | extern uint64_t g_proc_ref_addr;
107 | extern uint64_t g_proc_rele_addr;
108 |
109 | #endif
110 |
--------------------------------------------------------------------------------
/include/pf/pf_common.h:
--------------------------------------------------------------------------------
1 | #ifndef PF_COMMON
2 | #define PF_COMMON
3 |
4 | #include
5 | #include
6 |
7 | typedef struct xnu_pf_patch xnu_pf_patch_t;
8 |
9 | struct pf {
10 | const char *pf_name;
11 | uint64_t pf_matches[8];
12 | uint64_t pf_masks[8];
13 | uint32_t pf_mmcount;
14 | /* XNU_PF_ACCESS_8BIT, etc */
15 | uint32_t pf_access_type;
16 | bool (*pf_callback)(xnu_pf_patch_t *, void *);
17 | /* If applicable, the name of the kext used with xnu_pf_get_kext_header
18 | * If not applicable, NULL */
19 | const char *pf_kext;
20 | const char *pf_segment;
21 | /* If applicable, the section used with xnu_pf_section
22 | * If not applicable, NULL */
23 | const char *pf_section;
24 | uint8_t pf_unused;
25 | };
26 |
27 | #define LISTIZE(...) __VA_ARGS__
28 |
29 | #define PF_DECL32(name, matches, masks, mmcount, callback, seg) \
30 | { \
31 | .pf_name = name, \
32 | .pf_matches = matches, \
33 | .pf_masks = masks, \
34 | .pf_mmcount = mmcount, \
35 | .pf_access_type = XNU_PF_ACCESS_32BIT, \
36 | .pf_callback = callback, \
37 | .pf_kext = NULL, \
38 | .pf_segment = seg, \
39 | .pf_section = NULL, \
40 | .pf_unused = 0, \
41 | }
42 |
43 | #define PF_DECL_FULL(name, matches, masks, mmcount, access, callback, kext, seg, sect) \
44 | { \
45 | .pf_name = name, \
46 | .pf_matches = matches, \
47 | .pf_masks = masks, \
48 | .pf_mmcount = mmcount, \
49 | .pf_access_type = access, \
50 | .pf_callback = callback, \
51 | .pf_kext = kext, \
52 | .pf_segment = seg, \
53 | .pf_section = sect, \
54 | .pf_unused = 0, \
55 | }
56 |
57 | #define PF_UNUSED { .pf_unused = 1 }
58 |
59 | #define PF_END { .pf_unused = 0x41 }
60 |
61 | #endif
62 |
--------------------------------------------------------------------------------
/include/xnuspy/el1/debug.h:
--------------------------------------------------------------------------------
1 | #ifndef DEBUG
2 | #define DEBUG
3 |
4 | #include
5 |
6 | #if defined(XNUSPY_DEBUG)
7 | #define DEBUG_SPEW(fmt, args...) kprintf(fmt, ##args)
8 | #else
9 | #define DEBUG_SPEW(fmt, args...)
10 | #endif
11 |
12 | #if defined(XNUSPY_SERIAL)
13 | #define SERIAL_SPEW(fmt, args...) IOLog(fmt, ##args)
14 | #else
15 | #define SERIAL_SPEW(fmt, args...)
16 | #endif
17 |
18 | #define SPYDBG(fmt, args...) \
19 | do { \
20 | DEBUG_SPEW(fmt, ##args); \
21 | SERIAL_SPEW(fmt, ##args); \
22 | } while (0) \
23 |
24 | void desc_freelist(void);
25 | void desc_xnuspy_shmem(struct xnuspy_shmem *);
26 | /* XXX ONLY meant to be called from xnuspy_gc_thread, hence the lack
27 | * of locking. */
28 | void desc_unmaplist(void);
29 | void desc_usedlist(void);
30 |
31 | void desc_xnuspy_mapping(struct xnuspy_mapping *);
32 | void desc_xnuspy_mapping_metadata(struct xnuspy_mapping_metadata *);
33 | void desc_xnuspy_tramp(struct xnuspy_tramp *, uint32_t);
34 |
35 | #endif
36 |
--------------------------------------------------------------------------------
/include/xnuspy/el1/externs.h:
--------------------------------------------------------------------------------
1 | #ifndef EXTERNS
2 | #define EXTERNS
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #undef PAGE_SIZE
11 | #define PAGE_SIZE (0x4000uLL)
12 |
13 | #define iOS_13_x (19)
14 | #define iOS_14_x (20)
15 | #define iOS_15_x (21)
16 |
17 | #define MAP_MEM_VM_SHARE 0x400000 /* extract a VM range for remap */
18 |
19 | typedef unsigned int lck_rw_type_t;
20 |
21 | typedef void (*thread_continue_t)(void *param, int wait_result);
22 |
23 | typedef struct __lck_rw_t__ lck_rw_t;
24 |
25 | /* Start kernel offsets */
26 |
27 | extern void **allprocp;
28 | extern void (*bcopy_phys)(uint64_t src, uint64_t dst,
29 | vm_size_t bytes);
30 | extern int (*copyin)(const void *uaddr, void *kaddr,
31 | vm_size_t nbytes);
32 | extern int (*copyinstr)(const void *uaddr, void *kaddr,
33 | size_t len, size_t *done);
34 | extern int (*copyout)(const void *kaddr, uint64_t uaddr,
35 | vm_size_t nbytes);
36 | extern void *(*current_proc)(void);
37 | extern uint64_t hookme_in_range;
38 | extern uint64_t iOS_version;
39 | extern void (*io_lock)(void *io);
40 | extern void (*ipc_object_lock)(void *obj);
41 | extern void (*IOLog)(const char *fmt, ...);
42 | extern void (*IOSleep)(unsigned int millis);
43 | extern void (*ipc_port_release_send)(void *port);
44 | extern void (*ipc_port_release_send_and_unlock)(void *port);
45 | extern void *(*kalloc_canblock)(vm_size_t *sizep, bool canblock,
46 | void *site);
47 | extern void *(*kalloc_external)(vm_size_t sz);
48 | extern uint64_t kern_version_minor;
49 | extern void **kernel_mapp;
50 | extern uint64_t kernel_slide;
51 | extern kern_return_t (*kernel_thread_start)(thread_continue_t cont,
52 | void *parameter, void **new_thread);
53 | extern void (*kfree_addr)(void *addr);
54 | extern void (*kfree_ext)(void *kheap, void *addr,
55 | vm_size_t sz);
56 | extern void (*kprintf)(const char *fmt, ...);
57 | extern void *(*lck_grp_alloc_init)(const char *grp_name,
58 | void *attr);
59 | extern void (*lck_grp_free)(void *grp);
60 | extern void (*lck_mtx_lock)(void *lock);
61 | extern void (*lck_mtx_unlock)(void *lock);
62 | extern lck_rw_t *(*lck_rw_alloc_init)(void *grp, void *attr);
63 | extern uint32_t (*lck_rw_done)(lck_rw_t *lock);
64 | extern void (*lck_rw_free)(lck_rw_t *lock, void *grp);
65 | extern void (*lck_rw_lock_exclusive)(void *lock);
66 | extern void (*lck_rw_lock_shared)(void *lock);
67 | extern int (*lck_rw_lock_shared_to_exclusive)(lck_rw_t *lck);
68 | extern kern_return_t (*_mach_make_memory_entry_64)(void *target_map,
69 | uint64_t *size, uint64_t offset, vm_prot_t prot, void **object_handle,
70 | void *parent_handle);
71 | extern int (*mach_to_bsd_errno)(kern_return_t mach_err);
72 | extern kern_return_t (*mach_vm_map_external)(void *target_map,
73 | uint64_t *address, uint64_t size, uint64_t mask, int flags,
74 | void *memory_object, uint64_t offset, int copy,
75 | vm_prot_t cur_protection, vm_prot_t max_protection,
76 | vm_inherit_t inheritance);
77 | extern void *(*_memmove)(void *dest, const void *src, size_t n);
78 | extern void *(*_memset)(void *s, int c, size_t n);
79 | extern uint64_t offsetof_struct_thread_map;
80 | extern uint64_t offsetof_struct_vm_map_refcnt;
81 | extern __attribute__ ((noreturn)) void (*_panic)(const char *fmt, ...);
82 | extern uint64_t (*phystokv)(uint64_t pa);
83 | extern void **proc_list_mlockp;
84 | extern void (*proc_name)(int pid, char *buf, int size);
85 | extern pid_t (*proc_pid)(void *proc);
86 | extern void *(*proc_ref)(void *proc, bool w1);
87 | extern void *(*proc_ref_locked)(void *proc);
88 | extern int (*proc_rele)(void *proc);
89 | extern void (*proc_rele_locked)(void *proc);
90 | extern uint64_t (*proc_uniqueid)(void *proc);
91 | extern int (*_snprintf)(char *str, size_t size, const char *fmt, ...);
92 | extern size_t (*_strlen)(const char *s);
93 | extern int (*_strncmp)(const char *s1, const char *s2, size_t n);
94 | extern void (*thread_deallocate)(void *thread);
95 | extern void (*_thread_terminate)(void *thread);
96 | extern kern_return_t (*vm_allocate_external)(void *map, uint64_t *addr,
97 | uint64_t size, int flags);
98 | extern kern_return_t (*_vm_deallocate)(void *map,
99 | uint64_t start, uint64_t size);
100 | extern void (*vm_map_deallocate)(void *map);
101 | extern kern_return_t (*vm_map_unwire)(void *map, uint64_t start,
102 | uint64_t end, int user);
103 | extern kern_return_t (*vm_map_unwire_nested)(void *map, uint64_t start,
104 | uint64_t end, int user, uint64_t map_pmap, uint64_t pmap_addr);
105 | extern kern_return_t (*vm_map_wire_external)(void *map,
106 | uint64_t start, uint64_t end, vm_prot_t prot, int user_wire);
107 | extern struct xnuspy_tramp *xnuspy_tramp_mem;
108 | extern struct xnuspy_tramp *xnuspy_tramp_mem_end;
109 |
110 | /* End kernel offsets */
111 |
112 | extern STAILQ_HEAD(, stailq_entry) freelist;
113 | extern STAILQ_HEAD(, stailq_entry) usedlist;
114 | extern STAILQ_HEAD(, stailq_entry) unmaplist;
115 |
116 | extern lck_rw_t *xnuspy_rw_lck;
117 |
118 | #endif
119 |
--------------------------------------------------------------------------------
/include/xnuspy/el1/libc.h:
--------------------------------------------------------------------------------
1 | #ifndef LIBC
2 | #define LIBC
3 |
4 | #include
5 |
6 | void bzero(void *p, size_t n);
7 | void *memchr(const void *s, int c, size_t n);
8 | int memcmp(const void *s1, const void *s2, size_t n);
9 | void *memmem(const void *big, size_t blen, const void *little, size_t llen);
10 | void *memrchr(const void *s, int c, size_t n);
11 | char *strchr(const char *s, int c);
12 | char *strrchr(const char *s, int c);
13 | int strcmp(const char *s1, const char *s2);
14 | char *strstr(const char *big, const char *little);
15 | char *strnstr(const char *big, const char *little, size_t len);
16 |
17 | #endif
18 |
--------------------------------------------------------------------------------
/include/xnuspy/el1/mem.h:
--------------------------------------------------------------------------------
1 | #ifndef MEM
2 | #define MEM
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | __attribute__((naked)) uint64_t kvtophys(uint64_t);
9 | __attribute__((naked)) uint64_t uvtophys(uint64_t);
10 |
11 | void dcache_clean_PoU(void *address, size_t size);
12 | void icache_invalidate_PoU(void *address, size_t size);
13 |
14 | int kprotect(void *, uint64_t, vm_prot_t);
15 | int uprotect(void *, uint64_t, vm_prot_t);
16 |
17 | void kwrite_static(void *, void *, size_t);
18 | void kwrite_instr(uint64_t, uint32_t);
19 |
20 | int mkshmem_ktou(uint64_t, uint64_t, vm_prot_t, struct xnuspy_shmem *);
21 | int mkshmem_utok(uint64_t, uint64_t, vm_prot_t, struct xnuspy_shmem *);
22 | int mkshmem_raw(uint64_t, uint64_t, vm_prot_t, struct _vm_map *,
23 | struct _vm_map *, struct xnuspy_shmem *);
24 |
25 | int shmem_destroy(struct xnuspy_shmem *);
26 |
27 | void *unified_kalloc(size_t);
28 | void unified_kfree(void *);
29 |
30 | #endif
31 |
--------------------------------------------------------------------------------
/include/xnuspy/el1/pte.h:
--------------------------------------------------------------------------------
1 | #ifndef PTE
2 | #define PTE
3 |
4 | #include
5 |
6 | typedef uint64_t pte_t;
7 |
8 | pte_t *el0_ptep(void *);
9 | pte_t *el1_ptep(void *);
10 |
11 | void tlb_flush(void);
12 |
13 | #define ARM_TTE_TABLE_MASK (0x0000ffffffffc000)
14 |
15 | #define ARM_16K_TT_L1_SHIFT (36)
16 | #define ARM_16K_TT_L2_SHIFT (25)
17 | #define ARM_16K_TT_L3_SHIFT (14)
18 |
19 | #define ARM_TT_L1_SHIFT ARM_16K_TT_L1_SHIFT
20 | #define ARM_TT_L2_SHIFT ARM_16K_TT_L2_SHIFT
21 | #define ARM_TT_L3_SHIFT ARM_16K_TT_L3_SHIFT
22 |
23 | #define ARM_16K_TT_L1_INDEX_MASK (0x00007ff000000000)
24 | #define ARM_16K_TT_L2_INDEX_MASK (0x0000000ffe000000)
25 | #define ARM_16K_TT_L3_INDEX_MASK (0x0000000001ffc000)
26 |
27 | #define ARM_TT_L1_INDEX_MASK ARM_16K_TT_L1_INDEX_MASK
28 | #define ARM_TT_L2_INDEX_MASK ARM_16K_TT_L2_INDEX_MASK
29 | #define ARM_TT_L3_INDEX_MASK ARM_16K_TT_L3_INDEX_MASK
30 |
31 | #define ARM_PTE_NX (0x0040000000000000uLL)
32 | #define ARM_PTE_PNX (0x0020000000000000uLL)
33 |
34 | #define ARM_PTE_APMASK (0xc0uLL)
35 | #define ARM_PTE_AP(x) ((x) << 6)
36 |
37 | #define AP_RWNA (0x0) /* priv=read-write, user=no-access */
38 | #define AP_RWRW (0x1) /* priv=read-write, user=read-write */
39 | #define AP_RONA (0x2) /* priv=read-only, user=no-access */
40 | #define AP_RORO (0x3) /* priv=read-only, user=read-only */
41 | #define AP_MASK (0x3) /* mask to find ap bits */
42 |
43 | #endif
44 |
--------------------------------------------------------------------------------
/include/xnuspy/el1/tramp.h:
--------------------------------------------------------------------------------
1 | #ifndef TRAMP
2 | #define TRAMP
3 |
4 | #include
5 |
6 | void generate_original_tramp(uint64_t, uint32_t *, uint32_t *);
7 | void generate_replacement_tramp(uint32_t *);
8 |
9 | #endif
10 |
--------------------------------------------------------------------------------
/include/xnuspy/el1/utils.h:
--------------------------------------------------------------------------------
1 | #ifndef UTILS
2 | #define UTILS
3 |
4 | #include
5 | #include
6 |
7 | #include
8 |
9 | __attribute__ ((naked)) uint64_t current_thread(void);
10 | struct _vm_map *current_map(void);
11 | void vm_map_reference(void *);
12 |
13 | bool is_15_x(void);
14 | bool is_14_5_and_above(void);
15 | bool is_14_x_and_above(void);
16 | bool is_14_x_and_below(void);
17 | bool is_14_x(void);
18 | bool is_13_x(void);
19 |
20 | void *get_proc_list_mlock(void);
21 | void proc_list_lock(void);
22 | void proc_list_unlock(void);
23 |
24 | #endif
25 |
--------------------------------------------------------------------------------
/include/xnuspy/el1/wrappers.h:
--------------------------------------------------------------------------------
1 | #ifndef WRAPPERS
2 | #define WRAPPERS
3 |
4 | #include
5 |
6 | void ipc_port_release_send_wrapper(void *);
7 | kern_return_t vm_map_unwire_wrapper(void *, uint64_t, uint64_t, int);
8 | void *proc_ref_wrapper(void *, bool);
9 | int proc_rele_wrapper(void *, bool);
10 |
11 | #endif
12 |
--------------------------------------------------------------------------------
/include/xnuspy/el3/kpp.h:
--------------------------------------------------------------------------------
1 | #ifndef KPP
2 | #define KPP
3 |
4 | void patch_kpp(void);
5 |
6 | #endif
7 |
--------------------------------------------------------------------------------
/include/xnuspy/xnuspy_cache.h:
--------------------------------------------------------------------------------
1 | #ifndef XNUSPY_CACHE
2 | #define XNUSPY_CACHE
3 |
4 | #define SYSCTL__KERN_CHILDREN_PTR (0x0)
5 | #define SYSCTL_REGISTER_OID (0x8)
6 | #define SYSCTL_HANDLE_LONG (0x10)
7 | #define NAME2OID (0x18)
8 | #define SYSCTL_GEOMETRY_LOCK_PTR (0x20)
9 | #define LCK_RW_LOCK_SHARED (0x28)
10 | #define LCK_RW_DONE (0x30)
11 | #define DID_REGISTER_SYSCTL (0x38)
12 | #define H_S_C_SBN_EPILOGUE_ADDR (0x40)
13 | #define XNUSPY_SYSCTL_MIB_PTR (0x48)
14 | #define XNUSPY_SYSCTL_MIB_COUNT_PTR (0x50)
15 | #define XNUSPY_CTL_CALLNUM (0x58)
16 | #define IOS_VERSION (0x60)
17 | #define XNUSPY_CTL_ENTRYPOINT (0x68)
18 | #define XNUSPY_CTL_CODESTART (0x70)
19 | #define XNUSPY_CTL_CODESZ (0x78)
20 | #define XNUSPY_CTL_IS_RX (0x80)
21 | #define PHYSTOKV (0x88)
22 | #define BCOPY_PHYS (0x90)
23 |
24 | /* for kalloc/kfree, one of these will written to the cache depending
25 | * on iOS version
26 | */
27 | #define KALLOC_CANBLOCK (0x98)
28 | #define KALLOC_EXTERNAL (0x98)
29 |
30 | #define KFREE_ADDR (0xa0)
31 | #define KFREE_EXT (0xa0)
32 |
33 | #define iOS_13_x (19)
34 | #define iOS_14_x (20)
35 | #define iOS_15_x (21)
36 |
37 | #define KERN_VERSION_MINOR (0xa8)
38 |
39 | #endif
40 |
--------------------------------------------------------------------------------
/include/xnuspy/xnuspy_ctl.h:
--------------------------------------------------------------------------------
1 | #ifndef XNUSPY_CTL
2 | #define XNUSPY_CTL
3 |
4 | #include
5 |
6 | /* Flavors for xnuspy_ctl */
7 | enum {
8 | XNUSPY_CHECK_IF_PATCHED = 0,
9 | XNUSPY_INSTALL_HOOK,
10 | XNUSPY_REGISTER_DEATH_CALLBACK,
11 | XNUSPY_CALL_HOOKME,
12 | XNUSPY_CACHE_READ,
13 | XNUSPY_KREAD,
14 | XNUSPY_KWRITE,
15 | XNUSPY_GET_CURRENT_THREAD,
16 | #ifdef XNUSPY_PRIVATE
17 | XNUSPY_MAX_FLAVOR = XNUSPY_GET_CURRENT_THREAD,
18 | #endif
19 | };
20 |
21 | /* Values for XNUSPY_CACHE_READ - keep this alphabetical so it's
22 | * easier to find things */
23 |
24 | #ifdef XNUSPY_PRIVATE
25 | enum xnuspy_cache_id {
26 | #else
27 | enum {
28 | #endif
29 | /* struct proclist allproc @ bsd/sys/proc_internal.h */
30 | ALLPROC = 0,
31 | BCOPY_PHYS,
32 | BZERO,
33 | COPYIN,
34 | COPYINSTR,
35 | COPYOUT,
36 |
37 | /* Idential to XNU's implementation */
38 | CURRENT_MAP,
39 |
40 | CURRENT_PROC,
41 |
42 | /* Only valid for iOS 14.5 - iOS 14.8, inclusive. EINVAL will be
43 | * returned otherwise. */
44 | IO_LOCK,
45 |
46 | /* Only valid for iOS 15.x. EINVAL will be returned otherwise. */
47 | IPC_OBJECT_LOCK,
48 |
49 | IOLOG,
50 | IOSLEEP,
51 |
52 | /* Only valid for < iOS 14.5. EINVAL will be returned otherwise. */
53 | IPC_PORT_RELEASE_SEND,
54 |
55 | /* Only valid for >= iOS 14.5. EINVAL will be returned otherwise. */
56 | IPC_PORT_RELEASE_SEND_AND_UNLOCK,
57 |
58 | /* Selects the correct way to release a send right based on the
59 | * kernel version. Parameters are the same as XNU's
60 | * ipc_port_release_send. */
61 | IPC_PORT_RELEASE_SEND_WRAPPER,
62 |
63 | /* Only valid for iOS 13.x. EINVAL will be returned otherwise. */
64 | KALLOC_CANBLOCK,
65 |
66 | /* Only valid for iOS 14.x and iOS 15.x. EINVAL will be returned
67 | * otherwise. */
68 | KALLOC_EXTERNAL,
69 |
70 | /* vm_map_t kernel_map @ osfmk/vm/vm_kern.h */
71 | KERNEL_MAP,
72 |
73 | KERNEL_THREAD_START,
74 |
75 | /* Only valid for iOS 13.x. EINVAL will be returned otherwise. */
76 | KFREE_ADDR,
77 |
78 | /* Only valid for iOS 14.x and iOS 15.x. EINVAL will be returned
79 | * otherwise. */
80 | KFREE_EXT,
81 |
82 | KPRINTF,
83 | LCK_GRP_ALLOC_INIT,
84 | LCK_GRP_FREE,
85 | LCK_MTX_LOCK,
86 | LCK_MTX_UNLOCK,
87 | LCK_RW_ALLOC_INIT,
88 | LCK_RW_DONE,
89 | LCK_RW_FREE,
90 | LCK_RW_LOCK_EXCLUSIVE,
91 | LCK_RW_LOCK_SHARED,
92 | LCK_RW_LOCK_SHARED_TO_EXCLUSIVE,
93 | MACH_MAKE_MEMORY_ENTRY_64,
94 | MACH_TO_BSD_ERRNO,
95 | MACH_VM_MAP_EXTERNAL,
96 | MEMCHR,
97 | MEMCMP,
98 | MEMMEM,
99 | MEMMOVE,
100 | MEMRCHR,
101 | MEMSET,
102 | PANIC,
103 | PHYSTOKV,
104 |
105 | /* Selects the correct way to take proc_list_mlock based
106 | * on the kernel version.
107 | *
108 | * void proc_list_lock(void);
109 | *
110 | */
111 | PROC_LIST_LOCK,
112 |
113 | /* lck_mtx_t *proc_list_mlock @ bsd/sys/proc_internal.h */
114 | PROC_LIST_MLOCK,
115 |
116 | /* Selects the correct way to release proc_list_mlock based
117 | * on the kernel version.
118 | *
119 | * void proc_list_unlock(void);
120 | *
121 | */
122 | PROC_LIST_UNLOCK,
123 |
124 | PROC_NAME,
125 | PROC_PID,
126 |
127 | /* Only valid for 15.x. EINVAL will be returned otherwise.
128 | * Until 15 sources come out, here's what I think the function
129 | * signature is:
130 | *
131 | * proc_t proc_ref(proc_t proc, bool holding_proc_list_mlock);
132 | *
133 | * You can find a call to it in proc_exit. It looks like it is good
134 | * practice to make sure the returned proc pointer was the same one
135 | * as you passed in. Not sure what the return value being different
136 | * than the first parameter indicates... */
137 | PROC_REF,
138 |
139 | /* Only valid for 13.x and 14.x. EINVAL will be returned otherwise.
140 | * This function assumes the caller holds proc_list_mlock. */
141 | PROC_REF_LOCKED,
142 |
143 | /* Selects the correct way to take a reference on a proc structure
144 | * based on the kernel version.
145 | *
146 | * void *proc_ref_wrapper(void *proc, bool holding_proc_list_mlock);
147 | *
148 | * If you are on iOS 13.x or iOS 14.x and you pass false for the
149 | * second parameter, this function takes proc_list_mlock before
150 | * calling proc_ref_locked and releases it after that returns. If
151 | * you are on iOS 15.x, this tail calls proc_ref. Return value
152 | * is either the return value of proc_ref or proc_ref_locked. */
153 | PROC_REF_WRAPPER,
154 |
155 | /* Only valid for 15.x. EINVAL will be returned otherwise.
156 | * This function assumes the caller DOES NOT hold proc_list_mlock,
157 | * though I'm not sure if it's safe to hold that mutex and call this
158 | * function.
159 | * Until 15 sources come out, here's the function signature:
160 | *
161 | * int proc_rele(proc_t proc);
162 | *
163 | * Seems to always return 0. */
164 | PROC_RELE,
165 |
166 | /* Only valid for 13.x and 14.x. EINVAL will be returned otherwise.
167 | * This function assumes the caller holds proc_list_mlock. */
168 | PROC_RELE_LOCKED,
169 |
170 | /* Selects the correct way to release a reference on a proc structure
171 | * based on the kernel version.
172 | *
173 | * int proc_rele_wrapper(void *proc, bool holding_proc_list_mlock);
174 | *
175 | * If you are on iOS 13.x or iOS 14.x and you pass false for the
176 | * second parameter, this function takes proc_list_mlock before
177 | * calling proc_rele_locked and releases it after that returns. If
178 | * you are on iOS 15.x, this tail calls proc_rele and the second
179 | * parameter is ignored. Return value is either the return value
180 | * of proc_ref (for iOS 15.x) or zero (for iOS 13.x and iOS 14.x) */
181 | PROC_RELE_WRAPPER,
182 |
183 | PROC_UNIQUEID,
184 | SNPRINTF,
185 | STRCHR,
186 | STRRCHR,
187 | STRCMP,
188 | STRLEN,
189 | STRNCMP,
190 | STRSTR,
191 | STRNSTR,
192 | THREAD_DEALLOCATE,
193 | THREAD_TERMINATE,
194 | VM_ALLOCATE_EXTERNAL,
195 | VM_DEALLOCATE,
196 | VM_MAP_DEALLOCATE,
197 |
198 | /* Identical to XNU's implementation */
199 | VM_MAP_REFERENCE,
200 |
201 | /* Only valid for 13.x and 14.x. EINVAL will be returned otherwise. */
202 | VM_MAP_UNWIRE,
203 |
204 | /* Only valid for 15.x. EINVAL will be returned otherwise. */
205 | VM_MAP_UNWIRE_NESTED,
206 |
207 | /* Selects the correct way to unwire a vm_map based on the
208 | * kernel version. Parameters are the same as XNU's vm_map_unwire. */
209 | VM_MAP_UNWIRE_WRAPPER,
210 |
211 | VM_MAP_WIRE_EXTERNAL,
212 |
213 | /* --------------------------------------------
214 | * Everything above (with the exception of the small wrapper functions)
215 | * is from XNU, everything below are things from xnuspy you may
216 | * find useful
217 | * ---------------------------------------------
218 | */
219 |
220 | /* uint64_t *el0_ptep(void *uaddr)
221 | *
222 | * Given a user virtual address, this function returns a pointer to its
223 | * page table entry.
224 | *
225 | * Parameters:
226 | * uaddr: user virtual address.
227 | *
228 | * Returns:
229 | * Kernel virtual address of page table entry for uaddr.
230 | */
231 | EL0_PTEP,
232 |
233 | /* uint64_t *el1_ptep(void *kaddr)
234 | *
235 | * Given a kernel virtual address, this function returns a pointer to its
236 | * page table entry.
237 | *
238 | * Parameters:
239 | * kaddr: kernel virtual address.
240 | *
241 | * Returns:
242 | * Kernel virtual address of page table entry for kaddr.
243 | */
244 | EL1_PTEP,
245 |
246 | /* void hookme(void *arg)
247 | *
248 | * This function is a stub for you to hook to easily gain kernel code
249 | * execution without having to hook an actual kernel function. You can
250 | * get xnuspy to call it by invoking xnuspy_ctl with the
251 | * XNUSPY_CALL_HOOKME flavor.
252 | */
253 | HOOKME,
254 |
255 | /* uint64_t iOS_version
256 | *
257 | * This variable contains the major from the "Darwin Kernel Version"
258 | * string. On iOS 13.x, this is 19, on iOS 14.x, this is 20, and
259 | * on iOS 15.x, this is 21. */
260 | IOS_VERSION,
261 |
262 | /* uint64_t kernel_slide
263 | *
264 | * KASLR slide */
265 | KERNEL_SLIDE,
266 |
267 | /* uint64_t kern_version_minor
268 | *
269 | * This variable contains the minor from the "Darwin Kernel Version"
270 | * string. */
271 | KERN_VERSION_MINOR,
272 |
273 | /* int kprotect(void *kaddr, uint64_t size, vm_prot_t prot)
274 | *
275 | * Change protections of kernel memory at the page table level.
276 | * You are allowed to make writable, executable memory.
277 | *
278 | * Parameters:
279 | * kaddr: kernel virtual address of target.
280 | * size: the number of bytes in the target region.
281 | * prot: protections to apply. Only VM_PROT_READ, VM_PROT_WRITE, and
282 | * VM_PROT_EXECUTE are respected.
283 | *
284 | * Returns:
285 | * Zero if successful, non-zero otherwise.
286 | */
287 | KPROTECT,
288 |
289 | /* uint64_t kvtophys(uint64_t kaddr)
290 | *
291 | * Convert a kernel (EL1) virtual address to a physical address.
292 | *
293 | * Parameters:
294 | * kaddr: kernel virtual address.
295 | *
296 | * Returns:
297 | * Non-zero if address translation was successful, zero otherwise.
298 | */
299 | KVTOPHYS,
300 |
301 | /* void kwrite_instr(uint64_t addr, uint32_t instr)
302 | *
303 | * Patch a single instruction of executable kernel code. This function
304 | * handles permissions, data cache cleaning, and instruction cache
305 | * invalidation.
306 | *
307 | * Parameters:
308 | * addr: kernel virtual address.
309 | * instr: new instruction for addr.
310 | */
311 | KWRITE_INSTR,
312 |
313 | /* void kwrite_static(void *dst, void *buf, size_t sz)
314 | *
315 | * Write to static kernel memory, using bcopy_phys.
316 | *
317 | * Parameters:
318 | * dst: kernel virtual address of destination.
319 | * buf: kernel virtual address of data.
320 | * sz: how many bytes 'buf' is.
321 | */
322 | KWRITE_STATIC,
323 |
324 | /* The next three functions deal with shared memory. KTOU ("kernel to
325 | * user") and UTOK ("user to kernel") specify the "direction". "a to b",
326 | * where and are both vm_map pointers, means pages from will
327 | * be mapped into as shared memory. Pages from must have been
328 | * allocated via vm_allocate for these functions to succeed. KTOU and UTOK
329 | * automatically select the and vm_map pointers for convenience.
330 | * The RAW variant allows you to specify the and vm_map pointers.
331 | * You would use mkshmem_raw when you are unsure of current_task()->map
332 | * or the current CPU's TTBR0 inside your kernel code.
333 | *
334 | * int mkshmem_ktou(uint64_t kaddr, uint64_t sz, vm_prot_t prot,
335 | * struct xnuspy_shmem *shmemp);
336 | * int mkshmem_utok(uint64_t uaddr, uint64_t sz, vm_prot_t prot,
337 | * struct xnuspy_shmem *shmemp);
338 | * int mkshmem_raw(uint64_t addr, uint64_t sz, vm_prot_t prot,
339 | * vm_map_t from, vm_map_t to, struct xnuspy_shmem *shmemp);
340 | *
341 | * Parameters (for all three):
342 | * kaddr/uaddr/addr: virtual address somewhere inside
343 | * sz: page aligned mapping size
344 | * prot: virtual protections to apply to the created
345 | * shared mapping
346 | * shmemp: returned shmem. The structure definition can
347 | * be found at the end of this file.
348 | *
349 | * Parameters specific to mkshmem_raw:
350 | * from: source map, aka
351 | * to: destination map, aka
352 | *
353 | * Returns (for all three):
354 | * Zero on success (and populated shmemp structure), non-zero BSD errno
355 | * on failure.
356 | *
357 | * Other notes:
358 | * These functions use kprotect to apply VM protections, so any
359 | * combination of those are allowed. VM protections are only applied
360 | * to the newly-created mapping, not the source pages that came
361 | * from .
362 | */
363 | MKSHMEM_KTOU,
364 | MKSHMEM_UTOK,
365 | MKSHMEM_RAW,
366 |
367 | /* offsetof(struct thread, map), vm_map_t */
368 | OFFSETOF_STRUCT_THREAD_MAP,
369 |
370 | /* offsetof(struct _vm_map, map_refcnt), int (yes, int) */
371 | OFFSETOF_STRUCT_VM_MAP_REFCNT,
372 |
373 | /* int shmem_destroy(struct xnuspy_shmem *shmemp);
374 | *
375 | * Destory shared memory returned by mkshmem_ktou, mkshmem_utok, or
376 | * mkshmem_raw.
377 | *
378 | * Parameters:
379 | * shmemp: pointer to shmem structure
380 | *
381 | * Returns:
382 | * Zero on success, non-zero BSD errno on failure.
383 | */
384 | SHMEM_DESTROY,
385 |
386 | /* void tlb_flush(void)
387 | *
388 | * After modifying a page table, call this function to invalidate
389 | * the TLB.
390 | */
391 | TLB_FLUSH,
392 |
393 | /* The next two functions abstract away the different kalloc/kfree pairs
394 | * for different iOS versions and keeps track of allocation sizes. This
395 | * creates an API like malloc/free. Pointers returned from unified_kalloc
396 | * can only be freed with unified_kfree, and pointers returned by other
397 | * memory allocation functions cannot be freed with unified_kfree.
398 | *
399 | * uint8_t *buf = unified_kalloc(0x200);
400 | *
401 | * if(!buf)
402 | *
403 | *
404 | * buf[0] = '\0';
405 | *
406 | * unified_kfree(buf);
407 | *
408 | * -------------------------------
409 | *
410 | * void *unified_kalloc(size_t sz)
411 | *
412 | * Parameters:
413 | * sz: allocation size.
414 | *
415 | * Returns:
416 | * Upon success, a pointer to memory. If we are on 13.x, kalloc_canblock's
417 | * canblock parameter is false. Upon failure, NULL.
418 | *
419 | * -------------------------------
420 | *
421 | * void unified_kfree(void *ptr)
422 | *
423 | * Parameters:
424 | * ptr: a pointer returned from unified_kalloc.
425 | */
426 | UNIFIED_KALLOC,
427 | UNIFIED_KFREE,
428 |
429 | /* int uprotect(void *uaddr, uint64_t size, vm_prot_t prot)
430 | *
431 | * Change protections of user memory at the page table level.
432 | * You are allowed to make writable, executable memory.
433 | *
434 | * Parameters:
435 | * uaddr: user virtual address of target.
436 | * size: the number of bytes in the target region.
437 | * prot: protections to apply. Only VM_PROT_READ, VM_PROT_WRITE, and
438 | * VM_PROT_EXECUTE are respected.
439 | *
440 | * Returns:
441 | * Zero if successful, non-zero otherwise.
442 | */
443 | UPROTECT,
444 |
445 | /* uint64_t uvtophys(uint64_t uaddr)
446 | *
447 | * Convert a user (EL0) virtual address to a physical address.
448 | *
449 | * Parameters:
450 | * uaddr: user virtual address.
451 | *
452 | * Returns:
453 | * Non-zero if address translation was successful, zero otherwise.
454 | */
455 | UVTOPHYS,
456 |
457 | #ifdef XNUSPY_PRIVATE
458 | MAX_CACHE = UVTOPHYS,
459 | #endif
460 | };
461 |
462 | #define iOS_13_x (19)
463 | #define iOS_14_x (20)
464 | #define iOS_15_x (21)
465 |
466 | /* Structures for locks that work in both kernelspace and userspace.
467 | * Any locks you declare must be declared globally so they
468 | * are mapped as shared memory when you install your kernel hooks */
469 | /* kuslck_t: a simple spinlock */
470 | typedef struct {
471 | uint32_t word;
472 | } kuslck_t;
473 |
474 | #define KUSLCK_UNLOCKED (0)
475 | #define KUSLCK_LOCKED (1)
476 |
477 | /* kuslck_t lck = KUSLCK_INITIALIZER; */
478 | #define KUSLCK_INITIALIZER { .word = KUSLCK_UNLOCKED }
479 |
480 | #define kuslck_lock(lck) \
481 | do { \
482 | while(__atomic_exchange_n(&(lck).word, KUSLCK_LOCKED, \
483 | __ATOMIC_ACQ_REL) == 0){} \
484 | } while (0) \
485 |
486 | #define kuslck_unlock(lck) \
487 | do { \
488 | __atomic_store_n(&(lck).word, KUSLCK_UNLOCKED, __ATOMIC_RELEASE); \
489 | } while (0) \
490 |
491 | struct xnuspy_shmem {
492 | /* Base of shared memory */
493 | void *shm_base;
494 | /* Size of shared memory, page multiple */
495 | uint64_t shm_sz;
496 | #ifdef XNUSPY_PRIVATE
497 | /* Memory entry for the shared memory, ipc_port_t */
498 | void *shm_entry;
499 | /* The vm_map_t which the source pages belong to */
500 | void *shm_map_from;
501 | /* The vm_map_t which the source pages were mapped into */
502 | void *shm_map_to;
503 | #else
504 | void *opaque[3];
505 | #endif
506 | };
507 |
508 | #endif
509 |
--------------------------------------------------------------------------------
/include/xnuspy/xnuspy_structs.h:
--------------------------------------------------------------------------------
1 | #ifndef XNUSPY_STRUCTS
2 | #define XNUSPY_STRUCTS
3 |
4 | #include
5 |
6 | struct stailq_entry {
7 | void *elem;
8 | STAILQ_ENTRY(stailq_entry) link;
9 | };
10 |
11 | struct slist_entry {
12 | void *elem;
13 | SLIST_ENTRY(slist_entry) link;
14 | };
15 |
16 | /* struct xnuspy_shmem { */
17 | /* /1* Base of shared memory *1/ */
18 | /* void *shm_base; */
19 | /* /1* Size of shared memory, page multiple *1/ */
20 | /* uint64_t shm_sz; */
21 | /* /1* Memory entry for the shared memory, ipc_port_t *1/ */
22 | /* void *shm_entry; */
23 | /* /1* The vm_map_t which the source pages belong to *1/ */
24 | /* void *shm_map_from; */
25 | /* /1* The vm_map_t which the source pages were mapped into *1/ */
26 | /* void *shm_map_to; */
27 | /* }; */
28 |
29 | #define MAX_MAPPING_REFERENCES (0x1000000)
30 |
31 | /* This structure represents a shared __TEXT and __DATA mapping. There could
32 | * be a number of these structures per-process because different dynamic
33 | * libraries loaded into the address space of one process can install
34 | * hooks. */
35 | struct xnuspy_mapping {
36 | /* Reference count for this mapping, NOT the mapping metadata */
37 | _Atomic int64_t refcnt;
38 | /* Pointer to caller's Mach-O header */
39 | uint64_t mapping_addr_uva;
40 | /* Death callback to invoke when refcnt hits zero */
41 | void (*death_callback)(void);
42 | /* Kernel's mapping of the shared __TEXT and __DATA. This has
43 | * to be a pointer so I can easily enqueue it onto the unmaplist */
44 | struct xnuspy_shmem *segment_shmem;
45 | };
46 |
47 | /* This structure maintains all shared mappings for a given process. There
48 | * is one of these per-process. This will be deallocated when the mappings
49 | * linked list is empty. */
50 | struct xnuspy_mapping_metadata {
51 | /* Process which owns all of the mappings managed by this structure
52 | * (p_uniqueid) */
53 | uint64_t owner;
54 | /* Linked list of all shared mappings we've created for this process.
55 | * Protected by xnuspy_rw_lck. */
56 | SLIST_HEAD(, slist_entry) mappings;
57 | };
58 |
59 | /* This structure contains information for an xnuspy_tramp that isn't
60 | * necessary to keep in the struct itself. I do this to save space. These are
61 | * not reference counted because they're per-hook. */
62 | struct xnuspy_tramp_metadata {
63 | /* Hooked kernel function */
64 | uint64_t hooked;
65 | /* Overwritten instruction */
66 | uint32_t orig_instr;
67 | };
68 |
69 | /* This structure represents a function hook. Every xnuspy_tramp struct resides
70 | * on writeable, executable memory. */
71 | struct xnuspy_tramp {
72 | /* Kernel virtual address of userland replacement on shared mapping */
73 | uint64_t replacement;
74 | /* The trampoline for a hooked function. When the user installs a hook
75 | * on a function, the first instruction of that function is replaced
76 | * with a branch to here. An xnuspy trampoline looks like this:
77 | * tramp[0] LDR X16, #-0x8 (replacement)
78 | * tramp[1] BR X16
79 | */
80 | uint32_t tramp[2];
81 | /* An abstraction that represents the original function. It's just another
82 | * trampoline, but it can take on one of seven forms. The most common
83 | * form is this:
84 | * orig[0]
85 | * orig[1] LDR X16, #0x8
86 | * orig[2] BR X16
87 | * orig[3] [31:0]
88 | * orig[4] [63:32]
89 | *
90 | * The above form is taken when the original first instruction of the hooked
91 | * function is not an immediate conditional branch (b.cond), an immediate
92 | * compare and branch (cbz/cbnz), an immediate test and branch (tbz/tbnz),
93 | * an immediate unconditional branch (b), an immediate unconditional
94 | * branch with link (bl), load register (literal), or an ADR. These are
95 | * special cases because the immediates do not contain enough bits for me
96 | * to just "fix up" or assume we'll always be in range once we do, so I
97 | * need to emit an equivalent sequence of instructions.
98 | *
99 | * If the first instruction was B.cond