@@ -169,6 +169,7 @@ static void kpf_kernel_version_init(xnu_pf_range_t *text_const_range)
169
169
// Imports from shellcode.S
170
170
extern uint32_t sandbox_shellcode [], sandbox_shellcode_setuid_patch [], sandbox_shellcode_ptrs [], sandbox_shellcode_end [];
171
171
extern uint32_t launchd_execve_hook [], launchd_execve_hook_ptr [], launchd_execve_hook_offset [], launchd_execve_hook_pagesize [], launchd_execve_hook_mach_vm_allocate_kernel [];
172
+ extern uint32_t proc_set_syscall_filter_mask_shc [], proc_set_syscall_filter_mask_shc_target [], zalloc_ro_mut [];
172
173
173
174
uint32_t * _mac_mount = NULL ;
174
175
bool kpf_has_done_mac_mount = false;
@@ -798,25 +799,63 @@ bool vnode_lookup_callback(struct xnu_pf_patch* patch, uint32_t* opcode_stream)
798
799
return true;
799
800
}
800
801
802
+ uint32_t * _proc_set_syscall_filter_mask = NULL ;
803
+ uint32_t * protobox_patchpoint = NULL ;
804
+
801
805
bool kpf_protobox_callback (struct xnu_pf_patch * patch , uint32_t * opcode_stream )
802
806
{
803
- uint32_t adrp1 = opcode_stream [0 ],
804
- add1 = opcode_stream [1 ];
805
- const char * str1 = (const char * )(((uint64_t )(opcode_stream ) & ~0xfffULL ) + adrp_off (adrp1 ) + ((add1 >> 10 ) & 0xfff ));
806
-
807
- uint32_t adrp2 = opcode_stream [4 ],
808
- add2 = opcode_stream [5 ];
809
- const char * str2 = (const char * )(((uint64_t )(opcode_stream ) & ~0xfffULL ) + adrp_off (adrp2 ) + ((add2 >> 10 ) & 0xfff ));
810
-
811
- if (!strcmp (str1 , "Restore" ) && !strcmp (str2 , "Darwin" )) {
812
- // Make protobox think this device is in "Restore" mode
813
- // This will disable protobox
814
- opcode_stream [2 ] = 0xD2800020 ; // mov x0, #1
815
- printf ("KPF: Found and patched protobox check @ 0x%" PRIx64 "\n" , xnu_ptr_to_va (opcode_stream ));
816
- return true;
807
+ uint32_t * b = find_next_insn (opcode_stream , 0x10 , 0x14000000 , 0xfc000000 ); // b proc_set_syscall_filter_mask
808
+ if (!b ) {
809
+ panic_at (opcode_stream , "kpf_protobox: Failed to find b proc_set_syscall_filter_mask" );
817
810
}
818
811
819
- return false;
812
+ uint32_t * proc_set_syscall_filter_mask = follow_call (b );
813
+ uint32_t * stackframe = find_prev_insn (opcode_stream - 1 , 0x20 , 0xa9007bfd , 0xffc07fff ); // stp x29, x30, [sp, ...]
814
+ if (!stackframe )
815
+ {
816
+ panic_at (opcode_stream , "kpf_protobox: Failed to find stack frame" );
817
+ }
818
+
819
+ uint32_t * start = find_prev_insn (stackframe - 1 , 8 , 0xd10003ff , 0xffc003ff ); // sub sp, sp, ...
820
+ if (!start ) {
821
+ start = find_prev_insn (stackframe , 10 , 0xa9a003e0 , 0xffe003e0 ); // stp xN, xM, [sp, -0x...]!
822
+ }
823
+
824
+ if (!start ) {
825
+ panic_at (stackframe , "kpf_protobox: Failed to find start of function" );
826
+ }
827
+
828
+ uint32_t * bl = find_prev_insn (opcode_stream , 6 , 0x94000000 , 0xfc000000 ); // bl zone_require_ro
829
+ if (!bl ) {
830
+ panic_at (opcode_stream , "kpf_protobox: Failed to find zone_require_ro" );
831
+ }
832
+
833
+ * bl = 0xaa0003f1 ; // mov x17, x0
834
+
835
+ _proc_set_syscall_filter_mask = proc_set_syscall_filter_mask ;
836
+
837
+ protobox_patchpoint = b ;
838
+
839
+ printf ("KPF: found protobox\n" );
840
+ return true;
841
+ }
842
+
843
+ bool kpf_filter_mismatch_callback (struct xnu_pf_patch * patch , uint32_t * opcode_stream ) {
844
+ opcode_stream [0 ] = 0x14000000 | sxt32 (opcode_stream [0 ] >> 5 , 19 ); // cbz -> b
845
+ printf ("KPF: found syscall filter mismatch\n" );
846
+ return true;
847
+ }
848
+
849
+ uint32_t * _zalloc_ro_mut = NULL ;
850
+ bool kpf_zalloc_ro_mut_callback (struct xnu_pf_patch * patch , uint32_t * opcode_stream ) {
851
+ uint32_t * _zalloc_ro_mut_candidate = follow_call (& opcode_stream [6 ]);
852
+ if (!_zalloc_ro_mut ) _zalloc_ro_mut = _zalloc_ro_mut_candidate ;
853
+ if (_zalloc_ro_mut != _zalloc_ro_mut_candidate ) {
854
+ panic ("kpf_zalloc_ro_mut: Found multiple zalloc_ro_mut candidates" );
855
+ }
856
+
857
+ puts ("KPF: Found zalloc_ro_mut" );
858
+ return true;
820
859
}
821
860
822
861
void kpf_find_shellcode_funcs (xnu_pf_patchset_t * xnu_text_exec_patchset ) {
@@ -868,6 +907,29 @@ void kpf_find_shellcode_funcs(xnu_pf_patchset_t* xnu_text_exec_patchset) {
868
907
0xffffffff
869
908
};
870
909
xnu_pf_maskmatch (xnu_text_exec_patchset , "ret0_gadget" , iiii_matches , iiii_masks , sizeof (iiii_masks )/sizeof (uint64_t ), true, (void * )ret0_gadget_callback );
910
+
911
+ // find mac label related calls to zalloc_ro_mut
912
+ uint64_t zalloc_ro_mut_matches [] = {
913
+ 0x90000003 , // adrp x3, ...
914
+ 0x91000063 , // add x3, x3, ...
915
+ 0x52800080 , // mov w0, #0x4
916
+ 0xaa1003e1 , // mov x1, x{16-31}
917
+ 0xd2800002 , // mov x2, #0x0
918
+ 0x52800404 , // mov w4, #0x20
919
+ 0x94000000 // bl zalloc_ro_mut
920
+ };
921
+
922
+ uint64_t zalloc_ro_mut_masks [] = {
923
+ 0x9f00001f ,
924
+ 0xffc003ff ,
925
+ 0xffffffff ,
926
+ 0xfff0ffff ,
927
+ 0xffffffff ,
928
+ 0xffffffff ,
929
+ 0xfc000000
930
+ };
931
+
932
+ xnu_pf_maskmatch (xnu_text_exec_patchset , "zalloc_ro_mut" , zalloc_ro_mut_matches , zalloc_ro_mut_masks , sizeof (zalloc_ro_mut_matches ) / sizeof (uint64_t ), false, (void * )kpf_zalloc_ro_mut_callback );
871
933
}
872
934
873
935
static bool found_mach_traps = false;
@@ -1741,32 +1803,30 @@ void kpf_sandbox_kext_patches(xnu_pf_patchset_t* patchset, bool protobox_used) {
1741
1803
};
1742
1804
xnu_pf_maskmatch (patchset , "vnode_lookup" , matches , masks , sizeof (masks )/sizeof (uint64_t ), true, (void * )vnode_lookup_callback );
1743
1805
1744
- // Protobox on is an additional sandbox mechanism in iOS 16+ that introduces syscall masks, which is used to have syscall whitelists on some system processes
1745
- // When injecting into them or using something like Frida, it can prevent certain functionality
1746
- // Additionally it makes these processes crash on sandbox violations, meaning that calling even something simple like mach_thread_self in watchdogd will crash the process
1747
- // We disable it by making the code that enables it think the device is in Restore mode, as this check involves calling is_release_type with a string it's easy to find
1806
+ // /x 0800009008010091081970f8030140b9e00300aae10300aae20300aa:1f00009fff03c0ffff1ff0ffffffffffffffe0ffffffe0ffffffe0ff
1807
+ // iOS 15.4+
1748
1808
if (protobox_used ) {
1749
1809
uint64_t protobox_matches [] = {
1750
- 0x90000000 , // adrp x0, "Restore"@PAGE
1751
- 0x91000000 , // add x0, "Restore"@PAGEOFF
1752
- 0x94000000 , // bl _is_release_type
1753
- 0x37000000 , // tbnz w0, #0, ???
1754
- 0x90000000 , // adrp x0, "Darwin"@PAGE
1755
- 0x91000000 , // add x0, "Darwin"@PAGEOFF
1756
- 0x94000000 , // bl _is_release_type
1757
- 0x36000000 , // tb(n)z w0, #0, ???
1810
+ 0x90000008 , // adrp x8, ...
1811
+ 0x91000108 , // add, x8, x8
1812
+ 0xf8701908 , // ldr x8, [x8, w{16-31}, ... #0x3]
1813
+ 0xb9400103 , // ldr w3, [x8]
1814
+ 0xaa0003e0 , // mov x0, x{16-31}
1815
+ 0xaa0003e1 , // mov x1, x{16-31}
1816
+ 0xaa0003e2 // mov x2, x{16-31}
1758
1817
};
1818
+
1759
1819
uint64_t protobox_masks [] = {
1760
1820
0x9f00001f ,
1761
- 0xff8003ff ,
1762
- 0xfc000000 ,
1763
- 0xff00001f ,
1764
- 0x9f00001f ,
1765
- 0xff8003ff ,
1766
- 0xfc000000 ,
1767
- 0xfe00001f ,
1821
+ 0xffc003ff ,
1822
+ 0xfff01fff ,
1823
+ 0xffffffff ,
1824
+ 0xffe0ffff ,
1825
+ 0xffe0ffff ,
1826
+ 0xffe0ffff
1768
1827
};
1769
- xnu_pf_maskmatch (patchset , "protobox" , protobox_matches , protobox_masks , sizeof (protobox_masks )/sizeof (uint64_t ), true, (void * )kpf_protobox_callback );
1828
+
1829
+ xnu_pf_maskmatch (patchset , "protobox" , protobox_matches , protobox_masks , sizeof (protobox_masks ) / sizeof (uint64_t ), true, (void * )kpf_protobox_callback );
1770
1830
}
1771
1831
}
1772
1832
@@ -2466,20 +2526,17 @@ static void kpf_cmd(const char *cmd, char *args)
2466
2526
if (!protobox_string_range ) protobox_string_range = text_cstring_range ;
2467
2527
2468
2528
const char protobox_string [] = "(apply-protobox)" ;
2469
- const char * protobox_string_match = memmem (protobox_string_range -> cacheable_base , protobox_string_range -> size , protobox_string , sizeof (protobox_string ) - 1 );
2529
+ const char * protobox_string_match = memmem (protobox_string_range -> cacheable_base , protobox_string_range -> size , protobox_string , sizeof (protobox_string )- 1 );
2470
2530
2471
2531
#ifdef DEV_BUILD
2472
2532
// 15.0 beta 3 and later, except bridgeOS
2473
2533
if ((gKernelVersion .xnuMajor >= 8019 && (xnu_platform () != PLATFORM_BRIDGEOS )) != (protobox_string_match != NULL )) {
2474
2534
panic ("Protobox string doesn't match expected Darwin version" );
2475
2535
}
2476
2536
#endif
2537
+ bool protobox_used = (protobox_string_match != NULL && gKernelVersion .xnuMajor >= 8792 );
2477
2538
2478
- // 16.0 beta 1 and later
2479
- const char constraints_string [] = "mac_proc_check_launch_constraints" ;
2480
- const char * constraints_string_match = memmem (text_cstring_range -> cacheable_base , text_cstring_range -> size , constraints_string , sizeof (constraints_string ));
2481
-
2482
- kpf_sandbox_kext_patches (sandbox_patchset , (protobox_string_match != NULL ) && (constraints_string_match != NULL ));
2539
+ kpf_sandbox_kext_patches (sandbox_patchset , protobox_used );
2483
2540
xnu_pf_emit (sandbox_patchset );
2484
2541
xnu_pf_apply (sandbox_text_exec_range , sandbox_patchset );
2485
2542
xnu_pf_patchset_destroy (sandbox_patchset );
@@ -2564,7 +2621,6 @@ static void kpf_cmd(const char *cmd, char *args)
2564
2621
if (!vfs_context_current ) panic ("Missing patch: vfs_context_current" );
2565
2622
if (!kpf_has_done_mac_mount ) panic ("Missing patch: mac_mount" );
2566
2623
2567
-
2568
2624
if (!has_found_apfs_vfsop_mount && apfs_vfsop_mount_string_match != NULL ) {
2569
2625
if (palera1n_flags & palerain_option_rootful ) {
2570
2626
panic ("Missing patch: apfs_vfsop_mount" );
@@ -2689,6 +2745,29 @@ static void kpf_cmd(const char *cmd, char *args)
2689
2745
delta |= 0x94000000 ;
2690
2746
* mac_execve_hook = delta ;
2691
2747
}
2748
+
2749
+ if (protobox_used ) {
2750
+ if (!_zalloc_ro_mut ) panic ("Missing patch: zalloc_ro_mut" );
2751
+
2752
+ uint32_t * repatch_proc_set_syscall_filter_mask_shc = (uint32_t * )(proc_set_syscall_filter_mask_shc - shellcode_from + shellcode_to );
2753
+ uint32_t * repatch_proc_set_syscall_filter_mask_shc_target = (uint32_t * )(proc_set_syscall_filter_mask_shc_target - shellcode_from + shellcode_to );
2754
+ uint32_t * repatch_zalloc_ro_mut = (uint32_t * )(zalloc_ro_mut - shellcode_from + shellcode_to );
2755
+
2756
+ uint32_t delta = (& repatch_proc_set_syscall_filter_mask_shc [0 ]) - protobox_patchpoint ;
2757
+ delta &= 0x03ffffff ;
2758
+ delta |= 0x14000000 ;
2759
+ * protobox_patchpoint = delta ;
2760
+
2761
+ delta = (& _proc_set_syscall_filter_mask [0 ]) - repatch_proc_set_syscall_filter_mask_shc_target ;
2762
+ delta &= 0x03ffffff ;
2763
+ delta |= 0x14000000 ;
2764
+ * repatch_proc_set_syscall_filter_mask_shc_target = delta ;
2765
+
2766
+ delta = (& _zalloc_ro_mut [0 ]) - repatch_zalloc_ro_mut ;
2767
+ delta &= 0x03ffffff ;
2768
+ delta |= 0x14000000 ;
2769
+ * repatch_zalloc_ro_mut = delta ;
2770
+ }
2692
2771
2693
2772
if (!livefs_string_match ) // Only disable snapshot when we can remount realfs
2694
2773
{
0 commit comments