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:
- Kernel sysctl OID renaming —
hv_vmm_presentbecomesXv_vmm_present - Dyld shared cache (DSC) patching — shared libraries get the same C-string transformation
- Root-filesystem binary mangling — user-mode executables query the renamed OID
- 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 tob"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.pywith 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.pyprotect critical binaries likemobileactivationd
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →