How to Perform Firmware Patching with vphone‑cli: A Complete Guide to the Swift Patching Pipeline

vphone‑cli performs firmware patching through a pure‑Swift pipeline that modifies the iOS boot chain (iBSS → iBEC → LLB → kernel → kernel extensions) on the host machine using semantic analysis of ARM64 instructions rather than hard‑coded offsets.

The patching system is orchestrated by a central FirmwarePipeline class that coordinates component‑specific patchers implementing the Patcher protocol. Users invoke this pipeline through the patch‑firmware command or Makefile shortcuts, with each variant (regular, less, dev, jb, exp) controlling which modifications are applied to the firmware components in a VM's Restore directory.


Architecture Overview

The Firmware Pipeline

At the heart of vphone‑cli's patching system is FirmwarePipeline.swift, which implements the end‑to‑end workflow:

  • Loads firmware components from the VM directory (TXM files, kernel cache, device tree, AVP‑Booter, etc.)
  • Instantiates the appropriate patcher for each component based on the selected variant
  • Executes patchAll() to apply discovered modifications and write patched binaries back to disk

The pipeline is variant‑aware: it conditionally includes jailbreak hooks, development TXM patches, or experimental features depending on user input.

The Patcher Protocol

All component patchers conform to PatcherProtocol defined in sources/FirmwarePatcher/Core/PatcherProtocol.swift. The protocol requires:

protocol Patcher {
    func findAll() -> [PatchRecord]
    func apply()
    func log(_ message: String)
}

This abstraction allows each firmware component to implement custom discovery logic while sharing common infrastructure for instruction analysis and patch recording.


Key Components and Their Roles

TXM Patching (iBoot Chain)

File: sources/FirmwarePatcher/TXM/TXMPatcher.swift

The TXM patcher handles iBSS, iBEC, LLB, and related boot components. It locates critical boot routines using string references and control‑flow analysis, then applies patches to bypass signature checks or enable debug features.

Kernel Patching Infrastructure

Base File: sources/FirmwarePatcher/Kernel/KernelPatcherBase.swift

KernelPatcherBase.swift provides the shared machinery for all kernel patchers:

  • Mach‑O parsing: Locates __TEXT and __DATA segments, section headers, and symbol tables
  • ADRP/BL indexing: Builds an index of ADRP‑ADD and BL instruction pairs for rapid target lookup
  • String reference search: Finds Mach‑O string entries and resolves their virtual addresses
  • Patch emission: The emit(...) routine creates PatchRecord structs with original bytes, replacement bytes, and metadata

This infrastructure enables semantic patching—discovering patch locations by analyzing instruction patterns rather than relying on version‑specific offsets.

Core Kernel Patcher

File: sources/FirmwarePatcher/Kernel/KernelPatcher.swift

KernelPatcher.swift inherits from KernelPatcherBase.swift and applies the foundational kernel patches:

  • Panic function redirection
  • Kext text range identification
  • Virtual‑to‑file offset conversion

Jailbreak and Experimental Variants

Patcher File Purpose
KernelJBPatcher sources/FirmwarePatcher/Kernel/KernelJBPatcher.swift Applies jailbreak‑specific hooks for code injection and sandbox relaxation
KernelEXPPatcher sources/FirmwarePatcher/Kernel/KernelEXPPatcher.swift Experimental patches including hv_vmm rename and DSC byte‑5 mangling

Each inherits the base infrastructure and adds variant‑specific discovery logic.


Invoking the Pipeline

Command‑Line Interface

The patch‑firmware subcommand is implemented in PatchFirmwareCLI within sources/vphone-cli/VPhoneCLI.swift (lines 25–107). Available options:

Flag Description
--vm-directory PATH Path to VM containing Restore/ firmware files
--variant {regular,less,dev,jb,exp} Patching variant to apply
--records-out PATH Write JSON patch log for debugging
--force-exc-guard Apply EXC_GUARD workaround patches
--frida Enable Frida Stalker compatibility patches

Basic Usage


# Patch with regular variant (most common)

vphone-cli patch-firmware \
    --vm-directory ./vm \
    --variant regular

# Patch with jailbreak variant and output records

vphone-cli patch-firmware \
    --vm-directory ./vm \
    --variant jb \
    --records-out ./patch-records.json \
    --force-exc-guard

Variant Selection Guide

  • regular: Standard patches for production use
  • less: Minimal patches for "patch‑less‑compatible" boot scenarios
  • dev: Adds development TXM patches for debugging
  • jb: Full jailbreak support with kernel hooks
  • exp: Experimental features (requires understanding of implementation)

Makefile Integration

The repository provides convenient Make targets in the root Makefile (lines 353–358 and related). These build the patcher binary and invoke it with proper flags:


# Build the patcher binary

make patcher_build

# Patch with regular variant (equivalent CLI shown in comments)

make fw_patch

# $(PATCHER_BINARY) patch-firmware --vm-directory "$(VM_DIR_ABS)" --variant regular

# Jailbreak variant with optional flags

make fw_patch_jb FRIDA=1 FORCE_EXC_GUARD=1

# Minimal patches (requires sudo for VM manipulation)

make fw_patch_less

The Makefile handles path conversion, conditional flag injection, and dependency checking automatically.


How Semantic Patching Works

Unlike traditional firmware tools that use hard‑coded file offsets, vphone‑cli's patchers discover locations at runtime:

  1. Disassembly: ARM64Disassembler.swift provides ARM64 instruction decoding
  2. Pattern matching: ADRP + ADD sequences are matched to find pointer construction
  3. BL target resolution: Branch-and-link instructions are indexed and resolved
  4. String table scanning: Critical strings (e.g., "AppleSEPManager", "cryptex") are located and their references traced

This approach makes the pipeline resilient across iOS versions—as long as the semantic patterns remain stable, the same patcher works on new firmware without modification.


Output and Debugging

Patch Records

When --records-out is specified, the pipeline writes a JSON array of PatchRecord structs (defined in sources/FirmwarePatcher/Core/PatchRecord.swift):

[
  {
    "component": "kernel",
    "patcher": "KernelJBPatcher",
    "virtualAddress": "0xfffffff0070080a0",
    "fileOffset": 123456,
    "originalBytes": "1f2003d5",
    "patchedBytes": "000080d2",
    "description": "Disable AMFI: ret0 patch"
  }
]

This enables auditing, regression testing, and forensic analysis of applied modifications.

Logging

All patchers use the shared log(_:) helper to emit progress information. Set the environment variable VPHONE_LOG=debug for verbose output during patching operations.


Summary

  • vphone‑cli implements firmware patching through a Swift‑based pipeline centered on FirmwarePipeline.swift
  • Five variants (regular, less, dev, jb, exp) control which patches are applied
  • Semantic discovery via ARM64Disassembler.swift and KernelPatcherBase.swift provides version resilience
  • Component patchers for TXM, kernel base, jailbreak hooks, and experimental features each specialize the shared infrastructure
  • CLI and Makefile interfaces provide flexible invocation for manual use and automation

Frequently Asked Questions

What iOS versions does vphone‑cli's firmware patching support?

The semantic patching approach targets ARM64 instruction patterns rather than version‑specific offsets. As implemented in KernelPatcherBase.swift, the pipeline analyzes ADRP/BL sequences and string references that remain stable across iOS releases. Specific version support depends on when Apple changes the underlying code structure being patched.

Can I apply multiple variants in a single patch operation?

No—each patch operation selects exactly one variant. The FirmwarePipeline instantiation in VPhoneCLI.swift maps the --variant parameter to a single FirmwarePipeline.Variant case. To combine effects (e.g., jb with experimental features), you must run sequential patch operations or use a variant that encapsulates the desired combination.

Why does make fw_patch_less require sudo while other targets do not?

The less variant manipulates VM state in ways that require elevated privileges for certain filesystem or virtualization operations. The Makefile explicitly checks for sudo availability before executing fw_patch_less, whereas standard variants operate entirely on firmware files within the VM directory without system‑level modifications.

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 →