# IOMFB kern SwapEnd Patch Differences: iOS 26.x vs iOS 27.x Explained

> Discover IOMFB kern SwapEnd patch differences between iOS 26.x and 27.x. Learn how iOS 27.x handles larger structures with multiple patches.

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

---

**iOS 26.x requires only the JB-26 variable-size dispatch patch, while iOS 27.x needs three coordinated patches—JB-26, JB-27 handler-size modification, and a force-kern trampoline redirect—to handle the larger 0x6e0-byte IOMFBSwapRec structure.**

Virtualization of iOS through projects like **Lakr233/vphone-cli** requires careful binary patching of the **IOMobileFramebuffer (IOMFB) SwapEnd** user-client to bridge struct size mismatches between guest userland and host kernels. The primary keyword **IOMFB kern SwapEnd patches iOS 26 vs 27** highlights a fundamental architectural divergence in how these versions handle framebuffer presentation, necessitating different patching strategies for each major release.

## The Root Cause: IOMFBSwapRec Size Discrepancy

The **IOMFB SwapEnd** user-client serves as the gateway through which the guest iOS VM presents its framebuffer to the host. The kernel and userland must agree on the size of the **`IOMFBSwapRec`** structure, but this size changed between major versions:

- **iOS 26.x**: Native structure size of **0x588 bytes**
- **iOS 27.x**: Native structure size of **0x6e0 bytes**

This discrepancy triggers two distinct kernel-side gates that must be bypassed or modified for successful virtualization.

## iOS 26.x: Single Dispatch Gate Patch (JB-26)

For **iOS 26.x**, only one size verification gate requires modification. The **`IOExternalMethodDispatch.checkStructureInputSize`** field in the dispatch table enforces the 0x588-byte expectation.

According to the source in [`sources/FirmwarePatcher/Kernel/JBPatches/KernelJBPatchIomfbSwap.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/FirmwarePatcher/Kernel/JBPatches/KernelJBPatchIomfbSwap.swift), the **`patchIomfbSwapEndVariableSize()`** method (designated **JB-26**) rewrites this field to **`kIOUCVariableStructureSize`** (`0xffffffff`). This allows any struct size greater than or equal to 0x588, accommodating both native 26.x clients and future structures without further kernel modification.

No handler-level patching is required for iOS 26.x because the kernel expects the 0x588 size that the guest provides.

## iOS 27.x: Three-Layer Patching Strategy

**iOS 27.x** introduces additional complexity through a new "virt" display path and a stricter handler-level size check. Three coordinated patches are required:

### 1. Variable-Size Dispatch Gate (JB-26)

As with iOS 26.x, the dispatch table gate must be relaxed. The same **`patchIomfbSwapEndVariableSize()`** function sets `checkStructureInputSize` to `0xffffffff`, making the dispatch entry size-agnostic.

### 2. Handler Size Gate (JB-27)

iOS 27.x introduces a secondary gate within the handler itself. The kernel code contains a hardcoded comparison: **`cmp w2, #0x588`**, which branches to an error path if the size does not match exactly.

The **`patchIomfbSwapEndHandlerSize()`** method (designated **JB-27**), implemented in [`KernelJBPatchIomfbSwap.swift`](https://github.com/Lakr233/vphone-cli/blob/main/KernelJBPatchIomfbSwap.swift), rewrites this immediate value from `0x588` to **`0x6e0`**. This allows the handler to accept the larger native structure that iOS 27 userland transmits.

### 3. Force-Kern Trampoline Redirect

Critically, iOS 27 introduced a new **`_virt_Swap*`** trampoline path that bypasses the SwapEnd user-client entirely. Even after relaxing both size gates, the kernel never reaches the handler because the display flow uses the "virt" implementations instead of the "`_kern_*`" methods.

The **`patchIomfbForceKern`** patch, implemented in [`scripts/patchers/cfw_patch_iomfb_force_kern.py`](https://github.com/Lakr233/vphone-cli/blob/main/scripts/patchers/cfw_patch_iomfb_force_kern.py), retargets the public `_IOMobileFramebufferSwap*` trampolines to jump directly to the **`_kern_*`** implementations. This forces the iOS 27 guest to call the user-client's method-5 path (SwapEnd) instead of the virt path, making the previous patches effective.

## Source Code Implementation

The patch implementations are distributed across the **vphone-cli** repository:

- **[`sources/FirmwarePatcher/Kernel/JBPatches/KernelJBPatchIomfbSwap.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/FirmwarePatcher/Kernel/JBPatches/KernelJBPatchIomfbSwap.swift)**: Contains both `patchIomfbSwapEndVariableSize()` for JB-26 and `patchIomfbSwapEndHandlerSize()` for JB-27.
- **[`scripts/patchers/cfw_patch_iomfb_swapend.py`](https://github.com/Lakr233/vphone-cli/blob/main/scripts/patchers/cfw_patch_iomfb_swapend.py)**: Exposes the size-gate patches to the command-line interface, allowing per-target size adjustments.
- **[`scripts/patchers/cfw_patch_iomfb_force_kern.py`](https://github.com/Lakr233/vphone-cli/blob/main/scripts/patchers/cfw_patch_iomfb_force_kern.py)**: Provides the trampoline retargeting logic required exclusively for iOS 27 display handling.
- **[`research/0_binary_patch_comparison.md`](https://github.com/Lakr233/vphone-cli/blob/main/research/0_binary_patch_comparison.md)**: Documents the patch IDs (JB-26, JB-27, force-kern) and their strategic rationale.

## Applying the Patches

Use the Swift API for programmatic patching:

```swift
let patcher = KernelJBPatcher(...)

// Required for both iOS 26.x and 27.x
patcher.patchIomfbSwapEndVariableSize()

// Required only for iOS 27.x
patcher.patchIomfbSwapEndHandlerSize()

```

Or use the Python CLI wrappers for dyld shared cache patching:

```bash

# iOS 26.x or 27.x - relax the dispatch size check (JB-26)

python3 scripts/patchers/cfw.py patch-iomfb-swapend "$DSC_DIR" --target-size 0xFFFFFFFF

# iOS 27.x only - rewrite handler compare (JB-27) and force kern path

python3 scripts/patchers/cfw.py patch-iomfb-swapend "$DSC_DIR" --target-size 0x6e0
python3 scripts/patchers/cfw.py patch-iomfb-force-kern "$DSC_DIR"

```

## Summary

- **iOS 26.x**: Requires only **`patchIomfbSwapEndVariableSize`** (JB-26) to set the dispatch gate to variable size (`0xffffffff`).
- **iOS 27.x**: Requires three patches: the variable-size dispatch gate (JB-26), the **`patchIomfbSwapEndHandlerSize`** (JB-27) to update the handler's `cmp` instruction from `0x588` to `0x6e0`, and the **`patchIomfbForceKern`** trampoline redirect to bypass the new virt path.
- The force-kern patch is essential for iOS 27 because the kernel otherwise bypasses the SwapEnd user-client entirely through the `_virt_Swap*` trampolines.
- All patches are implemented in [`KernelJBPatchIomfbSwap.swift`](https://github.com/Lakr233/vphone-cli/blob/main/KernelJBPatchIomfbSwap.swift) (Swift) and exposed via [`cfw_patch_iomfb_swapend.py`](https://github.com/Lakr233/vphone-cli/blob/main/cfw_patch_iomfb_swapend.py) and [`cfw_patch_iomfb_force_kern.py`](https://github.com/Lakr233/vphone-cli/blob/main/cfw_patch_iomfb_force_kern.py) (Python).

## Frequently Asked Questions

### Why does iOS 27 require a force-kern patch when iOS 26 does not?

iOS 27 introduced new **`_virt_Swap*`** trampolines that route display operations around the SwapEnd user-client entirely. Without **`patchIomfbForceKern`**, the kernel uses this virt path and never reaches the SwapEnd handler, rendering the size-gate patches irrelevant. iOS 26.x lacks this alternative path, so the user-client is always invoked naturally.

### What are the exact IOMFBSwapRec structure sizes for each version?

**iOS 26.x** uses a native structure size of **0x588 bytes**, while **iOS 27.x** expanded this to **0x6e0 bytes**. The handler in iOS 27 still contains the old comparison value (`0x588`) hardcoded in its assembly, necessitating the JB-27 patch to update this immediate value.

### Where are these patches implemented in the vphone-cli codebase?

Both size-gate patches reside in **[`sources/FirmwarePatcher/Kernel/JBPatches/KernelJBPatchIomfbSwap.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/FirmwarePatcher/Kernel/JBPatches/KernelJBPatchIomfbSwap.swift)**. The force-kern trampoline patch is implemented in **[`scripts/patchers/cfw_patch_iomfb_force_kern.py`](https://github.com/Lakr233/vphone-cli/blob/main/scripts/patchers/cfw_patch_iomfb_force_kern.py)**, and the command-line interface for applying these patches is provided by **[`scripts/patchers/cfw_patch_iomfb_swapend.py`](https://github.com/Lakr233/vphone-cli/blob/main/scripts/patchers/cfw_patch_iomfb_swapend.py)**.

### Can I skip the handler-size patch on iOS 27 if I only use the force-kern redirect?

No. The force-kern redirect ensures the kernel reaches the SwapEnd handler, but the handler itself enforces an exact size check via **`cmp w2, #0x588`**. Without **`patchIomfbSwapEndHandlerSize`** rewriting this to `0x6e0`, the handler rejects the larger iOS 27 structure and returns an error, preventing framebuffer presentation.