# How the Jailbreak First-Boot Finalization Process Works in vPhone-CLI

> Understand the vphone-cli jailbreak first-boot finalization process. Discover how the LaunchDaemon automates system configuration and package installation for a seamless setup.

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

---

**The jailbreak first-boot finalization process runs automatically via a LaunchDaemon that executes [`/cores/vphone_jb_setup.sh`](https://github.com/Lakr233/vphone-cli/blob/main//cores/vphone_jb_setup.sh) on the initial normal boot, performing idempotent system configuration, package installation, and environment setup before writing a completion marker.**

The **jailbreak first-boot finalization process** in the [Lakr233/vphone-cli](https://github.com/Lakr233/vphone-cli) repository ensures that iOS virtual machines transition from a raw Procursus bootstrap to a fully functional jailbroken state. This process is orchestrated by a Bash script deployed to [`/cores/vphone_jb_setup.sh`](https://github.com/Lakr233/vphone-cli/blob/main//cores/vphone_jb_setup.sh) and triggered by a LaunchDaemon defined in `vphone_jb_setup.plist`. The script implements defensive programming practices—checking for completion markers and handling errors through `set -uo pipefail`—to ensure safe re-execution while establishing SSH access, installing Sileo, and configuring the package manager ecosystem.

## How the LaunchDaemon Triggers the Finalization

When you install a jailbreak (`.jb`) or experimental (`.exp`) variant through vPhone-CLI, the tool copies [`vphone_jb_setup.sh`](https://github.com/Lakr233/vphone-cli/blob/main/vphone_jb_setup.sh) into the VM’s `/cores` directory and installs `vphone_jb_setup.plist` into `/Library/LaunchDaemons`. This property list registers the script to execute automatically on the first normal boot of the iOS system.

The orchestrator code in [`VPhoneCreateOrchestrator.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneCreateOrchestrator.swift) confirms this behavior at lines 39-44, outputting:

```swift
print("[*] JB finalization will run automatically on first normal boot")
print("    via /cores/vphone_jb_setup.sh (LaunchDaemon).")
print("    Monitor progress via vphoned file browser: /var/log/vphone_jb_setup.log")

```

All script output redirects to `/var/log/vphone_jb_setup.log`, enabling debugging through the `vphoned` vsock-based file browser.

## Step-by-Step Breakdown of [`/cores/vphone_jb_setup.sh`](https://github.com/Lakr233/vphone-cli/blob/main//cores/vphone_jb_setup.sh)

The finalization script operates idempotently, checking for a done marker at `/var/mobile/.vphone_jb_setup_done` before proceeding (lines 38-42). If found, the script exits immediately to prevent duplicate configuration.

### Environment Preparation and Idempotency

Before modifying system state, the script establishes error handling via `set -uo pipefail` and constructs a sanitized `PATH` variable. The initial PATH construction (lines 19-25) iterates through standard system locations and Procursus-specific directories:

```bash
for d in \
    /var/jb/usr/bin \
    /var/jb/usr/sbin \
    /usr/local/bin \
    /usr/bin \
    /bin \
    /usr/sbin \
    /sbin; do
    [ -d "$d" ] && PATH="$PATH:$d"
done
export PATH

```

This ensures all subsequent commands resolve correctly regardless of the host environment.

### Bootstrap Execution and PATH Refresh

The script executes [`/var/jb/prep_bootstrap.sh`](https://github.com/Lakr233/vphone-cli/blob/main//var/jb/prep_bootstrap.sh) if present (lines 27-33), which finalizes the Procursus bootstrap and removes itself upon completion. After bootstrap execution, the script rebuilds the PATH (lines 35-44) to include any newly installed binaries from `/var/jb`.

### System-Level Modifications

**Launchctl Replacement:** To avoid crashes from missing symbols in the bundled version, the script replaces Procursus’s `launchctl` with the reliable `iosbinpack64` variant at lines 69-77:

```bash
ln -sf "$IOSBINPACK_LAUNCHCTL" "$JB_TARGET/usr/bin/launchctl"

```

**Symlink Creation:** The script creates a critical symlink at lines 84-90, linking `/private/var/jb` to the Procursus target directory. This establishes the standard jailbreak root path expected by many tweak packages.

**Ownership and Permission Fixes:** Lines 94-101 correct filesystem metadata by setting ownership to `501:501` for mobile user directories and `0:0` for system directories, while applying `0755` permissions to library paths.

### SSH and Security Setup

The script generates Dropbear host keys at lines 107-119 using `dropbearkey`, creating both RSA and ECDSA keys under `/var/dropbear` with strict `0600` permissions:

```bash
"$DROPBEARKEY" -t rsa -f /var/dropbear/dropbear_rsa_host_key
"$DROPBEARKEY" -t ecdsa -f /var/dropbear/dropbear_ecdsa_host_key
chmod 0600 /var/dropbear/*

```

### Package Manager Installation and Repository Configuration

**Sileo Installation:** Lines 61-69 install the Sileo package manager from a pre-staged `.deb` file located in the boot hash directory:

```bash
dpkg -i "$SILEO_DEB_PATH"

```

**Extra Package Installation:** The script scans the `debs/` folder (lines 77-96), comparing installed versions against available packages and installing any missing or newer dependencies.

**APT Repository Setup:** The script configures the Havoc and Frida repositories (lines 18-52), updates the package index with `apt-get update`, installs the `libkrw0-tfp0` kernel read/write library, and performs a full system upgrade:

```bash
printf '%s\n' 'deb https://havoc.app/ ./' > "$HAVOC_LIST"
apt-get update
apt-get install -y libkrw0-tfp0
apt-get upgrade -y

```

### TrollStore Lite and App Registration

The script installs **TrollStore Lite** at lines 60-73 using `apt-get install -y com.opa334.trollstorelite`. Success sets `TROLLSTORE_READY=1`, which gates the final completion marker.

For iOS 27 compatibility, the standard `uicache -a` command is non-functional. Instead, the script executes `/cores/vpregister` (lines 88-92) to register applications through the containerized LaunchServices API:

```bash
if [ -x /cores/vpregister ]; then
    /cores/vpregister
fi

```

### Shell Profile Configuration

Lines 98-104 create `.bashrc` and `.bash_profile` for the root user that source `/var/jb/etc/profile`, ensuring the jailbreak PATH persists across SSH sessions:

```bash
printf '%s\n' 'source /var/jb/etc/profile' > "$profile"

```

### Finalization and Marker Creation

The script concludes at lines 108-113 by writing the completion marker only if TrollStore Lite installed successfully:

```bash
if [ "$TROLLSTORE_READY" = "1" ]; then
    : > "$DONE_MARKER"
    echo "[+] vphone_jb_setup.sh completed successfully"
else
    echo "[!] Core steps done, but TrollStore not ready; marker not set"
fi

```

## Monitoring and Debugging the Process

You can monitor the first-boot finalization in real-time by accessing the VM’s log file:

```bash

# Via vphoned file browser or SSH

tail -f /var/log/vphone_jb_setup.log

```

To verify whether finalization has completed:

```bash
if [ -f /var/mobile/.vphone_jb_setup_done ]; then
    echo "Jailbreak finalization complete"
else
    echo "Finalization pending or failed"
fi

```

If you need to re-trigger the script manually for debugging:

```bash
launchctl load /Library/LaunchDaemons/com.vphone.jbsetup.plist
launchctl start com.vphone.jbsetup

```

## Summary

- The **jailbreak first-boot finalization process** runs via a LaunchDaemon executing [`/cores/vphone_jb_setup.sh`](https://github.com/Lakr233/vphone-cli/blob/main//cores/vphone_jb_setup.sh) automatically on the initial boot of jailbroken VMs created by vPhone-CLI.
- The script is **idempotent**, checking for `/var/mobile/.vphone_jb_setup_done` before processing and redirecting all output to `/var/log/vphone_jb_setup.log`.
- Key operations include replacing `launchctl`, symlinking `/var/jb`, fixing filesystem permissions, generating Dropbear SSH keys, running [`prep_bootstrap.sh`](https://github.com/Lakr233/vphone-cli/blob/main/prep_bootstrap.sh), and installing Sileo.
- The script configures APT repositories (Havoc, Frida), installs TrollStore Lite, and handles iOS 27-specific app registration through `/cores/vpregister`.
- Completion depends on successful TrollStore installation, ensuring the system only marks itself as finalized when fully operational.

## Frequently Asked Questions

### What happens if the jailbreak first-boot finalization script fails halfway through?

If [`vphone_jb_setup.sh`](https://github.com/Lakr233/vphone-cli/blob/main/vphone_jb_setup.sh) encounters an error, the `set -uo pipefail` directive causes immediate termination with an error code. Because the script writes the completion marker only after successful TrollStore installation, you can safely reboot the VM to trigger the LaunchDaemon again—the script will resume from the beginning or skip already-completed steps based on filesystem state.

### Can I run the finalization script manually without the LaunchDaemon?

Yes. You can execute [`/cores/vphone_jb_setup.sh`](https://github.com/Lakr233/vphone-cli/blob/main//cores/vphone_jb_setup.sh) directly from an SSH session or terminal as root. However, ensure you set the environment variables the script expects (such as `BOOT_HASH` pointing to the pre-boot directory) or load the LaunchDaemon via `launchctl load /Library/LaunchDaemons/com.vphone.jbsetup.plist` followed by `launchctl start com.vphone.jbsetup` to maintain proper execution context.

### Where does the script install Sileo and how does it handle custom packages?

The script installs Sileo from a `.deb` file located at `/cores/${BOOT_HASH}/sileo.deb` using `dpkg -i` (lines 61-69). For custom packages, it scans the `/cores/${BOOT_HASH}/debs/` directory and installs any packages not already present or newer than installed versions (lines 77-96), making it extensible for additional tools beyond the base jailbreak.

### Why does the script replace the Procursus launchctl binary?

The bundled Procursus `launchctl` may crash on certain iOS versions due to missing symbols or library mismatches. The script replaces it with a known-working version from `iosbinpack64` (lines 69-77), preserving the original as `launchctl.procursus`. This ensures reliable daemon management during the bootstrapping phase without breaking compatibility with Procursus utilities.