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:
+341
-86
@@ -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 n’est 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`.
|
||||
- L’UART 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 l’IRQ 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 d’origine 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 d’un 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 l’UEFI. Le script d’installation 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 l’UART 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 l’ancien 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, l’IPSW iOS 10.3.4 sera envoyé par l’`idevicerestore` original. La SecureROM vérifiera l’iBSS ; 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 l’injecteur 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 l’iBSS extrait de l’IPSW sans dépendre d’un 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 n’est 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.
|
||||
|
||||
Reference in New Issue
Block a user