How to Use pymobiledevice3 for DFU Restore in iOS VMs: A Complete Technical Guide

vphone-cli performs DFU restores of iOS virtual machines by delegating low-level firmware operations to the pymobiledevice3 Python library through a bundled bridge script.

This guide explains the architecture and implementation details for using pymobiledevice3 for DFU restore in iOS VMs within the Lakr233/vphone-cli project. The Swift-based CLI orchestrates Python processes via a bridging layer, enabling seamless firmware restoration inside virtualized iOS environments.

Architecture Overview

The restore workflow cleanly separates Swift orchestration from Python DFU logic. This design ensures portability across macOS hosts and CI environments while leveraging pymobiledevice3's native device communication capabilities.

Swift Orchestration Layer

The CLI entry point resides in VPhoneRestoreCLI.swift, which implements the vphone restore command. This layer handles argument parsing, VM bundle selection, and resource resolution before spawning the Python subprocess.

The core orchestration logic lives in VPhoneRestoreCommand.run(), where the pmd3(_:,extra:) helper constructs the bridge invocation:

var args = [
    resources.pmd3Bridge.path,    // → scripts/pymobiledevice3_bridge.py
    subcommand,                   // e.g., "restore-update"
    "--vm-dir", "."
]
if let udid { args += ["--udid", udid] }
args += ["--ecid", ecidValue] + extra
args += Array(repeating: "-v", count: min(v.rawValue, 2))

Python Bridge Layer

The scripts/pymobiledevice3_bridge.py script acts as a thin translation layer between Swift CLI arguments and pymobiledevice3's Python API. It exposes sub-commands such as restore-update and restore-get-shsh, handling DFU client sessions, SHSH blob fetching, and AEA image decryption for offline restores.

Environment Setup and Prerequisites

Before executing a DFU restore, VPhoneResources.swift ensures a compatible Python environment exists with required native dependencies.

Python Interpreter Resolution

The pythonExecutable() method selects a usable interpreter through the following priority order:

  1. VPHONE_PYTHON environment variable override
  2. Development virtual environment (.venv/bin/python3)
  3. Per-user managed venv (~/.vphone/venv)
  4. Bootstrap a new venv on first run if none exist

The selected interpreter must satisfy runtime checks for ipsw-parser and keystone-engine, the two core native components required by pymobiledevice3. These dependencies are declared in requirements.txt with the constraint pymobiledevice3>=9.5.0.

Step-by-Step DFU Restore Workflow

Understanding the end-to-end execution flow helps diagnose issues and extend functionality.

1. Resource Resolution

VPhoneResources.resolve() discovers the bridge script location and validates the Python environment. It exposes the bridge path via resources.pmd3Bridge, pointing to scripts/pymobiledevice3_bridge.py in the repository root.

2. Command Construction

The Swift layer builds the argument vector targeting the bridge script with these key parameters:

  • subcommand: The pymobiledevice3 operation (e.g., restore-update)
  • --vm-dir: Path to the iOS VM bundle directory
  • --udid: Optional device identifier for multi-device scenarios
  • --ecid: Required device ECID for DFU targeting
  • --tss: Path to SHSH blob for offline restores
  • -v: Verbosity flags (up to two levels)

3. Process Execution

VPhoneProcessRunner.runStreaming spawns the Python process with streaming output:

let python = try resources.pythonExecutable()
return try VPhoneProcessRunner.runStreaming(python, args,
                                            cwd: bundle.url,
                                            echo: v.showsToolDetail)

This streams stdout/stderr to the console in real-time, with showsToolDetail controlling echo behavior.

4. Post-Restore Metadata

Upon successful completion (exit code 0), VPhoneRestoreInfo.derive extracts iOS and CloudOS version metadata from the restored firmware, writing the results to restore-info.json within the VM bundle.

Command-Line Usage Examples

The following vphone restore commands demonstrate practical pymobiledevice3 integration patterns.

Basic DFU Restore

Restore a running VM using automatic ECID detection:

vphone restore myiPhone

Specifying Device Identifiers

When multiple devices are present, provide explicit UDID and ECID:

vphone restore myiPhone --udid 00001234-5678-90AB-CDEF-1234567890AB

Offline Restore with SHSH

Perform a fully offline restore using a cached SHSH blob and local AEA decryption:

vphone restore myiPhone --offline --tss /path/to/blob.shsh

SHSH Blob Extraction Only

Fetch the SHSH blob without performing the actual restore:

vphone restore myiPhone --get-shsh

Programmatic Implementation

You can replicate the CLI's restore logic in custom Swift tooling using the same bridging approach.

Swift Bridge Invocation

This simplified implementation mirrors VPhoneRestoreCommand.pmd3(_:,extra:):

func invokePymobiledevice3(_ subcommand: String,
                           vmBundle: URL,
                           ecid: String,
                           udid: String? = nil,
                           extra: [String] = []) throws -> Int32 {
    let resources = VPhoneResources.resolve()
    let python = try resources.pythonExecutable()
    
    var args = [
        resources.pmd3Bridge.path,
        subcommand,
        "--vm-dir", vmBundle.path,
        "--ecid", ecid
    ]
    
    if let udid = udid {
        args += ["--udid", udid]
    }
    args += extra
    
    return try VPhoneProcessRunner.runStreaming(
        python,
        args,
        cwd: vmBundle,
        echo: true
    )
}

Direct Python Bridge Execution

For debugging or custom Python workflows, invoke the bridge directly:

python3 scripts/pymobiledevice3_bridge.py restore-update \
    --vm-dir /path/to/vm.bundle \
    --ecid 1234567890 \
    --udid 00001234-5678-90AB-CDEF-1234567890AB \
    -v -v

The bridge script instantiates pymobiledevice3.restore.RestoreClient and executes the DFU protocol sequence against the specified ECID.

Summary

  • vphone-cli orchestrates pymobiledevice3 via a Python bridge script located at scripts/pymobiledevice3_bridge.py.
  • Environment management automatically bootstraps Python venvs and validates dependencies (ipsw-parser, keystone-engine) through VPhoneResources.swift.
  • Command construction in VPhoneRestoreCommand assembles arguments including --vm-dir, --ecid, and optional --tss flags for offline operations.
  • Process execution uses VPhoneProcessRunner.runStreaming for real-time output streaming during firmware restoration.
  • Metadata extraction via VPhoneRestoreInfo.derive records iOS version information to restore-info.json after successful restores.

Frequently Asked Questions

What Python version and dependencies does vphone-cli require for DFU restore?

vphone-cli requires Python 3 with pymobiledevice3 version 9.5.0 or higher. The interpreter must have ipsw-parser and keystone-engine installed, as these native libraries handle firmware parsing and ARM instruction emulation. The VPhoneResources.swift module automatically checks for these dependencies and can bootstrap a dedicated virtual environment at ~/.vphone/venv if needed.

How does the bridge script handle offline restores without internet connectivity?

When the --tss parameter is provided to the bridge script, pymobiledevice3_bridge.py loads the cached SHSH blob locally instead of requesting it from Apple's TSS servers. It also decrypts AEA (Apple Encrypted Archive) firmware images locally using the provided signatures, allowing full DFU restores without network access to Apple's signing infrastructure.

Can I use vphone-cli restore features on non-Apple Silicon Macs?

The architecture depends on pymobiledevice3's ability to communicate with iOS devices via USB or virtualized interfaces. While the Swift code is platform-agnostic, the underlying restore libraries (particularly those handling DFU mode and image decryption) typically require macOS with appropriate kernel drivers. The Python bridge itself runs on any platform supporting pymobiledevice3, but VM integration assumes a macOS host environment.

What information does vphone-cli record after a successful DFU restore?

Upon successful completion (exit code 0), the CLI invokes VPhoneRestoreInfo.derive to parse the restored firmware bundle and extract the iOS version number, build identifier, and CloudOS version metadata. This information is serialized to restore-info.json within the VM bundle directory, enabling version tracking and subsequent update eligibility checks.

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 →