Skip to content

Commit

Permalink
real box
Browse files Browse the repository at this point in the history
  • Loading branch information
asdfugil committed Jul 20, 2024
1 parent 452de90 commit 121abf4
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 135 deletions.
224 changes: 93 additions & 131 deletions checkra1n/kpf/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ static void kpf_kernel_version_init(xnu_pf_range_t *text_const_range)
// Imports from shellcode.S
extern uint32_t sandbox_shellcode[], sandbox_shellcode_setuid_patch[], sandbox_shellcode_ptrs[], sandbox_shellcode_end[];
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[];
extern uint32_t proc_set_syscall_filter_mask_shc[], proc_set_syscall_filter_mask_shc_target[], zalloc_ro_mut[];

uint32_t* _mac_mount = NULL;
bool kpf_has_done_mac_mount = false;
Expand Down Expand Up @@ -798,82 +799,45 @@ bool vnode_lookup_callback(struct xnu_pf_patch* patch, uint32_t* opcode_stream)
return true;
}

extern uint32_t one_area[];
uint64_t* repatch_one_area_ptr;
uint32_t* _proc_set_syscall_filter_mask = NULL;
uint32_t* protobox_patchpoint = NULL;

bool kpf_autobox_callback(struct xnu_pf_patch *patch, uint32_t *opcode_stream)
bool kpf_protobox_callback(struct xnu_pf_patch *patch, uint32_t *opcode_stream)
{
void* proc_syscall_filter_mask_size = (void*)((const char *)(((uint64_t)(opcode_stream) & ~0xfffULL)
+ adrp_off(opcode_stream[0]) + ((opcode_stream[1] >> 10) & 0xfff)));

uint32_t* b = find_next_insn(opcode_stream, 0x10, 0x14000000, 0xfc000000); // b proc_set_syscall_filter_mask
if (!b) {
panic_at(opcode_stream, "kpf_autobox: Failed to find b proc_set_syscall_filter_mask");
panic_at(opcode_stream, "kpf_protobox: Failed to find b proc_set_syscall_filter_mask");
}

uint32_t* proc_set_syscall_filter_mask = follow_call(b);
uint32_t *stackframe = find_prev_insn(opcode_stream - 1, 0x20, 0xa9007bfd, 0xffc07fff); // stp x29, x30, [sp, ...]
if(!stackframe)
{
panic_at(opcode_stream, "kpf_autobox: Failed to find stack frame");
panic_at(opcode_stream, "kpf_protobox: Failed to find stack frame");
}

uint32_t *start = find_prev_insn(stackframe - 1, 8, 0xd10003ff, 0xffc003ff); // sub sp, sp, ...
if(!start)
{
panic_at(stackframe, "kpf_autobox: Failed to find start of function");
if(!start) {
start = find_prev_insn(stackframe, 10, 0xa9a003e0, 0xffe003e0); // stp xN, xM, [sp, -0x...]!
}

/* Function logic
* int proc_set_syscall_filter_mask_shorthand(proc_t p, int which, void* maskptr, size_t masksize) {
* return repatch_proc_set_syscall_filter_mask(
* p, which, repatch_one_area_ptr,
* *repatch_proc_set_syscall_filter_size[which]
* );
* }
*/
start[0] = 0x10000148; // adr x8, _proc_set_syscall_filter_mask
start[1] = 0x10000169; // adr x9, _proc_syscall_filter_mask_size
start[2] = 0x10000182; // adr x2, _one_area_ptr
start[3] = 0xf9400108; // ldr x8, [x8]
start[4] = 0xf9400129; // ldr x9, [x9]
start[5] = 0xf9400042; // ldr x2, [x2]
start[6] = 0xf861d923; // ldr x3, [x9, w1, sxtw #3]
start[7] = 0xb9400063; // ldr w3, [x3]
start[8] = 0xd61f0100; // br x8
start[9] = 0xd503201f; // nop

uint64_t* repatch_proc_set_syscall_filter_mask = (uint64_t*)&start[10];
uint64_t* repatch_proc_set_syscall_filter_size = (repatch_proc_set_syscall_filter_mask + 1);
repatch_one_area_ptr = (repatch_proc_set_syscall_filter_mask + 2);

*repatch_proc_set_syscall_filter_mask = xnu_ptr_to_va(proc_set_syscall_filter_mask);
*repatch_proc_set_syscall_filter_size = xnu_ptr_to_va(proc_syscall_filter_mask_size);
*repatch_one_area_ptr = 0x4141414141414141;

printf("KPF: found autobox\n");
return true;
}
if (!start) {
panic_at(stackframe, "kpf_protobox: Failed to find start of function");
}

bool kpf_protobox_callback(struct xnu_pf_patch *patch, uint32_t *opcode_stream)
{
uint32_t adrp1 = opcode_stream[0],
add1 = opcode_stream[1];
const char *str1 = (const char *)(((uint64_t)(opcode_stream) & ~0xfffULL) + adrp_off(adrp1) + ((add1 >> 10) & 0xfff));

uint32_t adrp2 = opcode_stream[4],
add2 = opcode_stream[5];
const char *str2 = (const char *)(((uint64_t)(opcode_stream) & ~0xfffULL) + adrp_off(adrp2) + ((add2 >> 10) & 0xfff));

if (!strcmp(str1, "Restore") && !strcmp(str2, "Darwin")) {
// Make protobox think this device is in "Restore" mode
// This will disable protobox
opcode_stream[2] = 0xD2800020; // mov x0, #1
printf("KPF: Found and patched protobox check @ 0x%" PRIx64 "\n", xnu_ptr_to_va(opcode_stream));
return true;
uint32_t* bl = find_prev_insn(opcode_stream, 6, 0x94000000, 0xfc000000); // bl zone_require_ro
if (!bl) {
panic_at(opcode_stream, "kpf_protobox: Failed to find zone_require_ro");
}

return false;
*bl = 0xaa0003f1; // mov x17, x0

_proc_set_syscall_filter_mask = proc_set_syscall_filter_mask;

protobox_patchpoint = b;

printf("KPF: found protobox\n");
return true;
}

bool kpf_filter_mismatch_callback(struct xnu_pf_patch *patch, uint32_t *opcode_stream) {
Expand All @@ -882,6 +846,18 @@ bool kpf_filter_mismatch_callback(struct xnu_pf_patch *patch, uint32_t *opcode_s
return true;
}

uint32_t* _zalloc_ro_mut = NULL;
bool kpf_zalloc_ro_mut_callback(struct xnu_pf_patch *patch, uint32_t *opcode_stream) {
uint32_t* _zalloc_ro_mut_candidate = follow_call(&opcode_stream[6]);
if (!_zalloc_ro_mut) _zalloc_ro_mut = _zalloc_ro_mut_candidate;
if (_zalloc_ro_mut != _zalloc_ro_mut_candidate) {
panic("kpf_zalloc_ro_mut: Found multiple zalloc_ro_mut candidates");
}

puts("KPF: Found zalloc_ro_mut");
return true;
}

void kpf_find_shellcode_funcs(xnu_pf_patchset_t* xnu_text_exec_patchset) {
// to find this with r2 run:
// /x 00008192007fbef2:00ffffff00ffffff
Expand Down Expand Up @@ -931,6 +907,29 @@ void kpf_find_shellcode_funcs(xnu_pf_patchset_t* xnu_text_exec_patchset) {
0xffffffff
};
xnu_pf_maskmatch(xnu_text_exec_patchset, "ret0_gadget", iiii_matches, iiii_masks, sizeof(iiii_masks)/sizeof(uint64_t), true, (void*)ret0_gadget_callback);

// find mac label related calls to zalloc_ro_mut
uint64_t zalloc_ro_mut_matches[] = {
0x90000003, // adrp x3, ...
0x91000063, // add x3, x3, ...
0x52800080, // mov w0, #0x4
0xaa1003e1, // mov x1, x{16-31}
0xd2800002, // mov x2, #0x0
0x52800404, // mov w4, #0x20
0x94000000 // bl zalloc_ro_mut
};

uint64_t zalloc_ro_mut_masks[] = {
0x9f00001f,
0xffc003ff,
0xffffffff,
0xfff0ffff,
0xffffffff,
0xffffffff,
0xfc000000
};

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);
}

static bool found_mach_traps = false;
Expand Down Expand Up @@ -1779,7 +1778,7 @@ void kpf_amfi_kext_patches(xnu_pf_patchset_t* patchset) {
xnu_pf_maskmatch(patchset, "amfi_mac_syscall_low", iiii_matches, iiii_masks, sizeof(iiii_matches)/sizeof(uint64_t), false, (void*)kpf_amfi_mac_syscall_low);
}

void kpf_sandbox_kext_patches(xnu_pf_patchset_t* patchset, bool protobox_used, bool has_autobox) {
void kpf_sandbox_kext_patches(xnu_pf_patchset_t* patchset, bool protobox_used) {
uint64_t matches[] = {
0x35000000, // CBNZ
0x94000000, // BL _vfs_context_current
Expand All @@ -1804,79 +1803,34 @@ void kpf_sandbox_kext_patches(xnu_pf_patchset_t* patchset, bool protobox_used, b
};
xnu_pf_maskmatch(patchset, "vnode_lookup", matches, masks, sizeof(masks)/sizeof(uint64_t), true, (void*)vnode_lookup_callback);

if (has_autobox) {
uint64_t autobox_matches[] = {
// /x 0800009008010091081970f8030140b9e00300aae10300aae20300aa:1f00009fff03c0ffff1ff0ffffffffffffffe0ffffffe0ffffffe0ff
// iOS 15.4+
if (protobox_used) {
uint64_t protobox_matches[] = {
0x90000008, // adrp x8, ...
0x91000108, // add, x8, x8
0xf860c808, // ldr x8, ...
0xf8701908, // ldr x8, [x8, w{16-31}, ... #0x3]
0xb9400103, // ldr w3, [x8]
0xaa0003e0, // mov x0, x{16-31}
0xaa0003e1, // mov x1, x{16-31}
0xaa0003e2 // mov x2, x{16-31}
};

uint64_t autobox_masks[] = {
uint64_t protobox_masks[] = {
0x9f00001f,
0xffc003ff,
0xffe0ec1f,
0xfff01fff,
0xffffffff,
0xffe0ffff,
0xffe0ffff,
0xffe0ffff
};

xnu_pf_maskmatch(patchset, "autobox", autobox_matches, autobox_masks, sizeof(autobox_masks) / sizeof(uint64_t), true, (void *)kpf_autobox_callback);

// syscall mask mismatch: %s\" @%s:%
uint64_t mismatch_matches[] = {
0xb4000000, // cbz
0xf9400000, // ldr
0xaa0003e0, // mov x0, ...
0x52800001, // mov w1, #0x0
0x94000000, // bl proc_get_syscall_filter_mask
0xeb00001f, // cmp x0, ...
0x54000001, // b.ne Lmismatch_panic
0xf9400000, // ldr
0xaa0003e0, // mov x0, ...
0x52800021, // mov w1, #0x0
0x94000000, // bl proc_get_syscall_filter_mask
0xeb00001f, // cmp x0, ...
0x54000001, // b.ne Lmismatch_panic
0xf9400000, // ldr
0xaa0003e0, // mov x0, ...
0x52800041, // mov w1, #0x0
0x94000000, // bl proc_get_syscall_filter_mask
0xeb00001f, // cmp x0, ...
0x54000001 // b.ne Lmismatch_panic
};

uint64_t mismatch_masks[] = {
0xff000000,
0xffc00000,
0xffe0ffff,
0xffffffff,
0xfc000000,
0xffe0ffff,
0xff00001f,
0xffc00000,
0xffe0ffff,
0xffffffff,
0xfc000000,
0xffe0ffff,
0xff00001f,
0xffc00000,
0xffe0ffff,
0xffffffff,
0xfc000000,
0xffe0ffff,
0xff00001f
};
xnu_pf_maskmatch(patchset, "filter_mismatch", mismatch_matches, mismatch_masks, sizeof(mismatch_masks) / sizeof(uint64_t), true, (void *)kpf_filter_mismatch_callback);

xnu_pf_maskmatch(patchset, "protobox", protobox_matches, protobox_masks, sizeof(protobox_masks) / sizeof(uint64_t), true, (void *)kpf_protobox_callback);
}


if (protobox_used) {
/*if (protobox_used) {
// 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
// When injecting into them or using something like Frida, it can prevent certain functionality
// 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
Expand All @@ -1903,7 +1857,7 @@ void kpf_sandbox_kext_patches(xnu_pf_patchset_t* patchset, bool protobox_used, b
0xfe00001f,
};
xnu_pf_maskmatch(patchset, "protobox", protobox_matches, protobox_masks, sizeof(protobox_masks)/sizeof(uint64_t), true, (void *)kpf_protobox_callback);
}
}*/
}

bool vnop_rootvp_auth_callback(struct xnu_pf_patch *patch, uint32_t *opcode_stream) {
Expand Down Expand Up @@ -2601,29 +2555,18 @@ static void kpf_cmd(const char *cmd, char *args)
xnu_pf_range_t* protobox_string_range = xnu_pf_section(sandbox_header, "__TEXT", "__cstring");
if (!protobox_string_range) protobox_string_range = text_cstring_range;

const char protobox_string[] = "failed to initialize protobox collection";
const char protobox_string[] = "(apply-protobox)";
const char *protobox_string_match = memmem(protobox_string_range->cacheable_base, protobox_string_range->size, protobox_string, sizeof(protobox_string)-1);

const char autobox_string[] = "failed to initialize autobox collection";
const char* autobox_string_match = memmem(protobox_string_range->cacheable_base, protobox_string_range->size, autobox_string, sizeof(autobox_string)-1);

#ifdef DEV_BUILD
// 15.0 beta 3 and later, except bridgeOS
if ((gKernelVersion.xnuMajor >= 8019 && (gKernelVersion.xnuMajor <= 10063) && (xnu_platform() != PLATFORM_BRIDGEOS)) != (protobox_string_match != NULL)) {
if ((gKernelVersion.xnuMajor >= 8019 && (xnu_platform() != PLATFORM_BRIDGEOS)) != (protobox_string_match != NULL)) {
panic("Protobox string doesn't match expected Darwin version");
}

// 18.0 beta 1 and later, except bridgeOS
if ((gKernelVersion.xnuMajor >= 11215) != (autobox_string_match != NULL) && (xnu_platform() != PLATFORM_BRIDGEOS)) {
panic("Autobox string doesn't match expected Darwin version");
}
#endif
bool protobox_used = (protobox_string_match != NULL && gKernelVersion.xnuMajor >= 8792);

// 16.0 beta 1 and later
const char constraints_string[] = "mac_proc_check_launch_constraints";
const char *constraints_string_match = memmem(text_cstring_range->cacheable_base, text_cstring_range->size, constraints_string, sizeof(constraints_string));

kpf_sandbox_kext_patches(sandbox_patchset, (protobox_string_match != NULL && gKernelVersion.darwinMajor >= 8792 && autobox_string_match == NULL), autobox_string_match != NULL);
kpf_sandbox_kext_patches(sandbox_patchset, protobox_used);
xnu_pf_emit(sandbox_patchset);
xnu_pf_apply(sandbox_text_exec_range, sandbox_patchset);
xnu_pf_patchset_destroy(sandbox_patchset);
Expand Down Expand Up @@ -2833,8 +2776,27 @@ static void kpf_cmd(const char *cmd, char *args)
*mac_execve_hook = delta;
}

if (autobox_string_match != NULL) {
*repatch_one_area_ptr = xnu_ptr_to_va(one_area - shellcode_from + shellcode_to);
if (protobox_used) {
if (!_zalloc_ro_mut) panic("Missing patch: zalloc_ro_mut");

uint32_t* repatch_proc_set_syscall_filter_mask_shc = (uint32_t*)(proc_set_syscall_filter_mask_shc - shellcode_from + shellcode_to);
uint32_t* repatch_proc_set_syscall_filter_mask_shc_target = (uint32_t*)(proc_set_syscall_filter_mask_shc_target - shellcode_from + shellcode_to);
uint32_t* repatch_zalloc_ro_mut = (uint32_t*)(zalloc_ro_mut - shellcode_from + shellcode_to);

uint32_t delta = (&repatch_proc_set_syscall_filter_mask_shc[0]) - protobox_patchpoint;
delta &= 0x03ffffff;
delta |= 0x14000000;
*protobox_patchpoint = delta;

delta = (&_proc_set_syscall_filter_mask[0]) - repatch_proc_set_syscall_filter_mask_shc_target;
delta &= 0x03ffffff;
delta |= 0x14000000;
*repatch_proc_set_syscall_filter_mask_shc_target = delta;

delta = (&_zalloc_ro_mut[0]) - repatch_zalloc_ro_mut;
delta &= 0x03ffffff;
delta |= 0x14000000;
*repatch_zalloc_ro_mut = delta;
}

if(!livefs_string_match) // Only disable snapshot when we can remount realfs
Expand Down
45 changes: 41 additions & 4 deletions checkra1n/kpf/shellcode.S
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,47 @@ proc_selfname:
.quad 0x5151515151515151
vnode_check_open_orig:
.quad 0x5252525252525252

.globl _proc_set_syscall_filter_mask_shc
.globl _proc_set_syscall_filter_mask_shc_target
.globl _zalloc_ro_mut
.globl one_area
one_area:
.balign 0x100, 0xff

_proc_set_syscall_filter_mask_shc:
cbz x2, _proc_set_syscall_filter_mask_shc_target
sub sp, sp, 0x40
stp x19, x20, [sp, 0x10]
stp x21, x22, [sp, 0x20]
stp x29, x30, [sp, 0x30]
mov x19, x0
mov x20, x1
mov x21, x2
mov x22, x3
mov x8, #8
mov x0, x17
mov x1, x21
mov x2, #0
adr x3, one_area
udiv x4, x22, x8
msub x10, x4, x8, x22
cbz x10, Lbl_zalloc_ro_mut
add x4, x4, #1
Lbl_zalloc_ro_mut:
bl _zalloc_ro_mut
mov x0, x19
mov x1, x20
mov x2, x21
mov x3, x22
ldp x19, x20, [sp, 0x10]
ldp x21, x22, [sp, 0x20]
ldp x29, x30, [sp, 0x30]
add sp, sp, 0x40
_proc_set_syscall_filter_mask_shc_target:
b .
_zalloc_ro_mut:
b .

.align 2
.globl _launchd_execve_hook
Expand Down Expand Up @@ -433,10 +474,6 @@ _nvram_shc:
ret
_nvram_shc_end:

.globl _one_area
_one_area:
.balign 0x100, 0xff

.globl _kdi_shc
.globl _kdi_shc_orig
.globl _kdi_shc_get
Expand Down

0 comments on commit 121abf4

Please sign in to comment.