hw/arm: add authenticated A6 IMG3 boot lab

Model the A6 crypto, interrupt, USB, and platform blocks needed to boot SecureROM through iBSS into iBEC Recovery.

Add local lab identity, IMG3, and APTicket tooling, patched macOS recovery utilities, UART and GDB access, and English end-user documentation.
This commit is contained in:
2026-09-01 09:51:49 -07:00
parent 47977dd34a
commit 5d9a60a926
45 changed files with 6002 additions and 265 deletions
+341 -86
View File
@@ -1,111 +1,366 @@
# iPhone 5 / Apple A6 sur QEMU Windows natif
# Apple A6 / iPhone 5 secure-boot lab
## État actuel
This repository contains an experimental QEMU `iphone5` machine for studying
the A6 IMG3 boot path in an isolated environment. It runs the guest
SecureROM, iBSS, and iBEC code with a locally generated root of trust and a
locally generated AES-256 GID key. The verified endpoint is iBEC Recovery
mode; booting a ramdisk or iOS is not implemented.
- QEMU `arm-softmmu` est compilé en PE Win64 natif avec MSYS2 MinGW64. WSL nest pas utilisé.
- La machine `iphone5` exécute la SecureROM A6 `iBoot-1145.3` de 65 536 octets.
- Les fusibles exposent `CPID:8950`, `CPRV:20` et `CPFM:03`.
- LUART A6 est relié à la console QEMU (`Ctrl+A`, puis `C` pour le moniteur ; `Ctrl+A`, puis `X` pour quitter).
- Le contrôleur USB OTG, son EP0, les DMA et lIRQ 11 permettent à la SecureROM de terminer son énumération DFU.
- Le descripteur produit par cette SecureROM annonce `VID=05AC, PID=1229`. La façade Windows le normalise vers le PID DFU public `1227`, attendu par `libirecovery`.
- Le pilote KMDF/UDE `QemuA6Ude.sys` crée un véritable enfant PnP `USB\VID_05AC&PID_1227` sous Windows.
- `QemuA6UsbBridge.exe` relaie les contrôles DFU entre le pilote et QEMU sur `127.0.0.1:26050`.
- Un test externe `DFU_GETSTATE` a traversé le socket, le modèle OTG et la SecureROM, puis a renvoyé `dfuIDLE` (`2`).
- `idevicerestore.exe` et `libirecovery` restent dorigine et ne sont pas patchés.
No Apple private key or GID key is included or required. Firmware files and
generated lab identities are intentionally ignored by Git.
Le paquet pilote signé en mode test est généré localement dans
`windows\QemuA6Ude\package` ; les clés, certificats et binaires générés ne sont
pas versionnés.
## Verified flow
## Construction Windows native
The following path has been tested on macOS:
QEMU se configure depuis un terminal MSYS2 MinGW64 :
1. The 64 KiB A6 SecureROM starts in DFU mode.
2. Patched `idevicerestore` selects the `n41ap` build identity from
`BuildManifest.plist` and sends the locally signed and encrypted iBSS.
3. Guest SecureROM parses the IMG3, validates its RSA chain and signature,
asks the emulated AES engine to unwrap the KBAG with the local GID slot,
and decrypts `DATA`.
4. iBSS parses and validates the local APTicket, including its device fields,
boot-nonce binding, certificate chain, signature, and iBEC digest.
5. iBSS unwraps and decrypts iBEC. QEMU performs a warm authenticated handoff
of the resulting image to its linked address at `0xbff00000`.
6. iBEC prints its real `iBootStage2` banner on UART and enumerates as
Recovery (`05ac:1281`). `irecovery -q` reports `MODE: Recovery` and
`IBFL: 0x1a`.
This is not a cycle-accurate reproduction of Apple silicon. The original
guest IMG3 and APTicket parsers execute, but the root and GID material are
lab-owned, crypto is provided by QEMU MMIO models, debug UART activation is
optionally assisted after authentication, and the final iBEC relocation is a
QEMU handoff. Timing, analog behavior, fault behavior, and unimplemented
peripherals must not be treated as hardware-equivalent.
## Host requirements
On macOS, install the QEMU build dependencies and the recovery-tool
dependencies. A typical Homebrew setup is:
```sh
./configure --target-list=arm-softmmu
ninja -C build qemu-system-arm.exe
brew install ninja pkg-config glib pixman libslirp \
autoconf automake libtool libimobiledevice libusb libzip
```
Le pilote UDE nécessite Visual Studio 2022 Build Tools et le WDK avec UDE. Si
le WDK n'est pas installé à son emplacement standard, définir
`QA6_WDK_ROOT` vers sa racine (celle qui contient `Include`, `bin` et `tools`).
Depuis PowerShell :
Python 3 and OpenSSL are required by the image-generation scripts. You must
also provide your own 65,536-byte A6 SecureROM dump. The repository does not
distribute it.
```powershell
.\windows\QemuA6Ude\prepare-package.ps1
.\windows\QemuA6UsbBridge\build-bridge.ps1 -Configuration Release
```
## Build QEMU
## Première installation du pilote
La signature dun pilote noyau local exige le mode de signature test Windows. Cette opération modifie le BCD et demande un redémarrage. Depuis un PowerShell administrateur :
```powershell
.\windows\QemuA6Ude\enable-test-mode.ps1
Restart-Computer
```
Après le redémarrage, toujours en administrateur :
```powershell
.\windows\QemuA6Ude\install-driver.ps1
```
Si Secure Boot bloque `testsigning`, il faut le désactiver dans lUEFI. Le script dinstallation importe uniquement le certificat public de test puis crée le contrôleur racine `Root\QemuA6Ude` avec `devcon`.
## Lancement normal
Depuis PowerShell à la racine :
```powershell
.\Run-iPhone5.ps1 -SkipBuild
```
Le mode USB Windows est actif par défaut. Le lanceur démarre le pont en arrière-plan, garde lUART dans la console et écrit les échanges USB dans `build\a6-usb-bridge.log`.
Vérification dans un second PowerShell :
```powershell
pnputil /enum-devices /connected /class USB
& 'C:\msys64\mingw64\bin\idevicerestore.exe' -d 'iPhone_4.0_32bit_10.3.4_14G61_Restore.ipsw'
```
Pour conserver lancien injecteur DFU interne, fournir directement une image :
```powershell
.\Run-iPhone5.ps1 -DfuImagePath '.\build\firmware\iBSS.iphone5.RELEASE.dfu' -Trace
```
Pour démarrer sans façade USB Windows :
```powershell
.\Run-iPhone5.ps1 -NoWindowsUsb
```
## Prochain jalon
Une fois l’énumération PnP confirmée, lIPSW iOS 10.3.4 sera envoyé par l`idevicerestore` original. La SecureROM vérifiera liBSS ; après son exécution, il faudra modéliser les périphériques supplémentaires utilisés par iBSS/iBEC et gérer sa réénumération USB Recovery pour atteindre iBoot.
## Reprise sur macOS
Le fork QEMU et linjecteur DFU interne sont portables. Sur macOS, installez les
dépendances QEMU, configurez `arm-softmmu`, puis compilez :
From the repository root:
```sh
./configure --target-list=arm-softmmu
ninja -C build qemu-system-arm
```
Placez ensuite le dump dans `firmware/s5l8950x-secure-rom.bin`, puis lancez :
The launcher expects `build/qemu-system-arm`. Set `QEMU_BIN` if the binary is
elsewhere.
## Fetch the public bootloader files
The helper reads the iOS 10.3.4 IPSW ZIP directory with HTTP Range requests
and downloads only `BuildManifest.plist`, iBSS, and iBEC:
```sh
./Run-iPhone5-macOS.sh
scripts/fetch-a6-bootloaders.py --board n41
```
Pour charger liBSS extrait de lIPSW sans dépendre dun périphérique USB hôte :
The following files should then exist locally:
```text
firmware/BuildManifest.plist
firmware/iBSS.iphone5.RELEASE.dfu
firmware/iBSS.iphone5.RELEASE.bin
firmware/iBEC.iphone5.RELEASE.dfu
firmware/iBEC.iphone5.RELEASE.bin
```
The fetcher validates HTTP ranges, uncompressed sizes, and CRC-32 values. It
does not personalize, decrypt, sign, or modify the downloaded images.
## Build the macOS recovery tools
macOS does not expose the emulator as a system-wide USB device. Instead, the
QEMU USB model is connected over a localhost transport implemented in the
patched `libirecovery`. The normal IOKit backend remains unchanged when the
transport environment variable is absent.
Build the pinned and checksum-verified recovery tools locally:
```sh
DFU_IMAGE="$PWD/firmware/iBSS.n41.RELEASE.dfu" ./Run-iPhone5-macOS.sh
scripts/build-macos-recovery-tools.sh
```
La façade UDE est propre à Windows. Faire apparaître le téléphone comme un vrai périphérique USB sur macOS demanderait une extension DriverKit signée ; ce nest donc pas un raccourci par rapport au chemin UDE déjà construit.
They are installed under `build/limd-prefix`; nothing is installed into
`/usr/local`. Always use the repository wrappers:
```sh
scripts/irecovery-qemu
scripts/idevicerestore-qemu
```
The QEMU endpoint defaults to `127.0.0.1:26050`. Change both sides with
`USB_BRIDGE_PORT` and `QEMU_USB_ENDPOINT` when running concurrent instances.
## Generate a new lab identity and boot chain
Create an empty output directory containing a new RSA hierarchy, a random
AES-256 GID key, a derived SecureROM, signed IMG3 files, encrypted payloads,
and a locally signed APTicket:
```sh
scripts/build-a6-lab-chain.sh \
"/absolute/path/to/SecureROM for s5l8950xsi, iBoot-1145.3" \
build/a6-lab
```
The output directory must be new or empty. Private PEM files and
`gid-key.bin` are created with owner-only permissions. Do not commit or share
that directory. The default ticket nonce is the value produced by the
current deterministic A6 lab boot (`8d82693c897d1b9d`). The optional third
argument exists for experiments in which the guest nonce is changed.
Start QEMU in the first terminal:
```sh
A6_LAB_DIR="$PWD/build/a6-lab" GDB_PORT=12345 \
./Run-iPhone5-macOS.sh
```
Boot iBSS and iBEC in a second terminal:
```sh
A6_LAB_DIR="$PWD/build/a6-lab" \
scripts/idevicerestore-qemu -d -y -P firmware
```
This wrapper automatically enables the explicit QEMU lab boot-only path. It
does not contact a TSS server and stops after iBEC reaches Recovery; it does
not restore a filesystem. Confirm the result with:
```sh
scripts/irecovery-qemu -q
```
Expected identifying fields include:
```text
CPID: 0x8950
ECID: 0x0000000000200000
IBFL: 0x1a
MODE: Recovery
PRODUCT: iPhone5,1
MODEL: n41ap
```
## UART console
UART0 is mapped at `0x32b00000` and connected to QEMU's standard console by
`-serial mon:stdio`. Run the launcher directly from the terminal in which you
want to see serial output. No extra serial client is needed.
Useful console controls are:
- `Ctrl+A`, then `C`: switch between UART and the QEMU monitor.
- `Ctrl+A`, then `X`: quit QEMU.
Release iBSS/iBEC images do not always enable serial output themselves. The
launcher therefore sets their `debug-uarts` boot argument to `3` after IMG3
authentication by default. Disable this assistance when testing native
firmware behavior:
```sh
DEBUG_UART=0 A6_LAB_DIR="$PWD/build/a6-lab" \
./Run-iPhone5-macOS.sh
```
With the default setting, a successful boot prints the authentic guest
`iBootStage2` banner followed by `Entering recovery mode, starting command
prompt`. Repeated NAND reset errors are currently expected because NAND is
not modeled; they do not prevent the Recovery endpoint from appearing.
## Live debugging with LLDB, GDB, or IDA
Set `GDB_PORT` to expose QEMU's remote GDB stub on localhost. Add `PAUSED=1`
to stop before the SecureROM's first instruction:
```sh
A6_LAB_DIR="$PWD/build/a6-lab" GDB_PORT=12345 PAUSED=1 \
./Run-iPhone5-macOS.sh
```
Attach LLDB:
```sh
lldb -o 'gdb-remote 127.0.0.1:12345'
```
Without `PAUSED=1`, the same command can attach to a running boot. Only one
debugger may control the GDB stub at a time.
Useful load addresses are:
| Stage | Address |
| --- | ---: |
| SecureROM | `0x00000000` |
| iBSS | `0x10000000` |
| iBEC | `0xbff00000` |
| UART0 MMIO | `0x32b00000` |
For IDA, load `build/a6-lab/iBEC.lab-root.bin` as a raw little-endian ARM
binary with image base `0xbff00000`. Select `Remote GDB debugger`, connect to
`127.0.0.1:12345`, and configure the same load address in the debugger's
memory map. The live PC should enter the `0xbff00000` region after the iBEC
handoff.
For a static-only iBSS session that intentionally bypasses IMG3 validation:
```sh
build/qemu-system-arm \
-machine iphone5 \
-bios firmware/s5l8950x-secure-rom.bin \
-device loader,file=firmware/iBSS.iphone5.RELEASE.bin,addr=0x10000000,cpu-num=0,force-raw=on \
-display none -serial mon:stdio \
-S -gdb tcp:127.0.0.1:12345
```
That loader command is useful for early breakpoints, but it bypasses the
SecureROM parser, signature checks, AES work, and normal handoff state. It is
not evidence of an authenticated boot.
## Build signed and encrypted custom images
The simplest supported workflow is to provide raw replacement `DATA`
payloads and rebuild an entirely new identity directory. Custom payloads must
retain exactly one copy of the original embedded 1,215-byte trust-anchor slot
so the builder can replace it with the generated lab root.
```sh
A6_IBSS_PAYLOAD="$PWD/payloads/iBSS.custom.bin" \
A6_IBEC_PAYLOAD="$PWD/payloads/iBEC.custom.bin" \
scripts/build-a6-lab-chain.sh \
"/absolute/path/to/SecureROM for s5l8950xsi, iBoot-1145.3" \
build/a6-custom
```
Boot that directory by setting `A6_LAB_DIR="$PWD/build/a6-custom"` in both
the launcher and `idevicerestore` commands shown above.
For individual IMG3 experiments, first inspect a source template:
```sh
scripts/a6-img3-info.py firmware/iBSS.iphone5.RELEASE.dfu
scripts/a6-img3-info.py firmware/iBSS.iphone5.RELEASE.dfu \
--extract-data build/iBSS.extracted.bin
```
Patch an iBoot payload to trust the existing lab root, then create an iBSS
with an embedded SHSH/CERT signature and GID-wrapped KBAG:
```sh
scripts/a6-lab-patch-iboot-root.py \
--source-rom "/absolute/path/to/original/SecureROM" \
--identity build/a6-lab \
--input payloads/iBSS.custom.bin \
--output build/iBSS.custom.lab-root.bin
scripts/a6-lab-img3.py \
--template firmware/iBSS.iphone5.RELEASE.dfu \
--payload build/iBSS.custom.lab-root.bin \
--identity build/a6-lab \
--encrypt \
--output build/iBSS.custom.signed-encrypted.dfu
```
An iBEC uses the external APTicket layout. Build its encrypted IMG3 first,
then bind the APTicket to that exact component and the guest boot nonce:
```sh
scripts/a6-lab-patch-iboot-root.py \
--source-rom "/absolute/path/to/original/SecureROM" \
--identity build/a6-lab \
--input payloads/iBEC.custom.bin \
--output build/iBEC.custom.lab-root.bin
scripts/a6-lab-img3.py \
--template firmware/iBEC.iphone5.RELEASE.dfu \
--payload build/iBEC.custom.lab-root.bin \
--identity build/a6-lab \
--encrypt --ticketed \
--output build/iBEC.custom.ticketed-encrypted.img3
scripts/a6-lab-apticket.py \
--component build/iBEC.custom.ticketed-encrypted.img3 \
--identity build/a6-lab \
--boot-nonce 8d82693c897d1b9d \
--ticket-output build/iBEC.custom.apticket.der \
--output build/iBEC.custom.signed-encrypted.dfu
```
The tools refuse to overwrite outputs and write JSON sidecars with hashes,
sizes, signed ranges, encryption state, device fields, and manifest tags.
`a6-lab-img3.py` uses a random content key and IV for every encrypted image;
the content key is wrapped by AES-256-CBC with the generated lab GID key.
## Environment variables
| Variable | Purpose | Default |
| --- | --- | --- |
| `A6_LAB_DIR` | Generated identity and boot-chain directory | unset |
| `A6_IBSS_PAYLOAD` | Raw custom iBSS payload for the chain builder | stock extracted iBSS |
| `A6_IBEC_PAYLOAD` | Raw custom iBEC payload for the chain builder | stock extracted iBEC |
| `A6_BOOT_NONCE` | Eight-byte ticket nonce in hexadecimal | `8d82693c897d1b9d` |
| `QEMU_BIN` | QEMU executable used by the launcher | `build/qemu-system-arm` |
| `USB_BRIDGE_PORT` | QEMU localhost recovery transport; `0` disables it | `26050` |
| `QEMU_USB_ENDPOINT` | Endpoint used by the host recovery wrappers | `127.0.0.1:26050` |
| `GDB_PORT` | Remote GDB listener | unset |
| `PAUSED` | Start with the CPU stopped | `0` |
| `DEBUG_UART` | Enable post-authentication debug UART assistance | `1` |
| `NATIVE_IMG3` | Enable authenticated native IMG3 handoff helpers | `1` with `A6_LAB_DIR` |
| `DFU_IMAGE` | Optional internal one-shot DFU image | unset |
## Windows host path
The Windows path uses a UDE test driver and a native TCP bridge to present
the virtual Apple DFU device to unmodified Windows recovery tools. Build QEMU
from MSYS2 MinGW64, then prepare the driver and bridge from PowerShell:
```powershell
.\windows\QemuA6Ude\prepare-package.ps1
.\windows\QemuA6UsbBridge\build-bridge.ps1 -Configuration Release
```
The first installation requires an administrator shell, test-signing mode,
and a restart:
```powershell
.\windows\QemuA6Ude\enable-test-mode.ps1
Restart-Computer
.\windows\QemuA6Ude\install-driver.ps1
```
Launch with:
```powershell
.\Run-iPhone5.ps1 -SkipBuild -GdbPort 12345
```
The local-key IMG3 generation and macOS `idevicerestore` boot-only wrapper
are currently the verified end-to-end path. The Windows UDE bridge has been
validated for DFU control traffic but not for the complete local iBSS/iBEC
workflow.
## Current limitations
- The verified endpoint is iBEC Recovery, not a ramdisk or iOS userspace.
- NAND is not implemented, so the guest emits repeated NAND errors.
- UART transmit and MMIO access are verified. UART receive is modeled, but a
complete interactive iBoot command session over serial is not guaranteed.
- The localhost macOS backend is visible only to the patched libirecovery
tools; it does not appear in Finder or System Information.
- The implementation is intended for deterministic parser and boot-flow
research, not for hardware timing or fault-injection equivalence.