How to Boot iOS VMs on Macs Using vphone-cli: A Complete Guide

vphone-cli uses Apple's private Virtualization framework to boot iPhone virtual machines on macOS 15+ (Sequoia), supporting both GUI interactive mode and DFU recovery mode via command-line configuration.

This command-line tool, developed by Lakr233, provides a Swift-based interface for running iOS virtual machines on Apple silicon Macs. By leveraging private APIs and the VZVirtualMachine architecture, vphone-cli enables security researchers, jailbreak developers, and reverse engineers to boot, debug, and interact with iOS systems without physical hardware.

Prerequisites and System Requirements

Before running vphone-cli, ensure your environment meets these requirements:

  • macOS 15+ (Sequoia) — required for the private Virtualization framework features
  • Xcode 15+ — for compilation and private entitlement handling
  • SIP and AMFI disabled — necessary for private API access to hardware model creation
  • Prepared firmware bundle — config.plist generated by fw_prepare.sh containing the VM manifest

Boot Architecture Overview

The boot process in vphone-cli follows a modular architecture across several core source files:

Component Primary Role Key Source File
Entry point CLI argument parsing and app initialization sources/vphone-cli/main.swift
Command definitions Sub-command structure (boot, boot_dfu, install, record) sources/vphone-cli/VPhoneCLI.swift
VM builder Hardware model, NVRAM, peripherals, and start logic sources/vphone-cli/VPhoneVirtualMachine.swift
Lifecycle bridge Connects CLI options to macOS app delegate sources/vphone-cli/VPhoneAppDelegate.swift
Hardware model Private PV=3 iPhone hardware construction sources/vphone-cli/VPhoneHardwareModel.swift
Networking Vsock control channel and network device setup sources/VPhoneCore/VPhoneNetworking.swift
DFU patterns Boot-stage logic for recovery mode sources/VPhoneCore/VPhoneBootPatterns.swift

Building vphone-cli from Source

Compile the project with private entitlements using the provided Makefile:


# Ensure SIP/AMFI are disabled before proceeding

make build

This invokes Swift Package Manager with the necessary private framework linkages and entitlements required for VPhoneHardwareModel.swift to create the PV=3 hardware model through dynamic library loading.

Standard Boot Process

Step 1: Argument Parsing in VPhoneCLI.swift

The boot sub-command, defined in sources/vphone-cli/VPhoneCLI.swift, accepts configuration through an ArgumentParser-driven interface. Key flags include:

  • --config — path to the firmware manifest (config.plist)
  • --disk — main disk image path
  • --nvram — NVRAM storage image
  • --sep-storage — Secure Enclave processor storage
  • --cpu-count — virtual CPU allocation
  • --memory — RAM allocation (e.g., 8G)
  • --variant — firmware variant (regular, dev, etc.)
  • --rom — optional custom bootloader
  • --debug-port — GDB stub listener port
  • --no-vphoned — disable vsock control channel

Step 2: VM Construction in VPhoneVirtualMachine.swift

The VPhoneVirtualMachine class in sources/vphone-cli/VPhoneVirtualMachine.swift assembles a VZVirtualMachineConfiguration through these operations:

Hardware model creation — VPhoneHardware.createModel() instantiates a PV=3 iPhone-compatible hardware model using private initializers from VPhoneHardwareModel.swift

Machine identifier management — either loads an existing ECID/UDID from config.plist or generates a fresh VZMacMachineIdentifier for persistent identity

NVRAM configuration — writes boot arguments (serial=3 debug=0x104c04) to enable serial console output

Boot loader setup — configures VZMacOSBootLoader with optional custom ROM

Peripheral attachment:

  • Graphics display with configurable resolution
  • Audio device
  • USB keyboard input
  • Synthetic battery for power state simulation
  • Optional SEP coprocessor for Secure Enclave operations
  • Vsock-based guest control channel (unless --no-vphoned)
  • GDB debug stub on auto-assigned or specified port
  • PL011 UART serial port bridged to host stdin/stdout

Step 3: VM Start via VPhoneAppDelegate.swift

VPhoneAppDelegate.swift receives parsed options, instantiates VPhoneVirtualMachine, and calls start(forceDFU:). The NSApplication run-loop then drives the GUI window, menu bar, and optional screen recorder while delegating lifecycle events (guest stop, errors, network changes) to exit handlers.

Boot Modes and Command Examples

Regular GUI Boot

Launch an interactive iOS VM with full graphics and input:

vphone boot \
  --config ./config.plist \
  --disk ./Disk.img \
  --nvram ./NVRAM.img \
  --sep-storage ./SEPStorage.img \
  --cpu-count 8 \
  --memory 8G \
  --variant regular

DFU Mode for Recovery Operations

Use boot_dfu or boot --force-dfu to enter DFU mode, enabling irecovery connections:

vphone boot_dfu \
  --config ./config.plist \
  --disk ./Disk.img \
  --nvram ./NVRAM.img \
  --variant dev

The forceDFU parameter triggers logic from VPhoneBootPatterns.swift, preparing the boot stages for recovery protocol communication through the virtual USB connection.

Custom ROM with Debug Stub

Attach a modified bootloader and expose a GDB server:

vphone boot \
  --config ./config.plist \
  --disk ./Disk.img \
  --rom ./CustomROM.dmg \
  --debug-port 6001

Headless Operation Without Control Channel

Disable the vsock daemon for minimal resource usage:

vphone boot \
  --config ./config.plist \
  --disk ./Disk.img \
  --no-vphoned

Network Configuration

VPhoneNetworking.swift in sources/VPhoneCore/VPhoneNetworking.swift interprets the firmware manifest to configure:

  • NAT networking — default isolated mode with outbound connectivity
  • Bridged networking — direct physical interface attachment
  • No networking — completely isolated VM

The vsock-based control channel provides a host-guest communication path for automation and state queries when not disabled with --no-vphoned.

Summary

  • vphone-cli requires macOS 15+, Xcode 15+, and disabled SIP/AMFI for private Virtualization framework access
  • Core boot flow: main.swift → VPhoneCLI.swift → VPhoneAppDelegate.swift → VPhoneVirtualMachine.swift
  • VPhoneVirtualMachine.swift constructs the complete VM configuration including PV=3 hardware model, NVRAM boot-args, peripherals, and GDB debug capabilities
  • Two primary boot modes: standard GUI operation (boot) and DFU recovery mode (boot_dfu)
  • Serial console access via PL011 UART enables irecovery interaction for jailbreak and security research workflows

Frequently Asked Questions

What macOS version is required to boot iOS VMs with vphone-cli?

macOS 15 Sequoia or later is required. The private Virtualization framework APIs that enable iPhone hardware model creation (PV=3) were introduced in this version and are not available on earlier releases.

Why must SIP and AMFI be disabled to use vphone-cli?

The tool relies on private APIs to instantiate VZMacHardwareModel with iPhone-specific characteristics through VPhoneHardwareModel.swift. Apple's System Integrity Protection and AMFI normally block these dynamic library invocations. Disabling them is mandatory for the hardware model creation to succeed.

How do I interact with a VM booted in DFU mode?

DFU mode exposes a virtual USB recovery interface. Connect standard tools like irecovery or custom debugging utilities to interact with the device. The PL011 UART serial port, bridged to the host terminal, also provides low-level boot output and command access depending on the NVRAM boot-args configuration.

Can vphone-cli run iOS VMs without a GUI?

Partially. While the tool requires an NSApplication run-loop (making it technically GUI-based), you can minimize graphical overhead with --no-vphoned to disable the vsock control channel. Full headless operation without any windowing system is not currently supported due to the AppKit-dependent lifecycle management in VPhoneAppDelegate.swift.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →