mirror of
https://github.com/Lakr233/vphone-cli.git
synced 2026-04-05 04:59:05 +08:00
472 lines
29 KiB
Markdown
472 lines
29 KiB
Markdown
# vphone-cli
|
|
|
|
Virtual iPhone boot tool using Apple's Virtualization.framework with PCC research VMs.
|
|
|
|
## Quick Reference
|
|
|
|
- **Build:** `make build`
|
|
- **Boot (GUI):** `make boot`
|
|
- **Boot (DFU):** `make boot_dfu`
|
|
- **All targets:** `make help`
|
|
- **Python venv:** `make setup_venv` (installs to `.venv/`, activate with `source .venv/bin/activate`)
|
|
- **Platform:** macOS 15+ (Sequoia), SIP/AMFI disabled
|
|
- **Language:** Swift 6.0 (SwiftPM), private APIs via [Dynamic](https://github.com/mhdhejazi/Dynamic)
|
|
- **Python deps:** `capstone`, `keystone-engine`, `pyimg4` (see `requirements.txt`)
|
|
|
|
## Workflow Rules
|
|
|
|
- Always read `/TODO.md` before starting any substantial work.
|
|
- Always update `/TODO.md` when plan, progress, assumptions, blockers, or open questions change.
|
|
- If blocked or waiting on user input, write the exact blocker and next action in `/TODO.md`.
|
|
- If not exists, continue existing work until complete. If exists, follow `/TODO.md` instructions.
|
|
|
|
## Project Overview
|
|
|
|
CLI tool that boots virtual iPhones (PV=3) via Apple's Virtualization.framework, targeting Private Cloud Compute (PCC) research VMs. Used for iOS security research — firmware patching, boot chain modification, and runtime instrumentation.
|
|
|
|
## Architecture
|
|
|
|
```
|
|
Makefile # Single entry point — run `make help`
|
|
|
|
sources/
|
|
├── vphone.entitlements # Private API entitlements (5 keys)
|
|
└── vphone-cli/ # Swift 6.0 executable (pure Swift, no ObjC)
|
|
├── main.swift # Entry point — NSApplication + AppDelegate
|
|
├── VPhoneAppDelegate.swift # App lifecycle, SIGINT, VM start/stop
|
|
├── VPhoneCLI.swift # ArgumentParser options (no execution logic)
|
|
├── VPhoneBuildInfo.swift # Auto-generated build-time commit hash
|
|
│
|
|
│ # VM core
|
|
├── VPhoneVirtualMachine.swift # @MainActor VM configuration and lifecycle
|
|
├── VPhoneHardwareModel.swift # PV=3 hardware model via Dynamic
|
|
├── VPhoneVirtualMachineView.swift # Touch-enabled VZVirtualMachineView + helpers
|
|
├── VPhoneError.swift # Error types
|
|
│
|
|
│ # Guest daemon client (vsock)
|
|
├── VPhoneControl.swift # Host-side vsock client for vphoned (length-prefixed JSON)
|
|
│
|
|
│ # Window & UI
|
|
├── VPhoneWindowController.swift # @MainActor VM window management + toolbar
|
|
├── VPhoneKeyHelper.swift # Keyboard/hardware key event dispatch to VM
|
|
├── VPhoneLocationProvider.swift # CoreLocation → guest forwarding over vsock
|
|
│
|
|
│ # Menu bar (extensions on VPhoneMenuController)
|
|
├── VPhoneMenuController.swift # Menu bar controller (builds Keys, Type, Location, Connect)
|
|
├── VPhoneMenuKeys.swift # Keys menu — home, power, volume, spotlight buttons
|
|
├── VPhoneMenuType.swift # Type menu — paste ASCII text to guest
|
|
├── VPhoneMenuLocation.swift # Location menu — host location sync toggle
|
|
├── VPhoneMenuConnect.swift # Connect menu — devmode, ping, version, file browser
|
|
│
|
|
│ # File browser (SwiftUI)
|
|
├── VPhoneFileWindowController.swift # File browser window (NSHostingController)
|
|
├── VPhoneFileBrowserView.swift # SwiftUI file browser with search + drag-drop
|
|
├── VPhoneFileBrowserModel.swift # @Observable file browser state + transfers
|
|
└── VPhoneRemoteFile.swift # Remote file data model (path, size, permissions)
|
|
|
|
scripts/
|
|
├── vphoned/ # Guest daemon (Objective-C, runs inside iOS VM)
|
|
│ ├── vphoned.m # Main — vsock listener, message dispatch, auto-update
|
|
│ ├── vphoned_protocol.{h,m} # Length-prefixed JSON framing (shared with host)
|
|
│ ├── vphoned_hid.{h,m} # HID event injection (IOHIDEvent)
|
|
│ ├── vphoned_devmode.{h,m} # Developer Mode query/enable via XPC
|
|
│ ├── vphoned_location.{h,m} # CLLocationManager spoofing
|
|
│ ├── vphoned_files.{h,m} # File operations (list, get, put, mkdir, delete, rename)
|
|
│ ├── vphoned.plist # LaunchDaemon plist
|
|
│ ├── entitlements.plist # Guest entitlements
|
|
│ └── signcert.p12 # Signing certificate for re-signing
|
|
├── patchers/ # Python patcher package
|
|
│ ├── iboot.py # Dynamic iBoot patcher (iBSS/iBEC/LLB)
|
|
│ ├── iboot_jb.py # JB extension iBoot patcher (nonce skip)
|
|
│ ├── kernel.py # Dynamic kernel patcher (25 patches)
|
|
│ ├── kernel_jb.py # JB extension kernel patcher (~34 patches)
|
|
│ ├── txm.py # Dynamic TXM patcher
|
|
│ ├── txm_jb.py # JB extension TXM patcher (~13 patches)
|
|
│ └── cfw.py # CFW binary patcher (base + JB jetsam)
|
|
├── resources/ # Resource archives
|
|
│ ├── cfw_input.tar.zst
|
|
│ ├── cfw_jb_input.tar.zst # JB: procursus bootstrap + Sileo
|
|
│ └── ramdisk_input.tar.zst
|
|
├── fw_prepare.sh # Downloads IPSWs, merges cloudOS into iPhone
|
|
├── fw_manifest.py # Generates hybrid BuildManifest.plist & Restore.plist
|
|
├── fw_patch.py # Patches 6 boot-chain components (41+ modifications)
|
|
├── fw_patch_jb.py # Runs fw_patch + JB extension patches (iBSS/TXM/kernel)
|
|
├── ramdisk_build.py # Builds SSH ramdisk with trustcache
|
|
├── ramdisk_send.sh # Sends ramdisk to device via irecovery
|
|
├── cfw_install.sh # Installs custom firmware to VM disk
|
|
├── cfw_install_jb.sh # Wrapper: cfw_install with JB phases enabled
|
|
├── vm_create.sh # Creates VM directory (disk, SEP storage, ROMs)
|
|
├── setup_venv.sh # Creates Python venv with native keystone dylib
|
|
└── setup_libimobiledevice.sh # Builds libimobiledevice toolchain from source
|
|
|
|
research/
|
|
├── patch_comparison_all_variants.md # Regular/Dev/JB patch comparison table
|
|
└── ... # Component analysis and architecture docs
|
|
```
|
|
|
|
### Key Patterns
|
|
|
|
- **Private API access:** Private Virtualization.framework APIs are called via the [Dynamic](https://github.com/mhdhejazi/Dynamic) library (runtime method dispatch from pure Swift). No ObjC bridge needed.
|
|
- **App lifecycle:** Explicit `main.swift` creates `NSApplication` + `VPhoneAppDelegate`. CLI args parsed before the run loop starts. AppDelegate drives VM start, window, and shutdown.
|
|
- **Configuration:** CLI options parsed via `ArgumentParser`, converted to `VPhoneVirtualMachine.Options` struct, then used to build `VZVirtualMachineConfiguration`.
|
|
- **Error handling:** `VPhoneError` enum with `CustomStringConvertible` for user-facing messages.
|
|
- **Window management:** `VPhoneWindowController` wraps `NSWindow` + `VZVirtualMachineView`. Window size derived from configurable screen dimensions and scale factor. Touch input translated from mouse events to multi-touch via `VPhoneVirtualMachineView`.
|
|
- **Guest daemon (vphoned):** ObjC daemon running inside the iOS VM as a LaunchDaemon. Communicates with host over vsock port 1337 using length-prefixed JSON (`[uint32 BE length][UTF-8 JSON]`). Handles HID injection, developer mode, location spoofing, and file operations. Host side is `VPhoneControl` which auto-reconnects and supports binary auto-update on connect.
|
|
- **Control protocol:** All commands use async request-response via `VPhoneControl.sendRequest()` with pending request tracking. Menu actions (`VPhoneMenuConnect`) await responses and show results as `NSAlert` sheets on the VM window.
|
|
- **Menu system:** `VPhoneMenuController` owns the menu bar, built from extensions in separate files per menu (Keys, Type, Location, Connect). Each extension has its own `build*Menu()` method.
|
|
- **File browser:** SwiftUI-based (`VPhoneFileBrowserView` + `VPhoneFileBrowserModel`) hosted in a separate `NSWindow` via `NSHostingController`. Supports search, sort, upload/download, drag-drop. File operations go through `VPhoneControl` async APIs.
|
|
- **Location sync:** `VPhoneLocationProvider` wraps `CLLocationManager`, forwards host Mac's GPS coordinates to the guest over vsock when toggled from the Location menu.
|
|
|
|
---
|
|
|
|
## Firmware Assembly Pipeline
|
|
|
|
The firmware is a **PCC/iPhone hybrid** — PCC boot infrastructure wrapping iPhone iOS userland.
|
|
|
|
### Pipeline Stages
|
|
|
|
```
|
|
1. make fw_prepare Download iPhone + cloudOS IPSWs, merge, generate hybrid plists
|
|
↓
|
|
2. make fw_patch Patch 6 boot-chain components for signature bypass + debug
|
|
OR make fw_patch_jb Base patches + JB extensions (iBSS nonce, TXM CS, kernel JB)
|
|
↓
|
|
3. make ramdisk_build Build SSH ramdisk from SHSH blob, inject tools, sign with IM4M
|
|
↓
|
|
4. make vm_new Create VM directory (sparse disk, SEP storage, copy ROMs)
|
|
↓
|
|
5. make boot_dfu Boot VM in DFU mode
|
|
↓
|
|
6. make ramdisk_send Load boot chain + ramdisk via irecovery
|
|
↓
|
|
7. make cfw_install Mount Cryptex, patch userland, install base tools
|
|
OR make cfw_install_jb Base CFW + JB phases (jetsam patch, procursus bootstrap)
|
|
```
|
|
|
|
### Component Origins
|
|
|
|
The firmware merges two Apple IPSWs:
|
|
|
|
- **iPhone IPSW:** `iPhone17,3_26.1_23B85_Restore.ipsw` (d47ap)
|
|
- **cloudOS IPSW:** PCC vresearch101ap IPSW (CDN hash URL)
|
|
|
|
`fw_prepare.sh` extracts both, then copies cloudOS boot chain into the
|
|
iPhone restore directory (`kernelcache.*`, `Firmware/{agx,all_flash,ane,dfu,pmp}/*`,
|
|
`Firmware/*.im4p`). The cloudOS extract is deleted after merge.
|
|
|
|
#### Boot Chain — from PCC (cloudOS / vresearch101ap)
|
|
|
|
| Component | File | Patched | Patch Purpose |
|
|
| ------------ | ----------------------------------------------------------- | -------- | --------------------------------------------------- |
|
|
| AVPBooter | `AVPBooter.vresearch1.bin` | Yes (1) | DGST signature validation bypass |
|
|
| LLB | `Firmware/all_flash/LLB.vresearch101.RELEASE.im4p` | Yes (6) | Serial + image4 bypass + boot-args + rootfs + panic |
|
|
| iBSS | `Firmware/dfu/iBSS.vresearch101.RELEASE.im4p` | Yes (2) | Serial labels + image4 callback bypass |
|
|
| iBEC | `Firmware/dfu/iBEC.vresearch101.RELEASE.im4p` | Yes (3) | Serial + image4 bypass + boot-args |
|
|
| SPTM | `Firmware/all_flash/sptm.vresearch1.release.im4p` | No | — |
|
|
| TXM | `Firmware/txm.iphoneos.research.im4p` | Yes (1) | Trustcache validation bypass |
|
|
| SEP Firmware | `Firmware/all_flash/sep-firmware.vresearch101.RELEASE.im4p` | No | — |
|
|
| DeviceTree | `Firmware/all_flash/DeviceTree.vphone600ap.im4p` | No | — |
|
|
| KernelCache | `kernelcache.release.vphone600` | Yes (25) | APFS, MAC, debugger, launch constraints, etc. |
|
|
| GPU/ANE/PMP | `Firmware/{agx,ane,pmp}/*` | No | — |
|
|
|
|
> TXM filename says "iphoneos" but is copied from cloudOS IPSW (`fw_prepare.sh` line 81).
|
|
|
|
#### OS / Filesystem — from iPhone (iPhone17,3)
|
|
|
|
| Component | Notes |
|
|
| -------------------------------- | ---------------------- |
|
|
| OS | iPhone OS image |
|
|
| SystemVolume | System partition |
|
|
| StaticTrustCache | Static trust cache |
|
|
| Ap,SystemVolumeCanonicalMetadata | System volume metadata |
|
|
|
|
> Cryptex1 components (SystemOS/AppOS DMGs) are **not** included in the BuildManifest.
|
|
> They are only needed by `cfw_install.sh` which reads paths from the original iPhone manifest separately.
|
|
|
|
### Build Identity
|
|
|
|
`fw_manifest.py` generates a **single** DFU erase-install identity (20 components).
|
|
The VM always boots via DFU restore, so only one identity is needed.
|
|
|
|
| Variant | Boot Chain | Ramdisk |
|
|
| -------------------------------------------- | -------------------------------------------------- | --------- |
|
|
| `Darwin Cloud Customer Erase Install (IPSW)` | PCC RELEASE (LLB/iBSS/iBEC) + RESEARCH (iBoot/TXM) | PCC erase |
|
|
|
|
idevicerestore selects this identity by partial-matching `Info.Variant` against
|
|
`"Erase Install (IPSW)"` while excluding `"Research"`.
|
|
|
|
### Patched Components Summary
|
|
|
|
**Boot chain patches** (`fw_patch.py`) — all 6 targets from **PCC**:
|
|
|
|
| Component | Patches | Technique |
|
|
| ----------- | ------- | ------------------------------------------------------------------------------- |
|
|
| AVPBooter | 1 | `mov x0, #0` (DGST bypass) |
|
|
| iBSS | 2 | Dynamic via `patchers/iboot.py` (string anchors, instruction patterns) |
|
|
| iBEC | 3 | Dynamic via `patchers/iboot.py` (string anchors, instruction patterns) |
|
|
| LLB | 6 | Dynamic via `patchers/iboot.py` (string anchors, instruction patterns) |
|
|
| TXM | 1 | Dynamic via `patchers/txm.py` (trustcache hash lookup bypass) |
|
|
| KernelCache | 25 | Dynamic via `patchers/kernel.py` (string anchors, ADRP+ADD xrefs, BL frequency) |
|
|
|
|
**JB extension patches** (`fw_patch_jb.py`) — runs base patches first, then adds:
|
|
|
|
| Component | JB Patches | Technique |
|
|
| ----------- | ---------- | ----------------------------------------------------------------------------------- |
|
|
| iBSS | +1 | `patchers/iboot_jb.py` (skip nonce generation) |
|
|
| TXM | +13 | `patchers/txm_jb.py` (CS validation bypass, get-task-allow, debugger ent, dev mode) |
|
|
| KernelCache | +34 | `patchers/kernel_jb.py` (trustcache, execve, sandbox, task/VM, kcall10) |
|
|
|
|
**CFW patches** (`patchers/cfw.py` / `cfw_install.sh`) — targets from **iPhone** Cryptex SystemOS:
|
|
|
|
| Binary | Technique | Purpose | Mode |
|
|
| -------------------- | ---------------------------------------------------- | --------------------------------------------- | ---- |
|
|
| seputil | String patch (`/%s.gl` → `/AA.gl`) | Gigalocker UUID fix | Base |
|
|
| launchd_cache_loader | NOP (disassembly-anchored) | Bypass cache validation | Base |
|
|
| mobileactivationd | Return true (disassembly-anchored) | Skip activation check | Base |
|
|
| launchd.plist | Plist injection | Add bash/dropbear/trollvnc daemons | Base |
|
|
| launchd | Branch (skip jetsam guard) + LC_LOAD_DYLIB injection | Prevent jetsam panic + load launchdhook.dylib | JB |
|
|
|
|
**JB install phases** (`cfw_install_jb.sh` → `cfw_install.sh` with `CFW_JB_MODE=1`):
|
|
|
|
| Phase | Action |
|
|
| ----- | ---------------------------------------------------------------------------------------------------- |
|
|
| JB-1 | Patch `/mnt1/sbin/launchd`: inject `launchdhook.dylib` LC_LOAD_DYLIB + jetsam guard bypass |
|
|
| JB-2 | Install procursus bootstrap to `/mnt5/<hash>/jb-vphone/procursus` |
|
|
| JB-3 | Deploy BaseBin hooks (`systemhook.dylib`, `launchdhook.dylib`, `libellekit.dylib`) to `/mnt1/cores/` |
|
|
|
|
### Boot Flow
|
|
|
|
**Base** (`fw_patch` + `cfw_install`):
|
|
|
|
```
|
|
AVPBooter (ROM, PCC)
|
|
→ LLB (PCC, patched)
|
|
→ iBSS (PCC, patched, DFU)
|
|
→ iBEC (PCC, patched, DFU)
|
|
→ SPTM + TXM (PCC, TXM patched)
|
|
→ KernelCache (PCC, 25 patches)
|
|
→ Ramdisk (PCC or iPhone, SSH-injected)
|
|
→ iOS userland (iPhone, CFW-patched)
|
|
```
|
|
|
|
**Jailbreak** (`fw_patch_jb` + `cfw_install_jb`):
|
|
|
|
```
|
|
AVPBooter (ROM, PCC)
|
|
→ LLB (PCC, patched)
|
|
→ iBSS (PCC, patched + nonce skip)
|
|
→ iBEC (PCC, patched, DFU)
|
|
→ SPTM + TXM (PCC, TXM patched + CS/ent/devmode bypass)
|
|
→ KernelCache (PCC, 25 base + ~34 JB patches)
|
|
→ Ramdisk (SSH-injected)
|
|
→ iOS userland (CFW + jetsam fix + procursus)
|
|
```
|
|
|
|
### Ramdisk Build (`ramdisk_build.py`)
|
|
|
|
1. Extract IM4M from SHSH blob
|
|
2. Process 8 components: iBSS, iBEC, SPTM, DeviceTree, SEP, TXM, KernelCache, Ramdisk+Trustcache
|
|
3. For ramdisk: extract base DMG → create 254 MB APFS volume → mount → inject SSH tools from `resources/ramdisk_input.tar.zst` → re-sign Mach-Os with ldid + signcert.p12 → build trustcache
|
|
4. Sign all components with IM4M manifest → output to `Ramdisk/` directory as IMG4 files
|
|
|
|
### CFW Installation (`cfw_install.sh`)
|
|
|
|
7 phases (+ 2 JB phases), safe to re-run (idempotent):
|
|
|
|
1. Decrypt/mount Cryptex SystemOS and AppOS DMGs (`ipsw` + `aea`)
|
|
2. Patch seputil (gigalocker UUID)
|
|
3. Install GPU driver (AppleParavirtGPUMetalIOGPUFamily)
|
|
4. Install iosbinpack64 (jailbreak tools)
|
|
5. Patch launchd_cache_loader (NOP cache validation)
|
|
6. Patch mobileactivationd (activation bypass)
|
|
7. Install LaunchDaemons (bash, dropbear SSH, trollvnc)
|
|
|
|
**JB-only phases** (enabled via `make cfw_install_jb` or `CFW_JB_MODE=1`):
|
|
|
|
- JB-1: Patch launchd jetsam guard (prevents jetsam panic on boot)
|
|
- JB-2: Install procursus bootstrap + optional Sileo to `/mnt5/<hash>/jb-vphone/`
|
|
|
|
---
|
|
|
|
## Coding Conventions
|
|
|
|
### Swift
|
|
|
|
- **Language:** Swift 6.0 (strict concurrency).
|
|
- **Style:** Pragmatic, minimal. No unnecessary abstractions.
|
|
- **Sections:** Use `// MARK: -` to organize code within files.
|
|
- **Access control:** Default (internal). Only mark `private` when needed for clarity.
|
|
- **Concurrency:** `@MainActor` for VM and UI classes. `nonisolated` delegate methods use `MainActor.isolated {}` to hop back safely.
|
|
- **Naming:** Types are `VPhone`-prefixed (`VPhoneVirtualMachine`, `VPhoneWindowController`). Match Apple framework conventions.
|
|
- **Private APIs:** Use `Dynamic()` for runtime method dispatch. Touch objects use `NSClassFromString` + KVC to avoid designated initializer crashes.
|
|
- **NSWindow `isReleasedWhenClosed`:** Always set `window.isReleasedWhenClosed = false` for programmatically created windows managed by an `NSWindowController`. The default is `true`, which causes the window to be released on close while `NSWindowController` and `_NSWindowTransformAnimation` still hold references — `objc_release` crashes on a dangling pointer during CA transaction commit. Nib-loaded windows handled by `NSWindowController` get this set automatically, but programmatic windows do not.
|
|
|
|
### Shell Scripts
|
|
|
|
- Use `zsh` with `set -euo pipefail`.
|
|
- Scripts resolve their own directory via `${0:a:h}` or `$(cd "$(dirname "$0")" && pwd)`.
|
|
- Build uses `make build` which handles compilation and entitlement signing.
|
|
|
|
### Python Scripts
|
|
|
|
- Firmware patching uses `capstone` (disassembly), `keystone-engine` (assembly), and `pyimg4` (IM4P handling).
|
|
- `patchers/kernel.py` uses dynamic pattern finding (string anchors, ADRP+ADD xrefs, BL frequency analysis) — nothing is hardcoded to specific offsets.
|
|
- Each patch is logged with offset and before/after state.
|
|
- Scripts operate on a VM directory and auto-discover the `*Restore*` subdirectory.
|
|
- **Environment:** Use the project venv (`source .venv/bin/activate`). Create with `make setup_venv`. All deps in `requirements.txt`: `capstone`, `keystone-engine`, `pyimg4`.
|
|
|
|
## Build & Sign
|
|
|
|
The binary requires private entitlements to use PV=3 virtualization:
|
|
|
|
- `com.apple.private.virtualization`
|
|
- `com.apple.private.virtualization.security-research`
|
|
- `com.apple.security.virtualization`
|
|
- `com.apple.vm.networking`
|
|
- `com.apple.security.get-task-allow`
|
|
|
|
Always use `make build` — never `swift build` alone, as the unsigned binary will fail at runtime.
|
|
|
|
## VM Creation (`make vm_new`)
|
|
|
|
Creates a VM directory with:
|
|
|
|
- Sparse disk image (default 64 GB)
|
|
- SEP storage (512 KB flat file)
|
|
- AVPBooter + AVPSEPBooter ROMs (copied from `/System/Library/Frameworks/Virtualization.framework/`)
|
|
- machineIdentifier (created on first boot if missing, persisted for stable ECID)
|
|
- NVRAM (created/overwritten each boot)
|
|
|
|
All paths are passed explicitly via CLI (`--rom`, `--disk`, `--nvram`, `--machine-id`, `--sep-storage`, `--sep-rom`). SEP coprocessor is always enabled.
|
|
|
|
Display is configurable via `--screen-width`, `--screen-height`, `--screen-ppi`, `--screen-scale` (defaults: 1290x2796 @ 460 PPI, scale 3.0).
|
|
|
|
Override defaults: `make vm_new VM_DIR=myvm DISK_SIZE=32`.
|
|
|
|
## Design System
|
|
|
|
### Intent
|
|
|
|
**Who:** Security researchers working with Apple firmware and virtual devices. Technical, patient, comfortable in terminals. Likely running alongside GDB, serial consoles, and SSH sessions.
|
|
|
|
**Task:** Boot, configure, and interact with virtual iPhones for firmware research. Monitor boot state, capture serial output, debug at the firmware level.
|
|
|
|
**Feel:** Like a research instrument. Precise, informative, honest about internal state. No decoration — every pixel earns its place.
|
|
|
|
### Palette
|
|
|
|
- **Background:** Dark neutral (`#1a1a1a` — near-black, low blue to reduce eye strain during long sessions)
|
|
- **Surface:** `#242424` (elevated panels), `#2e2e2e` (interactive elements)
|
|
- **Text primary:** `#e0e0e0` (high contrast without being pure white)
|
|
- **Text secondary:** `#888888` (labels, metadata)
|
|
- **Accent — status green:** `#4ade80` (VM running, boot success)
|
|
- **Accent — amber:** `#fbbf24` (DFU mode, warnings, in-progress states)
|
|
- **Accent — red:** `#f87171` (errors, VM stopped with error)
|
|
- **Accent — blue:** `#60a5fa` (informational, links, interactive highlights)
|
|
|
|
Rationale: Dark surfaces match the terminal-adjacent workflow. Status colors borrow from oscilloscope/JTAG tooling — green for good, amber for attention, red for fault. No brand colors — this is a tool, not a product.
|
|
|
|
### Typography
|
|
|
|
- **UI font:** System monospace (SF Mono / Menlo). Everything in this tool is technical — monospace respects the content.
|
|
- **Headings:** System sans (SF Pro) semibold, used sparingly for section labels only.
|
|
- **Serial/log output:** Monospace, `#e0e0e0` on dark background. No syntax highlighting — raw output, exactly as received.
|
|
|
|
### Depth
|
|
|
|
- **Approach:** Flat with subtle 1px borders (`#333333`). No shadows, no blur. Depth through color difference only.
|
|
- **Rationale:** Shadows suggest consumer software. Borders suggest instrument panels. This is an instrument.
|
|
|
|
### Spacing
|
|
|
|
- **Base unit:** 8px
|
|
- **Component padding:** 12px (1.5 units)
|
|
- **Section gaps:** 16px (2 units)
|
|
- **Window margins:** 16px
|
|
|
|
### Components
|
|
|
|
- **Status indicator:** Small circle (8px) with color fill + label. No animation — state changes are instantaneous.
|
|
- **VM display:** Full-bleed within its container. No rounded corners on the display itself.
|
|
- **Log output:** Scrolling monospace region, bottom-anchored (newest at bottom). No line numbers unless requested.
|
|
- **Toolbar (if present):** Icon-only, 32px touch targets, subtle hover state (`#2e2e2e` -> `#3a3a3a`).
|
|
|
|
---
|
|
|
|
## JB Kernel Patcher Status (`patches-jb` branch)
|
|
|
|
Branch is 8 commits ahead of `main`. All changes are **additive** — non-JB code paths are unaffected.
|
|
|
|
### Diff vs Main
|
|
|
|
| File | Change | Impact on non-JB |
|
|
| ---------------------- | -------------------------------------------------- | ------------------------ |
|
|
| `kernel.py` | +1 line: `self.patches = []` reset in `find_all()` | None (harmless init) |
|
|
| `cfw.py` | +`patch-launchd-jetsam`, +`inject-dylib` commands | None (new commands only) |
|
|
| `kernel_jb.py` | **New file** — 2128 lines | N/A |
|
|
| `txm_jb.py` | **New file** — 335 lines | N/A |
|
|
| `iboot_jb.py` | **New file** — 105 lines | N/A |
|
|
| `fw_patch_jb.py` | **New file** — 115 lines (WIP) | N/A |
|
|
| `cfw_install_jb.sh` | **New file** — 214 lines | N/A |
|
|
| `cfw_jb_input.tar.zst` | **New file** — JB resources | N/A |
|
|
| `Makefile` | +JB targets (`fw_patch_jb`, `cfw_install_jb`) | None (additive) |
|
|
| `AGENTS.md` | Documentation updates | N/A |
|
|
|
|
### Patch Counts
|
|
|
|
**Base patcher** (`kernel.py`): **25 patches** — verified identical to main.
|
|
|
|
**JB patcher** (`kernel_jb.py`): **160 patches** from 22 methods:
|
|
|
|
- **19 of 22 PASSING** — Groups A (sandbox hooks, AMFI, execve), B (string-anchored), C (shellcode)
|
|
- **3 FAILING** — see below
|
|
|
|
### 3 Remaining Failures
|
|
|
|
| Patch | Upstream Offset | Root Cause | Proposed Strategy |
|
|
| ------------------------------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| `patch_nvram_verify_permission` | NOP BL at `0x1234034` | 332 identical IOKit methods match structural filter; "krn." string leads to wrong function | Find via "IONVRAMController" string → metaclass ctor → PAC disc `#0xcda1` → search `__DATA_CONST` vtable entries (first entry after 3 nulls) with matching PAC disc + BL to memmove |
|
|
| `patch_thid_should_crash` | Zero `0x67EB50` | String in `__PRELINK_INFO` plist (no code refs); value already `0x00000000` in PCC kernel | Safe to return True (no-op); or find via `sysctl_oid` struct search in `__DATA` |
|
|
| `patch_hook_cred_label_update_execve` | Shellcode at `0xAB17D8` + ops table at `0xA54518` | Needs `_vfs_context_current` (`0xCC5EAC`) and `_vnode_getattr` (`0xCC91C0`) — 0 symbols available | Find via sandbox ops table → original hook func → BL targets by caller count (vfs_context_current = highest, vnode_getattr = near `mov wN, #0x380`) |
|
|
|
|
### Key Findings (from `research/kernel_jb_patch_notes.md`)
|
|
|
|
**All offsets in `kernel.py` are file offsets** — `bl_callers` dict, `_is_bl()`, `_disas_at()`, `find_string_refs()` all use file offsets, not VAs.
|
|
|
|
**IONVRAMController vtable discovery chain**:
|
|
|
|
```
|
|
"IONVRAMController" string @ 0xA2FEB
|
|
→ ADRP+ADD refs → metaclass ctor @ 0x125D2C0
|
|
→ PAC discriminator: movk x17, #0xcda1, lsl #48
|
|
→ instance size: mov w3, #0x88
|
|
→ class vtable in __DATA_CONST @ 0x7410B8 (preceded by 3 null entries)
|
|
→ vtable[0] = 0x1233E40 = verifyPermission
|
|
→ BL to memmove (3114 callers) at +0x1F4 = 0x1234034 ← NOP this
|
|
```
|
|
|
|
**vfs_context_current / vnode_getattr resolution**:
|
|
|
|
```
|
|
sandbox ops table → entry[16] = original hook @ 0x239A0B4
|
|
→ disassemble hook → find BL targets:
|
|
- _vfs_context_current: BL target with >1000 callers, short function
|
|
- _vnode_getattr: BL target near "mov wN, #0x380", moderate callers
|
|
```
|
|
|
|
### Upstream Reference Offsets (iPhone17,3 26.1)
|
|
|
|
| Symbol | File Offset | Notes |
|
|
| -------------------------- | ------------------------ | ------------------- |
|
|
| kern_text | `0xA74000` — `0x24B0000` | |
|
|
| base_va | `0xFFFFFE0007004000` | |
|
|
| verifyPermission func | `0x1233E40` | vtable @ `0x7410B8` |
|
|
| verifyPermission patch | `0x1234034` | NOP BL to memmove |
|
|
| \_thid_should_crash var | `0x67EB50` | already 0 |
|
|
| \_vfs_context_current | `0xCC5EAC` | from BL encoding |
|
|
| \_vnode_getattr | `0xCC91C0` | from BL encoding |
|
|
| hook_cred_label orig | `0x239A0B4` | from B encoding |
|
|
| sandbox ops entry | `0xA54518` | index 16 |
|
|
| OSMetaClass::OSMetaClass() | `0x10EA790` | 5236 callers |
|
|
| memmove | `0x12CB0D0` | 3114 callers |
|