# How vphone-cli Patches the TXM Coprocessor for Different Firmware Variants

> Discover how vphone-cli patches the TXM coprocessor for diverse firmware variants using specialized Swift classes for release and developer builds.

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

---

**vphone-cli uses two specialized Swift classes—`TXMPatcher` for release builds and `TXMDevPatcher` for developer builds—to dynamically patch the TXM trust-cache checks and debugger gates in the flat binary firmware image.**

The **Lakr233/vphone-cli** repository implements a sophisticated firmware patching pipeline that treats the Trusted Execution Monitor (TXM) as a critical pre-kernel stage requiring variant-specific modifications. Understanding how vphone-cli TXM coprocessor patching works reveals why jailbreak and developer firmware builds require different binary modifications than standard release builds.

## The Two-Tier TXM Patcher Architecture

The patching system centers on two concrete implementations that share a common foundation but diverge based on the target firmware variant.

### The Base TXMPatcher Class (Release Variant)

The `TXMPatcher` class, defined in [`sources/FirmwarePatcher/TXM/TXMPatcher.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/FirmwarePatcher/TXM/TXMPatcher.swift), handles the fundamental requirements for all firmware builds. Its primary responsibility is implementing the **trust-cache bypass** that allows the kernel to load custom trust-caches instead of enforcing Apple's default security policy.

This patcher scans the flat binary TXM image for two specific anchor points: the *selector-24* hash-flags call site and the legacy binary-search guard. Upon locating these instructions using Capstone disassembly, it patches the conditional branches to **NOP** sequences or redirects them to harmless stubs, effectively neutralizing the trust-cache verification without altering the kernel itself.

### The Extended TXMDevPatcher Class (Developer Variants)

For **dev**, **jb**, and **exp** firmware variants, [`sources/FirmwarePatcher/TXM/TXMDevPatcher.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/FirmwarePatcher/TXM/TXMDevPatcher.swift) extends `TXMPatcher` with three additional modification groups:

- **Entitlement injection**: Locates string references to `"get-task-allow"` and replaces the entitlement blob loading routine by patching the branch link (BL) site that calls the original entitlement loader.
- **Debugger gate removal**: Identifies the `"selector-42|29"` stub used to gate debugger access, creates a **code cave** within the binary, and rewrites the branch instruction to always enable the debugging interface.
- **Developer-mode enablement**: Finds the internal developer-mode guard and patches its conditional branch to unconditionally succeed, bypassing production restrictions.

## How the Firmware Pipeline Selects the Right Patcher

The selection logic resides in [`sources/FirmwarePatcher/Pipeline/FirmwarePipeline.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/FirmwarePatcher/Pipeline/FirmwarePipeline.swift), which orchestrates the boot chain sequence:

```

AVPBooter → iBSS → iBEC → LLB → TXM → Kernel → DeviceTree

```

When the pipeline initializes, it evaluates the `FirmwareVariant` enum value provided in the options. If the variant matches `.dev`, `.jb`, or `.exp`, the pipeline instantiates `TXMDevPatcher`; otherwise, it uses the base `TXMPatcher`. Both classes operate on a mutable `ByteBuffer` created from the raw TXM image data, applying their respective patches before returning the modified binary to the pipeline.

```swift
// Simplified pipeline selection logic
if options.variant == .dev || options.variant == .jb || options.variant == .exp {
    let txmPatcher = TXMDevPatcher(data: txmData, verbose: true)
    txmPatcher.applyAll()
} else {
    let txmPatcher = TXMPatcher(data: txmData, verbose: true)
    txmPatcher.applyAll()
}

```

## Technical Implementation of TXM Patches

The patching process relies on dynamic binary analysis rather than fixed offsets, making it resilient across firmware revisions.

### Trust-Cache Bypass (Universal)

Both variants require neutralizing the TXM's trust-cache enforcement. The patcher uses `buffer.findString` to locate anchor strings like `"selector24"`, then disassembles the surrounding ARM64 instructions (ADRP + ADD + BL patterns) using Capstone. It calculates the correct NOP encoding via Keystone and overwrites the branch instructions that would otherwise halt the boot process when encountering an unsigned trust-cache.

### Entitlement Injection (Developer Variants Only)

When patching for jailbreak or developer mode, `TXMDevPatcher` searches for the `"get-task-allow"` string reference within the binary. After locating the entitlement loading routine, it creates a small code cave containing the custom entitlement blob pointer, then patches the original BL instruction to branch to this cave instead of the standard entitlement validator.

### Debugger Gate Removal (Developer Variants Only)

The debugger patch requires creating a functional code cave because the replacement logic is more complex than a simple NOP. The patcher identifies the `"selector-42|29"` validation stub, allocates space within an unused region of the TXM binary, writes shellcode that unconditionally enables debugging, and patches the original gate branch to redirect execution to this cave using `patchBranchToCave`.

### Developer-Mode Enablement (Developer Variants Only)

Similar to the debugger patch, this modification locates the internal developer-mode verification routine and patches its conditional branch (typically a CBZ or CBNZ instruction) to always take the "success" path, effectively hardcoding developer mode to active regardless of hardware fuses.

## Dynamic Binary Scanning and Cave Generation

Because the TXM is a **flat binary without Mach-O headers**, vphone-cli cannot rely on symbol tables or pre-computed offsets. Instead, both patcher classes dynamically scan for string anchors and instruction patterns every time they run. This approach ensures compatibility across different firmware versions where binary layout shifts might otherwise break hardcoded patches.

When the patcher needs to inject custom logic (for debugger enablement or entitlement replacement), it employs a **code cave** strategy:

1. Scans for null-filled or unused regions within the TXM image
2. Aligns the cave to architecture boundaries (typically 4-byte aligned for ARM64)
3. Writes the replacement shellcode or data blob into the cave
4. Calculates the relative branch offset from the original patch site to the cave
5. Uses `patchBranchBack` to return execution flow to the original routine after the custom code executes

## Summary

- **vphone-cli** implements TXM patching through two Swift classes in the `sources/FirmwarePatcher/TXM/` directory.
- **TXMPatcher** handles release builds by bypassing trust-cache checks via NOP patches to selector-24 and legacy hash guards.
- **TXMDevPatcher** extends the base class to add entitlement injection, debugger gate removal, and developer-mode enforcement for jailbreak variants.
- The **FirmwarePipeline** selects the appropriate patcher based on the `FirmwareVariant` enum value.
- Both patchers use **Capstone** for disassembly and **Keystone** for re-assembly to ensure architecture-correct instruction encoding.
- **Dynamic scanning** of the flat binary TXM image ensures patches work across firmware revisions without fixed offsets.

## Frequently Asked Questions

### What is the TXM coprocessor in iOS firmware?

The TXM (Trusted Execution Monitor) is a pre-kernel coprocessor binary that initializes security policies, including trust-cache validation and debugger authorization, before handing control to the main kernel. According to the vphone-cli source code, the TXM appears in the boot chain between LLB (Low Level Bootloader) and the Kernel, making it a critical enforcement point for device security policies.

### Why does vphone-cli use dynamic scanning instead of fixed offsets?

The TXM ships as a **flat binary** without Mach-O headers or symbol tables, meaning instruction locations vary between firmware versions. By using Capstone to disassemble and scan for string anchors like `"selector24"` and `"get-task-allow"` at runtime, the patcher remains functional across iOS updates that would break hardcoded offset-based patching.

### What is the difference between release and research TXM binaries?

Per the research documentation in [`research/txm_variant_diff.md`](https://github.com/Lakr233/vphone-cli/blob/main/research/txm_variant_diff.md), the release and research TXM binaries are **identical** (sharing the same SHA-256 hash) and differ only in a cosmetic variant string embedded in the binary. Consequently, vphone-cli does not maintain separate TXM files for different builds; instead, it applies the same base binary with variant-specific patches (trust-cache only for release, additional debugger/entitlement patches for research/dev builds).

### How do I specify which TXM variant patcher to use?

You specify the variant using the command-line interface when invoking the firmware pipeline. The `--variant` flag accepts values like `regular`, `dev`, `jb`, or `exp`, which the [`FirmwarePipeline.swift`](https://github.com/Lakr233/vphone-cli/blob/main/FirmwarePipeline.swift) uses to instantiate either `TXMPatcher` or `TXMDevPatcher`:

```bash
vphone-cli --txm <txm-im4p> --variant dev    # Uses TXMDevPatcher

vphone-cli --txm <txm-im4p> --variant regular # Uses TXMPatcher

```