Files
QEMU-S5L8950X/A6-STATUS.md
T
Yaya48 5d9a60a926 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.
2026-09-01 09:51:49 -07:00

12 KiB

Apple A6 / iPhone 5 secure-boot lab

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.

No Apple private key or GID key is included or required. Firmware files and generated lab identities are intentionally ignored by Git.

Verified flow

The following path has been tested on macOS:

  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:

brew install ninja pkg-config glib pixman libslirp \
  autoconf automake libtool libimobiledevice libusb libzip

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.

Build QEMU

From the repository root:

./configure --target-list=arm-softmmu
ninja -C build qemu-system-arm

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:

scripts/fetch-a6-bootloaders.py --board n41

The following files should then exist locally:

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:

scripts/build-macos-recovery-tools.sh

They are installed under build/limd-prefix; nothing is installed into /usr/local. Always use the repository wrappers:

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:

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:

A6_LAB_DIR="$PWD/build/a6-lab" GDB_PORT=12345 \
  ./Run-iPhone5-macOS.sh

Boot iBSS and iBEC in a second terminal:

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:

scripts/irecovery-qemu -q

Expected identifying fields include:

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:

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:

A6_LAB_DIR="$PWD/build/a6-lab" GDB_PORT=12345 PAUSED=1 \
  ./Run-iPhone5-macOS.sh

Attach LLDB:

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:

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.

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:

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:

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:

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:

.\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:

.\windows\QemuA6Ude\enable-test-mode.ps1
Restart-Computer
.\windows\QemuA6Ude\install-driver.ps1

Launch with:

.\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.