How to Patch iOS Boot Chain Components with FirmwarePatcher in vPhone-CLI

FirmwarePatcher in vPhone-CLI modifies kernel, dyld shared cache (DSC), and root-filesystem binaries to make a virtual iPhone report itself as real hardware by renaming sysctl OIDs and mangling hard-coded C-strings across the entire iOS boot chain.

The FirmwarePatcher is a Python-based patching framework in the Lakr233/vphone-cli repository that enables custom firmware (CFW) creation for virtualized iOS devices. It systematically transforms boot chain components to bypass hypervisor detection, allowing jailbreaks and hardware-like behavior in VM environments.

Core Patching Strategy

The patcher targets all layers of the iOS boot chain with a unified byte-mangling approach:

  1. Kernel sysctl OID renaming — hv_vmm_present becomes Xv_vmm_present
  2. Dyld shared cache (DSC) patching — shared libraries get the same C-string transformation
  3. Root-filesystem binary mangling — user-mode executables query the renamed OID
  4. Ancillary fixes — watchdogd VM-checks, IOMFB swap-end handling, automatic re-signing

FirmwarePatcher Architecture and Key Files

Understanding the source layout is essential for effective use:

File Purpose
scripts/patchers/cfw.py Central driver exposing all patch commands
scripts/patchers/cfw_patch_hv_vmm.py Single Mach-O binary byte-mangler
scripts/patchers/cfw_patch_hv_vmm_dsc.py DSC chunk walker and patcher
scripts/patchers/cfw_patch_hv_vmm_rootfs.py Root-fs orchestration and path management
scripts/patchers/cfw_macho_codesign.py Automatic Mach-O re-signing
scripts/patchers/cfw_patch_watchdogd.py Example daemon-specific patch
Makefile Make targets (fw_patch, fw_patch_jb, etc.)
fw_prepare.sh IPSW extraction and workspace setup
cfw_install.sh Final CFW installation to VM

Step-by-Step Firmware Patching Workflow

1. Install Dependencies

pip install -r requirements.txt

Required packages: capstone, keystone-engine, pyimg4.

2. Prepare the iOS Firmware

./fw_prepare.sh <IPSW_URL_OR_PATH>

This extracts the IPSW, merges the "cloudOS" rootfs, and creates a working directory structure.

3. Patch the Kernel and Root Filesystem

make fw_patch

Internally invokes ./scripts/patchers/cfw_patch_hv_vmm_rootfs.py to:

  • Rename the sysctl OID in kernel internals
  • Mangle every b"kern.hv_vmm_present\x00" occurrence to b"kern.Xv_vmm_present\x00"

The function cfw_patch_hv_vmm_rootfs.get_patch_paths() locates binaries from ALL_KNOWN_ROOTFS_PATHS and applies cfw_patch_hv_vmm.patch_hv_vmm to each.

4. Patch the Dyld Shared Cache

python3 scripts/patchers/cfw.py patch-hv-vmm-dsc <chunks_dir> [--dry-run]

The <chunks_dir> is typically /System/Library/Caches/com.apple.dyld from the mounted SystemOS snapshot. The DSC patcher walks chunks, finds the needle C-string, applies byte 5 transformation (h → X), and re-attests modified pages.

5. Apply Daemon-Specific Patches

python3 scripts/patchers/cfw.py patch-watchdogd /usr/libexec/watchdogd

Additional commands target VM-related checks in specific daemons and frameworks like IOMFB.

6. Install the Patched CFW

./cfw_install.sh          # Standard variant

./cfw_install_jb.sh       # Jailbreak variant

Code Examples

Standalone Binary Patching

from scripts.patchers.cfw_patch_hv_vmm import patch_hv_vmm

binary_path = "/usr/libexec/watchdogd"
patched_count = patch_hv_vmm(binary_path, dry_run=False)
print(f"Patched {patched_count} occurrence(s) in {binary_path}")

Checking the Blacklist

Some binaries must remain unpatched to preserve functionality like device activation:

from scripts.patchers.cfw_patch_hv_vmm_rootfs import DONT_PATCH_ROOTFS_PATHS

# Verify sign-in related daemons are protected

assert "/usr/libexec/mobileactivationd" in DONT_PATCH_ROOTFS_PATHS

Direct DSC Patching (Advanced)

python3 scripts/patchers/cfw.py patch-hv-vmm-dsc \
    /path/to/dyld_shared_cache \
    --dry-run  # Preview changes without writing

Idempotency and Safety Features

The FirmwarePatcher is idempotent: running commands multiple times skips already-patched binaries. The detection mechanism checks for the transformed needle b"kern.Xv_vmm_present\x00" before applying changes.

Automatic code signature preservation via cfw_macho_codesign.py ensures patched binaries remain valid Mach-O files without manual intervention.

Summary

  • FirmwarePatcher transforms the entire iOS boot chain through unified C-string mangling (hv_vmm_present → Xv_vmm_present)
  • Entry point is scripts/patchers/cfw.py with subcommands for kernel, DSC, rootfs, and daemon-specific patches
  • Make targets (make fw_patch, make fw_patch_jb) automate the full workflow
  • All patches are idempotent and automatically re-signed to maintain valid Mach-O structures
  • Blacklists in cfw_patch_hv_vmm_rootfs.py protect critical binaries like mobileactivationd

Frequently Asked Questions

What is the exact byte transformation applied by FirmwarePatcher?

The patcher changes byte 5 of the C-string from h to X: "kern.hv_vmm_present\0" becomes "kern.Xv_vmm_present\0". This is applied consistently across kernel, DSC, and user-mode binaries so they all query the renamed sysctl OID.

Can I patch only specific binaries instead of the entire firmware?

Yes. Use cfw_patch_hv_vmm.patch_hv_vmm() directly for single binaries, or modify ALL_KNOWN_ROOTFS_PATHS in cfw_patch_hv_vmm_rootfs.py to limit the batch scope. The blacklist DONT_PATCH_ROOTFS_PATHS always takes precedence.

How does FirmwarePatcher handle code signing?

cfw_macho_codesign.py automatically re-signs any Mach-O file written back to disk. This happens transparently during patch_hv_vmm() operations—no manual codesign invocation is required.

What is the difference between make fw_patch and make fw_patch_jb?

fw_patch creates a standard custom firmware for virtualization research. fw_patch_jb includes additional jailbreak-oriented patches and invokes cfw_install_jb.sh for installation. Both use the same core FirmwarePatcher infrastructure.

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 →