Files
vphone-cli/research/kernel_patch_jb/patch_amfi_execve_kill_path.md
Lakr 5388e0c9c5 Squash merge startup-hang-fix into main
Prefix research patch comparison doc and normalize root markdown names

Rename research root markdown files to scoped topic names
2026-03-06 02:42:12 +08:00

11 KiB

A2 patch_amfi_execve_kill_path (fully re-validated)

This document was re-done from static analysis only (IDA MCP), treating previous notes as untrusted.

1) Exact patch target and effect

  • Patched function (AMFI callback): 0xFFFFFE000863FC6C (jbA2_patch_amfi_execve_kill_handler).
  • Patch point label: 0xFFFFFE00086400FC (jbA2_patchpoint_mov_w0_1_to_0).
  • Instruction before patch: MOV W0, #1.
  • Instruction after patch: MOV W0, #0.
  • The instruction is in the shared kill epilogue (0x86400F8 log + 0x86400FC return code), so all kill branches are converted to allow.

2) Why this function is called (full dispatch picture)

2.1 AMFI registers this callback into MAC policy ops slot +0x90

  • In AMFI init 0xFFFFFE0008640718 (jb_a1_supp_amfi_register_mac_policy):
    • 0x8640A90 loads callback address 0x863FC6C.
    • 0x8640A98 sets PAC discriminator 0xEC79.
    • 0x8640AA0 stores into policy ops slot qword_FFFFFE0007851550 (renamed jbA2_patch_ops_slot_0x90).

2.2 Kernel MAC dispatcher calls ops slot +0x90 during exec image processing

  • Dispatcher: 0xFFFFFE00082D9D0C (jbA2_supp_mac_policy_dispatch_ops90_execve).
  • Key instructions:
    • 0x82D9DB8: load policy ops base from each policy ([policy + 0x20]).
    • 0x82D9DBC: load callback from [ops + 0x90].
    • 0x82D9FC8: BLRAA X24, X17 with X17 = 0xEC79.
  • The PAC discriminator matches AMFI registration (0xEC79), proving this slot resolves to the AMFI callback above.

2.3 Exec pipeline path into that dispatcher

  • 0xFFFFFE0007F81F00 (jbA2_supp_execve_mac_policy_bridge) directly calls 0x82D9D0C.
  • 0xFFFFFE0007FA6858 builds a callback descriptor containing 0x7F81F00, then submits it via sub_FFFFFE0007F81364.
  • Upstream chain:
    • 0x7FA4A58 (jbA2_supp_imgact_validate_and_activate) -> calls 0x7FA6858.
    • 0x7FAB530 (jbA2_supp_imgact_exec_driver) -> calls 0x7FA4A58.
    • 0x7FAD47C (jbA2_supp_exec_activate_image) -> calls 0x7FAB530.
  • So this callback is in the core exec image activation path, not an optional debug path.

3) Why unsigned binaries fail without A2

Inside 0x863FC6C, multiple checks branch to the shared kill return (W0=1):

  • Completely unsigned code path (first AMFI kill string block).
  • Restricted Execution Mode denial paths (state 2/3/4).
  • Legacy VPN plugin denial.
  • Dyld signature denial ("dyld signature cannot be verified").
  • Generic kill path ("...killing %s (pid %u): %s") after deep signature/entitlement validation helper failures.

Because all of them converge on the same return code, any one of these conditions kills exec.

4) Why launchd dylib flow also depends on A2

The same callback enforces dyld/signature and entitlement consistency during exec image activation:

  • The explicit dyld kill string path is in this function ("dyld signature cannot be verified...").
  • The helper path (sub_FFFFFE0008640310 -> sub_FFFFFE00086442F8) can fail with reasons like "no code signature", DER/XML entitlement mismatch, etc., then returns to the same kill epilogue.

So when launchd (or its startup path) encounters unsigned / non-trustcached / entitlement-inconsistent dylib state, exec is killed through this same callback. A2 changes that final kill return to allow.

5) Why one instruction is enough

  • All kill branches funnel into one epilogue return code at 0x86400FC.
  • Changing only that MOV W0,#1 to MOV W0,#0 keeps assertions, logging, and all prechecks intact, but changes final policy decision from deny to allow.

6) IDA marking done (requested grouping)

Supplement group

  • 0x82D9D0C -> jbA2_supp_mac_policy_dispatch_ops90_execve
  • 0x7F81F00 -> jbA2_supp_execve_mac_policy_bridge
  • 0x7FA4A58 -> jbA2_supp_imgact_validate_and_activate
  • 0x7FAB530 -> jbA2_supp_imgact_exec_driver
  • 0x7FAD47C -> jbA2_supp_exec_activate_image
  • 0x7FAD448 -> jbA2_supp_exec_activate_image_wrapper
  • 0x7851550 -> jbA2_patch_ops_slot_0x90

Patched-function group

  • 0x863FC6C -> jbA2_patch_amfi_execve_kill_handler
  • 0x86400F8 -> jbA2_patchloc_kill_log_then_ret
  • 0x86400FC -> jbA2_patchpoint_mov_w0_1_to_0

7) Old failure mode (reconfirmed)

The earlier BL/CBZ-site patching hit vnode-type assertion checks near function start (sub_FFFFFE0007CCC40C / sub_FFFFFE0007CCC41C), not the actual kill decision. That corrupts precondition logic and can panic. The shared-epilogue patch avoids that class of bug.

Symbol Consistency Audit (2026-03-05)

  • Status: partial
  • _hook_cred_label_update_execve and related execve symbols are recovered, but several AMFI callback wrapper addresses in this doc remain unlabeled in kernel_info.
  • Address-level control-flow evidence is still valid; symbol names are partially recovered only.

Patch Metadata

  • Patch document: patch_amfi_execve_kill_path.md (A2).
  • Primary patcher module: scripts/patchers/kernel_jb_patch_amfi_execve.py.
  • Analysis mode: static binary analysis (IDA-MCP + disassembly + recovered symbols), no runtime patch execution.

Patch Goal

Convert AMFI execve shared kill return from deny to allow by flipping the final return-code instruction.

Target Function(s) and Binary Location

  • Primary target: AMFI execve kill handler at 0xfffffe000863fc6c (analyst label jbA2_patch_amfi_execve_kill_handler).
  • Patchpoint: 0xfffffe00086400fc (mov w0,#1 -> mov w0,#0).

Kernel Source File Location

  • Component: AppleMobileFileIntegrity execve callback logic in kernel collection (private component).
  • Related open-source entry context: bsd/kern/kern_exec.c and bsd/kern/mach_loader.c.
  • Confidence: medium.

Function Call Stack

  • Primary traced chain (from 2) Why this function is called (full dispatch picture)):
  • In AMFI init 0xFFFFFE0008640718 (jb_a1_supp_amfi_register_mac_policy):
  • 0x8640A90 loads callback address 0x863FC6C.
  • 0x8640A98 sets PAC discriminator 0xEC79.
  • 0x8640AA0 stores into policy ops slot qword_FFFFFE0007851550 (renamed jbA2_patch_ops_slot_0x90).
  • Dispatcher: 0xFFFFFE00082D9D0C (jbA2_supp_mac_policy_dispatch_ops90_execve).
  • The upstream entry(s) and patched decision node are linked by direct xref/callsite evidence in this file.

Patch Hit Points

  • Key patchpoint evidence (from 1) Exact patch target and effect):
  • Patched function (AMFI callback): 0xFFFFFE000863FC6C (jbA2_patch_amfi_execve_kill_handler).
  • Patch point label: 0xFFFFFE00086400FC (jbA2_patchpoint_mov_w0_1_to_0).
  • Instruction before patch: MOV W0, #1.
  • Instruction after patch: MOV W0, #0.
  • The instruction is in the shared kill epilogue (0x86400F8 log + 0x86400FC return code), so all kill branches are converted to allow.
  • The before/after instruction transform is constrained to this validated site.

Current Patch Search Logic

  • Implemented in scripts/patchers/kernel_jb_patch_amfi_execve.py.
  • Site resolution uses anchor + opcode-shape + control-flow context; ambiguous candidates are rejected.
  • The patch is applied only after a unique candidate is confirmed in-function.
  • Uses string anchors + instruction-pattern constraints + structural filters (for example callsite shape, branch form, register/imm checks).

Pseudocode (Before)

if (kill_condition) {
    log_reason(...);
    return 1;
}

Pseudocode (After)

if (kill_condition) {
    log_reason(...);
    return 0;
}

Validation (Static Evidence)

  • Verified with IDA-MCP disassembly/decompilation, xrefs, and callgraph context for the selected site.
  • Cross-checked against recovered symbols in research/kernel_info/json/kernelcache.research.vphone600.bin.symbols.json.
  • Address-level evidence in this document is consistent with patcher matcher intent.

Expected Failure/Panic if Unpatched

  • AMFI kill epilogue returns deny (w0=1), causing exec rejection for guarded paths (including dyld-signature related failures).

Risk / Side Effects

  • This patch weakens a kernel policy gate by design and can broaden behavior beyond stock security assumptions.
  • Potential side effects include reduced diagnostics fidelity and wider privileged surface for patched workflows.

Symbol Consistency Check

  • Recovered-symbol status in kernelcache.research.vphone600.bin.symbols.json: match.
  • Canonical symbol hit(s): _hook_cred_label_update_execve.
  • Where canonical names are absent, this document relies on address-level control-flow and instruction evidence; analyst aliases are explicitly marked as aliases.
  • IDA-MCP lookup snapshot (2026-03-05): _hook_cred_label_update_execve is present, while the analyzed AMFI helper body at 0xfffffe000863fc6c is currently labeled as __ZN18AppleMobileApNonce21_saveNonceInfoInNVRAMEPKc in this IDA state, confirming symbol-name drift at that site.

Open Questions and Confidence

  • Open question: verify future firmware drift does not move this site into an equivalent but semantically different branch.
  • Overall confidence for this patch analysis: high (symbol match + control-flow/byte evidence).

Evidence Appendix

  • Detailed addresses, xrefs, and rationale are preserved in the existing analysis sections above.
  • For byte-for-byte patch details, refer to the patch-site and call-trace subsections in this file.

Runtime + IDA Verification (2026-03-05)

  • Verification timestamp (UTC): 2026-03-05T14:55:58.795709+00:00
  • Kernel input: /Users/qaq/Documents/Firmwares/PCC-CloudOS-26.3-23D128/kernelcache.research.vphone600
  • Base VA: 0xFFFFFE0007004000
  • Runtime status: hit (1 patch writes, method_return=True)
  • Included in KernelJBPatcher.find_all(): True
  • IDA mapping: 1/1 points in recognized functions; 0 points are code-cave/data-table writes.
  • IDA mapping status: ok (IDA runtime mapping loaded.)
  • Call-chain mapping status: ok (IDA call-chain report loaded.)
  • Call-chain validation: 1 function nodes, 3 patch-point VAs.
  • IDA function sample: __Z25_cred_label_update_execveP5ucredS0_P4procP5vnodexS4_P5labelS6_S6_PjPvmPi
  • Chain function sample: __Z25_cred_label_update_execveP5ucredS0_P4procP5vnodexS4_P5labelS6_S6_PjPvmPi
  • Caller sample: __ZL35_initializeAppleMobileFileIntegrityv
  • Callee sample: __Z25_cred_label_update_execveP5ucredS0_P4procP5vnodexS4_P5labelS6_S6_PjPvmPi, __ZN24AppleMobileFileIntegrity27submitAuxiliaryInfoAnalyticEP5vnodeP7cs_blob, sub_FFFFFE0007B4EA8C, sub_FFFFFE0007CD7750, sub_FFFFFE0007CD7760, sub_FFFFFE0007F8C478
  • Verdict: valid
  • Recommendation: Keep enabled for this kernel build; continue monitoring for pattern drift.
  • Key verified points:
  • 0xFFFFFE000864E38C (__Z25_cred_label_update_execveP5ucredS0_P4procP5vnodexS4_P5labelS6_S6_PjPvmPi): mov w0,#0 [AMFI kill return → allow] | 20008052 -> 00008052
  • Artifacts: research/kernel_patch_jb/runtime_verification/runtime_verification_report.json
  • Artifacts: research/kernel_patch_jb/runtime_verification/ida_runtime_patch_points.json
  • Artifacts: research/kernel_patch_jb/runtime_verification/ida_patch_chain_report.json
  • Artifacts: research/kernel_patch_jb/runtime_verification/ida_patch_chain_report.md