Skip to content

Cryptex Support#344

Open
mpass99 wants to merge 4 commits into
Lakr233:mainfrom
mpass99:feature/cryptex-support
Open

Cryptex Support#344
mpass99 wants to merge 4 commits into
Lakr233:mainfrom
mpass99:feature/cryptex-support

Conversation

@mpass99

@mpass99 mpass99 commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

This PR adds functionality to install and list Cryptexes via vphoned.

Cryptexes are overlay file systems that can contain data, executables, and daemons, which can be added at runtime within the boundaries of Apple's security ecosystem.
Cryptexes are also being used in the context of Apple's physical Security Research Devices. Therefore, this feature allows security researchers to easily use their Cryptex toolchains also for researching with the vphone.

While developing the cryptex support for the vphone, we hit a limitation of pymobiledevice3. We opened doronz88/pymobiledevice3#1701 and hope to remove f05a53a once this is resolved. Meanwhile, we perform the restore with Apple's MobileDevice library (f05a53a). We have limited this to the patchless mode, for now.

In this PR, we use and copy the cryptexctl executable from the cloudOS filesystem as a utility. A future PR, however, might use the (private Swift) CryptexKit framework directly from vphoned.

mpass99 added 4 commits June 8, 2026 15:24
due to setup incompatibilities of idevicerestore and pymobiledevice in regard to REM and Cryptex support.
by allowing all Mach-O executables in both REM phases.

(cherry picked from commit 34e820a5baab19e1f149de10da71db2ccf462350)
(cherry picked from commit af4e207129b310d294c356f01e11d5a8167292ac)
@mpass99

mpass99 commented Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

I just noticed that a MobileDevice restored vphone in Patchless mode panics from time to time. The reason is currently unknown.

Logs

static IOReturn AppleMobileFileIntegrityUserClient::loadTrustCache(OSObject *, void *, IOExternalMethodArguments *): PID 416 is requesting a trust cache load
Nested panic detected - entry count: 2 panic_caller: 0x<ptr>
Panicked thread: <ptr>, backtrace: 0x<ptr>, tid: 6123
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0xfffffdf000d0bea0
		  lr: 0x<ptr>  fp: 0xfffffdf000d0bec0
		  lr: 0x<ptr>  fp: 0xfffffdf000d0bf60
		  lr: 0x<ptr>  fp: 0xfffffdf000d0bfe0
		  lr: 0x<ptr>  fp: 0xfffffdf000d0bff0
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0xfffffdf00108f9f0
		  lr: 0x<ptr>  fp: 0xfffffdf00108fa10
		  lr: 0x<ptr>  fp: 0xfffffdf00108fa50
		  lr: 0x<ptr>  fp: 0xfffffdf00108fa70
		  lr: 0x<ptr>  fp: 0xfffffdf00108fb10
		  lr: 0x<ptr>  fp: 0xfffffdf00108fb80
		  lr: 0x<ptr>  fp: 0xfffffdf00108fbf0
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x000000023e999cd4  fp: 0x0000000000000000
      Kernel Extensions in backtrace:
         com.apple.sptm(25.1)[483B7ACD-3530-3B47-A0D4-D54DF1297E2B]@0x<ptr>->0x<ptr>
         com.apple.txm(25.1)[01108044-259B-370C-891A-7FFF39799C39]@0x<ptr>->0x<ptr>
         com.apple.driver.AppleMobileFileIntegrity(1.0.5)[DC4F4B6A-E3A4-3F23-8517-8534A1D40838]@0x<ptr>->0x<ptr>
            dependency: com.apple.driver.ApplePMGR(1)[1497C1AD-9E67-39B6-9861-2B871441DD83]@<ptr>-><ptr>
            dependency: com.apple.iokit.CoreAnalyticsFamily(1)[0F1FB7DB-F11C-3B27-85B3-E593C2BF7A18]@<ptr>-><ptr>
            dependency: com.apple.kec.corecrypto(26.0)[A80B80EC-469D-3B03-A024-36FDDD9AE18B]@<ptr>-><ptr>
            dependency: com.apple.kext.CoreTrust(1)[0B3E96FA-DA1E-30F2-BFB8-346ACDDE181B]@<ptr>-><ptr>
            dependency: com.apple.security.AppleImage4(7.0.0)[41E89479-AF32-305E-8061-931E08819969]@<ptr>-><ptr>
Nested panic detected - entry count: 3 panic_caller: 0x<ptr>
Panicked thread: <ptr>, backtrace: 0x<ptr>, tid: 6123
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0xfffffdf000d0bea0
		  lr: 0x<ptr>  fp: 0xfffffdf000d0bec0
		  lr: 0x<ptr>  fp: 0xfffffdf000d0bf60
		  lr: 0x<ptr>  fp: 0xfffffdf000d0bfe0
		  lr: 0x<ptr>  fp: 0xfffffdf000d0bff0
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0xfffffdf00108f9f0
		  lr: 0x<ptr>  fp: 0xfffffdf00108fa10
		  lr: 0x<ptr>  fp: 0xfffffdf00108fa50
		  lr: 0x<ptr>  fp: 0xfffffdf00108fa70
		  lr: 0x<ptr>  fp: 0xfffffdf00108fb10
		  lr: 0x<ptr>  fp: 0xfffffdf00108fb80
		  lr: 0x<ptr>  fp: 0xfffffdf00108fbf0
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x000000023e999cd4  fp: 0x0000000000000000
      Kernel Extensions in backtrace:
         com.apple.sptm(25.1)[483B7ACD-3530-3B47-A0D4-D54DF1297E2B]@0x<ptr>->0x<ptr>
         com.apple.txm(25.1)[01108044-259B-370C-891A-7FFF39799C39]@0x<ptr>->0x<ptr>
         com.apple.driver.AppleMobileFileIntegrity(1.0.5)[DC4F4B6A-E3A4-3F23-8517-8534A1D40838]@0x<ptr>->0x<ptr>
            dependency: com.apple.driver.ApplePMGR(1)[1497C1AD-9E67-39B6-9861-2B871441DD83]@<ptr>-><ptr>
            dependency: com.apple.iokit.CoreAnalyticsFamily(1)[0F1FB7DB-F11C-3B27-85B3-E593C2BF7A18]@<ptr>-><ptr>
            dependency: com.apple.kec.corecrypto(26.0)[A80B80EC-469D-3B03-A024-36FDDD9AE18B]@<ptr>-><ptr>
            dependency: com.apple.kext.CoreTrust(1)[0B3E96FA-DA1E-30F2-BFB8-346ACDDE181B]@<ptr>-><ptr>
            dependency: com.apple.security.AppleImage4(7.0.0)[41E89479-AF32-305E-8061-931E08819969]@<ptr>-><ptr>
Nested panic detected - entry count: 4 panic_caller: 0x<ptr>
Panicked thread: <ptr>, backtrace: 0x<ptr>, tid: 6123
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0xfffffdf000d0bea0
		  lr: 0x<ptr>  fp: 0xfffffdf000d0bec0
		  lr: 0x<ptr>  fp: 0xfffffdf000d0bf60
		  lr: 0x<ptr>  fp: 0xfffffdf000d0bfe0
		  lr: 0x<ptr>  fp: 0xfffffdf000d0bff0
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0xfffffdf00108f9f0
		  lr: 0x<ptr>  fp: 0xfffffdf00108fa10
		  lr: 0x<ptr>  fp: 0xfffffdf00108fa50
		  lr: 0x<ptr>  fp: 0xfffffdf00108fa70
		  lr: 0x<ptr>  fp: 0xfffffdf00108fb10
		  lr: 0x<ptr>  fp: 0xfffffdf00108fb80
		  lr: 0x<ptr>  fp: 0xfffffdf00108fbf0
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
		  lr: 0x<ptr>  fp: 0x<ptr>
Backtrace continues...
      Kernel Extensions in backtrace:
         com.apple.sptm(25.1)[483B7ACD-3530-3B47-A0D4-D54DF1297E2B]@0x<ptr>->0x<ptr>
         com.apple.txm(25.1)[01108044-259B-370C-891A-7FFF39799C39]@0x<ptr>->0x<ptr>
         com.apple.driver.AppleMobileFileIntegrity(1.0.5)[DC4F4B6A-E3A4-3F23-8517-8534A1D40838]@0x<ptr>->0x<ptr>
            dependency: com.apple.driver.ApplePMGR(1)[1497C1AD-9E67-39B6-9861-2B871441DD83]@<ptr>-><ptr>
            dependency: com.apple.iokit.CoreAnalyticsFamily(1)[0F1FB7DB-F11C-3B27-85B3-E593C2BF7A18]@<ptr>-><ptr>
            dependency: com.apple.kec.corecrypto(26.0)[A80B80EC-469D-3B03-A024-36FDDD9AE18B]@<ptr>-><ptr>
            dependency: com.apple.kext.CoreTrust(1)[0B3E96FA-DA1E-30F2-BFB8-346ACDDE181B]@<ptr>-><ptr>
            dependency: com.apple.security.AppleImage4(7.0.0)[41E89479-AF32-305E-8061-931E08819969]@<ptr>-><ptr>
Nested panic count exceeds limit 5, machine will reset or spin

@zqxwce

zqxwce commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

any news on debugging the crash? I am not sure it is smart to merge this without knowing more about why it has a statistical failure.

@zqxwce zqxwce left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fable review of the PR:

🔴 Blocking

1. Every cryptex operation reports failure to the host — even on success

vp_handle_cryptex_command (scripts/vphoned/vphoned_cryptex.m) builds its response once as vp_make_response(@"err", reqId) and never resets t on the success paths — it only sets r[@"ok"]. But the host read loop decides success/failure purely from t and ignores ok:

// sources/vphone-cli/VPhoneControl.swift ~823
if type == "err" {
    let detail = msg["msg"] as? String ?? "unknown error"
    DispatchQueue.main.async { pending.handler(.failure(ControlError.guestError(detail))) }
    continue
}

So a successful cryptex_install / cryptex_list comes back as t:"err" → thrown as guestError(<cryptexctl stdout>) → surfaced to the user as a failure alert, every time. Every other handler does this correctly, e.g. vphoned_apps.m uses vp_make_response(@"app_launch", …) + r[@"ok"] = @YES on success and reserves @"err" for failures.

Fix: set r[@"t"] to a success type (cryptex_install / cryptex_list) on the happy paths (or build the dict with the success type up front and switch to @"err" only on failure).

2. fw_manifest.py narrows Restore.plist SupportedProductTypes for all variants

scripts/fw_manifest.py changes Restore.plist's SupportedProductTypes from the union of the iPhone + cloudOS lists to the hardcoded ["iPhone99,11", "ComputeModule14,2"]. Against the extracted IPSW that drops iPhone17,3, ComputeModule14,1, ComputeModule17,2, Mac14,14. This script runs at prepare time for every variant, including the existing pymobiledevice3 (non-patchless) restore path — a shared change for a patchless-only feature. It also now disagrees with sources/FirmwarePatcher/Manifest/FirmwareManifest.swift (still emits the union).

iPhone99,11 (the identity the VM presents) is retained, so it probably still passes, but this is an unverified regression to the shared restore path. The BuildManifest addition of ComputeModule14,2 looks genuinely needed for the MobileDevice restore; the Restore.plist narrowing looks like collateral.

Fix: keep Restore.plist's SupportedProductTypes as the union (add ComputeModule14,2 to it if required) rather than replacing it, and confirm a regular/jb restore still completes.

🟠 Restore path (patchless-only, but worth fixing)

All in VPhoneRestoreCLI / the callbacks in sources/vphone-cli/VPhoneCLI.swift:

  • 5-minute hang on any pre-restore failure. In newConnectionCallback, the "Failed to enter recovery", "Not in DFU mode", and "Disappeared" paths set .failed but never call completion.signal() — only restoreProgressCallback signals. So run() blocks the full 300s and then reports the generic "timeout" instead of the real cause. Signal on every terminal path.
  • BootedOS → recovery transition is dead-wrong. After AMDeviceEnterRecovery, the DFU guard re-checks the stale deviceState (still BootedOS) and always falls through to "Not in DFU mode". Re-read the state after entering recovery, or return and let rediscovery drive the restore.
  • Real error reason is discarded. The failure message reads restoreContext.status.errReason — a stale struct copy synced only by a defer that runs after the throw is evaluated — so failures always print "failed: No reason" even though restoreProgressCallback captured the real CFError. Read from contextWrapper.context and drop the restoreContext + defer dance.
  • Force-casts can trap the process. progress as! Int32 and error as! CFError (CF→NSNumber/NSError bridging), plus AMRestorableDeviceCopyDefaultRestoreOptions() as! and try! restoreVariantName(...). Any unexpected private-API payload SIGABRTs mid-restore. Prefer as? with graceful defaults.
  • Unsynchronized cross-thread access. MobileDevice callbacks fire on a background thread and mutate RestoreContext.status; the main thread reads it. Only the terminal write is ordered by signal/wait; the .notstarted/.started transitions race with nothing. Guard status with a lock (also a Swift 6 concurrency soundness gap).
  • --config is a required option but is never used in run(), yet restore_mobiledevice passes --config ./config.plist. Wire it in or drop it. The --ipsw help text also looks copy-pasted from --variant.

🟠 Guest daemon / shell robustness

  • extract_cryptexctl can abort fw_prepare. scripts/fw_prepare.sh does cp … "$tools_prefix/cryptexctl" without mkdir -p "$tools_prefix"; .tools/ is gitignored, so on a tree that hasn't run make setup_tools, set -euo pipefail aborts prep. Also disk=$(ls -AU $disk_dir | head -1) is unquoted/unchecked (empty → cryptic hdiutil error), and a failed cp leaks the attached image (the hdiutil detach never runs).
  • Nil-argument crashes in the guest. ExtractCryptex does [@"Extraction issue" stringByAppendingString:archiveError]; if archiveError is nil (several unarchive.m early returns don't set it), that throws NSInvalidArgumentException, and the vphoned.m dispatch loop has no @try/@catch, so the whole client connection is torn down. Likewise a missing variant/path puts a NULL mid-argv, silently truncating the cryptexctl command line.
  • Process deadlock on large output. VPhoneCryptex.swift's runProcess calls waitUntilExit() before draining the pipe; cryptexctl create -v / hdiutil can exceed the ~64 KB pipe buffer and hang forever. Drain the pipe before waiting (or use a background reader).

🟡 Minor / polish

  • PersonalizeCryptex shadows ok/contents/name, ignores the createDirectory result, and returns on the first entry (fine if "one cryptex only" is intended — a comment would help).
  • addCryptexctl prints and silently returns if .tools/cryptexctl is missing → the firmware ships without cryptexctl and the guest feature is quietly disabled. Consider making this a hard error.
  • exit(42) inside the reusable runProcess bypasses defer cleanup (leaks temp dirs/mounts) and can't be surfaced by the GUI install path.
  • CryptexError.ProcessError doesn't name the failing command (one helper runs ~20 subprocesses).
  • setUpdatedComponentsInRestorePlist replaces SystemRestoreImageFileSystems wholesale with no before/after log.
  • Typo "No reponse." (VPhoneControl.swift); run-on error strings ("Extraction issue").
  • Dropping --base-trust-cache in the patchless trustcache: worth a comment on why it's safe (merged mount is a superset) and a note in research/, per the repo's docs convention.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants