Where to Find the vphone-cli Source Code for Firmware Patching
All firmware-patching logic in vphone-cli resides in the sources/FirmwarePatcher directory, organized around the Patcher protocol and orchestrated by the FirmwarePipeline class.
The vphone-cli repository by Lakr233 provides a Swift-based toolkit for virtualizing iOS devices. If you are looking to understand or modify how the tool patches firmware images, you will find the complete implementation under the dedicated sources/FirmwarePatcher path. This modular architecture handles everything from IM4P container parsing to ARM64 instruction-level modifications across the boot chain.
Core Architecture of the Firmware Patching System
The patching system is built on a protocol-oriented design that separates discovery, orchestration, and component-specific logic.
The Patcher Protocol
At the heart of the system lies the Patcher protocol defined in sources/FirmwarePatcher/Core/PatcherProtocol.swift. This protocol establishes the common API that every component patcher must implement:
findAll()→ Discovers patchable locations within the binaryapply()→ Writes modifications to the bufferlog()→ Provides verbose output during operations
Each concrete implementation works with a BinaryBuffer instance and produces PatchRecord objects—defined in sources/FirmwarePatcher/Core/PatchRecord.swift—that capture metadata such as file offsets, original bytes, and disassembly context.
FirmwarePipeline Orchestrator
The FirmwarePipeline class in sources/FirmwarePatcher/Pipeline/FirmwarePipeline.swift serves as the high-level entry point. It manages the complete lifecycle of firmware modification:
- Discovery: Locates the Restore directory within the VM bundle
- Version Detection: Determines the base iOS version to enable conditional patches
- Component Loading: Uses
ContainerFirmwareLoaderto handle IM4P containers transparently - Variant Selection: Builds a component list based on the selected variant (
regular,dev,jb,exp, orless) - Execution: Sequentially calls
findAll()andapply()on each patcher - Persistence: Writes patched payloads back to disk
Component-Specific Patcher Implementations
Individual patchers reside in subdirectories organized by firmware component. Each implements the Patcher protocol and contains ARM64 disassembly logic using the Capstone and Keystone libraries.
Boot Chain and TXM Patchers
The boot chain components—including AVPBooter, iBSS, iBEC, LLB, and TXM—are handled by dedicated patchers:
TXMPatcher.swift(sources/FirmwarePatcher/TXM/TXMPatcher.swift): Implements trust-cache bypass patches for the TXM componentTXMDevPatcher.swift(sources/FirmwarePatcher/TXM/TXMDevPatcher.swift): Adds development and jailbreak-specific entitlements plus debugger patchesIBootPatcher.swift(sources/FirmwarePatcher/IBoot/IBootPatcher.swift): Handles iBSS, iBEC, and LLB modifications for standard variantsIBootJBPatcher.swift: Extends base iBoot patching with jailbreak-specific modifications
Kernel and DeviceTree Patchers
For higher-level firmware components:
KernelPatcher.swift(sources/FirmwarePatcher/Kernel/KernelPatcher.swift): Applies base kernel modifications including exception-guard and developer mode patchesKernelJBPatcher.swift(sources/FirmwarePatcher/Kernel/KernelJBPatcher.swift): Implements jailbreak-specific kernel patchesDeviceTreePatcher.swift(sources/FirmwarePatcher/DeviceTree/DeviceTreePatcher.swift): Modifies the device tree for identity-rewrite operations, primarily used in the EXP variant
Low-Level Binary Handling
The patching infrastructure relies on robust binary utilities for manipulation of raw firmware data.
IM4P Container Management
The IM4PHandler.swift file (sources/FirmwarePatcher/Binary/IM4PHandler.swift) provides transparent handling of IM4P containers. The ContainerFirmwareLoader class abstracts the extraction and repacking of payload data, allowing patchers to work with raw bytes without managing container headers manually.
BinaryBuffer Utilities
BinaryBuffer.swift (sources/FirmwarePatcher/Binary/BinaryBuffer.swift) offers low-level utilities for reading and writing bytes, searching for instruction patterns, and managing memory-mapped firmware images. All patchers interact with firmware data through this abstraction layer.
Using the Firmware Patching API
You can interact with the patching system either through the high-level pipeline or by instantiating individual patchers.
Running the Complete Pipeline
To execute all patches for a specific variant:
import Foundation
import VPhoneCore
let vmDir = URL(fileURLWithPath: "/path/to/vphone/vm")
let pipeline = FirmwarePipeline(
vmDirectory: vmDir,
variant: .jb,
verbose: true,
noBinpack: false,
noVphoned: false,
forceExcGuard: false,
enableFrida: false
)
do {
let patchRecords = try pipeline.patchAll()
print("✅ Finished – applied \(patchRecords.count) patches")
} catch {
print("❌ Patching failed: \(error)")
}
Applying Individual Patches
For targeted modifications to a specific component:
import Foundation
let txmURL = URL(fileURLWithPath: "/path/to/txm.im4p")
let loader = FirmwarePipeline.ContainerFirmwareLoader()
let rawData = try loader.load(from: txmURL)
let txmPatcher = TXMPatcher(data: rawData, verbose: true)
let records = try txmPatcher.findAll()
print("Found \(records.count) TXM patches")
try txmPatcher.apply()
try loader.save(txmPatcher.patchedData, to: txmURL)
Creating Custom Patchers
To implement a new patching component, conform to the Patcher protocol:
final class MyCustomPatcher: Patcher {
let component = "mycomponent"
let verbose: Bool
private var buffer: BinaryBuffer
private var patches: [PatchRecord] = []
init(data: Data, verbose: Bool = true) {
self.buffer = BinaryBuffer(data)
self.verbose = verbose
}
func findAll() throws -> [PatchRecord] {
// Locate target instructions and populate patches array
return patches
}
func apply() throws -> Int {
for record in patches {
buffer.writeBytes(at: record.fileOffset, bytes: record.patchedBytes)
}
return patches.count
}
}
Summary
- The vphone-cli firmware patching source code is located entirely within the
sources/FirmwarePatcherdirectory of the Lakr233/vphone-cli repository. - The architecture centers on the
Patcherprotocol (PatcherProtocol.swift), which defines thefindAll()andapply()methods used by all components. FirmwarePipeline.swiftorchestrates the complete workflow, from discovering the Restore directory to writing patched binaries.- Component-specific logic is split across dedicated files like
TXMPatcher.swift,KernelPatcher.swift, andDeviceTreePatcher.swift. - Low-level binary operations rely on
BinaryBuffer.swiftfor byte manipulation andIM4PHandler.swiftfor container management. - All patchers record their changes using
PatchRecordobjects, enabling full audit trails of modifications.
Frequently Asked Questions
Where is the entry point for firmware patching in vphone-cli?
The entry point is the FirmwarePipeline class in sources/FirmwarePatcher/Pipeline/FirmwarePipeline.swift. This class provides the patchAll() method, which executes the complete patching workflow across all firmware components based on the selected variant (regular, dev, jb, or exp).
How does vphone-cli handle different patching variants like jailbreak or developer mode?
The pipeline builds a component list using factory closures that instantiate different patcher combinations based on the variant parameter passed during initialization. For example, the .jb variant includes TXMDevPatcher and KernelJBPatcher, while the .regular variant uses only base patchers like TXMPatcher and KernelPatcher.
What libraries does vphone-cli use for ARM64 disassembly and assembly?
According to the source code, vphone-cli utilizes the Capstone disassembly framework and the Keystone assembly engine. These libraries enable the patchers to locate specific instruction sequences in the firmware and generate replacement bytecode for patches.
Can I use vphone-cli patching logic outside of the full virtualization context?
Yes. While FirmwarePipeline provides the integrated workflow, you can import the VPhoneCore module and instantiate individual patchers directly. Pass raw firmware data to constructors like TXMPatcher(data:verbose:) or KernelPatcher(data:variant:verbose:), then call findAll() and apply() independently of the pipeline orchestrator.
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 →