How to Install Custom Firmware (CFW) with vphone-cli: Complete Technical Guide

TLDR: vphone-cli installs Custom Firmware (CFW) by mounting the virtual iPhone’s Disk.img on the host, copying patched system files and Cryptexes onto APFS volumes, and atomically switching the boot snapshot to the modified "live" volume using a coordinated two-script workflow.

Installing Custom Firmware on a virtual iPhone requires precise manipulation of APFS containers and system binaries. The Lakr233/vphone-cli project automates this complex process through a dual-stage shell script architecture that handles disk attachment, binary patching, and snapshot management. This guide explains exactly how CFW installation works, from mounting the raw disk image to flipping the boot snapshot for persistent modifications.

CFW Installation Architecture

The installation process is orchestrated by two distinct scripts that separate host-level disk operations from guest-level system modifications.

Host-Side Orchestration Script

The scripts/cfw_install_host.sh script manages the host-level disk attachment and snapshot switching. According to the source code, it performs the following operations:

  • Attaches the VM’s Disk.img as a raw block device using macOS disk utilities
  • Identifies the APFS container and locates the System volume within the virtual disk
  • Re-executes with root privileges (required for owners-honored mounts)
  • Invokes the appropriate variant-specific installer based on the --variant flag
  • Flips the boot snapshot offline using tools/apfs_snap_rename.py after the installer completes, ensuring the VM boots the freshly-patched volume on next launch

Variant-Specific Installer

The scripts/cfw_install.sh (default "regular" variant) executes the actual system modifications inside the mounted APFS volumes. This script leverages scripts/patchers/cfw.py to extract Cryptexes from the IPSW’s BuildManifest and performs comprehensive system patching.

Step-by-Step Installation Process

Prerequisites and Initial Setup

Before installing CFW, the virtual machine must be in a restored state with the Disk.img created from a valid IPSW. Ensure the VM is powered off to prevent file system corruption during mounting.


# Prepare a restored VM (run once)

make restore        # Downloads an IPSW and creates vm/Disk.img

make poweroff       # Ensures the VM is not running

Mounting and Modifying the Disk Image

The host script attaches Disk.img as a raw block device and determines the correct APFS container. It requires root privileges to mount the System volume with owners honored.


# Install the regular CFW (default variant)

sudo scripts/cfw_install_host.sh

# Or use the Makefile shortcut: make cfw_install

The script automatically selects the installation variant. You can specify alternative variants using command-line flags:

sudo scripts/cfw_install_host.sh --variant jb   # Jailbreak CFW

sudo scripts/cfw_install_host.sh --variant dev  # Development CFW  

sudo scripts/cfw_install_host.sh --variant exp  # Experimental CFW

Binary Patching and System Injection

Once the System volume is mounted, scripts/cfw_install.sh performs the following modifications as implemented in scripts/patchers/cfw.py:

  • Cryptex Extraction: Extracts system Cryptexes from the IPSW BuildManifest and copies them to the appropriate APFS volume locations
  • Binary Patching: Modifies several critical system binaries including seputil, launchd_cache_loader, and mobileactivationd (preserving original backups with .bak extensions)
  • iOS 27 Compatibility: Optionally patches iOS-27-specific components such as diskimagesiod, IOMFB size parameters, and DSC maxSlide values
  • Symbolic Link Creation: Establishes required dyld symlinks for dynamic library loading

Driver and Daemon Deployment

The installer injects additional system components not present in the stock IPSW:

  • GPU Acceleration: Installs the AppleParavirtGPUMetalIOGPUFamily driver for paravirtualized graphics support
  • Jailbreak Environment: Deploys iosbinpack64 containing jailbreak user-land binaries
  • Host Communication: Compiles and signs the vphoned Objective-C daemon using the private signing certificate bundled in scripts/cfw_input/
  • Launch Daemon Injection: Modifies launchd.plist to register additional services including dropbear (SSH), trollvnc (VNC), and rpcserver_ios

Boot Snapshot Switching

After file modifications complete, scripts/cfw_install_host.sh invokes tools/apfs_snap_rename.py to atomically switch the APFS boot snapshot from the recovery image to the live, modified system volume. This operation makes the CFW installation persistent and bootable.

Booting the Modified System

Once the snapshot is switched, boot the virtual iPhone to access the CFW environment:

make boot

The system boots into the modified volume with SSH available on port 22222 using the default password alpine.

Idempotent Installation Behavior

The vphone-cli CFW installation is designed to be idempotent. Running the installation script multiple times safely reuses already-extracted Cryptexes, re-signs binaries from their *.bak copies, and overwrites existing files without corruption. This allows for iterative development and testing of custom firmware modifications.

Summary

  • vphone-cli uses a two-stage installation process: scripts/cfw_install_host.sh handles disk attachment and snapshot switching, while scripts/cfw_install.sh performs binary patching
  • The host script requires root privileges to mount APFS volumes with owners honored and uses tools/apfs_snap_rename.py to flip the boot snapshot
  • Binary patching via scripts/patchers/cfw.py modifies critical components like seputil, launchd_cache_loader, and mobileactivationd while preserving backups
  • The installer deploys additional drivers (AppleParavirtGPUMetalIOGPUFamily), jailbreak tools (iosbinpack64), and the vphoned communication daemon
  • Installation supports multiple variants (--variant jb, dev, exp) selectable via command-line flags
  • The process is idempotent, allowing safe re-installation without re-extracting Cryptexes

Frequently Asked Questions

What file system does vphone-cli modify during CFW installation?

vphone-cli modifies the APFS (Apple File System) volumes contained within the virtual iPhone's Disk.img. Specifically, it mounts the System volume to inject Cryptexes, patched binaries, and launch daemons, then uses tools/apfs_snap_rename.py to switch the boot snapshot from the recovery image to the modified live volume.

Why does the CFW installation require root privileges?

Root privileges are required for owners-honored mounts of the APFS volumes. When the host script scripts/cfw_install_host.sh attaches Disk.img, it must mount the virtual iPhone's file system with full ownership permissions to preserve Unix permissions, extended attributes, and special file modes (like setuid binaries) during the copy and patching operations.

Which binaries does the CFW patcher modify?

According to scripts/patchers/cfw.py, the patcher modifies several critical system binaries including seputil, launchd_cache_loader, and mobileactivationd, along with their backups. For iOS 27 compatibility, it also patches diskimagesiod, adjusts IOMFB size parameters, and modifies DSC maxSlide values. All modifications preserve the original files with .bak extensions for safe recovery.

Can I install multiple CFW variants on the same Disk.img?

Yes, the installation process is idempotent and supports switching between variants using the --variant flag (options include jb for jailbreak, dev for development, and exp for experimental). Running sudo scripts/cfw_install_host.sh --variant [type] will re-patch the existing installation with the selected variant's specific modifications, reusing already-extracted Cryptexes and re-signing binaries from their preserved *.bak copies.

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 →