# What Happens in Phase 2 of the Firmware Patching (CFW Installation) Process

> Discover Phase 2 of CFW installation. Learn how binary patches, dylib injection, and checksum verification transform your iOS IPSW into custom firmware for iBoot, launchd, and system services.

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

---

**Phase 2 is the core patch-application step that transforms a pristine iOS IPSW image into a custom firmware (CFW) by applying binary patches to iBoot, launchd, and system services, injecting dylibs, and verifying checksums before boot.**

The vphone-cli project provides a pipeline for virtualizing iOS on Apple Silicon Macs. After Phase 1 prepares a merged cloud-OS and iPhone hybrid image, Phase 2 of the firmware patching process executes the actual CFW installation by modifying critical system binaries in-place within the VM’s working directory.

## Boot-Nonce Handling (Sub-step 2-1)

The first operation in Phase 2 establishes the **boot-nonce** environment variable required for the iOS bootloader to accept the custom image. According to the research documented in [`research/iboot_patches.md`](https://github.com/Lakr233/vphone-cli/blob/main/research/iboot_patches.md), the [`scripts/cfw_install.sh`](https://github.com/Lakr233/vphone-cli/blob/main/scripts/cfw_install.sh) orchestrator checks for an existing `BOOT_NONCE` variable in the environment. If absent, it invokes a helper utility to generate a fresh random nonce and injects it directly into the `iBoot` binary before the system boots. This ensures the secure boot chain recognizes the patched firmware as valid during subsequent startup phases.

## Launchd Jetsam Patch (Sub-step 2-2)

Next, Phase 2 disables aggressive memory throttling that would otherwise terminate the VM’s background processes. The Python module [`scripts/patchers/cfw_patch_jetsam.py`](https://github.com/Lakr233/vphone-cli/blob/main/scripts/patchers/cfw_patch_jetsam.py) performs this modification by:

1. Locating the anchor string `"jetsam property category"` within the `launchd` binary
2. Resolving the surrounding code reference via **ADRP+ADD** instruction pairs
3. Scanning for the conditional branch that enforces throttling
4. Rewriting the branch to an unconditional jump (`b <target>`) using the Keystone assembler engine

The detailed algorithm flow is documented in [`research/cfw_patch_launchd_jetsam.md`](https://github.com/Lakr233/vphone-cli/blob/main/research/cfw_patch_launchd_jetsam.md). This patch prevents the virtualized iOS environment from killing essential daemons under memory pressure.

## System-Service Patches (Sub-step 2-3)

Beyond launchd, Phase 2 applies additional binary patches to boot-time services including `launchdhook.dylib`, the `kernel`, and `boot-args`. Each patcher module located under `scripts/patchers/` follows a consistent pattern:

- **Locate** an anchor string or symbol within the target binary
- **Resolve** virtual addresses through ADRP+ADD sequences
- **Identify** conditional branches controlling VM-specific restrictions
- **Replace** branches with unconditional jumps or NOP instructions to enable private-API usage and load custom kernel extensions

These modifications collectively bypass VM-specific restrictions and enable jailbreak capabilities required for experimental variants.

## Dylib Injection (Sub-step 2-4)

After patching core binaries, Phase 2 injects the custom dynamic library `/cores/launchdhook.dylib` to implement runtime hooks. The `inject-dylib` helper, called from [`cfw_install_jb.sh`](https://github.com/Lakr233/vphone-cli/blob/main/cfw_install_jb.sh), performs the following:

- Copies the dylib into the VM’s `/cores/` directory
- Adds an appropriate load command to the target binary (typically the patched `launchd`)
- Ensures the library loads early in the boot sequence to intercept system calls

This injection mechanism provides the runtime environment necessary for CFW-specific functionality.

## Verification and Logging (Sub-step 2-5)

The final sub-step validates all modifications before allowing the VM to boot. The orchestration script calculates **SHA-256 checksums** for every patched binary, comparing before-and-after digests to confirm successful writes. If any verification fails, the pipeline aborts immediately and prevents the VM from booting with corrupted firmware. Status lines print to the console throughout the process, providing a concise audit trail of applied patches.

## Key Source Files and Entry Points

Understanding Phase 2 requires familiarity with these specific files in the Lakr233/vphone-cli repository:

- **[`scripts/cfw_install.sh`](https://github.com/Lakr233/vphone-cli/blob/main/scripts/cfw_install.sh)** — The primary orchestrator that sequences all Phase 2 operations in the correct order.
- **[`scripts/patchers/cfw.py`](https://github.com/Lakr233/vphone-cli/blob/main/scripts/patchers/cfw.py)** — Central command-line entry point that dispatches individual patcher modules.
- **[`scripts/patchers/cfw_patch_jetsam.py`](https://github.com/Lakr233/vphone-cli/blob/main/scripts/patchers/cfw_patch_jetsam.py)** — Implements the specific launchd Jetsam throttle bypass.
- **[`research/iboot_patches.md`](https://github.com/Lakr233/vphone-cli/blob/main/research/iboot_patches.md)** — Documents the boot-nonce generation and injection logic.
- **[`research/cfw_patch_launchd_jetsam.md`](https://github.com/Lakr233/vphone-cli/blob/main/research/cfw_patch_launchd_jetsam.md)** — Provides the technical deep-dive into the Jetsam patch algorithm.

## How to Run Phase 2 Manually

While the standard workflow executes Phase 2 automatically, you can invoke specific components manually for debugging or development:

```bash

# Run the complete CFW installation pipeline (Phases 1-3)

make cfw_install

# Or execute Phase 2 explicitly via the installation script

./scripts/cfw_install.sh

```

Inspect the Jetsam patch behavior without writing changes:

```bash
python3 scripts/patchers/cfw_patch_jetsam.py \
    --binary ./vm_root/usr/sbin/launchd \
    --dry-run

```

Verify the boot-nonce was properly set during Phase 2:

```bash
grep BOOT_NONCE ./vm_root/boot/efi/bootargs.txt

```

## Summary

- **Phase 2** applies in-place binary modifications to the firmware prepared in Phase 1, located in `/var/vm/`.
- The process follows a strict sequence: boot-nonce handling, launchd Jetsam patching, system-service patches, dylib injection, and cryptographic verification.
- All patches use **Keystone** for assembly and target ARM64 instruction sequences (ADRP+ADD) to locate patch points.
- **[`scripts/cfw_install.sh`](https://github.com/Lakr233/vphone-cli/blob/main/scripts/cfw_install.sh)** orchestrates the entire phase, calling specialized Python modules under `scripts/patchers/`.
- SHA-256 checksums verify every modification; failures abort the boot process to prevent corruption.

## Frequently Asked Questions

### What happens if the boot-nonce is missing during Phase 2?

If the `BOOT_NONCE` environment variable is not set, the Phase 2 script automatically generates a fresh random nonce and injects it into the iBoot binary. This ensures the secure boot chain accepts the custom firmware without manual intervention.

### Why does Phase 2 patch the launchd Jetsam settings?

The Jetsam patch prevents iOS from aggressively killing background processes due to memory pressure. In a virtualized environment, the default Jetsam throttling would terminate essential VM daemons; the patch rewrites the conditional branch to an unconditional jump, effectively disabling this restriction.

### Where are the patched firmware files stored during Phase 2?

All modifications occur **in-place** within the VM’s working directory, typically `/var/vm/`. The original IPSW components from Phase 1 are overwritten with their CFW-ready counterparts, including patched versions of `iBoot`, `launchd`, and the `kernel`.

### Can I run individual Phase 2 patches without executing the full script?

Yes. While [`scripts/cfw_install.sh`](https://github.com/Lakr233/vphone-cli/blob/main/scripts/cfw_install.sh) runs the complete sequence, individual Python modules under `scripts/patchers/` can be executed standalone. For example, [`cfw_patch_jetsam.py`](https://github.com/Lakr233/vphone-cli/blob/main/cfw_patch_jetsam.py) accepts `--binary` and `--dry-run` arguments to test specific patches against a target binary without modifying the full VM image.