# How the vphone-cli Restore Pipeline Fetches SHSH Blobs and Performs DFU Restore

> Learn how the vphone-cli restore pipeline fetches SHSH blobs from Apple's TSS service and performs DFU restores programmatically using Swift and Python scripts.

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

---

**The vphone-cli restore pipeline coordinates Swift CLI orchestration with Python bridge scripts to first retrieve SHSH blobs from Apple's TSS service using the device's ECID, then boot the virtual machine into DFU mode and stream the signed firmware payload via vsock to the guest daemon to complete the restore process.**

The Lakr233/vphone-cli project implements a fully automated restoration workflow for virtual iOS devices. By combining Swift-based VM management with Python-driven communication to Apple's signing infrastructure, the pipeline eliminates manual intervention during SHSH retrieval and DFU flashing. This architecture enables both online restores with live TSS negotiation and offline restores using cached signature blobs.

## Resolving Device Identifiers and VM Bundles

Before contacting Apple's servers, the pipeline must identify the target device. In [`sources/vphone-cli/VPhoneRestoreCLI.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/VPhoneRestoreCLI.swift), the `run()` method invokes `VPhoneRestoreOps.resolveECID` (defined in [`sources/VPhoneCore/VPhoneRestoreOps.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/VPhoneCore/VPhoneRestoreOps.swift)) to determine the device's unique ECID. The resolver first checks for an explicit `--ecid` argument; if omitted, it reads from [`udid-prediction.txt`](https://github.com/Lakr233/vphone-cli/blob/main/udid-prediction.txt) generated during the DFU boot sequence. This identifier anchors all subsequent TSS communication and blob storage.

## Fetching SHSH Blobs via the Python Bridge

The SHSH retrieval phase leverages a hybrid Swift-Python execution model. When the user invokes `vphone-cli restore <vm-name> --get-shsh`, the Swift layer constructs a command array targeting [`scripts/pymobiledevice3_bridge.py`](https://github.com/Lakr233/vphone-cli/blob/main/scripts/pymobiledevice3_bridge.py) with the `restore-get-shsh` subcommand.

```swift
// VPhoneRestoreCLI.swift (lines 45-47)
if getShsh {
    throw ExitCode(try pmd3("restore-get-shsh", extra: []))
}

```

The helper `pmd3(_:)` builds the full argument set including `--vm-dir`, `--ecid`, and verbosity flags, then executes via [`VPhoneProcessRunner.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneProcessRunner.swift). The Python bridge contacts Apple's TSS service using libmobiledevice, submits the ECID/UDID pair, and writes the returned plist to `<ecid>.shsh` within the VM bundle directory. This file contains the signed hashes required to authorize the subsequent restore.

## Booting into DFU Mode

The DFU restore requires the virtual machine to boot without the standard guest control channel. `VPhoneCreateOrchestrator` (lines 378-384) spawns the CLI binary with the `--dfu` flag, configuring `VZVirtualMachine` for a restricted boot environment. Alternatively, users can invoke `make boot_dfu`, which builds the binary and launches the VM in DFU-only mode, preparing the virtual hardware to receive the restore payload.

## Executing the Restore Update

Once the VM runs in DFU mode, the orchestrator triggers the actual restoration. The Swift CLI invokes the `restore-update` subcommand through the same Python bridge:

```swift
// VPhoneRestoreCLI.swift (lines 61-66)
code = try pmd3("restore-update", extra: [])

```

The bridge streams the IPSW contents—including iBSS, iBEC, and ramdisk images—over the VM's vsock channel to the `vphoned` daemon running inside the guest. The daemon applies the SHSH signature previously fetched and executes the libimobiledevice restore sequence, effectively flashing the firmware to the virtual device.

## Offline Restore with Cached SHSH

The pipeline supports air-gapped operations through the `--offline` flag. When specified, `VPhoneRestoreCLI` locates the cached `*.shsh` file within the VM bundle and passes it to the Python bridge via the `--tss` parameter. The bridge skips TSS server contact and uses the cached blob for signature verification, allowing restoration in isolated network environments.

```bash

# Offline restore workflow

vphone-cli vm launch MyPhone --dfu &
vphone-cli restore MyPhone --offline  # Uses cached <ecid>.shsh

```

## Post-Restore Version Bookkeeping

Upon successful completion (exit code 0), the CLI calls `recordRestoreVersions` to extract iOS and cloudOS version metadata from the restored bundle's plist files. Using `VPhoneRestoreInfo.derive`, the system writes this data to [`restore-info.json`](https://github.com/Lakr233/vphone-cli/blob/main/restore-info.json) in the VM directory, creating a permanent record of the versions installed during the restore operation.

## Complete Workflow Examples

The following commands demonstrate the full pipeline from SHSH retrieval to completed restore:

```bash

# 1. Fetch SHSH blob only (online)

vphone-cli restore MyPhone --get-shsh

# Generates: MyPhone/<ecid>.shsh

# 2. Full online restore (DFU boot + restore)

vphone-cli vm launch MyPhone --dfu &
vphone-cli restore MyPhone

# 3. Offline restore using cached blob

vphone-cli vm launch MyPhone --dfu &
vphone-cli restore MyPhone --offline --tss MyPhone/<ecid>.shsh

```

## Summary

- The **vphone-cli** restore pipeline uses `VPhoneRestoreOps.resolveECID` to identify the virtual device before any network communication occurs.
- **SHSH blobs** are fetched via [`pymobiledevice3_bridge.py`](https://github.com/Lakr233/vphone-cli/blob/main/pymobiledevice3_bridge.py) using the `restore-get-shsh` command and cached as `<ecid>.shsh` files within the VM bundle.
- The **DFU boot** sequence is triggered by the `--dfu` flag in `VPhoneCreateOrchestrator`, preparing the VM to receive firmware payloads.
- **Restore execution** streams IPSW components over vsock to the `vphoned` daemon, which applies the SHSH signature and flashes the device using libimobiledevice logic.
- **Offline restores** bypass Apple's TSS servers by passing cached SHSH files via the `--tss` argument to the Python bridge.
- **Version metadata** is automatically recorded to [`restore-info.json`](https://github.com/Lakr233/vphone-cli/blob/main/restore-info.json) upon successful completion via `recordRestoreVersions`.

## Frequently Asked Questions

### How does the Python bridge interact with Apple's TSS servers?

The [`pymobiledevice3_bridge.py`](https://github.com/Lakr233/vphone-cli/blob/main/pymobiledevice3_bridge.py) script uses libmobiledevice bindings to construct and send a TSS request containing the device's ECID and firmware identifiers. It receives the signed SHSH blob from Apple's signing service and writes it as a plist file to the VM bundle directory, enabling cryptographic authorization of the restore process.

### What files does vphone-cli modify during the restore process?

The CLI writes the SHSH blob to `<ecid>.shsh` in the VM directory, updates [`restore-info.json`](https://github.com/Lakr233/vphone-cli/blob/main/restore-info.json) with version metadata via `VPhoneRestoreInfo.derive`, and modifies temporary AEA image caches when handling encrypted IPSW components during offline restores.

### Can I perform a restore without booting into DFU mode?

No, the restore pipeline specifically requires the VM to be running in DFU mode initiated via `--dfu` or `make boot_dfu`. This mode disables the standard guest control channel and prepares the virtual hardware to accept the low-level restore payload streamed by `vphoned`.

### Where are SHSH blobs cached for offline restores?

SHSH blobs are stored in the VM bundle directory as files named `<ecid>.shsh`, where `<ecid>` matches the device's unique identifier resolved during the initial `VPhoneRestoreOps.resolveECID` call. These files persist between operations and are referenced via the `--tss` parameter during offline restore execution.