vphone-cli boots a virtual iPhone via Apple's Virtualization.framework

vphone-cli boots a virtual iPhone via Apple's Virtualization.framework

A developer working under the GitHub handle Lakr233 has released vphone-cli, an open source command line tool that boots a virtual iPhone on an Apple Silicon Mac. It runs on Apple's own Virtualization.framework together with what the project's documentation calls PCC research VM infrastructure, and it automates the full path from a bare firmware image to a booted device: download, patch, DFU restore, custom firmware (CFW) install, then first boot.

Running it needs a real, non-virtual Apple Silicon Mac on macOS 15 (Sequoia) or later, with Xcode and the iOS SDK installed so the tool can cross-compile its guest daemon, plus System Integrity Protection (SIP) and AMFI code-signing checks relaxed on the host so vphone-cli's own unsigned binary can carry the private PV=3 entitlements it needs. Installing it means cloning its GitHub repository with git clone --recurse-submodules and running its own setup and build scripts, or pulling it from a separate Homebrew tap, zqxwce/tap/vphone-cli.

A single command, vphone-cli vm create -V (for example -V jb for the jailbreak variant), runs the entire pipeline for a chosen iOS version, such as 26.1: it downloads and merges the IPSW firmware images, patches the boot chain, boots the device into DFU mode, restores it, and installs the patched custom firmware. vphone-cli vm launch then boots the finished VM. Each of those steps can also be run individually for finer control, and one of five available patch variants sets how much of the device's security gets bypassed. Other subcommands list and inspect existing VMs, change a VM's CPU, memory and disk allocation, clone one instantly with a fresh device identity through a fast APFS clone, and export or import a VM as a compressed archive.

Once booted, the virtual iPhone is reachable over SSH on port 22222, logging in as mobile with the password alpine in jailbreak mode or as root in the regular, non-jailbroken mode, and over VNC on port 5901 for its screen. The running VM's own Install menu also accepts .ipa and .tipa app files dropped or picked directly. Every file vphone-cli creates lives under ~/.vphone/ by default, kept outside the app bundle and the source tree so the signed app stays portable; that root can be redirected with the VPHONE_ROOT environment variable, and two narrower variables, VPHONE_LIBRARY_ROOT and VPHONE_VENV_DIR, override just the tool cache and the Python virtual environment.

The documentation lists two ways to satisfy the host's SIP/AMFI requirement. One fully disables SIP and then disables AMFI through a boot argument, which it calls the most permissive option. The other leaves SIP on in a debug-relaxed mode and instead allowlists the vphone-cli binary against AMFI with a bundled amfidont tool, leaving AMFI itself enabled system-wide. The documentation also spells out specific failure modes: the guest cannot boot at all if the host Mac is itself a virtual machine, because its PV=3 guest boot mode cannot nest inside another VM; choosing Japan or the EU as the region during iOS setup stops system apps from installing because of extra regulatory checks the VM cannot satisfy, so it recommends a region such as the United States instead; and apps that crash on launch with an EXC_GUARD / GUARD_TYPE_MACH_PORT error, tracked as GitHub issue #291, need the image re-patched with a --force-exc-guard flag, which the documentation says is always required for iOS 18 based firmware.

Separately, the documentation describes a bug in the bundled ldid-procursus signing tool, present up to and including version 2.1.5-procursus7, the version currently shipped by Homebrew. A function called bytes(uint64_t) calls the compiler built-in __builtin_clzll on zero without guarding against it, which is undefined behavior; on this build it resolves to a zero length that underflows an unsigned loop counter, so ldid ends up writing a growing buffer one byte at a time instead of finishing. Any entitlements property list with an integer value of exactly 0, which the documentation notes some genuine Apple system binaries do have, triggers it, hanging the cfw install step with unbounded memory growth until the process is killed. The fix already exists upstream but has not reached a tagged release, so the documented workaround is to kill the hung process and rebuild ldid-procursus from source with brew install --HEAD ldid-procursus.

vphone-cli also exposes a host control socket, vphone.sock, for programmatic control of the guest: screenshots, touch and swipe input, hardware keys and clipboard access, with every action returning an inline screenshot. The documentation points to a separate project, vphone-mcp, that wraps this socket as an MCP server, aimed at AI-driven end-to-end testing.

Key facts

  • vphone-cli, an open source CLI published under the GitHub account Lakr233, boots a virtual iPhone on an Apple Silicon Mac using Apple's Virtualization.framework and what its documentation calls PCC research VM infrastructure; the host needs macOS 15 (Sequoia) or later.
  • One command, vphone-cli vm create, runs the full pipeline (firmware download, boot-chain patch, DFU restore, custom firmware install, first boot) for one of five available patch variants offering increasing levels of security bypass.
  • The resulting VM is reachable over SSH on port 22222 (mobile, password alpine, in jailbreak mode; root in regular/dev mode) and over VNC on port 5901; running it also requires relaxing SIP and AMFI on the host.
  • A bug in the bundled ldid-procursus tool, present up to version 2.1.5-procursus7 (the current Homebrew stable), can hang the firmware-install step indefinitely with unbounded memory growth whenever it re-signs a system binary whose entitlements plist has an integer value of exactly 0; the fix exists upstream but is not yet in a tagged release.
  • vphone-cli exposes a host control socket for programmatic screenshots, touch and swipe input; a companion project, vphone-mcp, wraps that socket as an MCP server for AI-driven end-to-end testing.

Why it matters

vphone-cli folds several separately fiddly steps into one scriptable pipeline: cross-compiling a guest daemon, downloading and merging Apple's IPSW firmware images, patching the iOS boot chain, driving a DFU restore, and installing custom firmware, all built on Apple's own Virtualization.framework and what the project calls PCC research VM infrastructure. The result is a virtual iPhone that can be created, cloned instantly with a fresh device identity, exported as a compressed archive, or torn down entirely from the command line, rather than a physical device that has to be reflashed by hand each time. It also ships a control socket built for automation, screenshots, touch, swipes, hardware keys and clipboard, which a companion project, vphone-mcp, wraps as an MCP server for AI-driven end-to-end testing.

Who it affects

The direct audience is macOS and iOS developers and jailbreak-tooling users on Apple Silicon Macs; the host requirements alone (macOS 15+, Xcode and the iOS SDK, a relaxed SIP/AMFI) rule out Intel Macs and locked-down machines. QA and test engineers who need to script iOS behavior without a rack of physical devices are a second audience, given the SSH, VNC and control-socket access to the guest. The vphone-mcp companion project extends that further, to developers building AI agents that need to drive a real, if patched, iOS environment for automated testing rather than a simulator.

How to use it

vphone-cli is an open source project on GitHub, at Lakr233/vphone-cli. Setup needs an Apple Silicon Mac on macOS 15 (Sequoia) or later, Xcode with the iOS SDK to cross-compile the guest daemon, and SIP/AMFI relaxed on the host. Install it by cloning the repository with git clone --recurse-submodules and running its setup and build scripts, or through a separate Homebrew tap, zqxwce/tap/vphone-cli. From there, vphone-cli vm create -V builds a device end to end for a chosen iOS version, and vphone-cli vm launch boots it; the guest is then reachable over SSH on port 22222 or VNC on port 5901, and its state lives under ~/.vphone/ by default, redirectable with the VPHONE_ROOT environment variable.

How solid is it

The documentation reads as detailed and actively maintained. It names a precise root cause for one known bug, a missing zero-guard in a ldid-procursus function that triggers undefined behavior, cites the exact affected version (up to 2.1.5-procursus7, the current Homebrew stable), links a tracked GitHub issue (#291) for a separate crash, and points to a dedicated file, research/0_binary_patch_comparison.md, that compares its five patch variants component by component. Against that, the source gives no version number or release date for vphone-cli itself, no real name or affiliation for the account behind it, Lakr233, and no benchmark figures for boot time, download size or resource use, so claims about its overall maturity cannot be checked beyond what the documentation itself states.

Risks and caveats

Both documented setup paths weaken host security: one fully disables SIP and then disables AMFI via a boot argument, which the documentation itself calls the most permissive option; the other leaves SIP on but still allowlists the vphone-cli binary against AMFI so it can run unsigned. The guest iOS is patched with one of five variants offering increasing security bypass, including a jailbreak variant. The ldid-procursus signing bug can hang the firmware-install step indefinitely with unbounded memory growth on certain real Apple binaries, and until a tagged fix ships the workaround is to kill the process and rebuild the tool from source. Nested virtualization is not supported, so the host cannot itself be a VM. The documentation does not address the legal status or App Store policy implications of bypassing SIP and AMFI or jailbreaking the guest iOS.