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

> Boot iOS VMs on Macs with vphone-cli. This guide details using Apple's Virtualization framework on macOS 15+ for interactive or DFU mode iPhone VMs via command line.

- Repository: [Lakr/vphone-cli](https://github.com/Lakr233/vphone-cli)
- Tags: how-to-guide
- Published: 2026-09-09

---

**`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`](https://github.com/Lakr233/vphone-cli/blob/main/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`](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/main.swift) |
| Command definitions | Sub-command structure (`boot`, `boot_dfu`, `install`, `record`) | [`sources/vphone-cli/VPhoneCLI.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/VPhoneCLI.swift) |
| VM builder | Hardware model, NVRAM, peripherals, and start logic | [`sources/vphone-cli/VPhoneVirtualMachine.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/VPhoneVirtualMachine.swift) |
| Lifecycle bridge | Connects CLI options to macOS app delegate | [`sources/vphone-cli/VPhoneAppDelegate.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/VPhoneAppDelegate.swift) |
| Hardware model | Private PV=3 iPhone hardware construction | [`sources/vphone-cli/VPhoneHardwareModel.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/VPhoneHardwareModel.swift) |
| Networking | Vsock control channel and network device setup | [`sources/VPhoneCore/VPhoneNetworking.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/VPhoneCore/VPhoneNetworking.swift) |
| DFU patterns | Boot-stage logic for recovery mode | [`sources/VPhoneCore/VPhoneBootPatterns.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/VPhoneCore/VPhoneBootPatterns.swift) |

## Building vphone-cli from Source

Compile the project with private entitlements using the provided Makefile:

```bash

# 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`](https://github.com/Lakr233/vphone-cli/blob/main/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`](https://github.com/Lakr233/vphone-cli/blob/main/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`](https://github.com/Lakr233/vphone-cli/blob/main/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`](https://github.com/Lakr233/vphone-cli/blob/main/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`](https://github.com/Lakr233/vphone-cli/blob/main/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:

```bash
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:

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

```

The `forceDFU` parameter triggers logic from [`VPhoneBootPatterns.swift`](https://github.com/Lakr233/vphone-cli/blob/main/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:

```bash
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:

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

```

## Network Configuration

[`VPhoneNetworking.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneNetworking.swift) in [`sources/VPhoneCore/VPhoneNetworking.swift`](https://github.com/Lakr233/vphone-cli/blob/main/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`](https://github.com/Lakr233/vphone-cli/blob/main/main.swift) → [`VPhoneCLI.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneCLI.swift) → [`VPhoneAppDelegate.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneAppDelegate.swift) → [`VPhoneVirtualMachine.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVirtualMachine.swift)
- **[`VPhoneVirtualMachine.swift`](https://github.com/Lakr233/vphone-cli/blob/main/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`](https://github.com/Lakr233/vphone-cli/blob/main/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`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneAppDelegate.swift).