A 2026 fault-injection talk, two retro boot chains
Black Hat Asia 2026 hosted a briefing called When Flash Reveals Its Secrets: Advanced Glitching Leveraging Hidden CPU–eMMC Behavior. The premise is modern: take a hardened embedded SoC with Secure Boot, no UART debug output, and a signed boot chain, then bypass the signature check with a fault injection (FI) attack. The contribution is the localization method that turns a blind, brute-force glitch into a precision strike.
What made it click for us is how directly the threat model maps onto two different Nintendo consoles. The original Super Nintendo does not sign its firmware; it uses a pair of custom microcontrollers that shake hands over a 4 MHz serial link, and if the handshake fails the console is held in reset. That is the original CIC — Checking Integrated Circuit — and it is the closest thing 1990 had to a boot-time signature check. The SNES Classic (2017) is a different machine: a small ARM SoC that really does run U-Boot, a Linux kernel, and a cryptsetup-encrypted NAND rootfs. Modding one means understanding the CIC stream; modding the other means understanding a real Secure Boot chain. We are working on both.
"Two consoles, same problem: a verification gate you must satisfy before the CPU runs your payload. One gate is a 7-bit LFSR in a lockout chip. The other is a 256-bit key in a stock kernel ramdisk. The attacker’s advantage is the same: the bus is easier to read than the CPU."
The talk: correlating two buses to find the verification moment
The core problem the briefing solves is when to glitch. Secure Boot verification is a tiny window inside a boot sequence that can run for hundreds of milliseconds. Without a trigger, an attacker sweeps voltage or electromagnetic pulses across the entire boot, accepting a tiny hit rate, high noise, and a real chance of permanently damaging the CPU. The authors’ answer is to stop looking at the CPU alone and start correlating it with a peripheral.
Concretely, the authors place an electromagnetic probe near the CPU core to capture micro-EM emissions, and simultaneously monitor the eMMC bus — the GND, D0, and CLK lines — for the low-level timing of flash reads. By building a cross-domain hardware signal correlation model, they identify the actual instant the boot ROM performs its signature verification, then fire a single precisely timed fault. The attack window compresses from the second scale down to the millisecond or even nanosecond scale. The technique is demonstrated bypassing Secure Boot on real embedded devices with no serial output at all.
The broader lesson is the methodology, not any one target: when a verification step leaves no software trace, look for the physical trace it leaves on a peripheral. The CPU is a black box; the bus it talks to is not. That insight is older than the SoCs in the talk, and it is exactly the insight the retro modding community has been operating on — sometimes implicitly — for years.
The SNES Classic: a retro console with real U-Boot and cryptsetup
The SNES Classic Edition (model CLV-201) is an Allwinner A33 (R16) single-board computer in a small plastic case. Its boot chain is a textbook embedded Secure Boot: a BROM in the SoC loads FES1 (eGON.BT0, a small SRAM initializer), FES1 initializes DRAM, then U-Boot is loaded to 0x47000000. U-Boot’s bootcmd reads a kernel from NAND sector 0x30 (or memboots from 0x43800000), and the kernel’s initramfs decrypts the rootfs partition with a 32-byte key before mounting it.
This is the console where the analogy becomes real. There is real U-Boot (we have extracted uboot.bin and patched its bootcmd to run sunxi_flash phy_read so the host can dump NAND over FEL). There is real cryptsetup: the rootfs is encrypted with AES-XTS and a 32-byte key stored in the stock kernel ramdisk, injected through the kernel command line as hakchi-key-file=base64:.... There is no CIC in this machine, because the authentication has moved up the stack: the kernel and rootfs must be intact, and the .sfrom files that Canoe reads must carry the correct header and ROM data.
How the modding community rewrites the chain
Hakchi2 CE is the standard modding toolkit. Its work is a chain-wide patch: a custom U-Boot (with a patched bootcmd that loads a modded kernel), a modded kernel (with the key injected and an initramfs that mounts a rootfs overlay), and a userland that adds games to /var/lib/hakchi/games/. The attacker does not defeat the verification gate; it becomes the verification gate. The original factory chain is replaced with one the user controls.
The same physical-layer thinking from the Black Hat talk shows up here too. To dump the 512 MB NAND safely, you do not ask the running Linux to copy it over USB. You patch U-Boot to read NAND sectors into DRAM at 0x43800000, return to FEL, then read the DRAM buffer over USB. The CPU is the black box; the sunxi_flash phy_read call and the FEL bus are the observable traces. We are currently running that exact sequence with ./scripts/sn.sh dump nand as a read-only, resumable dump.
# patch uboot.bin bootcmd at offset 0x6a54b to:
sunxi_flash phy_read 43800000 <sector> <count>; efex
# load into DRAM, run, U-Boot returns to FEL when done
sunxi-fel spl fes1.bin
sunxi-fel write 0x47000000 uboot-dump.bin
sunxi-fel exe 0x47000000
sunxi-fel read 0x43800000 <host_file> <bytes> Notice the similarity. The Black Hat authors localize the signature check by watching the eMMC bus. The SNES Classic modder localizes the NAND read by watching the FEL link and patching the U-Boot command. Both start from the same idea: the CPU will not tell you what it is doing, but the bus it reads from will.
The original Super Nintendo: the CIC as a hardware signature check
The original 1990s Super Nintendo has none of that software. It has the CIC: a lock chip on the motherboard (F411) and a key chip in the cartridge (D411 or D413), talking to each other over a 4 MHz clock on cartridge pin 56 with data lines on pins 24 and 55. If the stream does not match, the lock holds /RESET low and the game never starts. Region lockout and unauthorized-cartridge rejection are the same mechanism.
The CIC’s program counter is a 3-bit bank combined with a 7-bit polynomial counter (a small LFSR). The seed — selected by the chip’s stream-select bits, ordered 3-0-1-2 — determines which stream each side produces. NTSC and PAL cartridges use different seeds (D411 vs D413), which is the entire region-lock mechanism. There is no cryptographic primitive here; the “secret” is the bitstream itself, generated by a small state machine running on a known clock. That is exactly the kind of observable, deterministic verification step the Black Hat talk targets.
The reset vector and the SPC700 IPL
On power-on, the Ricoh 5A22 reads the reset vector from $00:FFFC in the cartridge memory map. A minimal reset handler does the 65c816 mode switch and jumps to GAME_MAIN:
; reset vector at $00:FFFC points here
RESET:
sei ; disable interrupts
clc
xce ; switch to native mode
rep #$30 ; 16-bit accumulator & index
lda #$1FFF
tcs ; stack pointer
jmp GAME_MAIN ; hand off to hardware init Then there is the SPC700, a second 8-bit processor with its own 64-byte boot ROM (IPL) at $FFC0. It clears its RAM, writes $AA/$BB to $2140/$2141, and waits for the 5A22 to hand-feed an audio driver byte-by-byte. The original SNES therefore has two independent boot chains — CPU and APU — both of which the cartridge must satisfy. This is not U-Boot and cryptsetup, but the role is the same: an early, non-negotiable verification step before user code runs.
How the modding community attacks both chains
The SNES Classic and the original SNES are attacked with the same conceptual spectrum, just at different layers.
Where a glitch would land on each target
Applying the Black Hat methodology to the SNES Classic means watching the NAND bus during U-Boot bootcmd execution. The cryptsetup key is read from the kernel command line or ramdisk, then /dev/nandb is decrypted and mounted. If you could time a fault to the exact instruction that compares or loads the key, you could trick the kernel into decrypting with a different key, mounting an altered rootfs, or skipping the mount check. The observable side channel is the FEL link and the NAND I/O pattern.
On the original SNES, the CIC data lines (pins 24 and 55) and CIC clock (pin 56) are the bus. The lock chip’s decision to release /RESET is the signature-verification branch. A precisely timed voltage or EM pulse at the lock chip’s compare instruction could flip the branch outcome — forcing /RESET high even on a mismatched stream. The retro case is more tractable: the CIC bus is slow, deterministic, and entirely unencrypted, with no anti-glitch hardening.
/RESET release on pin 26./RESET high on the original.Our project: one ROM, two targets
This is where the research connects to what we are building. CatGame is a C++20 engine. We are porting a subset of it to the 65c816 so it can run on real SNES hardware. The toolchain is LLVM-mos with -mcpu=mosw65816, plus a custom linker we wrote to emit a banked ROM with the correct reset/NMI/IRQ vectors. The output is a .sfc file.
# 65c816 = Ricoh 5A22 / SNES CPU
mos-clang++ --target=mos -mcpu=mosw65816 \
-std=c++20 -Os -ffreestanding \
-T snes_banked.ld \ # our custom linker
-o game.sfc engine_snes.cpp That .sfc is the canonical SNES ROM. For the original console, we can wrap it in a cartridge with a real key CIC, a SuperCIC PIC, or a from-scratch CIC stream generator in an FPGA. For the SNES Classic, the same .sfc is converted to a .sfrom (the Canoe emulator format), placed in the decrypted rootfs under /usr/share/games/ or the Hakchi overlay /var/lib/hakchi/games/, then the rootfs is re-packed, re-encrypted, and flashed back to NAND. The verification gate is different, but the payload is the same ROM.
.sfc that can be deployed as a physical cartridge (with CIC handling) or converted to .sfrom for the SNES Classic.The original console is the harder compatibility test: every cycle, every bank, every PPU register, and every CIC data bit must be correct. The SNES Classic is the easier deployment test: the emulator does the heavy lifting, but the payload must pass the U-Boot/kernel/rootfs chain and the cryptsetup-encrypted NAND. Both paths converge on the same 65c816 binary, which is why LLVM-mos and the custom linker are the center of the work.
What this changes about the build
The cartridge project now has three parallel tracks, and the Black Hat talk clarified which layer is hard on each track.
| Track | Status | What it needs |
|---|---|---|
| 65c816 engine ROM (PPU init, SPC700 boot, game loop) | in progress | LLVM-mos targeting mosw65816, custom linker script, C++20 freestanding code |
| Cartridge verification (CIC key / SuperCIC / FPGA) | roadmap | A key CIC or a from-scratch stream re-implementation validated against the lock |
| SNES Classic deployment (.sfrom, rootfs repack, NAND flash) | roadmap | ./scripts/sn.sh dump nand completed, rootfs decrypted, .sfrom format verified |
"Owning the reset vector means owning the bootloader. Owning the CIC stream means owning the original’s signature check. Owning the U-Boot and rootfs means owning the Classic. The payload is the same in all three cases."
Caveats and limitations
The SNES Classic and the original SNES are different computers. The Classic is an ARM Linux box with U-Boot and cryptsetup. The original is a 65c816 game console with a CIC lockout chip. We cover both because the same LLVM-mos ROM is the payload for both, but the boot chains are not interchangeable.
No decryption keys are published in this post. The SNES Classic rootfs is encrypted with a 32-byte key extracted from the stock kernel ramdisk. We describe the key’s location and role, but not its value. The key is considered a device secret and is stored only in our local backup tree under data/sn/backups/key-file.
NAND flash is not performed yet. The SNES Classic next steps in our notes include re-packing and re-flashing rootfs. At the time of writing we are still completing the read-only NAND dump with ./scripts/sn.sh dump nand. No write operations have been performed on the device.
The Black Hat talk targets modern embedded SoCs, not retro consoles. The eMMC bus correlation method is demonstrated on automotive-grade SoCs. We are applying the methodology (correlate a peripheral bus with CPU activity to localize a verification step) to the CIC and the SNES Classic, not claiming the talk’s results transfer directly.
No glitching was performed. This post describes how a fault-injection attack would be structured in principle. We are building our own cartridge and our own SNES Classic deployment path, not attacking stock consoles or extracting keys we do not own.
CIC stream details are from community documentation. The seed values, pin assignments, and LFSR structure come from the SNESdev Wiki, SnesLab, and the SuperFamicom Development Wiki, cross-referenced with ikari’s SuperCIC source. The “glitch window” discussion is architectural, not a measured timing profile.
LLVM-mos SNES target status. LLVM-mos ships NES mapper targets out of the box; the SNES is not a stock platform target. Our mosw65816 targeting and the custom linker script are our own work in progress. The compile command is representative, not a verified build invocation.
Where this connects
This is part of a longer thread on the cartridge port, the SNES Classic deployment, and boot security. The engine architecture we are shrinking to 65c816 is documented in our ECS architecture notes; the tile rendering model we are adapting is in the GPU instanced tile rendering post. The broader security research program lives on the sec subdomain, and the engine’s API surface is on api. We will post the first .sfc build log, the .sfrom conversion, and the SNES Classic HDMI acceptance test as the roadmap items land.
