# 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 ```python # 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 filter** → **332 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 ```python # 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: ```c 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 ```python # 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) ```bash 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 ```python #!/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 |