Files
vphone-cli/research/kernel_jb_patch_notes.md
Lakr cfee3ea076 Add JB finalizer script; remove IPA signing UI
Add scripts/cfw_install_jb_post.sh — an idempotent SSH-based finalizer to complete JB bootstrap on a normally-booted vphone (creates /var/jb symlink, fixes ownership, runs prep_bootstrap, creates markers, installs Sileo, and runs apt; requires sshpass). Add Makefile help, .PHONY and target cfw_install_jb_finalize to invoke the script. Remove host-side IPA signing/installing and related UI: delete VPhoneSigner, VPhoneIPAInstaller, VPhoneMenuInstall and remove signer/ipaInstaller fields and menu items/callbacks from the vphone-cli UI (also removed the DevMode enable WIP flow). Misc: minor table/formatting tweaks in AGENTS.md and research docs.
2026-03-07 18:34:49 +08:00

25 KiB

Kernel JB Remaining Patches — Research Notes

Last updated: 2026-03-07

Overview

scripts/patchers/kernel_jb.py has 24 patch methods in find_all(). Current status:

  • 24 PASSING: All patches implemented and functional
  • 0 FAILING

Two methods added since initial document: patch_shared_region_map, patch_io_secure_bsd_root. Three previously failing patches (patch_nvram_verify_permission, patch_thid_should_crash, patch_hook_cred_label_update_execve) have been implemented — see details below.

On 2026-03-06, three patches were retargeted after IDA-MCP re-analysis revealed their matchers were hitting wrong sites:

  • patch_bsd_init_auth — was hitting exec_handle_sugid instead of the real bsd_init rootauth gate
  • patch_io_secure_bsd_root — was patching the "SecureRoot" dispatch branch instead of the "SecureRootName" deny-return
  • patch_vm_fault_enter_prepare — was NOPing a pmap_lock_phys_page() call instead of the upstream cs_bypass gate

Upstream reference: /Users/qaq/Documents/GitHub/super-tart-vphone/CFW/patch_fw.py

Test kernel: vm/iPhone17,3_26.1_23B85_Restore/kernelcache.release.vphone600 (IM4P-wrapped, bvx2 compressed)

Key facts about the kernel:

  • 0 symbols resolved (fully stripped)
  • base_va = 0xFFFFFE0007004000 (typical PCC)
  • kern_text = 0xA74000 - 0x24B0000
  • All offsets in kernel.py helpers are file offsets (not VA)
  • bl_callers dict: keyed by file offset → list of caller file offsets

Patch 1: patch_nvram_verify_permission — FAILING

Upstream Reference

# patch __ZL16verifyPermission16IONVRAMOperationPKhPKcb
patch(0x1234034, 0xd503201f)  # NOP

One single NOP at file offset 0x1234034. The BL being NOPed calls memmove (3114 callers).

Function Analysis

Function start: 0x1233E40 (PACIBSP) Function end: 0x1234094 (next PACIBSP) Size: 0x254 bytes BL callers: 0 (IOKit virtual method, dispatched via vtable) Instruction: retab at end

Full BL targets in the function:

Offset Delta Target Callers Likely Identity
0x1233F0C +0x0CC 0x0AD10DC 6190 lck_rw_done / lock_release
0x1234034 +0x1F4 0x12CB0D0 3114 memmove ← PATCH THIS
0x1234048 +0x208 0x0ACB418 423 OSObject::release
0x1234070 +0x230 0x0AD029C 4921 lck_rw_lock_exclusive
0x123407C +0x23C 0x0AD10DC 6190 lck_rw_done
0x123408C +0x24C 0x0AD10DC 6190 lck_rw_done

Key instructions in the function:

  • CASA at +0x54 (offset 0x1233E94) — atomic compare-and-swap for lock acquisition
  • CASL at 3 locations — lock release
  • 4x BLRAA — authenticated indirect calls through vtable pointers
  • movk x17, #0xcda1, lsl #48 — PAC discriminator for IONVRAMController class
  • RETAB — PAC return
  • mov x8, #-1; str x8, [x19] — cleanup pattern near end
  • ubfiz x2, x8, #3, #0x20 before BL memmove — size = count * 8

"Remove from array" pattern (at patch site):

0x1233FD8: adrp x8, #0x272f000
0x1233FDC: ldr x8, [x8, #0x10]      ; load observer list struct
0x1233FE0: cbz x8, skip             ; if null, skip
0x1233FE4: ldr w11, [x8, #0x10]     ; load count
0x1233FE8: cbz w11, skip            ; if 0, skip
0x1233FEC: mov x10, #0              ; index = 0
0x1233FF0: ldr x9, [x8, #0x18]     ; load array base
  loop:
0x1233FF4: add x12, x9, x10, lsl #3
0x1233FF8: ldr x12, [x12]          ; array[index]
0x1233FFC: cmp x12, x19            ; compare with self
0x1234000: b.eq found
0x1234004: add x10, x10, #1        ; index++
0x1234008: cmp x11, x10
0x123400C: b.ne loop
  found:
0x1234014: sub w11, w11, #1        ; count--
0x1234018: str w11, [x8, #0x10]    ; store
0x123401C: subs w8, w11, w10       ; remaining
0x1234020: b.ls skip
0x1234024: ubfiz x2, x8, #3, #0x20 ; size = remaining * 8
0x1234028: add x0, x9, w10, uxtw #3
0x123402C: add w8, w10, #1
0x1234030: add x1, x9, w8, uxtw #3
0x1234034: bl memmove              ; ← NOP THIS

What I've Tried (and Failed)

  1. "krn." string anchor → Leads to function at 0x11F7EE8, NOT 0x1233E40. Wrong function entirely.

  2. "nvram-write-access" entitlement string → Also leads to a different function.

  3. CASA + 0 callers + retab + ubfiz + memmove filter332 matches. All IOKit virtual methods follow the same "remove observer from array" pattern with CASA locking.

  4. IONVRAMController metaclass string → Found at 0xA2FEB. Has ADRP+ADD refs at 0x125D2C0, 0x125D310, 0x125D38C (metaclass constructors). These set up the metaclass, NOT instance methods.

  5. Chained fixup pointer search for IONVRAMController string → Failed (different encoding).

Findings That DO Work

IONVRAMController vtable found via chained fixup search:

The verifyPermission function at 0x1233E40 is referenced as a chained fixup pointer in __DATA_CONST:

__DATA_CONST @ 0x7410B8: raw=0x8011377101233E40 → decoded=0x1233E40 (verifyPermission)

Vtable layout at 0x7410B8:

Vtable Idx File Offset Content First Insn
[-3] 0x7410A0 NULL
[-2] 0x7410A8 NULL
[-1] 0x7410B0 NULL
[0] 0x7410B8 0x1233E40 verifyPermission pacibsp
[1] 0x7410C0 0x1233BF0 sister method pacibsp
[2] 0x7410C8 0x10EA4E0 ret
[3] 0x7410D0 0x10EA4D8 mov

IONVRAMController metaclass constructor pattern:

0x125D2C0: pacibsp
  adrp x0, #0x26fe000
  add x0, x0, #0xa38        ; x0 = metaclass obj @ 0x26FEA38
  adrp x1, #0xa2000
  add x1, x1, #0xfeb        ; x1 = "IONVRAMController" @ 0xA2FEB
  adrp x2, #0x26fe000
  add x2, x2, #0xbf0        ; x2 = superclass metaclass @ 0x26FEBF0
  mov w3, #0x88              ; w3 = instance size = 136
  bl OSMetaClass::OSMetaClass()  ; [5236 callers]
  adrp x16, #0x76d000
  add x16, x16, #0xd60
  add x16, x16, #0x10       ; x16 = metaclass vtable @ 0x76DD70
  movk x17, #0xcda1, lsl #48  ; PAC discriminator
  pacda x16, x17
  str x16, [x0]             ; store PAC'd metaclass vtable
  retab

There's ALSO a combined class registration function at 0x12376D8 that registers multiple classes and references the instance vtable:

0x12377F8: adrp x16, #0x741000
  add x16, x16, #0x0a8       ; → 0x7410A8 (vtable[-2])

Wait — it actually points to 0x7410A8, not 0x7410B8. The vtable pointer with the +0x10 adjustment gives 0x7410A8 + 0x10 = 0x7410B8 which is entry [0]. This is how IOKit vtables work: the isa pointer stores vtable_base + 0x10 to skip the RTTI header.

Proposed Dynamic Strategy

Chain: "IONVRAMController" string → ADRP+ADD refs → metaclass constructor → extract instance size 0x88 → find the combined class registration function (0x12376D8) that calls OSMetaClass::OSMetaClass() with mov w3, #0x88 AND uses "IONVRAMController" name → extract the vtable base from the ADRP+ADD+ADD that follows → vtable[0] = verifyPermission → find BL to memmove-like target (>2000 callers) and NOP it.

Alternative (simpler): From the metaclass constructor, extract the PAC discriminator #0xcda1 and the instance size #0x88. Then search __DATA_CONST for chained fixup pointer entries where:

  • The preceding 3 entries (at -8, -16, -24) are NULL (vtable header)
  • The decoded function pointer has 0 BL callers
  • The function contains CASA
  • The function ends with RETAB
  • The function contains a BL to memmove (>2000 callers)
  • The function contains movk x17, #0xcda1 (the IONVRAMController PAC discriminator)

This last filter is the KEY discriminator. Among the 332 candidate functions, only IONVRAMController methods use PAC disc 0xcda1. Combined with "first entry in vtable" (preceded by 3 nulls), this should be unique.

Simplest approach: Search all chained fixup pointers in __DATA_CONST where:

  1. Preceded by 3 null entries (vtable start)
  2. Decoded target is a function in kern_text
  3. Function contains movk x17, #0xcda1, lsl #48
  4. Function contains BL to target with >2000 callers (memmove)
  5. NOP that BL

Patch 2: patch_thid_should_crash — FAILING

Upstream Reference

# patch _thid_should_crash to 0
patch(0x67EB50, 0x0)

Writes 4 bytes of zero at file offset 0x67EB50.

Analysis

  • Offset 0x67EB50 is in a DATA segment (not code)
  • The current value at this offset is already 0x00000000 in the test kernel
  • This is a sysctl boolean variable (kern.thid_should_crash)
  • The patch is effectively a no-op on this kernel

What I've Tried

  1. Symbol resolution → 0 symbols, fails.
  2. "thid_should_crash" string → Found, but has no ADRP+ADD code references. The string is in __PRELINK_INFO (XML plist), not in a standalone __cstring section.
  3. Sysctl structure search → Searched for a raw VA pointer to the string in DATA segments. Failed because the string VA is in the plist text, not a standalone pointer.
  4. Pattern search for value=1 → The value is already 0 at the upstream offset, so searching for value=1 finds nothing.

Proposed Dynamic Strategy

The variable at 0x67EB50 is in the kernel's __DATA segment (BSS or initialized data). Since:

  • The string is only in __PRELINK_INFO (plist), not usable as a code anchor
  • The variable has no symbols
  • The value is already 0

Option A: Skip this patch gracefully. If the value is already 0, the patch has no effect. Log a message and return True (success, nothing to do).

Option B: Find via sysctl table structure. The sysctl_oid structure in __DATA contains:

  • A pointer to the name string
  • A pointer to the data variable
  • Various flags

But the name string pointer would be a chained fixup pointer to the string in __PRELINK_INFO, which is hard to search for.

Option C: Find via __PRELINK_INFO plist parsing. Parse the XML plist to find the _PrelinkKCID or sysctl registration info. This is complex and fragile.

Recommended: Option A — the variable is already 0 in PCC kernels. Emit a write-zero anyway at the upstream-equivalent location if we can find it, or just return True if we can't find the variable (safe no-op).

Actually, better approach: search __DATA segments for a sysctl_oid struct. The struct layout includes:

struct sysctl_oid {
    struct sysctl_oid_list *oid_parent;  // +0x00
    SLIST_ENTRY(sysctl_oid) oid_link;   // +0x08
    int oid_number;                      // +0x10
    int oid_kind;                        // +0x14
    void *oid_arg1;                      // +0x18 → points to the variable
    int oid_arg2;                        // +0x20
    const char *oid_name;               // +0x28 → points to "thid_should_crash" string
    ...
};

So search all __DATA segments for an 8-byte value at offset +0x28 that decodes to the "thid_should_crash" string offset. Then read +0x18 to get the variable pointer.

But the string is in __PRELINK_INFO, which complicates decoding the chained fixup pointer.


Patch 3: patch_hook_cred_label_update_execve — FAILING

Upstream Reference

# Shellcode at 0xAB17D8 (46 instructions, ~184 bytes)
# Two critical BL targets:
#   BL _vfs_context_current at idx 9:  0x940851AC → target = 0xCC5EAC
#   BL _vnode_getattr at idx 17:       0x94085E69 → target = 0xCC91C0
# Ops table patch at 0xA54518: redirect to shellcode
# B _hook_cred_label_update_execve at idx 44: 0x146420B7 → target = 0x239A0B4

Why It Fails

The patch needs two kernel functions that have no symbols:

  • _vfs_context_current at file offset 0xCC5EAC
  • _vnode_getattr at file offset 0xCC91C0

Without these, the shellcode can't be assembled (the BL offsets depend on the target addresses).

Analysis of _vfs_context_current (0xCC5EAC)

Expected: A very short function (2-4 instructions) that:
  - Reads the current thread (mrs xN, TPIDR_EL1 or load from per-CPU data)
  - Loads the VFS context from the thread struct
  - Returns it in x0

Should have extremely high caller count (VFS is used everywhere).

Let me verify: check bl_callers.get(0xCC5EAC, []) — should have many callers.

Analysis of _vnode_getattr (0xCC91C0)

Expected: A moderate-sized function that:
  - Takes (vnode, vnode_attr, vfs_context) parameters
  - Calls the vnode op (VNOP_GETATTR)
  - Returns error code

Should have moderate caller count (hundreds).

Finding Strategy for _vfs_context_current

  1. From sandbox ops table: We already have _find_sandbox_ops_table_via_conf(). The hook_cred_label_update_execve entry (index 16) in the ops table points to the original sandbox hook function (at 0x239A0B4 per upstream).

  2. From the original hook function: Disassemble the original hook function. It likely calls _vfs_context_current (to get the VFS context for vnode operations). Find the BL target in the hook that has a very high caller count — that's likely _vfs_context_current.

  3. Pattern match: Search kern_text for short functions (size < 0x20) with:

    • mrs xN, TPIDR_EL1 instruction
    • Very high caller count (>1000)
    • Return type is pointer (loads from struct offset)

Finding Strategy for _vnode_getattr

  1. From the original hook function: The hook function likely also calls _vnode_getattr. Find BL targets in the hook that have moderate caller count.

  2. String anchor: Search for "vnode_getattr" string (not in plist but in __cstring). Find ADRP+ADD refs, trace to function.

  3. Pattern match: The function signature includes a vnode_attr structure initialization with size 0x380.

Proposed Implementation

1. Find sandbox ops table → read entry at index 16 → get original hook func
2. Disassemble original hook function
3. Find _vfs_context_current: BL target in the hook with highest caller count (>1000)
4. Find _vnode_getattr: BL target that:
   - Has moderate callers (50-1000)
   - The calling site has nearby `mov wN, #0x380` (vnode_attr struct size)
5. With both functions found, build shellcode and patch ops table

Patch Status Summary

Patch Status Implementation
nvram_verify_permission IMPLEMENTED Uses "krn." string anchor → NOP TBZ/TBNZ guard near string ref
thid_should_crash IMPLEMENTED Multi-strategy: symbol lookup, sysctl_oid struct scanning, ADRP+ADD fallback
hook_cred_label_update_execve IMPLEMENTED Inline vfs_context via mrs x8, tpidr_el1 + stp; vnode_getattr via string anchor; dynamic hook index + code cave

Previously Fixed Patches

patch_task_for_pid — FIXED

Problem: Old code searched for "proc_ro_ref_task" string → wrong function. Solution: Pattern search: 0 BL callers + 2x ldadda + 2x ldr wN,[xN,#0x490]; str wN,[xN,#0xc] + movk #0xc8a2 + non-panic BL >500 callers. NOP the second ldr wN,[xN,#0x490]. Upstream: patch(0xFC383C, 0xd503201f) — NOP in function at 0xFC3718.

patch_load_dylinker — FIXED

Problem: Old code searched for "/usr/lib/dyld" → wrong function (0 BL callers, no string ref). Solution: Search for functions with 3+ TST xN, #-0x40000000000000; B.EQ; MOVK xN, #0xc8a2 triplets and 0 BL callers. Replace LAST TST with unconditional B to B.EQ target. Upstream: patch(0x1052A28, B #0x44) — in function at 0x105239C.

patch_syscallmask_apply_to_proc — FIXED

Historical problem: the earlier repo-side “fix” still matched the wrong place. Runtime verification later showed the old hit landed in _profile_syscallmask_destroy underflow handling, not the real syscallmask apply wrapper. Current understanding: faithful upstream C22 is a low-wrapper shellcode patch that mutates the effective Unix/Mach/KOBJ mask bytes to all 0xFF, then continues into the normal setter. It is not a NULL-mask install and not an early-return patch. Current status: rebuilt structurally as a 3-write retarget (save selector, branch to cave, all-ones cave + setter tail) and separately documented in research/kernel_patch_jb/patch_syscallmask_apply_to_proc.md; user reported boot success with the rebuilt C22 on 2026-03-06.

patch_iouc_failed_macf — RETARGETED

Historical repo behavior: patched 0xFFFFFE000825B0C0 at entry with mov x0, xzr ; retab after PACIBSP. Problem: fresh IDA review shows this is a large IOUserClient open/setup path, not a tiny standalone deny helper; entry early-return skips broader work including output-state preparation. Current status: rebuilt as A5-v2. It now patches only the narrow post-mac_iokit_check_open gate in the same function: 0xFFFFFE000825BA98 (CBZ W0, allow) becomes unconditional B allow. Focused dry-run emits exactly one write at file offset 0x01257A98.

patch_nvram_verify_permission — FIXED

Problem: 332 identical IOKit methods match structural filter; "krn." string leads to wrong function. Solution: Uses "krn." string anchor to find the function, then NOPs TBZ/TBNZ guard near the string ref. Different mechanism from upstream (NOP BL memmove) but achieves the same NVRAM bypass.

patch_thid_should_crash — FIXED

Problem: String in __PRELINK_INFO plist (no code refs); value already 0x00000000 in PCC kernel. Solution: Multi-strategy approach — symbol lookup, string search + sysctl_oid struct scanning (checking forward 128 bytes for chained fixup pointers), and ADRP+ADD fallback.

patch_hook_cred_label_update_execve — FIXED

Problem: Needed _vfs_context_current and _vnode_getattr — 0 symbols available. Solution: Eliminated _vfs_context_current entirely — shellcode constructs vfs_context inline on stack via mrs x8, tpidr_el1 + stp x8, x0, [sp, #0x70]. _vnode_getattr found via "vnode_getattr" string anchor. Hook index found dynamically (scan first 30 ops entries). Code cave allocated via _find_code_cave(180).

patch_bsd_init_auth — RETARGETED (2026-03-06)

Historical repo behavior: matched ldr x0,[xN,#0x2b8]; cbz x0; bl pattern, which landed on exec_handle_sugid at 0xFFFFFE0007FB09DC — a false positive caused by /dev/null string overlap in the heuristic scoring. Problem: the old matcher targeted the wrong function entirely; patching exec_handle_sugid instead of the real bsd_init rootauth gate could break boot by mutating an exec/credential path. Current status: retargeted to the real FSIOC_KERNEL_ROOTAUTH return check in bsd_init. The new matcher recovers bsd_init via in-kernel string xrefs, locates the rootvp panic block ("rootvp not authenticated after mounting"), finds the unique in-function indirect call (BLRAA) preceded by the 0x80046833 (FSIOC_KERNEL_ROOTAUTH) literal, and NOPs the subsequent CBNZ W0, panic. Live patch hit: 0xFFFFFE0007F7B98C / file offset 0x00F7798C. See research/kernel_patch_jb/patch_bsd_init_auth.md.

patch_io_secure_bsd_root — RETARGETED (2026-03-06)

Historical repo behavior: fallback heuristic selected the first BL* + CBZ W0 site in AppleARMPE::callPlatformFunction, landing on the "SecureRoot" name-match gate at 0xFFFFFE000836E1F0 / file offset 0x0136A1F0. This changed generic platform-function dispatch routing, not just the deny return. Problem: the patched branch was the isEqualTo("SecureRoot") check, not the "SecureRootName" policy result used by IOSecureBSDRoot(). The old CBZ->B rewrite could corrupt control flow for unrelated platform-function calls. Current status: retargeted to the final "SecureRootName" deny-return selector: CSEL W22, WZR, W9, NE at 0xFFFFFE000836E464 / file offset 0x0136A464 is replaced with MOV W22, #0. This preserves the string comparison, callback synchronization, and state updates, and only forces the final policy return from kIOReturnNotPrivileged to success. See research/kernel_patch_jb/patch_io_secure_bsd_root.md.

patch_vm_fault_enter_prepare — RETARGETED (2026-03-06)

Historical repo behavior: matcher looked for BL(rare) + LDRB [xN,#0x2c] + TBZ and NOPed the BL at 0xFFFFFE0007BB898C, which was actually a pmap_lock_phys_page() call inside the VM_PAGE_CONSUME_CLUSTERED macro — breaking lock/unlock pairing in the VM fault path. Problem: the derived matcher overfit the wrong local shape. The upstream 26.1 patch targeted the cs_bypass fast-path gate (TBZ W22, #3), not the clustered-page lock helper. NOPing only the lock acquire while the unlock still ran caused unbalanced lock state, explaining boot failures. Current status: retargeted to the upstream semantic site — TBZ W22, #3, ... (where W22 bit 3 = fault_info->cs_bypass) at file offset 0x00BA9E1C / VA 0xFFFFFE0007BADE1C is replaced with NOP, forcing the cs_bypass fast path unconditionally. This matches XNU's vm_fault_cs_check_violation() logic and preserves lock pairing and page accounting. See research/kernel_patch_jb/patch_vm_fault_enter_prepare.md.


Environment Notes

Running on macOS (current)

cd /Users/qaq/Documents/GitHub/vphone-cli
source .venv/bin/activate
python3 -c "
import sys; sys.path.insert(0, 'scripts')
from fw_patch import load_firmware
from patchers.kernel_jb import KernelJBPatcher
_, data, _, _ = load_firmware('vm/iPhone17,3_26.1_23B85_Restore/kernelcache.release.vphone600')
p = KernelJBPatcher(data)
patches = p.find_all()
print(f'Total patches: {len(patches)}')
"

Running on Linux (cloud)

Requirements:

  • Python 3.10+
  • pip install capstone keystone-engine pyimg4
  • Note: keystone-engine may need cmake and C++ compiler on Linux
  • Copy the kernelcache file and upstream reference
  • The setup_venv.sh script has macOS-specific keystone dylib handling — on Linux, pip install should work directly

Files needed:

  • scripts/patchers/kernel.py (base class)
  • scripts/patchers/kernel_jb.py (JB patcher)
  • scripts/patchers/__init__.py
  • scripts/fw_patch.py (for load_firmware())
  • vm/iPhone17,3_26.1_23B85_Restore/kernelcache.release.vphone600 (test kernel)
  • /Users/qaq/Documents/GitHub/super-tart-vphone/CFW/patch_fw.py (upstream reference)

Quick Test Script

#!/usr/bin/env python3
"""Test all 24 JB kernel patch methods."""
import sys
sys.path.insert(0, 'scripts')
from fw_patch import load_firmware
from patchers.kernel_jb import KernelJBPatcher

_, data, _, _ = load_firmware('vm/iPhone17,3_26.1_23B85_Restore/kernelcache.release.vphone600')
p = KernelJBPatcher(data, verbose=True)
patches = p.find_all()
print(f'\n>>> Total: {len(patches)} patches from 24 methods')

Upstream Offsets Reference (iPhone17,3 26.1 23B85)

Symbol / Patch File Offset Notes
kern_text start 0xA74000
kern_text end 0x24B0000
base_va 0xFFFFFE0007004000
_thid_should_crash var 0x67EB50 DATA, value=0
_task_for_pid func 0xFC3718 patch at 0xFC383C
_load_dylinker patch 0x1052A28 TST → B
verifyPermission func 0x1233E40 patch BL at 0x1234034
verifyPermission vtable 0x7410B8 __DATA_CONST
IONVRAMController metaclass 0x26FEA38
IONVRAMController metaclass ctor 0x125D2C0 refs "IONVRAMController" string
IONVRAMController PAC disc 0xcda1 movk x17, #0xcda1
IONVRAMController instance size 0x88 mov w3, #0x88
_vfs_context_current 0xCC5EAC (from upstream BL encoding)
_vnode_getattr 0xCC91C0 (from upstream BL encoding)
shellcode cave (upstream) 0xAB1740 syscallmask
shellcode cave 2 (upstream) 0xAB17D8 hook_cred_label
sandbox ops table (hook entry) 0xA54518 index 16
_hook_cred_label_update_execve 0x239A0B4 original hook func
memmove 0x12CB0D0 3114 callers
OSMetaClass::OSMetaClass() 0x10EA790 5236 callers
_panic varies 8000+ callers typically