# How vphone-cli Performs DFU Restore on a Virtual iPhone: Complete Technical Guide

> Learn how vphone-cli performs DFU restore on a virtual iPhone. This guide details booting in DFU mode, orchestrating firmware restore, and fetching SHSH blobs.

- Repository: [Lakr/vphone-cli](https://github.com/Lakr233/vphone-cli)
- Tags: deep-dive
- Published: 2026-09-05

---

**vphone-cli performs DFU restore on a virtual iPhone by booting the VM in DFU mode using private Virtualization.framework APIs, then orchestrating a multi-stage workflow via `VPhoneCreateOrchestrator` that probes the recovery endpoint, fetches SHSH blobs, and executes the firmware restore through the `pmd3` Python bridge.**

The open-source **Lakr233/vphone-cli** project enables developers to virtualize iOS devices on Apple Silicon Macs. Understanding how it handles DFU restore on a virtual iPhone requires examining its Swift implementation that interfaces with undocumented `Virtualization.framework` flags and external restoration utilities to simulate physical device workflows.

## Booting the Virtual Machine in DFU Mode

The restore process begins in [`VPhoneVirtualMachine.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVirtualMachine.swift), where the `start(forceDFU:)` method configures the virtual machine to boot into DFU mode. This functionality relies on a private API flag that is not publicly exposed in Apple's `Virtualization.framework`.

When `forceDFU` is set to `true`, the code creates a `VZMacOSVirtualMachineStartOptions` instance and invokes the undocumented `_setForceDFU` method through dynamic runtime binding:

```swift
// VPhoneVirtualMachine.swift (lines 52-63)
let opts = VZMacOSVirtualMachineStartOptions()
Dynamic(opts)._setForceDFU(forceDFU)          // Private API invocation

```

After setting the flag, the VM starts headlessly. If DFU mode is active, the CLI prints a diagnostic message indicating the device can be accessed with `irecovery`, the standard entry point for DFU communication:

```swift
print("[vphone] Starting\(forceDFU ? " DFU" : "")…")
if forceDFU { print("[vphone] VM started in DFU mode - connect with irecovery") }

```

## Orchestrating the DFU Restore Workflow

The high-level coordination happens in [`VPhoneCreateOrchestrator.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneCreateOrchestrator.swift), specifically within `runRestorePhase(bundleURL:verbosity:)`. This orchestrator manages the entire lifecycle: from launching the DFU process to validating post-restore state.

### Launching the Managed DFU Process

To keep the VM running in DFU mode while performing host-side operations, the orchestrator spawns a **managed background process** using `VPhoneManagedProcess`. This process executes the same `vphone-cli` binary with the `--dfu` flag and a configuration path:

```swift
// VPhoneCreateOrchestrator.swift (lines 66-69)
let dfu = VPhoneManagedProcess(selfExecutable,
                               ["--config", configURL.path, "--dfu"],
                               cwd: bundleURL, echo: false)
try dfu.start()
defer { dfu.terminate() }

```

The `defer` block ensures the DFU process terminates after the restore completes, preventing zombie VM instances.

### Probing the Recovery Endpoint

Once the VM is running, the orchestrator must confirm the virtual device has entered recovery/DFU mode and is reachable. It repeatedly invokes the `pmd3` Python bridge with the `recovery-probe` sub-command, targeting the specific **ECID** (Exclusive Chip ID) of the virtual device:

```swift
// VPhoneCreateOrchestrator.swift (lines 69-78)
let result = try? VPhoneProcessRunner.runCapturing(
    python, [resources.pmd3Bridge.path,
             "recovery-probe", "--ecid", "0x\(ecid)", "--timeout", "2"])

```

The system attempts this probe up to 90 times with 2-second timeouts, ensuring the virtual hardware has initialized sufficiently to accept restoration commands.

## Acquiring SHSH Blobs and Executing Restore

After confirming device connectivity, the workflow proceeds in two distinct phases: fetching the signed SHSH blob (required for firmware validation), then performing the actual system restore.

### Fetching the SHSH Blob

The orchestrator calls `pmd3 restore-get-shsh` to obtain a signed SHSH blob from Apple's TSS servers. This step requires the **UDID** (Unique Device Identifier) and **ECID** of the virtual iPhone:

```swift
// VPhoneCreateOrchestrator.swift (lines 78-84)
let shshArgs = [resources.pmd3Bridge.path,
                "restore-get-shsh", "--vm-dir", ".", "--udid", udid,
                "--ecid", "0x\(ecid)"] + verbosityArgs
let shshCode = try VPhoneProcessRunner.runStreaming(python,
                                                    shshArgs, cwd: bundleURL,
                                                    echo: v.showsToolDetail)

```

The blob is saved to the VM bundle directory, serving as the cryptographic authorization token for the firmware installation.

### Running the Firmware Restore

With the SHSH blob secured, the orchestrator executes `pmd3 restore-update` to perform the actual firmware installation. This command streams restore progress to the console:

```swift
// VPhoneCreateOrchestrator.swift (lines 86-92)
let restoreArgs = [resources.pmd3Bridge.path,
                   "restore-update", "--vm-dir", ".", "--udid", udid,
                   "--ecid", "0x\(ecid)"] + verbosityArgs
let restoreCode = try VPhoneProcessRunner.runStreaming(
    python, restoreArgs, cwd: bundleURL, echo: v.showsToolDetail)

```

## Post-Restore Validation and Cleanup

After the restore command completes, the orchestrator performs critical validation to confirm success. It monitors the DFU process output for panic messages that indicate the VM has rebooted into the newly restored state:

```swift
// VPhoneCreateOrchestrator.swift (lines 97-108)
let dfuOutcome = dfu.waitForOutput(matching: "(?i)panic|kernel panic", timeout: 30)
switch dfuOutcome { … }

```

Detection of a **panic** or **kernel panic** message within 30 seconds signals that the virtual device has successfully rebooted and loaded the new firmware. The orchestrator then records version metadata to [`restore-info.json`](https://github.com/Lakr233/vphone-cli/blob/main/restore-info.json) within the bundle directory before terminating the managed DFU process.

## Practical Command-Line Examples

These commands implement the technical workflow described above:

**Perform a complete DFU restore (online mode):**

```bash

# Create VM bundle (first run only)

vphone-cli create my-phone

# Restore (automatically boots DFU, fetches SHSH, installs firmware)

vphone-cli restore my-phone

```

**Fetch SHSH blob only (without restoring):**

```bash
vphone-cli restore my-phone --get-shsh

```

**Restore using cached SHSH and decrypted AEA images (offline mode):**

```bash
vphone-cli restore my-phone --offline

```

According to the source code in [`VPhoneRestoreCLI.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneRestoreCLI.swift), these flags delegate to the same `VPhoneCreateOrchestrator` path, with the `--dfu` flag passed automatically during the restore phase.

## Summary

- **Private API Dependency**: DFU mode activation requires the undocumented `_setForceDFU` flag on `VZMacOSVirtualMachineStartOptions` in [`VPhoneVirtualMachine.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVirtualMachine.swift).
- **Managed Process Architecture**: The orchestrator uses `VPhoneManagedProcess` to maintain the VM in DFU mode while performing host-side restore operations.
- **Python Bridge Integration**: All low-level restore logic (probing, SHSH fetching, firmware installation) is delegated to the external `pmd3` Python tool via `VPhoneProcessRunner`.
- **State Detection**: Successful restoration is verified by monitoring the serial output for panic messages, indicating the kernel has booted the new firmware image.
- **Metadata Tracking**: Post-restore, the system records device information in [`restore-info.json`](https://github.com/Lakr233/vphone-cli/blob/main/restore-info.json) for future reference.

## Frequently Asked Questions

### How does vphone-cli enable DFU mode without physical hardware buttons?

The tool uses a **private Virtualization.framework API** accessed via runtime dynamic binding. In [`VPhoneVirtualMachine.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVirtualMachine.swift), the code calls `_setForceDFU(true)` on `VZMacOSVirtualMachineStartOptions`, a flag that forces the virtual machine to initialize in DFU state without requiring physical button combinations.

### What is the pmd3 Python bridge and why is it necessary?

The `pmd3` bridge is an external Python utility that handles Apple-specific restore protocols (TSS communication, IMG4 parsing, and device communication). Since these protocols require specialized cryptographic handling and USB communication patterns, `vphone-cli` delegates to this established tool rather than reimplementing the protocol stack in Swift, as seen in the `recovery-probe` and `restore-update` invocations.

### How does the orchestrator detect a successful restore completion?

The system monitors the virtual machine's serial console output for specific panic strings. According to [`VPhoneCreateOrchestrator.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneCreateOrchestrator.swift), it waits up to 30 seconds for output matching the regex `(?i)panic|kernel panic`. Detection of such messages indicates the device has rebooted and loaded the new firmware kernel, at which point the DFU process is terminated.

### Can I restore a virtual iPhone without an internet connection?

Yes, using the `--offline` flag. This mode requires a pre-existing `.shsh` blob file and decrypted AEA firmware images in the VM bundle directory. The [`VPhoneRestoreOps.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneRestoreOps.swift) file contains helper utilities for ECID resolution and AEA image decryption that support this offline workflow, bypassing the `restore-get-shsh` network request.