Files
vphone-cli/research/0_binary_patch_comparison.md

308 lines
36 KiB
Markdown

# Patch Comparison: Regular / Development / Jailbreak
## Boot Chain Patches
### AVPBooter
| # | Patch | Purpose | Regular | Dev | JB |
| --- | ------------ | -------------------------------- | :-----: | :-: | :-: |
| 1 | `mov x0, #0` | DGST signature validation bypass | Y | Y | Y |
### iBSS
| # | Patch | Purpose | Regular | Dev | JB |
| --- | ----------------------------------- | ------------------------------------------------------------- | :-----: | :-: | :-: |
| 1 | Serial labels (2x) | "Loaded iBSS" in serial log | Y | Y | Y |
| 2 | `image4_validate_property_callback` | Signature bypass (`b.ne` -> NOP, `mov x0,x22` -> `mov x0,#0`) | Y | Y | Y |
| 3 | Skip `generate_nonce` | Keep apnonce stable for SHSH (`tbz` -> unconditional `b`) | - | - | Y |
### iBEC
| # | Patch | Purpose | Regular | Dev | JB |
| --- | ----------------------------------- | ------------------------------------------ | :-----: | :-: | :-: |
| 1 | Serial labels (2x) | "Loaded iBEC" in serial log | Y | Y | Y |
| 2 | `image4_validate_property_callback` | Signature bypass | Y | Y | Y |
| 3 | Boot-args redirect | ADRP+ADD -> `serial=3 -v debug=0x2014e %s` | Y | Y | Y |
### LLB
| # | Patch | Purpose | Regular | Dev | JB |
| --- | ----------------------------------- | ------------------------------------------ | :-----: | :-: | :-: |
| 1 | Serial labels (2x) | "Loaded LLB" in serial log | Y | Y | Y |
| 2 | `image4_validate_property_callback` | Signature bypass | Y | Y | Y |
| 3 | Boot-args redirect | ADRP+ADD -> `serial=3 -v debug=0x2014e %s` | Y | Y | Y |
| 4 | Rootfs bypass (5 patches) | Allow edited rootfs loading | Y | Y | Y |
| 5 | Panic bypass | NOP `cbnz` after `mov w8,#0x328` check | Y | Y | Y |
### TXM
| # | Patch | Purpose | Regular | Dev | JB |
| --- | ------------------------------------------------- | ----------------------------------------- | :-----: | :-: | :-: |
| 1 | Trustcache binary-search bypass | `bl hash_cmp` -> `mov x0, #0` | Y | Y | Y |
| 2 | Selector24 bypass: `mov w0, #0xa1` | Return PASS (byte 1 = 0) after prologue | - | Y | Y |
| 3 | Selector24 bypass: `b <epilogue>` | Skip validation, jump to register restore | - | Y | Y |
| 4 | get-task-allow (selector 41\|29) | `bl` -> `mov x0, #1` | - | Y | Y |
| 5 | Selector42\|29 shellcode: branch to cave | Redirect dispatch stub to shellcode | - | Y | Y |
| 6 | Selector42\|29 shellcode: NOP pad | UDF -> NOP in code cave | - | Y | Y |
| 7 | Selector42\|29 shellcode: `mov x0, #1` | Set return value to true | - | Y | Y |
| 8 | Selector42\|29 shellcode: `strb w0, [x20, #0x30]` | Set manifest flag | - | Y | Y |
| 9 | Selector42\|29 shellcode: `mov x0, x20` | Restore context pointer | - | Y | Y |
| 10 | Selector42\|29 shellcode: branch back | Return from shellcode to stub+4 | - | Y | Y |
| 11 | Debugger entitlement (selector 42\|37) | `bl` -> `mov w0, #1` | - | Y | Y |
| 12 | Developer mode bypass | NOP conditional guard before deny path | - | Y | Y |
## Kernelcache
### Base Patches (All Variants)
| # | Patch | Function | Purpose | Regular | Dev | JB |
| ----- | -------------------------- | -------------------------------- | -------------------------------------------------- | :-----: | :-: | :-: |
| 1 | NOP `tbnz w8,#5` | `_apfs_vfsop_mount` | Skip root snapshot sealed-volume check | Y | Y | Y |
| 2 | NOP conditional | `_authapfs_seal_is_broken` | Skip root volume seal panic | Y | Y | Y |
| 3 | NOP conditional | `_bsd_init` | Skip rootvp not-authenticated panic | Y | Y | Y |
| 4-5 | `mov w0,#0; ret` | `_proc_check_launch_constraints` | Bypass launch constraints | Y | Y | Y |
| 6-7 | `mov x0,#1` (2x) | `PE_i_can_has_debugger` | Enable kernel debugger | Y | Y | Y |
| 8 | NOP | `_postValidation` | Skip AMFI post-validation | Y | Y | Y |
| 9 | `cmp w0,w0` | `_postValidation` | Force comparison true | Y | Y | Y |
| 10-11 | `mov w0,#1` (2x) | `_check_dyld_policy_internal` | Allow dyld loading | Y | Y | Y |
| 12 | `mov w0,#0` | `_apfs_graft` | Allow APFS graft | Y | Y | Y |
| 13 | `cmp x0,x0` | `_apfs_vfsop_mount` | Skip mount check | Y | Y | Y |
| 14 | `mov w0,#0` | `_apfs_mount_upgrade_checks` | Allow mount upgrade | Y | Y | Y |
| 15 | `mov w0,#0` | `_handle_fsioc_graft` | Allow fsioc graft | Y | Y | Y |
| 16 | NOP (3x) | `handle_get_dev_by_role` | Bypass APFS role-lookup deny gates for boot mounts | Y | Y | Y |
| 17-26 | `mov x0,#0; ret` (5 hooks) | Sandbox MACF ops table | Stub 5 sandbox hooks | Y | Y | Y |
### JB-Only Kernel Methods (Reference List)
| # | Group | Method | Function | Purpose | JB Enabled |
| ----- | ----- | ------------------------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :--------: |
| JB-01 | A | `patch_amfi_cdhash_in_trustcache` | `AMFIIsCDHashInTrustCache` | Always return true + store hash | Y |
| JB-02 | A | `patch_amfi_execve_kill_path` | AMFI execve kill return site | Convert shared kill return from deny to allow (superseded by C21; standalone only) | N |
| JB-03 | C | `patch_cred_label_update_execve` | `_cred_label_update_execve` | Reworked C21-v3: C21-v1 already boots; v3 keeps split late exits and additionally ORs success-only helper bits `0xC` after clearing `0x3F00`; still disabled pending boot validation | N |
| JB-04 | C | `patch_hook_cred_label_update_execve` | sandbox `mpo_cred_label_update_execve` wrapper (`ops[18]` -> `sub_FFFFFE00093BDB64`) | Faithful upstream C23 trampoline: copy `VSUID`/`VSGID` owner state into pending cred, set `P_SUGID`, then branch back to wrapper | Y |
| JB-05 | C | `patch_kcall10` | `sysent[439]` (`SYS_kas_info` replacement) | Rebuilt ABI-correct kcall cave: `target + 7 args -> uint64 x0`; re-enabled after focused dry-run validation | Y |
| JB-06 | B | `patch_post_validation_additional` | `_postValidation` (additional) | Disable SHA256-only hash-type reject | Y |
| JB-07 | C | `patch_syscallmask_apply_to_proc` | syscallmask apply wrapper (`_proc_apply_syscall_masks` path) | Faithful upstream C22: mutate installed Unix/Mach/KOBJ masks to all-ones via structural cave, then continue into setter; distinct from `NULL`-mask alternative | Y |
| JB-08 | A | `patch_task_conversion_eval_internal` | `_task_conversion_eval_internal` | Allow task conversion | Y |
| JB-09 | A | `patch_sandbox_hooks_extended` | Sandbox MACF ops (extended) | Stub remaining 30+ sandbox hooks (incl. IOKit 201..210) | Y |
| JB-10 | A | `patch_iouc_failed_macf` | IOUC MACF shared gate | A5-v2: patch only the post-`mac_iokit_check_open` deny gate (`CBZ W0, allow` -> `B allow`) and keep the rest of the IOUserClient open path intact | Y |
| JB-11 | B | `patch_proc_security_policy` | `_proc_security_policy` | Bypass security policy | Y |
| JB-12 | B | `patch_proc_pidinfo` | `_proc_pidinfo` | Allow pid 0 info | Y |
| JB-13 | B | `patch_convert_port_to_map` | `_convert_port_to_map_with_flavor` | Skip kernel map panic | Y |
| JB-14 | B | `patch_bsd_init_auth` | `_bsd_init` rootauth-failure branch | Ignore `FSIOC_KERNEL_ROOTAUTH` failure in `bsd_init`; same gate as base patch #3 when layered | Y |
| JB-15 | B | `patch_dounmount` | `_dounmount` | Allow unmount via upstream coveredvp cleanup-call NOP | Y |
| JB-16 | B | `patch_io_secure_bsd_root` | `AppleARMPE::callPlatformFunction` (`"SecureRootName"` return select), called from `IOSecureBSDRoot` | Force `"SecureRootName"` policy return to success without altering callback flow; implementation retargeted 2026-03-06 | Y |
| JB-17 | B | `patch_load_dylinker` | `_load_dylinker` | Skip strict `LC_LOAD_DYLINKER == "/usr/lib/dyld"` gate | Y |
| JB-18 | B | `patch_mac_mount` | `___mac_mount` | Upstream mount-role wrapper bypass (`tbnz` NOP + role-byte zeroing) | Y |
| JB-19 | B | `patch_nvram_verify_permission` | `_verifyPermission` (NVRAM) | Allow NVRAM writes | Y |
| JB-20 | B | `patch_shared_region_map` | `_shared_region_map_and_slide_setup` | Force root-vs-process-root mount compare to succeed before Cryptex fallback | Y |
| JB-21 | B | `patch_spawn_validate_persona` | `_spawn_validate_persona` | Upstream dual-`cbz` persona helper bypass | Y |
| JB-22 | B | `patch_task_for_pid` | `_task_for_pid` | Allow task_for_pid via upstream early `pid == 0` gate NOP | Y |
| JB-23 | B | `patch_thid_should_crash` | `_thid_should_crash` | Prevent GUARD_TYPE_MACH_PORT crash | Y |
| JB-24 | B | `patch_vm_fault_enter_prepare` | `_vm_fault_enter_prepare` | Force `cs_bypass` fast path in runtime fault validation | Y |
| JB-25 | B | `patch_vm_map_protect` | `_vm_map_protect` | Skip upstream write-downgrade gate in `vm_map_protect` | Y |
## CFW Installation Patches
### Binary Patches Applied Over SSH Ramdisk
| # | Patch | Binary | Purpose | Regular | Dev | JB |
| --- | ------------------------- | ---------------------- | ------------------------------------------------------------- | :-----: | :-: | :-: |
| 1 | `/%s.gl` -> `/AA.gl` | `seputil` | Gigalocker UUID fix | Y | Y | Y |
| 2 | NOP cache validation | `launchd_cache_loader` | Allow modified `launchd.plist` | Y | Y | Y |
| 3 | `mov x0,#1; ret` | `mobileactivationd` | Activation bypass | Y | Y | Y |
| 4 | Plist injection | `launchd.plist` | bash/dropbear/trollvnc/vphoned daemons | Y | Y | Y |
| 5 | `b` (skip jetsam guard) | `launchd` | Prevent jetsam panic on boot | - | Y | Y |
| 6 | `LC_LOAD_DYLIB` injection | `launchd` | Load short alias `/b` (copy of `launchdhook.dylib`) at launch | - | - | Y |
### Installed Components
| # | Component | Description | Regular | Dev | JB |
| --- | -------------------------- | ------------------------------------------------------------------------------------------------------------------ | :-----: | :-: | :-: |
| 1 | Cryptex SystemOS + AppOS | Decrypt AEA + mount + copy to device | Y | Y | Y |
| 2 | GPU driver | AppleParavirtGPUMetalIOGPUFamily bundle | Y | Y | Y |
| 3 | `iosbinpack64` | Jailbreak tools (base set) | Y | Y | Y |
| 4 | `iosbinpack64` dev overlay | Replace `rpcserver_ios` with dev build | - | Y | - |
| 5 | `vphoned` | vsock HID/control daemon (built + signed) | Y | Y | Y |
| 6 | LaunchDaemons | bash/dropbear/trollvnc/rpcserver_ios/vphoned plists | Y | Y | Y |
| 7 | Procursus bootstrap | Bootstrap filesystem + optional Sileo deb | - | - | Y |
| 8 | BaseBin hooks | `systemhook.dylib` / `launchdhook.dylib` / `libellekit.dylib` -> `/cores/` plus `/b` alias for `launchdhook.dylib` | - | - | Y |
| 9 | `TweakLoader.dylib` | Lean user-tweak loader built from source and installed to `/var/jb/usr/lib/TweakLoader.dylib` | - | - | Y |
### CFW Installer Flow Matrix (Script-Level)
| Flow Item | Regular (`cfw_install.sh`) | Dev (`cfw_install_dev.sh`) | JB (`cfw_install_jb.sh`) |
| --------------------------------------------- | ------------------------------- | -------------------------- | --------------------------------------------- |
| Base CFW phases (1/7 -> 7/7) | Runs directly | Runs directly | Runs via `CFW_SKIP_HALT=1 zsh cfw_install.sh` |
| Dev overlay (`rpcserver_ios` replacement) | - | Y (`apply_dev_overlay`) | - |
| SSH readiness wait before install | Y (`wait_for_device_ssh_ready`) | - | Y (inherited from base run) |
| launchd jetsam patch (`patch-launchd-jetsam`) | - | Y (base-flow injection) | Y (JB-1) |
| launchd dylib injection (`inject-dylib /b`) | - | - | Y (JB-1) |
| Procursus bootstrap deployment | - | - | Y (JB-2) |
| BaseBin hook deployment (`*.dylib` -> `/mnt1/cores`) | - | - | Y (JB-3) |
| First-boot JB finalization (`vphone_jb_setup.sh`) | - | - | Y (post-boot; now fails before done marker if TrollStore Lite install does not complete) |
| Additional input resources | `cfw_input` | `cfw_input` + `resources/cfw_dev/rpcserver_ios` | `cfw_input` + `cfw_jb_input` |
| Extra tool requirement beyond base | - | - | `zstd` |
| Halt behavior | Halts unless `CFW_SKIP_HALT=1` | Halts unless `CFW_SKIP_HALT=1` | Always halts after JB phases |
## Summary
| Component | Regular | Dev | JB |
| ------------------------ | ------: | --: | --: |
| AVPBooter | 1 | 1 | 1 |
| iBSS | 2 | 2 | 3 |
| iBEC | 3 | 3 | 3 |
| LLB | 6 | 6 | 6 |
| TXM | 1 | 12 | 12 |
| Kernel (base) | 28 | 28 | 28 |
| Kernel (JB methods) | - | - | 59 |
| Boot chain total | 41 | 52 | 112 |
| CFW binary patches | 4 | 5 | 6 |
| CFW installed components | 6 | 7 | 9 |
| CFW total | 10 | 12 | 15 |
| Grand total | 51 | 64 | 127 |
## Ramdisk Variant Matrix
| Variant | Pre-step | `Ramdisk/txm.img4` | `Ramdisk/krnl.ramdisk.img4` | `Ramdisk/krnl.img4` | Effective kernel used by `ramdisk_send.sh` |
| ------------- | ------------------- | -------------------------------- | -------------------------------------------------------------------------------- | ----------------------------------------- | --------------------------------------------------- |
| `RAMDISK` | `make fw_patch` | release TXM + base TXM patch (1) | base kernel (28), legacy `*.ramdisk` preferred else derive from pristine CloudOS | restore kernel from `fw_patch` (28) | `krnl.ramdisk.img4` preferred, fallback `krnl.img4` |
| `DEV+RAMDISK` | `make fw_patch_dev` | release TXM + base TXM patch (1) | base kernel (28), same derivation rule | restore kernel from `fw_patch_dev` (28) | `krnl.ramdisk.img4` preferred, fallback `krnl.img4` |
| `JB+RAMDISK` | `make fw_patch_jb` | release TXM + base TXM patch (1) | base kernel (28), same derivation rule | restore kernel from `fw_patch_jb` (28+59) | `krnl.ramdisk.img4` preferred, fallback `krnl.img4` |
## Cross-Version Dynamic Snapshot
| Case | TXM_JB_PATCHES | KERNEL_JB_PATCHES |
| ------------------- | -------------: | ----------------: |
| PCC 26.1 (`23B85`) | 14 | 59 |
| PCC 26.3 (`23D128`) | 14 | 59 |
| iOS 26.1 (`23B85`) | 14 | 59 |
| iOS 26.3 (`23D127`) | 14 | 59 |
## Swift Migration Notes (2026-03-10)
- Swift `FirmwarePatcher` now matches the Python reference patch output across all checked components:
- `avpbooter` 1/1
- `ibss` 4/4
- `ibec` 7/7
- `llb` 13/13
- `txm` 1/1
- `txm_dev` 12/12
- `kernelcache` 28/28
- `ibss_jb` 1/1
- `kernelcache_jb` 84/84
- JB parity fixes completed in Swift:
- C23 `vnode_getattr` resolution now follows the Python backward BL scan and resolves `0x00CD44F8`.
- C22 syscallmask cave encodings were corrected and centralized in `ARM64Constants.swift`.
- Task-conversion matcher masks and kernel-text scan range were corrected, restoring the patch at `0x00B0C400`.
- `jbDecodeBranchTarget()` now correctly decodes `cbz/cbnz`, restoring the real `_bsd_init` rootauth gate at `0x00F7798C`.
- IOUC MACF matching now uses Python-equivalent disassembly semantics for the aggregator shape, restoring the deny-to-allow patch at `0x01260644`.
- C24 `kcall10` cave instruction bytes were re-verified against macOS `clang`/`as`; no Swift byte changes were needed.
- The Swift pipeline is now directly invokable from the product binary:
- `vphone-cli patch-firmware --vm-directory <dir> --variant {regular|dev|jb}`
- `vphone-cli patch-component --component {txm|kernel-base} --input <file> --output <raw>` is available for non-firmware tooling that still needs a single patched payload during ramdisk packaging
- default loader now preserves IM4P containers via `IM4PHandler`
- DeviceTree patching now uses the real Swift `DeviceTreePatcher` in the pipeline
- project `make fw_patch`, `make fw_patch_dev`, and `make fw_patch_jb` targets now invoke this Swift pipeline via the unsigned debug `vphone-cli` build, while the signed release build remains reserved for VM boot/DFU paths
- on 2026-03-11, the legacy Python firmware patcher entrypoints and patch modules were temporarily restored from pre-removal history for parity/debug work.
- after byte-for-byte parity was revalidated against Python on `26.1` and `26.3` for `regular`, `dev`, and `jb`, those legacy firmware-patcher Python sources and transient comparison/export helpers were removed again so the repo keeps Swift as the single firmware-patching implementation.
- Swift pipeline follow-up fixes completed after CLI bring-up:
- `findFile()` now supports glob patterns such as `AVPBooter*.bin` instead of treating them as literal paths.
- JB variant sequencing now runs base iBSS/kernel patchers first, then the JB extension patchers.
- Sequential pipeline application now merges each patcher's `PatchRecord` writes onto the shared output buffer while keeping later patcher searches anchored to the original payload, matching the standalone Swift/Python validation model.
- `apply()` now reuses an already-populated `patches` array instead of re-running `findAll()`, so `patch-firmware` / `patch-component` no longer double-scan or double-print the same component diagnostics on a single invocation.
- unaligned integer reads across the firmware patcher now go through a shared safe `Data.loadLE(...)` helper, fixing the JB IM4P crash (`Swift/UnsafeRawPointer.swift:449` misaligned raw pointer load).
- `TXMPatcher` now preserves pristine Python parity by preferring the legacy trustcache binary-search site when present, and only falls back to the selector24 hash-flags call chain (`ldr x1, [x20,#0x38]` -> `add x2, sp, #4` -> `bl` -> `ldp x0, x1, [x20,#0x30]` -> `add x2, sp, #8` -> `bl`) when rerunning on a VM tree that already carries the dev/JB selector24 early-return patch.
- `scripts/fw_prepare.sh` now deletes stale sibling `*Restore*` directories in the working VM directory before patching continues, so a fresh `make fw_prepare && make fw_patch` cannot accidentally select an older prepared firmware tree (for example `26.1`) when a newer one (for example `26.3`) was just generated.
- IM4P/output parity fixes completed after synthetic full-pipeline comparison:
- `IM4PHandler.save()` no longer forces a generic LZFSE re-encode.
- Swift now rebuilds IM4Ps in the same effective shape as the Python patch flow and only preserves trailing `PAYP` metadata for `TXM` (`trxm`) and `kernelcache` (`krnl`).
- `IBootPatcher` serial labels now match Python casing exactly (`Loaded iBSS`, `Loaded iBEC`, `Loaded LLB`).
- `DeviceTreePatcher` now serializes the full patched flat tree, matching Python `dtree.py`, instead of relying on in-place property writes alone.
- Synthetic CLI dry-run status on 2026-03-10 using IM4P-backed inputs under `ipsws/patch_refactor_input`:
- regular: 58 patch records
- dev: 69 patch records
- jb: 154 patch records
- Full synthetic Python-vs-Swift pipeline comparison status on 2026-03-10 using `scripts/compare_swift_python_pipeline.py`:
- regular: all 7 component payloads match
- dev: all 7 component payloads match
- jb: all 7 component payloads match
- Real prepared-firmware Python-vs-Swift pipeline comparison status on 2026-03-10 using `vm/` after `make fw_prepare`:
- historical note: the now-removed `scripts/compare_swift_python_pipeline.py` cloned only the prepared `*Restore*` tree plus `AVPBooter*.bin`, `AVPSEPBooter*.bin`, and `config.plist`, avoiding `No space left on device` failures from copying `Disk.img` after `make vm_new`.
- regular: all 7 component payloads match
- dev: all 7 component payloads match
- jb: all 7 component payloads match
- Runtime validation blocker observed on 2026-03-10:
- `NONE_INTERACTIVE=1 SKIP_PROJECT_SETUP=1 make setup_machine JB=1` reaches the Swift patch stage and reports `[patch-firmware] applied 154 patches for jb`, then fails when the flow transitions into `make boot_dfu`.
- `make boot_dfu` originally failed at launch-policy time with exit `137` / signal `9` because the release `vphone-cli` could not launch on this host.
- `amfidont` was then validated on-host:
- it can attach to `/usr/libexec/amfid`
- the initial path allow rule failed because `AMFIPathValidator` reports URL-encoded paths (`/Volumes/My%20Shared%20Files/...`)
- rerunning `amfidont` with the encoded project path and the release-binary CDHash allows the signed release `vphone-cli` to launch
- this workflow is now packaged as `make amfidont_allow_vphone` / `scripts/start_amfidont_for_vphone.sh`
- With launch policy bypassed, `make boot_dfu` advances into VM setup, emits `vm/udid-prediction.txt`, and then fails with `VZErrorDomain Code=2 "Virtualization is not available on this hardware."`
- `VPhoneAppDelegate` startup failure handling was tightened so these fatal boot/DFU startup errors now exit non-zero; `make boot_dfu` now reports `make: *** [boot_dfu] Error 1` for the nested-virtualization failure instead of incorrectly returning success.
- The host itself is a nested Apple VM (`Model Name: Apple Virtual Machine 1`, `kern.hv_vmm_present=1`), so the remaining blocker is lack of nested Virtualization.framework availability rather than firmware patching or AMFI bypass.
- `boot_binary_check` now uses strict host preflight and fails earlier on this class of host with `make: *** [boot_binary_check] Error 3`, avoiding a wasted VM-start attempt once the nested-virtualization condition is already known.
- Added `make boot_host_preflight` / `scripts/boot_host_preflight.sh` to capture this state in one command:
- model: `Apple Virtual Machine 1`
- `kern.hv_vmm_present`: `1`
- SIP: disabled
- `allow-research-guests`: disabled
- current `kern.bootargs`: empty
- next-boot `nvram boot-args`: `amfi_get_out_of_my_way=1 -v` (staged on 2026-03-10; requires reboot before it affects launch policy)
- `spctl --status`: assessments enabled
- `spctl --assess` rejects the signed release binary
- unsigned debug `vphone-cli --help`: exit `0`
- signed release `vphone-cli --help`: exit `137`
- freshly signed debug control binary `--help`: exit `137`
## Automation Notes (2026-03-06)
- `scripts/setup_machine.sh` non-interactive flow fix: renamed local variable `status` to `boot_state` in first-boot log wait and boot-analysis wait helpers to avoid zsh `status` read-only special parameter collision.
- `scripts/setup_machine.sh` non-interactive first-boot wait fix: replaced `(( waited++ ))` with `(( ++waited ))` in `monitor_boot_log_until` to avoid `set -e` abort when arithmetic expression evaluates to `0`.
- `scripts/jb_patch_autotest.sh` loop fix for sweep stability under `set -e`: replaced `((idx++))` with `(( ++idx ))`.
- `scripts/jb_patch_autotest.sh` zsh compatibility fix: renamed per-case result variable `status` to `case_status` to avoid `status` read-only special parameter collision.
- `scripts/jb_patch_autotest.sh` selection logic update:
- default run now excludes methods listed in `KernelJBPatcher._DEV_SINGLE_WORKING_METHODS` (pending-only sweep).
- set `JB_AUTOTEST_INCLUDE_WORKING=1` to include already-working methods and run the full list.
- Sweep run record:
- `setup_logs/jb_patch_tests_20260306_114417` (2026-03-06): aborted at `[1/20]` with `read-only variable: status` in `jb_patch_autotest.sh`.
- `setup_logs/jb_patch_tests_20260306_115027` (2026-03-06): rerun after `status` fix, pending-only mode (`Total methods: 19`).
- Final run result from `jb_patch_tests_20260306_115027` at `2026-03-06 13:17`:
- Finished: 19/19 (`PASS=15`, `FAIL=4`, all fails `rc=2`).
- Failing methods at that time: `patch_bsd_init_auth`, `patch_io_secure_bsd_root`, `patch_vm_fault_enter_prepare`, `patch_cred_label_update_execve`.
- 2026-03-06 follow-up: `patch_io_secure_bsd_root` failure is now attributed to a wrong-site patch in `AppleARMPE::callPlatformFunction` (`"SecureRoot"` gate at `0xFFFFFE000836E1F0`), not the intended `"SecureRootName"` deny-return path. The code was retargeted the same day to `0xFFFFFE000836E464` and re-enabled for the next restore/boot check.
- 2026-03-06 follow-up: `patch_bsd_init_auth` was retargeted after confirming the old matcher was hitting unrelated code; keep disabled in default schedule until a fresh clean-baseline boot test passes.
- Final case: `[19/19] patch_syscallmask_apply_to_proc` (`PASS`).
- 2026-03-06 re-analysis: that historical `PASS` is now treated as a false positive for functionality, because the recorded bytes landed at `0xfffffe00093ae6e4`/`0xfffffe00093ae6e8` inside `_profile_syscallmask_destroy` underflow handling, not in `_proc_apply_syscall_masks`.
- 2026-03-06 code update: `scripts/patchers/kernel_jb_patch_syscallmask.py` was rebuilt to target the real syscallmask apply wrapper structurally and now dry-runs on `PCC-CloudOS-26.1-23B85 kernelcache.research.vphone600` with 3 writes: `0x02395530`, `0x023955E8`, and cave `0x00AB1720`. User-side boot validation succeeded the same day.
- 2026-03-06 follow-up: `patch_kcall10` was rebuilt from the old ABI-unsafe pseudo-10-arg design into an ABI-correct `sysent[439]` cave. Focused dry-run on `PCC-CloudOS-26.1-23B85 kernelcache.research.vphone600` now emits 4 writes: cave `0x00AB1720`, `sy_call` `0x0073E180`, `sy_arg_munge32` `0x0073E188`, and metadata `0x0073E190`; the method was re-enabled in `_GROUP_C_METHODS`.
- Observed failure symptom in current failing set: first boot panic before command injection (or boot process early exit).
- Post-run schedule change (per user request):
- commented out failing methods from default `KernelJBPatcher._PATCH_METHODS` schedule in `scripts/patchers/kernel_jb.py`:
- `patch_bsd_init_auth`
- `patch_io_secure_bsd_root`
- `patch_vm_fault_enter_prepare`
- `patch_cred_label_update_execve`
- 2026-03-06 re-research note for `patch_cred_label_update_execve`:
- old entry-time early-return strategy was identified as boot-unsafe because it skipped AMFI exec-time `csflags` and entitlement propagation entirely.
- implementation was reworked to a success-tail trampoline that preserves normal AMFI processing and only clears restrictive `csflags` bits on the success path.
- default JB schedule still keeps the method disabled until the reworked strategy is boot-validated.
- Manual DEV+single (`setup_machine` + `PATCH=<method>`) working set now includes:
- `patch_amfi_cdhash_in_trustcache`
- `patch_amfi_execve_kill_path`
- `patch_task_conversion_eval_internal`
- `patch_sandbox_hooks_extended`
- `patch_post_validation_additional`
- 2026-03-07 host-side note:
- reviewed private Virtualization.framework display APIs against the recorder pipeline in `sources/vphone-cli/VPhoneScreenRecorder.swift`.
- replaced the old AppKit-first recorder path with a private-display-only implementation built around hidden `VZGraphicsDisplay._takeScreenshotWithCompletionHandler:` capture.
- added still screenshot actions that can copy the captured image to the pasteboard or save a PNG to disk using the same private capture path.
- `make build` is used as the sanity check path; live VM validation is still needed to confirm the exact screenshot object type returned on macOS 15.
- 2026-03-15 tooling source sync update:
- removed ad-hoc `git clone` source fetching from `scripts/setup_tools.sh` and `scripts/setup_libimobiledevice.sh`.
- added pinned git-submodule sources under `scripts/repos/` for: `trustcache`, `insert_dylib`, `libplist`, `libimobiledevice-glue`, `libusbmuxd`, `libtatsu`, `libimobiledevice`, `libirecovery`, `idevicerestore`.
- setup scripts now initialize required submodules via `git submodule update --init --recursive <path>` and stage build copies under local tool build directories.