Commit Graph
49 Commits
Author SHA1 Message Date
LakrandClaude Opus 5.5 ae5e4531a5 Name every patch {component}-{effect}-{name}
The 117 bundled patch identifiers had grown five naming schemes
(kernel.x, jb.x, kernelcache_jb.x, txm_dev.x, bare names). Each one is now
{component}-{effect}-{name}:

- component: avpbooter, ibss, ibec, llb, txm, kernel, devicetree, dyld,
  preboot, or system-<binary> for a guest binary or file.
- effect: boot when the patch is boot-essential, exp when the standard
  preset leaves it off, cfw otherwise. A catalog test enforces this.
- name: snake_case, no hyphen, so the identifier splits from the right.

Record sites are now always <identifier>.<site>. The underscore-prefix
rule in covers(recordIdentifier:) and in the gate is gone: the new names
contain underscores, so kernel-boot-post_validation would otherwise have
covered kernel-boot-post_validation_unsigned. The 25 records that relied
on it (amfi_trustcache_1, launch_constraints_mov, sandbox_ext_N, ...) now
use a dot.

Old identifiers are not migrated. A VM whose PatchPlan or PatchSelection
names one must be patched again. The bundle becomes 2.2.0 and Launchpad
requires 2.2.0, so it never meets an old identifier from a bundle.

Launchpad's patch table shows Component, Effect and Name columns in place
of Identifier and Patch Set; the set moves to the detail line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 15:20:20 +09:00
LakrandClaude Opus 5 8d7d914f52 Let Xcode install an app the guest did not get from Apple
Xcode could not install anything onto a guest unless it was signed with an
Apple leaf certificate, even though the guest runs unsigned code perfectly
well. Measured on a booted 26.6.2 guest: unsigned and ldid-shaped bundles
fail at 0xE800801C, a `codesign --sign -` bundle at 0xE8008014, all from
+[MICodeSigningVerifier _validateSignatureAndCopyInfoForURL:withOptions:error:].
A bundle pushed in through vphoned's apps.install, signed with nothing but
this project's own signature, installs and reaches the foreground — so the
kernel, lsd and SpringBoard already accept it and installd's check is the
only gate.

libmis accepts an ad-hoc signature outright when the caller passes the
AllowAdHocSigning option, which installd never does, and it fills the whole
info dictionary itself. So libmisfix.dylib interposes
MISValidateSignatureAndCopyInfo and adds the option, and cfw install attaches
it to installd with an LC_LOAD_WEAK_DYLIB. Nothing in the dyld shared cache
is touched, deliberately: writing a cache code page is what leaves a 27.0
guest unable to boot in #532.

The same dylib answers the other refusal. A paid team's profile fails at
0xE8008012 because the VM's UDID is in nobody's ProvisionedDevices, and only
a free personal team gets auto-registration. misagent obtains that UDID from
MGCopyAnswer -- its other source, an emulated UDID in the kernel's
codesigning configuration, is unreachable here: the sysctl is a four-byte
flags word and amfi_emulate_device_udid is in neither the kernelcache nor
TXM. Interposing MGCopyAnswer lets libmisfix.plist name a device the team has
already registered. Off until a UDID is set there.

What Xcode and lockdown report is unchanged and still the guest's own UDID;
TXM builds that one from the device tree before the kernel runs. The two
answers disagree on purpose, because agreeing would mean a re-restore for a
UDID that still could not match a real device's.

Also fixes #532's second defect: DyldSharedCacheMISTrustAuthPatcher now
recognises its own output, so a second cfw install reports alreadyPatched
instead of aborting the install.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-30 15:20:20 +09:00
LakrandClaude Opus 5.5 d930e502fa Remove --force-dsc-maxslide from every command and from Launchpad
The flag could not do anything any more. `dsc_maxslide.zero` is pinned to
iOS 27, and on a 27 base the installer's force branch was never reached:
it sat below the `27.` and `26.0`/`18.` cases. Issue #531 credited it with
a fix it could not have made.

The self-gate needs no force on 27. The pristine 24A435 cache reads
size 0x17D504000 + maxSlide 0x20000000 = 0x19D504000, over the 6 GiB
region, and `patch-dsc-maxslide --dry-run` reports overflow. XNU's
shared_region_map_and_slide_2_np picks a 16 KiB-aligned slide below
maxSlide and maps each range FIXED in the 0x180000000 submap, so
size + maxSlide <= region is a sufficient test.

Removed from vm create, restore, cfw install and install-root, the
create options, the Launchpad new-machine sheet and control verbs, and
the helper's installCustomFirmware XPC signature. A helper built before
this has a different hash and shows as outdated, so Launchpad reinstalls
it first. `patch-dsc-maxslide --force` stays on the standalone verb.

Docs: troubleshooting no longer offers the long-gone --force-exc-guard,
and FORCE_DSC_MAXSLIDE is gone from the patcher, verb help, research
notes and the patch-set skill. Row 10 of the patch comparison records
the 24A435 numbers and the source check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 15:20:20 +09:00
Lakr 64aa5f6b3e Merge branch 'main' of https://github.com/Lakr233/vphone-cli 2026-09-30 12:19:31 +09:00
LakrandClaude Opus 5 a0e04c8b19 Let a free-certificate app launch on a hacktivated guest
A guest restored by this project is hacktivated, so it never receives an
activation record and online-auth-agent can never obtain the device
identity an authorization request is signed with. libmis's
checkTrustAndAuthorization therefore returns 0xE8008026 and the profile
stays in "Profile Needs Network Validation" for good: an app signed with
a free personal-team Apple Development certificate installs, then
refuses to launch, and Settings' "Verify App" cannot clear it because
the network step it offers is the step that cannot complete. A paid
team's profile is not marked as needing online authorization, which is
why this was never seen before.

DyldSharedCacheMISTrustAuthPatcher short-circuits the function to return
success, writing mov x0, #0; retab after the prologue's pacibsp so the
PAC pair stays balanced. The function is static and carries no symbol,
so it is anchored on the log string that names it outright and then
required to seed 0xE8008026 in its prologue before anything is written:
two independent routes that must agree. Replacement bytes are the
existing keystone-checked ARM64.movX0_0 and ARM64.retab constants, and
the modified page is re-attested. A cache whose libmis lacks the string
reports absent and exits 0, an already-patched cache is a no-op, and a
cache with the string but no seeding prologue is an error rather than a
guess.

The declaration mis_trust_auth carries no applicability and is not boot
essential: the guest is hacktivated on every base, so the failure exists
on every base. cfw install applies it unconditionally.

Validated on a fresh iPhone17,3 26.6.2 (23G90) + cloudOS 26.4 guest: the
patcher reached the same site through the DSC chunk path that was derived
statically from the extracted library, the guest booted normally, and a
free-team app now installs, verifies, launches and accepts an Xcode
attach.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-30 12:18:44 +09:00
Lennart Kotzur 107cbd0e64 Fix macOS 27 CFW disk selection and debugserver seatbelt (#526)
* fix(cfw): select image disk on macOS 27

Select the APFS store's parent disk when hdiutil lists the synthesized container first.

Use the selected disk for both CFW installation and PCC GPU recovery.

* fix(debugserver): replace entitlements without seatbelt profile

Sign with the complete edited entitlement dictionary instead of merging it with the original signature.

A merge restores seatbelt-profiles, so removing that key did not take effect.
2026-09-30 11:11:44 +09:00
LakrandClaude Sonnet 5.5 090df08195 Reword user-facing errors, app info and Launchpad copy in plain written English
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-29 23:35:59 +09:00
LakrandClaude Opus 5.5 6a8d2c7669 Size and show VM disks in decimal GB
--disk-size and Launchpad's stepper say GB, but Disk.img was truncated
to GiB, so a 128 GB machine showed 137 GB inside iOS. Disks are now
created at N × 10^9 bytes, and vm list and Launchpad divide by 10^9,
matching iOS. Existing machines keep their size and now show it in the
same unit iOS does (a former "64 GB" disk reads 68 GB).

Fixes #523

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 13:13:49 +09:00
LakrandClaude Opus 5.5 235272673a Keep only the camera from EXP and drop the location app hook
Issue #438: guests built after the former EXP patches joined the JB flow
lost location. standard is now the JB baseline plus the virtual camera.

- watchdogd.hv_vmm_cache joins the hv_vmm_present concealment group and
  loses bootEssential: watchdogd only panics once the OID is renamed.
- The eight DeviceTree identity rewrites and the Preboot DeviceTree
  rewrite, newly declared as preboot_devicetree.identity, are blocked in
  standard. cfw install now asks the plan before the Preboot rewrite.
- Camera DT nodes, cam offsets and camera_dsc stay on.
- libvlocation.dylib and its SystemHook load are removed. location.set,
  clear and current call IcliKit directly again, which confirms a request
  by reading back a fresh, software-simulated fix at that coordinate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:12:15 +09:00
LakrandClaude Opus 5 dc4b5340e3 Prefilter the two whole-text kernel scans before Capstone
`fw patch --preset standard` spent 28.8 s of 49 s inside one patch.
Sampling a Release run (8623 samples) put 93% in the vm_map_protect
Shape C scan and 72% of that inside `cs_disasm` — not decoding, but in
Capstone's printer: printInst / printAliasInstr / matchAliasPatterns,
vsnprintf / SStream_concat, and map_set_alias_id -> name2id's strcmp
chain. The real decode, AArch64_LLVM_getInstruction, was 6%.

The scan is deliberately unscoped, so it walks all 8.4 MB of kernel text
and was decoding five instructions at each of ~2.1M offsets only to
reject nearly all of them on the first one.

Gate it on the raw instruction word first, the way buildADRPIndex and
the vm_map_delete scan already do. The gate only ever rejects: a word
that survives takes exactly the decode and the checks it always did, and
every positive determination stays Capstone's.

Both encodings of `mov wD, #6` are accepted even though only MOVZ can
reach the existing `mnemonic == "mov"` check — the MOV-bitmask alias
applies only when the immediate is not MOVZ-encodable, so
`orr w9, wzr, #6` (0x321F07E9) prints as `orr`. Letting it through
anyway keeps the gate independent of that aliasing rule, which is the
one way a cheap prefilter could silently narrow the match. ARM64InstTests
pins both words and the printer's answer for each.

patchThreadSetStateEntitlementFlag has the same shape (extended only) and
gets the same treatment via isBorBL.

Release, 17,3_26.4 + cloudOS 26.4: the patch step 28.81 s -> 1.28 s,
whole run 48.98 s -> 21.68 s standard, ~61 s -> ~28 s extended,
instructions retired 1.006e12 -> 5.38e11.

Verified byte-identical: four bases (26.1 / 26.4 / 26.6.2 / 27.0) x both
presets, HEAD vs HEAD+prefilter, every file in each restore tree hashed —
12/12 identical, same 172 standard / 183 extended counts, same 0x1DC6EA0
rewrite, no undeclared-patch warnings. FirmwarePatcherTests: 410 tests,
132 issues, unchanged from HEAD and all missing local reference samples.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-28 21:52:33 +09:00
LakrandClaude Opus 5.5 73bbf18ba0 Batch actions, export progress and cancel in Launchpad
The toolbar splits into the library and the selection: New Machine is a
menu holding New Machine and Import, and Start or Stop shares a capsule
with the actions menu.

With several machines selected the actions menu offers one Settings edit
that writes only the fields changed, an Export that writes <name>.tzst
for each into a folder, and Delete, followed by start and stop.

Exports show a progress bar in the State column and the inspector, run
one at a time, and can be cancelled from the context menu while one runs
or waits. A cancelled export's partial archive is removed.

vphone-cli's progress bar prints `progress <done> <total>` lines when
VPHONE_PROGRESS=lines is set and stderr is not a terminal. Launchpad sets
it for piped commands and keeps those lines out of logs and error details.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 21:45:04 +09:00
Lakr 657755eb99 chore: swift format 6.2 2026-09-28 21:03:05 +09:00
LakrandClaude Opus 5 b30637a605 Take the hv_vmm_present concealment out of the default patch selection
It bricks a freshly restored 26.4 guest. bluetoothd caches its
sysctlbyname("kern.hv_vmm_present") answer in a dispatch_once (23E246:
the call at 0x1004ac7b4, dispatch_once at 0x1004ac798, flag at
0x100b51bc0); with the OID renamed it gets ENOENT and caches 0, so its
chip-selection singleton (0x10042fa40) picks a transport from the
MGIsDeviceOneOfType table instead. Nothing there matches a virtual
iPhone, the transport singleton at 0x100b50bd0 stays NULL, and it faults
on `ldr w23, [x0, #0x31c]` at +0x402864 and crash-loops until launchd
throttles com.apple.bluetoothd. locationd's CLSeparationAlertsServiceSilo
then blocks on a synchronous call to that throttled service, the
com.apple.locationd.migrator plugin hangs for over an hour, and
SpringBoard waits on migration: black screen, no panic, nothing in the
log naming the cause.

The two halves — kernelcache_exp.hv_vmm (kernel OID rename plus the
kernel-internal cstring mangle) and hv_vmm_dsc (the shared-cache mangle
the system installer runs) — are one behaviour in everything but name,
and neither is useful alone: the rename without the mangle breaks the
graphics and ML paths, the mangle without the rename does nothing. They
are now hypervisorConcealmentPatches, blocked by standard and present in
extended, and a catalogue test refuses any shipped preset that enables
one without the other. Both lose bootEssential, which they never were:
a shipped preset that drops a boot-essential patch warns on every run.

buildComponentList no longer builds KernelExperimentalPatcher when the
patch is off, rather than building it and letting the gate refuse the
write — a patcher constructed to write nothing still logs as if it might.
The DSC half needed no code change; the installer already runs
patch-hv-vmm-dsc only when the plan enables it. A VM with no recorded
plan still gets both, deliberately: that is what its guest was restored
with.

Everything else the former EXP integration brought over stays on:
DeviceTree identity and camera, camera_dsc, the watchdogd cache patch,
and the post-restore Preboot DeviceTree rewrite.

The user-mode xref inventory is corrected too. It listed bluetoothd as
carrying the string with no reference to it, which was measured on 26.1
(23B85) and is not true of 23E246 — so the line is marked per-build
rather than deleted, the 26.4 call sites are written down, and the
"standalone binaries fall into unpatched → ENOENT → cache 0
automatically" step in the shipping design is flagged as the bug it is.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-28 19:59:04 +09:00
LakrandClaude Opus 5 30c8512c89 Declare every patch in a patch set and select it with a preset
Patches were scattered across the patchers that applied them: nothing listed
what a run would do, and nothing could turn one off. This adds the manifest
layer that names them and the preset layer that chooses.

VPhonePatchKit is a distribution framework (library evolution on) holding the
model: VPhoneVersion, VPhoneVersionRequirement, VPhonePatchDeclaration,
VPhonePatchSetManifest, VPhonePatchPreset, VPhonePatchPlan and the gate a
patcher consults before each write. Capstone and the ARM64 encoder moved in
behind an internal import, so nothing downstream sees the package.

Ten bundled sets in FirmwarePatcher/PatchSets declare every existing patch,
checked against the patchers by FirmwarePatchSetCatalogTests. Two presets ship
in VPhone.bundle: standard, and extended for the experimental sets. A
version-pinned patch is present in the manifest but off unless a preset or a
per-VM checkmark asks for it, and neither can widen its version gate.

Patch sets also load from outside the tool. A .vphonepatchset is a macOS
loadable bundle whose Contents/Resources/Manifest.plist is read before any of
its code is mapped, and whose executable exports one symbol,
vphone_patch_set_principal, returning a VPhonePatchSetPrincipal that hands the
pipeline one BufferedPatcher per component the plan enabled.

Not NSPrincipalClass, which is how a loadable bundle normally names its entry
point: library evolution makes VPhonePatchSetPrincipal a resilient superclass,
so a subclass of it needs runtime metadata initialization and is not registered
with the ObjC runtime when the image is mapped. NSClassFromString cannot find
it, and Bundle.principalClass then silently returns whichever class was
registered — the example set's patcher rather than its principal. A @_cdecl
symbol found with dlsym has none of that.

External sets are boot-chain only, because root cfw install loads no external
set; a preset that names one lives in ~/.vphone/patches_presets and cannot
shadow a shipped identifier. `vphone-cli patchset import` copies a set into
~/.vphone/patchsets and ad hoc signs it if it arrived unsigned, so a bundle
straight out of Xcode loads: the linker signs its Mach-O but seals no
resources, which codesign rejects until one pass over the bundle fixes it. The
signature is re-checked from disk at every load, and PatchSetLoaderTests proves
that over the example set — inspect, validate, tamper, load, patch, gate off.

BufferedPatcher replaces the nine concrete downcasts the pipeline used to read
patched bytes back with, which is what lets an out-of-tree patcher return any.

Launchpad gains a patch table per machine, `vphone-cli fw set-patches` writes
the selection, and Skills/authoring-patch-sets documents the whole flow.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-28 19:58:18 +09:00
LakrandClaude Opus 5.5 835c4db23d Share downloaded IPSWs and recovered GPU drivers across machines (#516)
Remote IPSWs were cached inside each machine (<machine>/.ipsw-cache), so
every new machine downloaded both IPSWs again. Launchpad runs the same
fw prepare with catalog URLs and had the same problem. Fixes #513.

- Remote IPSWs go to ~/.vphone/ipsws (follows VPHONE_ROOT); vm create
  and fw prepare take --ipsw-cache to put it elsewhere.
- The GPU driver recovered from cloudOS is cached per build in
  ~/.vphone/gpu-drivers, so later machines on the same cloudOS skip the
  temporary cloudOS restore.
- Two prepares finishing the same URL no longer fail on the rename, the
  cache directory is made writable before a download can fail, and
  partial downloads abandoned for an hour are removed.
- vm export leaves out .ipsw-cache from older machines and staging
  directories left by a failed detach, and its progress total prunes
  excluded directories the same way the writer does.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 16:04:09 +09:00
sizucen cd45b8fab2 Fix iOS 26.3 launchd signature space 2026-09-27 18:48:44 +09:00
ee8b70ca8a VPhoneSign: drop LC_SOURCE_VERSION when the command area has no room
cfw install on iOS 18.6.2 fails at the final launchd re-sign:

    no room for the signature load command: content starts at 3208,
    3224 bytes of commands

launchd ships with only 16 bytes of header padding. inject-dylib spends
the stripped LC_CODE_SIGNATURE slot plus that padding on the 32-byte
LC_LOAD_WEAK_DYLIB for /vh, so when signed() rebuilds the command area
there is nowhere left for the fresh LC_CODE_SIGNATURE.

When the rebuilt area would overrun the first section, drop
LC_SOURCE_VERSION — 16 informational bytes nothing loads — and lay the
area out again; only fail if it still does not fit.

Verified against the shipping iOS 18.6.2 (22G100) launchd: with the
command removed, inject-dylib + sign succeed and cfw install completes
end to end.

Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-authored-by: multica-agent <github@multica.ai>
2026-09-27 00:01:44 +09:00
Lakr 9d12c106c9 Avoid self-owned disk false positive during CFW install 2026-09-25 21:26:37 +09:00
Lakr 6e9732de68 Preserve VM boot state when cloning and launching 2026-09-25 20:56:40 +09:00
Lakr 4fc4f1b115 Deliver VM location through guest app hook
Publish validated location state to authorized CoreLocation clients, keep guest hooks in sync, and add a Release artifact workflow for unsigned CI packages.
2026-09-25 20:08:40 +09:00
Lakr233andClaude Opus 5.5 46802eb728 Close review gaps in the hardening pass
- cfw install on a Disk.img that cannot be cloned renames the root
  snapshot through a fresh no-follow descriptor. That descriptor must
  still be the single-link inode checked at the start. It no longer
  reopens the path minutes later.
- Guest clipboard images use the download size limit again, so images
  over 64 MiB copy as before.
- The --api-listen proxy always forwards admitted requests with
  Host: localhost, so any loopback or LAN listen address works with
  vphoned's Host check.
- Cancelling a CFW install from Launchpad needs no authorization and
  never prompts. The helper still stops only an install the same user
  started.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 17:45:19 +07:00
fbdbe21968 Harden host root, guest and bundle trust boundaries
A repo-wide security review found issues in the root CFW install, the
Launchpad helper, VM bundle handling and the guest boundary. This fixes
them and applies swift format.

- cfw install mounts guest volumes nosuid,nodev,nobrowse in a root-only
  temp folder and does every guest read and write through an open folder
  handle, never following links. BuildManifest cryptex paths must stay in
  the restore folder, and only a private copy is attached.
- Root no longer chowns or chmods the whole VM folder after an install.
  The shared walk skips hard links, symlinks, special files and other
  volumes.
- Every Launchpad helper action needs administrator authorization. Only
  the user who started a CFW install can cancel it. The helper refuses
  setuid, hard-linked, special or escaping-symlink entries in a bundle.
- Manifest file names must be single names in the bundle and point to
  regular files. vm import refuses links that leave the bundle.
- Guest file names from the file browser, QuickLook, drag-out and crash
  logs are validated and written exclusively, without overwriting, and
  are quarantined.
- The guest HTTP client no longer traps on a bare Content-Length, caps
  bodies and enforces a per-request deadline.
- The --api-listen proxy needs a per-launch token. vphoned refuses
  browser-origin and non-local Host requests.
- vphoned stops following links when it sets up Irisin and the camera
  files.

Thanks to fresh-fx59 for reporting the guest file name, HTTP parsing,
cfw install and manifest path issues in #469.

Co-authored-by: Aleksey Aksenov <5788874+fresh-fx59@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 17:30:11 +07:00
58c433d664 Install cryptexes from an image restore --offline already decrypted
restore --offline decrypts each .dmg.aea in place and keeps the name the
manifest expects. cfw install then asked that plain image for its AEA key
and stopped with notAEA. Check the AEA1 magic first and mount a plain
image directly.

Ported from #334, which fixed the same failure in the shell installers.

Co-authored-by: renegadelink <30816473+renegadelink@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 16:13:33 +07:00
Lakr233andClaude Opus 5.5 bc44f4e207 Stop fw prepare when the two IPSWs are swapped or wrong
fw prepare now reads each BuildManifest before it extracts anything. The
iPhone IPSW must list iPhone17,3 in SupportedProductTypes and the cloudOS
IPSW must have a vresearch101ap build identity. Swapped sources get an
error that says to swap them; any other mismatch names the file and what
it should be. Before, a swapped pair extracted both archives and then
failed with "Unable to find the release identity for vresearch101ap".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 15:41:11 +07:00
Lakr233andClaude Opus 5.5 7813b87998 Fix the remaining Swift, Objective-C and linker warnings
- vphoned: add the WebSocket handlers through syncOperations on the
  event loop, so the non-Sendable frame aggregator never crosses a
  concurrency boundary.
- Kernel patchers: drop `try` on the non-throwing parseMachO(), and log
  the recovered csflags reload in the cred label patch. No patch bytes
  change.
- Custom firmware installer: discard the deferred tool result explicitly.
- Video file producer: load the video track once with loadTracks.
- vcamcaptured: mask the class address as a plain integer.
- GPU compiler plugin: name its 18 runtime-resolved LLVM/MTL symbols with
  -U instead of -undefined dynamic_lookup. The import table is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 15:08:46 +07:00
Lakr233andClaude Opus 5.5 c2433edddf Build the vendored restore C code without warnings
Both C targets now build with USE_HEADERMAP = NO. The project header map
resolved a quoted "config.h" in MobileRestoreCore (and in
libimobiledevice-glue's termcolors.h) to libirecovery's copy, so two
config.h files were stacked in one translation unit and every PACKAGE
macro was redefined.

The 64 shorten-64-to-32 sites get the narrower type where the value is
already 32-bit (fls.c, fdr.c, zip indices in ipsw.c) and an explicit cast
where an API or a format field fixes the width. Behaviour is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 15:07:40 +07:00
Lakr233andClaude Opus 5.5 fc57dca56b Load the camera hooks without a bootstrap and add the environment update
The camera hooks were built and shipped but never reached the guest, so
Camera.app could not show a streamed frame. cfw install now places
libvcamcaptured.dylib and libcamfix.dylib in /usr/lib beside the launchd
hook and SystemHook. SystemHook treats /usr/libexec/cameracaptured as an
injection target and loads the daemon hook there, and loads libcamfix into
app processes that have AVFoundation loaded. Both hooks install their own
Objective-C method replacements, so neither needs ElleKit or a bootstrap.

A running guest gets changed copies of those four libraries through the
new vphoned environment update. environment.status reports the SHA-256 of
each library in /usr/lib; environment.install checks the uploaded copies,
remounts / read-write when needed, renames each library into place and
remounts / read-only again, because jailbreak detection reads a writable
root as rootful. It stops cameracaptured when a camera hook or SystemHook
changed and reports when the launchd hook needs a guest restart. The VM
process runs the update once per connection, after the vphoned
self-update, uploading only libraries whose hashes differ.

Not yet verified in a guest; the validation steps are in
Research/0_binary_patch_comparison.md and Research/vphoned_http_api.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 14:57:12 +07:00
Lakr233andClaude Opus 5.5 961f18c075 Move guest payloads into Contents/Resources/guest-resources
VPhone.bundle kept vphoned, the guest dylibs and the GPU compiler plugin
beside the host programs in Contents/MacOS. Everything installed into the
guest now lives in Contents/Resources/guest-resources: vphoned (formerly
vphoned.signed), its launch daemon plist, the launchd hook, SystemHook,
both camera hooks with their filters, and the GPU compiler plugin.
Contents/MacOS holds only vphone-vm, vphone-cli, VPhoneEscalator and the
span compatibility library.

ValidateBundle.sh checks the platform of every Mach-O: iOS binaries only
in guest-resources, none in Contents/MacOS, and no Mach-O elsewhere. The
old Resources/guest directory and guest binaries in Contents/MacOS are
rejected. codesign --verify --strict and --deep both accept the layout,
and vphoned keeps its own entitlements.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 14:57:12 +07:00
Lakr233andClaude Opus 5.5 1f22bfe5d5 Replace remaining user-visible string concatenation with interpolation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 13:59:46 +07:00
Lakr233andClaude Opus 5.5 c27ea64740 Rewrite error messages and labels to say what failed and what to do next
Reword CLI, firmware patcher, restore, escalator, VM window and Launchpad
errors, status text and labels as complete sentences that name the failed
step and the recovery action, and localize the new strings in the VM and
Launchpad catalogs for ja, ko, vi and zh-Hans.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 13:56:36 +07:00
Lakr cabb80a13e Ship only pre-signed vphoned in VPhone bundle 2026-09-25 14:56:47 +09:00
Lakr 228326de04 Integrate former EXP patches into public JB firmware flow 2026-09-25 13:27:47 +09:00
Lakr 421d2853c0 Avoid redundant vphoned update on first boot 2026-09-25 03:53:15 +09:00
Lakr233andClaude Opus 5.5 9efd2264b3 Depend on ArchiveKit 1.0.0 and icli 0.6.8
libarchive.xcframework 0.1.1 shipped a Swift module, LibArchive, that
differed from its C module, libarchive, only in case. Xcode 27 puts both
in one products directory, and on a case-insensitive volume the lookup
for libarchive found LibArchive.swiftmodule, so the nested
VPhoneArchiveKit build failed with "cannot load module 'LibArchive' as
'libarchive'" and the VPhone bundle could not be built. 1.0.0 renames
the module and products to ArchiveKit; icli 0.6.8 moves to it as well,
so the workspace resolves one version.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 00:51:36 +07:00
Lakr233andClaude Opus 5.5 b7ceef03b9 Localize Guest Tools and let menu shortcuts win over the VM view
Guest Tools strings use String(localized:) against the VPhone bundle, with
String.LocalizationValue interpolation for formatted text. The catalog
gains the 71 new keys with zh-Hans, ja, ko and vi translations, inserted
in place so existing entries are unchanged.

capturesSystemKeys let the VM view take every key press before the menu
bar saw it, so menu shortcuts such as ⇧⌘F and ⌘W reached the guest
instead. A local key monitor on the VM window now offers each key press
to the main menu first and passes it to the guest only when no enabled
menu item handles it. This replaces the view's performKeyEquivalent
override, which never ran while system keys were captured.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 00:00:07 +07:00
Lakr f7a4a279e4 Localize VPhone interface and format pending changes 2026-09-25 01:48:27 +09:00
Lakr 6b8673175a Reapply "Add minimal vphone launchd hook and inert system hook"
This reverts commit 924a9af554.
2026-09-25 01:06:54 +09:00
Lakr e5460ff087 Run bundle validation as part of VPhone build 2026-09-25 00:43:37 +09:00
Lakr 924a9af554 Revert "Add minimal vphone launchd hook and inert system hook"
This reverts commit 9efcaa6517.
2026-09-24 23:58:35 +09:00
Lakr 0394ee6a0f Repair vphone guest controls, camera transport, and IcliKit integration 2026-09-24 23:57:46 +09:00
Lakr 9efcaa6517 Add minimal vphone launchd hook and inert system hook 2026-09-24 23:18:34 +09:00
Lakr cb518e6aef Remove obsolete shared restore and staging directory compatibility 2026-09-24 22:35:11 +09:00
Lakr f09ed9c14e Finish firmware cache and image cleanup review 2026-09-24 22:27:48 +09:00
Lakr ea6cfb151f Keep firmware work inside machine directories and clean up mounts 2026-09-24 22:22:43 +09:00
Lakr db4c305753 Fix vphoned startup and VM launch on iOS 26 2026-09-24 22:13:15 +09:00
Lakr 456511f8e8 Build distributable VPhone bundle and remove OpenAPI document 2026-09-24 21:42:30 +09:00
Lakr 7d42b1542c Keep visible Products groups without productRefGroup setting 2026-09-24 20:41:17 +09:00
Lakr 2b58537598 Separate VM child signing and finalize Xcode warning cleanup 2026-09-24 20:37:57 +09:00
Lakr ea082eb027 chore: moved to xcode project 2026-09-24 20:23:44 +09:00