# CFW Kernel Patches and CFW Installation Phases for Different iOS Variants in vphone-cli

> Understand CFW kernel patches and CFW installation phases for vphone-cli. Learn how variant flags affect Swift patchers and script execution across iOS variants.

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

---

**CFW kernel patches modify the iOS kernel binary during the firmware build process, while CFW installation phases copy binaries into the VM bundle after restore; both are gated by the variant flag (`regular`, `dev`, `jb`, `exp`, or `less`), which determines which Swift patchers run and which shell scripts execute.**

The open-source tool `vphone-cli` constructs Custom Firmware (CFW) for virtual iPhones by orchestrating kernel patchers written in Swift and installation scripts written in Bash. Understanding the distinction between these two layers—and how they vary across iOS firmware variants—is critical for developers debugging boot failures or extending the toolchain with new patches.

## Architecture: Kernel Patches vs Installation Phases

The `vphone-cli` pipeline separates concerns into two distinct layers that both respect the user-selected variant.

**Kernel patches** are Swift classes that mutate the kernel binary before the VM boots. According to the Lakr233/vphone-cli source code, these live under `sources/FirmwarePatcher/Kernel/` and include base patches, jailbreak extensions, and experimental modifications.

**Installation phases** are shell scripts that run after the restore step completes. These scripts, located in `scripts/`, mount the VM’s `Disk.img`, copy patched binaries, flip APFS snapshots, and apply variant-specific file sets. The orchestration logic resides in [`sources/vphone-cli/VPhoneCreateOrchestrator.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/VPhoneCreateOrchestrator.swift), which constructs the ordered component list based on the `--variant` argument.

## Kernel Patch Differences by Variant

The [`FirmwarePipeline.swift`](https://github.com/Lakr233/vphone-cli/blob/main/FirmwarePipeline.swift) file dispatches patchers conditionally. The following breakdown shows which kernel classes execute for each iOS variant.

### Regular Variant

**`KernelPatcher`** – Applies base patches including APFS snapshot modifications, launch-constraint relaxations, dyld-policy adjustments, and sandbox hooks. This is the minimal set required to boot a clean iOS image in the virtual environment. Source: [`sources/FirmwarePatcher/Kernel/KernelPatcher.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/FirmwarePatcher/Kernel/KernelPatcher.swift).

### Dev Variant

**`KernelPatcher` with `applyExcGuard = true`** – Executes the same base patches as `regular`, but additionally disables EXC-GUARD (Mach-port guard) checks. This enables developer-mode debugging by relaxing certain security validations. The flag is passed during the `KernelPatcher` initialization in the pipeline.

### JB (Jailbreak) Variant

**`KernelPatcher` → `KernelJBPatcher`** – Chains the base patcher with [`KernelJBPatcher.swift`](https://github.com/Lakr233/vphone-cli/blob/main/KernelJBPatcher.swift), which adds jailbreak-specific extensions such as `KernelJBPatchVmMapDelete` and `KernelJBPatchThreadSetState`. This layer rewrites sandbox hooks and patches iOS-specific kexts to remove restrictions. The pipeline adds `KernelJBPatcher` only when the variant is `jb` or `exp`.

### EXP (Experimental) Variant

**`KernelPatcher` → `KernelJBPatcher` → `KernelEXPPatcher`** – Applies all JB patches, then invokes [`KernelEXPPatcher.swift`](https://github.com/Lakr233/vphone-cli/blob/main/KernelEXPPatcher.swift) for research-only changes. These include `KernelEXPPatchHvVmmRename` (renaming hv_vmm), extra Dynamic Shared Cache (DSC) tweaks, and device-tree modifications. This variant is intended for experimental hardware virtualization research.

### Less (Patch-Less) Variant

**No kernel patcher invoked** – The pipeline skips all Swift patchers when the variant is `less`. This produces an unmodified kernel used solely for testing raw restore flows without any binary alteration.

The dispatch logic in [`FirmwarePipeline.swift`](https://github.com/Lakr233/vphone-cli/blob/main/FirmwarePipeline.swift) implements these conditionals:

```swift
// sources/FirmwarePatcher/Pipeline/FirmwarePipeline.swift
if variant != .less {
    // add KernelPatcher
}
if variant == .jb || variant == .exp {
    // add KernelJBPatcher
}
if variant == .exp {
    // add KernelEXPPatcher
}

```

## CFW Installation Phase Differences by Variant

After kernel patching, the installation pipeline runs shell scripts that vary by variant. The base installer handles phases 1-7, while extended variants append additional phases.

### Base Installation (Phases 1-7)

**Script:** [`scripts/cfw_install.sh`](https://github.com/Lakr233/vphone-cli/blob/main/scripts/cfw_install.sh)

Executes for **all variants** (`regular`, `dev`, `jb`, `exp`, `less`). This script extracts the `cfw_input/` tarball, cryptographically signs binaries, and copies them into the staging area. It represents the common foundation upon which variant-specific phases are layered.

### Jailbreak Phase (Phase 8)

**Script:** [`scripts/cfw_install_jb.sh`](https://github.com/Lakr233/vphone-cli/blob/main/scripts/cfw_install_jb.sh)

Executes only for **`jb`** and **`exp`** variants. This phase applies the `jb/` directory contents to the disk image, installs additional kexts, and runs `ldid` with jailbreak entitlements. It bridges the gap between kernel-level patches and user-space jailbreak tools.

### Experimental Phases (Phases 9-13)

**Script:** [`scripts/cfw_install_exp.sh`](https://github.com/Lakr233/vphone-cli/blob/main/scripts/cfw_install_exp.sh)

Executes **only for `exp`**. These steps apply the hv_vmm DSC patch, additional camera DSC patches, watchdogd modifications, device-tree (DT) alterations, and build-version opt-ins. These changes are experimental and may destabilize the VM if used outside research contexts.

### Host-Mount Finalization

**Script:** [`scripts/cfw_install_host.sh`](https://github.com/Lakr233/vphone-cli/blob/main/scripts/cfw_install_host.sh)

Executes for **all variants** except where explicitly skipped. After the VM powers off, this script mounts the VM’s `Disk.img` on the host, copies the fully patched binaries into place, and flips the APFS snapshot offline. It is the final synchronization step before the VM boots with CFW.

### Patch-Less Flow Adjustments

For the **`less`** variant, the orchestrator sets `CFW_SKIP_HALT=1` to prevent the final halt behavior, and skips the JB/EXP-specific installer scripts entirely. Only the raw restore image is used, with no host-mount file injection beyond the base copy.

The variant-aware orchestration in [`VPhoneCreateOrchestrator.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneCreateOrchestrator.swift) controls script selection:

```swift
// sources/vphone-cli/VPhoneCreateOrchestrator.swift
if variantOption == .jb || variantOption == .exp {
    // Run base CFW install then JB/EXP phases
}
if isLess {
    args += ["--variant", "less"]
}

```

## Complete Execution Flows by Variant

The following tables summarize which kernel patchers and installation scripts execute for each variant.

**Regular:**
- **Kernel:** `KernelPatcher`
- **Install:** [`cfw_install.sh`](https://github.com/Lakr233/vphone-cli/blob/main/cfw_install.sh) → [`cfw_install_host.sh`](https://github.com/Lakr233/vphone-cli/blob/main/cfw_install_host.sh)

**Dev:**
- **Kernel:** `KernelPatcher` (EXC-GUARD disabled)
- **Install:** [`cfw_install.sh`](https://github.com/Lakr233/vphone-cli/blob/main/cfw_install.sh) → [`cfw_install_host.sh`](https://github.com/Lakr233/vphone-cli/blob/main/cfw_install_host.sh)

**JB:**
- **Kernel:** `KernelPatcher` + `KernelJBPatcher`
- **Install:** [`cfw_install.sh`](https://github.com/Lakr233/vphone-cli/blob/main/cfw_install.sh) → [`cfw_install_jb.sh`](https://github.com/Lakr233/vphone-cli/blob/main/cfw_install_jb.sh) → [`cfw_install_host.sh`](https://github.com/Lakr233/vphone-cli/blob/main/cfw_install_host.sh)

**EXP:**
- **Kernel:** `KernelPatcher` + `KernelJBPatcher` + `KernelEXPPatcher`
- **Install:** [`cfw_install.sh`](https://github.com/Lakr233/vphone-cli/blob/main/cfw_install.sh) → [`cfw_install_jb.sh`](https://github.com/Lakr233/vphone-cli/blob/main/cfw_install_jb.sh) → [`cfw_install_exp.sh`](https://github.com/Lakr233/vphone-cli/blob/main/cfw_install_exp.sh) → [`cfw_install_host.sh`](https://github.com/Lakr233/vphone-cli/blob/main/cfw_install_host.sh)

**Less:**
- **Kernel:** None
- **Install:** [`cfw_install.sh`](https://github.com/Lakr233/vphone-cli/blob/main/cfw_install.sh) (skip halt) → [`cfw_install_host.sh`](https://github.com/Lakr233/vphone-cli/blob/main/cfw_install_host.sh) (no extra phases)

## Practical Code Examples

### Selecting a Variant via CLI

```bash

# Regular CFW with base patches only

make boot --variant regular

# Dev variant with EXC-GUARD patches

make boot --variant dev

# Jailbreak variant with kernel hooks and JB installer phases

make boot --variant jb

# Experimental variant with full patch chain

make boot --variant exp

# Patch-less variant for raw restore testing

make boot --variant less

```

These commands invoke `VPhoneCreateOrchestrator`, which selects the appropriate `FirmwarePipeline` components and installer scripts.

### Adding a Custom Experimental Patch

To extend the EXP variant with a new kernel patch, create a struct conforming to `KernelPatch` in `sources/FirmwarePatcher/Kernel/`:

```swift
public struct KernelEXPPatchCustomSandbox: KernelPatch {
    public static let name = "CustomSandboxBypass"
    
    public func apply(to buffer: inout PatchBuffer) -> Bool {
        // Locate specific instruction pattern
        guard let hit = buffer.find(mnemonic: "mov", operandContains: "0xdead") else {
            return false
        }
        // Replace with NOPs
        buffer.replace(at: hit.offset, with: .nop)
        return true
    }
}

```

Register the patch in [`KernelEXPPatcher.swift`](https://github.com/Lakr233/vphone-cli/blob/main/KernelEXPPatcher.swift) and ensure [`FirmwarePipeline.swift`](https://github.com/Lakr233/vphone-cli/blob/main/FirmwarePipeline.swift) includes it when `variant == .exp`.

### Manual Host-Mount Installation

For debugging or manual CFW application after VM shutdown:

```bash
scripts/cfw_install_host.sh --variant exp /path/to/VM.bundle

```

This mounts `Disk.img`, synchronizes patched binaries, and prepares the APFS snapshot for the next boot.

## Summary

- **Kernel patches** are Swift-based binary modifications applied before boot; **installation phases** are Bash scripts that stage files after restore.
- The **`regular`** variant uses only `KernelPatcher` and base installer scripts, while **`dev`** adds EXC-GUARD patches without extra installation steps.
- **`jb`** chains `KernelJBPatcher` and runs [`cfw_install_jb.sh`](https://github.com/Lakr233/vphone-cli/blob/main/cfw_install_jb.sh) for jailbreak-specific file injection.
- **`exp`** adds `KernelEXPPatcher` and runs [`cfw_install_exp.sh`](https://github.com/Lakr233/vphone-cli/blob/main/cfw_install_exp.sh) for experimental hardware virtualization research.
- **`less`** skips all kernel patchers and extra installer phases, using only the raw restore flow.
- Variant selection logic is centralized in [`FirmwarePipeline.swift`](https://github.com/Lakr233/vphone-cli/blob/main/FirmwarePipeline.swift) (kernel dispatch) and [`VPhoneCreateOrchestrator.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneCreateOrchestrator.swift) (script orchestration).

## Frequently Asked Questions

### What distinguishes the JB variant from the EXP variant?

The **JB** variant applies jailbreak kernel patches and installer phases sufficient for standard jailbreak functionality. The **EXP** variant includes all JB patches plus `KernelEXPPatcher` (adding hv_vmm renames and experimental DSC tweaks) and runs additional installer phases 9-13 from [`cfw_install_exp.sh`](https://github.com/Lakr233/vphone-cli/blob/main/cfw_install_exp.sh) for research purposes.

### How does the 'less' variant affect the installation pipeline?

The **less** variant skips all Swift kernel patchers entirely and sets `CFW_SKIP_HALT=1` to bypass the final halt behavior. It executes only the base [`cfw_install.sh`](https://github.com/Lakr233/vphone-cli/blob/main/cfw_install.sh) and [`cfw_install_host.sh`](https://github.com/Lakr233/vphone-cli/blob/main/cfw_install_host.sh) without the JB or EXP-specific file injection phases, making it suitable for testing raw restore images.

### Can I run installation phases without applying kernel patches?

No. According to the implementation in [`VPhoneCreateOrchestrator.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneCreateOrchestrator.swift), the installation scripts are invoked as part of the CFW creation workflow. While the `less` variant skips kernel patches, the installation phases still run to copy the (unpatched) base image. There is no variant that runs JB/EXP installer phases without their corresponding kernel patches.

### Where is the variant selection logic implemented?

Variant selection is split across two key files. **Kernel patch dispatch** is handled in [`sources/FirmwarePatcher/Pipeline/FirmwarePipeline.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/FirmwarePatcher/Pipeline/FirmwarePipeline.swift), which conditionally adds `KernelJBPatcher` and `KernelEXPPatcher`. **Installer script selection** is implemented in [`sources/vphone-cli/VPhoneCreateOrchestrator.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/VPhoneCreateOrchestrator.swift), which constructs shell command arguments based on the `--variant` flag passed by the user.