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:
VPHONE_PYTHONenvironment variable override- Development virtual environment (
.venv/bin/python3) - Per-user managed venv (
~/.vphone/venv) - 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-cliorchestrates pymobiledevice3 via a Python bridge script located atscripts/pymobiledevice3_bridge.py.- Environment management automatically bootstraps Python venvs and validates dependencies (ipsw-parser, keystone-engine) through
VPhoneResources.swift. - Command construction in
VPhoneRestoreCommandassembles arguments including--vm-dir,--ecid, and optional--tssflags for offline operations. - Process execution uses
VPhoneProcessRunner.runStreamingfor real-time output streaming during firmware restoration. - Metadata extraction via
VPhoneRestoreInfo.deriverecords iOS version information torestore-info.jsonafter 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →