Lakr233

    Lakr233/vphone-cli

    #164 this week

    ios
    Swift
    MIT
    14.1K stars
    1.7K forks
    14.1K GitHub watchers
    Updated 9/20/2026
    View on GitHub

    Build with Backblaze B2

    SDKs, agent skills, IDE extensions, and reference pipelines from Backblaze Labs. All open source.

    Explore Backblaze Labs

    Loading star history...

    Use Cases & Benefits

    • Boots and manages virtual iPhone VMs on Apple Silicon Macs using Apple's Virtualization.framework and custom patched firmware.
    • Automates the full VM lifecycle including IPSW download, patching, DFU restore, and custom firmware installation with multiple jailbreak variants.
    • Use for security research requiring iOS VM environments with varying jailbreak and anti-VM detection bypass levels.
    • Use for automated end-to-end testing of iOS apps via programmatic VM control and screenshot feedback.
    • Use for developers needing isolated, configurable virtual iPhones for debugging or experimenting with iOS system modifications.

    About vphone-cli

    vphone-cli

    Boot a virtual iPhone via Apple's Virtualization.framework using PCC research VM infrastructure.

    poc

    Prerequisites

    Host:

    Dependencies:

    brew install [email protected] aria2 wget gnu-tar openssl@3 ldid-procursus sshpass keystone cmake libusb ipsw zstd
    

    Install

    brew install zqxwce/tap/vphone-cli
    

    Build

    git clone --recurse-submodules https://github.com/Lakr233/vphone-cli.git
    
    ./scripts/setup_tools.sh      # install deps, build toolchain submodules, create the Python venv
    ./scripts/build.sh            # build + sign vphone-cli, bundle the .app, cross-compile vphoned
    
    cd .build/vphone-cli.app/Contents/MacOS/
    vphone-cli --help
    

    Quick Start

    One command creates a VM end-to-end (download → patch → DFU restore → CFW install → first boot):

    vphone-cli vm create myphone -V jb        # -V / --variant
    
    vphone-cli vm launch myphone
    

    Commands

    vphone-cli vm create runs the whole pipeline; the individual steps below let you drive it manually or re-run one stage.

    Manage

    vphone-cli vm list                         # list VMs (--json for scripting)
    vphone-cli vm info myphone                  # show one VM
    vphone-cli vm new myphone                   # create an empty bundle (cpu/mem/disk options)
    vphone-cli vm config myphone --cpu 8 --memory 8192
    vphone-cli vm clone myphone myphone-2       # fast APFS clone, fresh device identity
    vphone-cli vm export myphone --out myphone.tzst   # zstd fast by default (--max = xz -9); --out may be a dir (auto-names <vm>.tzst/.txz); skips restore dir + staging files
    vphone-cli vm import myphone.tzst --name restored
    vphone-cli vm rename myphone iphone16
    vphone-cli vm delete iphone16
    

    Build a VM manually (what vm create automates)

    vphone-cli vm new myphone                              # 1. empty bundle
    vphone-cli fw prepare myphone --iphone-version 26.1     # 2. download + merge IPSWs
    vphone-cli fw patch myphone --variant jb                # 3. patch the boot chain
    
    vphone-cli vm launch myphone --dfu &                    # 4. boot into DFU (background)
    vphone-cli restore myphone --get-shsh                   #    fetch SHSH
    vphone-cli restore myphone                              #    DFU restore
    vphone-cli vm stop myphone                              #    stop the DFU boot
    
    vphone-cli cfw install myphone --variant jb             # 5. install CFW (host-mount; asks for sudo)
    vphone-cli vm launch myphone                            # 6. first boot
    

    Update to a newer iOS by pointing fw prepare at an IPSW: --iphone-source /path/to.ipsw --cloudos-source /path/to.ipsw.

    Firmware Variants

    Five patch variants with increasing security bypass — pass one to --variant:

    VariantBoot ChainCFWNotes
    less4 patches2 phasesPatchless — keeps iOS mitigations enabled
    regular42 patches10 phasesAMFI/SSV/Img4/TXM bypass
    dev53 patches12 phases+ TXM entitlement/debug bypass
    jb113 patches14 phases+ full jailbreak (Sileo, TrollStore auto-install on first boot)
    exp141 patches18 phasesJB superset + anti-VM-detection research patches

    See research/0_binary_patch_comparison.md for the per-component breakdown.

    Running & Connecting

    • SSH (jailbreak): ssh -p 22222 mobile@<vm-ip> (password alpine)
    • SSH (regular/dev): ssh -p 22222 root@<vm-ip>
    • VNC: vnc://<vm-ip>:5901

    Locations

    Everything vphone-cli creates lives under ~/.vphone/ — kept outside the repo and the .app so the signed bundle stays portable. Redirect the whole tree with $VPHONE_ROOT:

    PathContents
    ~/.vphone/The per-user data root — override the entire location with $VPHONE_ROOT.
    ~/.vphone/VMs/VM bundles — one directory per VM. This is the library; override with $VPHONE_LIBRARY_ROOT.
    ~/.vphone/ipsws/Downloaded iPhone + cloudOS IPSWs, cached and reused across VMs.
    ~/.vphone/tools/Cached APFS seal-volume artifacts (apfs_sealvolume_<version>) fetched during fw prepare.
    ~/.vphone/debs/Cached .deb packages the jb/exp CFW install lays into the guest (Sileo, apt, …).
    ~/.vphone/venv/Auto-provisioned Python environment (see Python runtime; override with $VPHONE_VENV_DIR).

    Precedence: the per-item overrides ($VPHONE_LIBRARY_ROOT, $VPHONE_VENV_DIR) win over $VPHONE_ROOT, which wins over the ~/.vphone default. The ipsws/, tools/, and debs/ caches always sit directly under whichever root is active.

    SIP/AMFI Relaxation

    Option A — fully disable SIP, then disable AMFI via boot-arg (most permissive).

    In Recovery (long-press power → Terminal):

    csrutil disable
    csrutil allow-research-guests enable
    

    Then reboot into macOS and set the AMFI boot-arg (needs SIP fully off to take effect):

    sudo nvram boot-args="amfi_get_out_of_my_way=1 -v"   # reboot after
    

    Option B — keep SIP on (debug-only relaxed), then allowlist the binary with amfidont (leaves AMFI enabled system-wide).

    In Recovery:

    csrutil enable --without debug
    csrutil allow-research-guests enable
    

    Then reboot into macOS and:

    vphone-amfidont         # .build/vphone-cli.app/Contents/Resources/vphone-amfidont for local builds
    

    Tested Environments

    HostiPhoneCloudOS
    Mac16,11 27.0b217,3_18.6.2_22G10026.1-23B85
    Mac16,8 26.5.117,3_26.0_23A34126.1-23B85
    Mac16,8 26.5.117,3_26.0.1_23A35526.1-23B85
    Mac16,12 26.317,3_26.1_23B8526.1-23B85
    Mac16,12 26.317,3_26.3_23D12726.1-23B85
    Mac16,12 26.317,3_26.3_23D12726.3-23D128
    Mac16,12 26.317,3_26.3.1_23D813326.3-23D128
    Mac16,11 26.217,3_26.4_23E24626.4-23E5207q
    Mac16,11 26.217,3_26.5_23F7726.4-23E5207q
    Mac16,11 27.0b217,3_26.5.2_23F8426.4-23E5207q
    Mac16,6 26.4.117,3_26.6_23G7126.4-23E5207q
    Mac16,11 27.0b217,3_26.6.1_23G8326.4-23E5207q
    Mac16,11 27.0b217,3_27.0_24A5380h26.4-23E5207q
    Mac16,6 26.4.117,3_27.0_24A5390f26.4-23E5207q
    Mac16,6 26.6.117,3_27.0_24A5408d26.4-23E5207q
    Mac16,11 27.0b217,3_27.0_24A5418b26.4-23E5207q
    Mac16,11 27.0b217,3_27.0_24A5424a26.4-23E5207q

    FAQ

    zsh: killed ./vphone-cli — AMFI/debug restrictions aren't bypassed; see Prerequisites (amfi_get_out_of_my_way=1 or amfidont).

    Virtualization is not available on this hardware — your Mac is itself a VM; PV=3 guest boot can't nest. Use a non-nested macOS 15+ host.

    Stuck on "Press home to continue" — connect via VNC and right-click (two-finger click) to simulate the home button.

    System apps won't install — during iOS setup, don't pick Japan or the EU as your region (extra regulatory checks the VM can't satisfy); pick e.g. United States.

    App crashes on launch with EXC_GUARD / GUARD_TYPE_MACH_PORT — re-patch with vphone-cli fw patch <name> --variant <v> --force-exc-guard, then re-restore/install (#291). Always on for iOS 18 bases.

    Install a .ipa/.tipa — use the running VM's Install menu (drag-drop or file picker).

    cfw install hangs re-signing a system binary (e.g. Campo), memory climbing unbounded — known bug in ldid-procursus up to 2.1.5-procursus7 (the current Homebrew stable): bytes(uint64_t) calls __builtin_clzll(0) with no zero-guard, which is undefined behavior, and on this build resolves to a 0-length that underflows an unsigned loop counter — ldid spins writing one byte at a time into a growing buffer instead of terminating. Triggered by any entitlements plist containing an integer value of exactly 0 (some real Apple system binaries have these). Fixed upstream but not yet in a tagged release; rebuild from source: brew install --HEAD ldid-procursus && brew link --overwrite ldid-procursus. Kill the hung ldid process first (sudo kill -9 <pid>) if you already hit it.

    Automation

    vphone-cli exposes a host control socket (<bundle>/vphone.sock) for programmatic control — screenshots, touch, swipes, hardware keys, clipboard — each action returning an inline screenshot for AI-driven E2E testing. See vphone-mcp for an MCP server wrapping it.

    Acknowledgements

    Discover Repositories

    Search across tracked repositories by name or description