patchTproOff (kernel-exp-frida_tpro_off)
Scope
Opt-in Frida patch in com.vphone.patchset.kernel.frida, off in every preset
but experimental, gated to cloudOS 26.4+. Port of tpro-off from
mowisec/frida_patches_srd
(Apache-2.0), which derived it on an iOS 27 Security Research Device.
Problem
dyld keeps its state in TPRO pages and flips them between read-only and
read-write itself. Every libdyld API entry asserts that they are read-only and
otherwise aborts with TPRO regions should not be writable on entry to dyld.
Frida's spawn handshake re-enters libdyld while dyld's own TPRO window is still
open, so the spawned process aborts:
frida -f com.apple.Preferencesfails withunexpectedly hit a crash with codes [ 0x6000000, 0x0 ] … while initializing suspended process;- an app caught by spawn gating crashes once it is resumed.
The crash reports show abort_report_np called from libdyld
(_dyld_for_each_objc_class / _dyld_objc_class_count); the guest's processes
carry TPRO_CONST regions, so the vphone guest has TPRO.
Approach — turn TPRO off in the kernel
_xprr_tpro_enabled is a uint32 in __DATA_CONST, statically 1. Every
reference is a read guarding the TPRO path, whose false arm is the path the
kernel already takes for processes without TPRO. Writing 0 makes every process
take it, so dyld's check never sees a writable TPRO region. This is global, not
per-process.
Semantic Reveal Procedure
The flag is data, so the guard that reads it is matched as code and the address is resolved from it:
- Rejection-only pre-filter on
orr wD, wN, #2(VM_REGION_FLAG_TPRO_ENABLED). - Decode the nine-instruction window ending after it, at its VA, and require:
adrp xA/ldr wA, [xA, #off](same register) /cbz wA, skip/ldr/cmp/b.lo skip(same target as thecbz) /ldrh wF, [xN, #f]/orr wF, wF, #2/strh wF, [xN, #f](same register and memory operand as theldrh). - Exactly one window must match; otherwise fail closed.
- Flag VA = ADRP page + LDR displacement. It must resolve to a file offset inside
__DATA_CONSTand hold 1; otherwise fail closed. - Write four zero bytes.
26.4 Static Validation
Kernel: kernelcache.research.vphone600 from cloudOS 26.4
(c0ecdb4b…). patch-component --component kernel-cfw --target-os 26.5 --frida
emits one record:
The mowisec finder (patch_kernel.py, build-tag check bypassed) resolves the same
flag address on this kernel.
Runtime Validation (iOS 26.5 guest, cloudOS 26.4, Frida 17.24.3)
Validation Requirements
- Dry run emits exactly one
kernel-exp-frida_tpro_offrecord, original bytes01 00 00 00. - If the guard window does not match exactly once, or the flag is outside
__DATA_CONSTor not 1, the patch fails closed.