SpringBoard did carry SystemHook; what it lacked was libmisfix beside it.
Which libraries a process gets is decided in its parent, and launchd starts
SpringBoard itself, so SystemHook's list naming it was never consulted. A
probe reading KERN_PROCARGS2 showed DYLD_INSERT_LIBRARIES held SystemHook
alone in SpringBoard and both libraries in installd and misagent.
- vpIsMISFixTarget moves to InjectionEnvironment.h and the launchd hook
asks it too, inserting libmisfix only when the dylib exists.
- vpInsertHooks dropped the extra library when the environment already
named SystemHook; fixed, with make test-injection-environment.
- No guest binary carries a libmisfix load command. The three declarations
that added them are gone, cfw install puts each .bak back and removes
/mf, and inject-dylib --reclaim-source-version goes with its only caller.
- SystemHook's logs are world-writable: a root-created 0644 file silently
dropped every line from a mobile process, which is what made SpringBoard
look as though it never carried the hook.
Measured on test-26.4 and test-27.0, both recreated from local IPSWs: from
the first boot SpringBoard, installd and misagent carry both libraries, and
AirBuild installed through installd opens on both.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A paid team's IPA installed on test-27.0 and was refused at launch with
0xE8008026: SpringBoard asks MIS itself, and it never carried the hook. The
spawn route SystemHook-vphone.c listed it under was never reached.
- system-springboard-cfw-launch_authorization links libmisfix into
SpringBoard with a weak load command, as installd and misagent are.
- SpringBoard's header has 16 spare bytes, so the command names a /mf
root alias and inject-dylib --reclaim-source-version drops
LC_SOURCE_VERSION to leave the re-signer room for its signature.
- MISFixInstallPolicy now runs in installd only.
Measured on test-27.0 after a cold boot: SpringBoard loads libmisfix, MIS
returns 0x0 for AirBuild, and it launches.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
libmisfix reached installd and misagent as an LC_LOAD_WEAK_DYLIB that
cfw install wrote into each binary. SystemHook already interposes
posix_spawn and already decides per path what a child gets, so it owns
this now: installd, misagent and SpringBoard get libmisfix added to
DYLD_INSERT_LIBRARIES, and nothing else does.
Linked versus inserted is not a detail here, and is probably the bug.
A weak load command makes the hook a dependency of the main executable,
which is enough to interpose the calls that executable makes itself —
misagent asks MobileGestalt for the UDID directly, and its override has
always worked. It is not enough for a call made between two shared-cache
images, and installd's check is exactly that: +[MICodeSigningVerifier
_validateSignatureAndCopyInfoForURL:withOptions:error:] lives in
MobileInstallation and calls libmis, with installd's own image not
involved. That call kept seeing the guest's real UDID and refusing the
app with 0xE8008015 even after a fresh installd. DYLD_INSERT_LIBRARIES
loads the hook ahead of everything else, which is where an interpose
covers the cache's own uses of a symbol too.
SpringBoard is in the list for the gap dropping the cache patch left
open: it asks MIS again at launch, so an app signed with a free
personal-team certificate could be installed and then refused with
0xE8008026. It already received SystemHook, because vpIsAppPath matches
any path containing ".app/"; it just never received this hook.
Targets are matched on the end of the path, so a bootstrap or cryptex
copy of the same binary is caught too. vpInsertHook keeps its signature
and forwards to vpInsertHooks, so the launchd hook is unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
#519: vphoned wrote jbroot/dev as the link text /rootfs/dev. The kernel
resolves link text, not vroot paths, so it dangled: every shell failed on
/dev/null and sshd never started. It is now /dev, an existing
/rootfs/dev link is replaced, and rootfs -> / is created.
#520: Irisin unpacks packages without RootHide dpkg's hook, so nothing
linked .jbroot in deeper package directories, and sudo could not load
libsudo_util from usr/libexec/sudo.
- vphoned walks the bootstrap for directories holding Mach-O files and
links each one, at install, at startup, and one second after the root's
Library/dpkg changes. That pass also runs the base steps that waited for
pwd_mkdb or ssh-keygen, so sshd has host keys once openssh is installed.
- The spawn hooks follow the executable's LC_RPATH and LC_LOAD_DYLIB
entries inside the root and link each dependency's directory, within a
fixed bound. SystemHook does the same for TweakLoader before its dlopen.
- launchd starts xpcproxy and bootstrap daemons through posix_spawnp, which
the launchd hook now interposes. SystemHook is chain-loaded into every
child whatever its environment; DISABLE_TWEAKS and safe mode only keep
ElleKit out.
The installer moves to Daemon/Bootstrap, with RootHide and rootless code
in their own folders.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
Publish validated location state to authorized CoreLocation clients, keep guest hooks in sync, and add a Release artifact workflow for unsigned CI packages.
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>