# How Firmware Components Are Patched in vphone-cli: A Technical Deep Dive

> Discover how vphone-cli patches firmware components using a Swift pipeline that traverses the iPhone boot chain and applies binary patchers for virtualization. Learn the technical details.

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

---

**vphone-cli replaces the legacy Python firmware patcher with a Swift-based pipeline that walks the iPhone boot chain, applies specialized binary patchers to each firmware component, and repackages the modified payloads for virtualization.**

The open-source [**Lakr233/vphone-cli**](https://github.com/Lakr233/vphone-cli) project implements a complete firmware patching system for running iOS in virtualized environments. Understanding how firmware components are patched in vphone-cli requires examining its pipeline architecture, per-component patcher classes, and pattern-driven binary modification strategy.

## The FirmwarePipeline Orchestrator

At the heart of the system lies `FirmwarePipeline`, defined in [`sources/FirmwarePatcher/Pipeline/FirmwarePipeline.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/FirmwarePatcher/Pipeline/FirmwarePipeline.swift). This class coordinates the entire patching lifecycle, from discovery to serialization.

### Component Discovery and Variant Selection

The pipeline begins by discovering the virtual machine's *Restore* directory and determining the iOS base version. It constructs an ordered list of **ComponentDescriptor** objects that catalog each firmware piece—including AVPBooter, iBSS, iBEC, LLB, TXM, kernel, and DeviceTree.

vphone-cli supports five build variants that dictate which patchers are active:

- `less` – Minimal patching for lightweight virtualization
- `regular` – Standard patching without jailbreak components
- `dev` – Development mode with additional debugging hooks
- `jb` – Jailbreak-enabled patching
- `exp` – Experimental features including identity rewrite

Each variant selects a different set of patchers. For example, when processing iBSS with the `jb` or `exp` variants, the pipeline injects `IBootJBPatcher` alongside the base `IBootPatcher` according to the logic in [`sources/FirmwarePatcher/Pipeline/FirmwarePipeline.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/FirmwarePatcher/Pipeline/FirmwarePipeline.swift) (lines 67-90).

### Firmware Loading Abstraction

The `FirmwareLoader` protocol abstracts IM4P container handling. The default `ContainerFirmwareLoader` extracts raw payloads via `IM4PHandler`, passes them to the appropriate patcher instances, and repackages the modified binary on save. This abstraction allows the pipeline to handle both raw firmware images and encrypted IM4P containers transparently.

## Per-Component Patcher Architecture

Every firmware component has a dedicated patcher class implementing the `Patcher` protocol. These classes discover modification targets using the Capstone disassembly framework coupled with a custom `ARM64Disassembler`.

### IBootPatcher (iBSS/iBEC/LLB)

The `IBootPatcher` class in [`sources/FirmwarePatcher/IBoot/IBootPatcher.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/FirmwarePatcher/IBoot/IBootPatcher.swift) handles the critical bootloaders. It applies several specialized modifications:

- **Serial banner updates** – Rewrites device identifier strings in the binary
- **Image4 callback fixes** – Locates the `b.ne` + `mov x0, x22` pattern and patches the verification callback
- **Root filesystem bypass** – For LLB, finds `mov w8, #<errorCode>` patterns and NOPs the error path to bypass root-fs checks
- **Panic bypass** – Prevents the device from entering panic mode during boot
- **Boot-args rewriting** – Locates the `"%s"` format string, finds the corresponding `ADRP` + `ADD` instruction pair, and re-encodes them to point at a new boot-arguments string

### Kernel Patchers

Three distinct patchers handle the Darwin kernel:

- **KernelPatcher** – Applies base modifications including exception guard (`exc-guard`) entitlement tweaks
- **KernelJBPatcher** – Injects jailbreak-specific patches such as IOS-27 guards and Frida support hooks
- **KernelEXPPatcher** – Applies experimental modifications including the `hv_vmm` rename for hypervisor testing

### DeviceTree and Filesystem Patchers

- **DeviceTreePatcher** – Injects identity-rewrite properties when the `exp` variant is active
- **CryptexFilesystemPatcher** – Rewrites the filesystem manifest for the `less` variant to remove unnecessary cryptex volumes
- **ManifestHashPatcher** – Updates firmware manifest hashes when signature patching is omitted

## Pattern-Driven Binary Patching

Rather than using hardcoded offsets, vphone-cli employs pattern matching to locate patch sites across different iOS versions.

### Chunked Disassembly Strategy

To minimize memory usage when processing large firmware images, patchers process binaries in overlapping 8 KiB chunks (`chunkSize = 0x2000` with `chunkOverlap = 0x100`). This ensures instruction patterns that span chunk boundaries are still detected. The `ARM64Encoder` helper then emits replacement instructions (such as `NOP` sleds or re-encoded `ADRP` sequences) to implement the patches.

### Boot-Args Rewriting Implementation

For iBEC and LLB components, the pipeline performs complex string replacement:

1. Locates the `"%s"` format string in the binary
2. Identifies the `ADRP` + `ADD` instruction pair that loads the string address
3. Allocates a zero-filled slot for the new boot-arguments string
4. Re-encodes the instructions using `ARM64Encoder` to point at the new location

This process is implemented in [`sources/FirmwarePatcher/IBoot/IBootPatcher.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/FirmwarePatcher/IBoot/IBootPatcher.swift) (lines 158-190 and 224-260).

## Implementation Example

The following Swift code demonstrates initializing and executing the firmware pipeline:

```swift
import Foundation
import VPhoneCore

// Path to a VM directory containing extracted iPhone firmware
let vmURL = URL(fileURLWithPath: "/path/to/vphone600/VM")

// Create pipeline for jailbreak + experimental variant
let pipeline = FirmwarePipeline(
    vmDirectory: vmURL,
    variant: .jb,          // Options: .less, .regular, .dev, .jb, .exp
    verbose: true,
    noBinpack: false,
    noVphoned: false,
    forceExcGuard: false,
    enableFrida: false)

// Execute patching process
do {
    let records = try pipeline.patchAll()
    print("✅ Patched \(records.count) sites across all components.")
} catch {
    print("❌ Patch failed: \(error)")
}

```

The `patchAll()` method iterates over the component list, loads each firmware file via `FirmwareLoader`, executes the patcher factories, applies the resulting `PatchRecord` objects, and writes the modified payloads back to disk as implemented in [`sources/FirmwarePatcher/Pipeline/FirmwarePipeline.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/FirmwarePatcher/Pipeline/FirmwarePipeline.swift) (lines 120-180).

## Summary

- **Pipeline Architecture** – `FirmwarePipeline` orchestrates component discovery, variant selection, and patch application across the entire iOS boot chain.
- **Modular Patchers** – Each component (iBSS, kernel, DeviceTree) has a dedicated patcher class that implements the `Patcher` protocol and emits `PatchRecord` objects.
- **Pattern Matching** – Patch locations are identified dynamically using Capstone disassembly rather than hardcoded offsets, enabling support for multiple iOS versions.
- **Memory Efficiency** – The 8 KiB chunked disassembly strategy keeps memory footprint low while handling multi-gigabyte firmware images.
- **Variants** – Five build variants (`less`, `regular`, `dev`, `jb`, `exp`) control which patches are applied, from minimal virtualization to full jailbreak support.

## Frequently Asked Questions

### What firmware image formats does vphone-cli support?

vphone-cli supports both raw binary payloads and IM4P containers through the `ContainerFirmwareLoader` abstraction. The loader uses `IM4PHandler` to decrypt and extract payloads from Apple's encrypted IM4P format, then repackages them after modification.

### How does the chunked disassembly strategy prevent missed patches?

The system processes firmware in 8 KiB chunks (`0x2000` bytes) with a 256-byte overlap (`0x100`). This overlapping window ensures that instruction patterns spanning the boundary between two chunks are fully visible to the disassembler, preventing edge-case misses while maintaining low memory usage.

### What distinguishes the `jb` and `exp` variants from `regular` patching?

The `jb` variant injects `IBootJBPatcher` and `KernelJBPatcher` classes that disable code signing checks and inject Frida hooks. The `exp` variant adds experimental features including identity-rewrite properties in DeviceTree and the `hv_vmm` hypervisor rename in the kernel, whereas `regular` only applies patches necessary for basic virtualization without jailbreak capabilities.

### How does vphone-cli locate specific functions to patch without symbol tables?

The patchers use the Capstone disassembly engine combined with `ARM64Disassembler` to search for unique instruction patterns. For example, the root-fs bypass locates `mov w8, #<errorCode>` sequences, while the image4 callback fix searches for `b.ne` followed by `mov x0, x22`. Once identified, `ARM64Encoder` generates replacement instructions (typically NOPs or branch instructions) that are written back into the binary as `PatchRecord` objects containing the original and patched bytes.