Glitching the SPC58 BAF: EMFI Into a Locked Automotive Bootloader
Two sparks and you're inside the bootloader. ⚡
Every microcontroller with secure boot has the same soft spot: somewhere in silicon, a single branch decides whether you are trusted. Get the value right and it runs your code; get it wrong and it locks the door. Fault injection doesn't guess the value — it reaches into the chip at the instant of the decision and knocks the answer sideways.
This is a field write-up about one attack that reliably lands on real automotive controllers — the boot gate of ST's SPC58, a 32-bit Power Architecture MCU (the SPC58N "Chorus" line) used in engine and vehicle control units. The target here is a locked SPC58-based ECU I own, and the work is authorized bootloader-key recovery. What follows is the procedure that opens this class of part — the sequence, and where each pulse lands — not a table of winning offsets.
"This isn't ECU reversing. It's one of the top glitches that actually work on automotive controllers — and yes, it works."

At a glance:
- OEM part → 1 glitch (header check only)
- Locked / in-field controller → 2 glitches (header + watchdog)
- Loader lands in SRAM — code runs on-chip
- Result: flash R / W — dumped
What the BAF actually checks¶
When an SPC58 comes out of reset it does not run your firmware first. It runs ST's own boot code out of a small protected region called the BAF — Boot Assist Flash. The BAF's whole job is to answer one question: is there a valid application in flash to jump to?
It answers by reading the boot header — the Reset Configuration Half-Word and boot pointer (RCHW) — out of the user flash region. If the header looks valid, the BAF hands control to the application at its entry point and your chance is gone: the locked firmware is now in charge. If the header is not valid, the BAF has nowhere to go, so it falls back to a serial download mode — it will accept a small program over CAN or UART straight into SRAM and execute it.
That fallback is the entire prize. If you can make the BAF believe there is no valid application, it opens a door and lets you run code with the chip's own privileges — enough to bring up a loader and read or write flash. You don't have to forge a valid header. You just have to make the check come out the wrong way, once.
power-on reset
│ BAF boot ROM takes control
▼
read boot header from flash (RCHW + application boot pointer)
│
▼ ◄── glitch here
◆ valid application header?
│
├── NO / corrupted ──► serial download mode (accept code → SRAM → run) ← the door
│
└── YES ────────────► jump to application (OEM firmware runs · game over)
A well-timed pulse as the BAF evaluates the header pushes the branch away from "jump to application" and into "serial download" — the chip walks itself into the mode you want.
OEM opens on the first hit. In-field fights back.¶
How many glitches you need comes down to what the chip has been told about itself. A part still in a permissive OEM state only guards the header check. A controller that has been locked and put in the field guards more than that — it also watches for exactly the abnormal boot you are trying to cause, and it will reset itself before you can use the door.
OEM / permissive part — one glitch, header check only
- Let it out of reset. ESR0 / reset-out goes high, the CUP starts — that edge is the trigger. Wait.
- ◊ Glitch the flash-header check. The BAF reads the header as invalid and drops into serial download.
- CAN init, then upload. Wait a few ms for the BAF, send the CAN init message — a reply means the door is open. Push the loader into SRAM and run it: read / write flash.
Locked / in-field controller — two glitches, header + watchdog
- Let it out of reset. ESR0 / reset-out high, the CUP starts — same trigger edge. Wait.
- ◊ Glitch the flash-header check. Bypass the jump to the locked program start so the app never runs.
- ◊ Glitch out the in-field status. Wait, then a second pulse on the life-cycle / watchdog check so the controller doesn't reset itself out from under you.
- CAN init, then upload. Wait a few ms for the BAF, send the CAN init message — a reply confirms it. Push the loader into SRAM: read / write.
The second glitch is the whole difference. Bypassing the header check alone gets an in-field part into the right code path, but the controller notices it is in an abnormal state and the watchdog resets it before you can do anything. The second pulse lands on that in-field/life-cycle status check and keeps the reset from firing — so the serial door you just opened is still open a moment later, long enough to push a loader in.
Field model, not a datasheet. The "header check" and "in-field status" gates are how the boot behaves under fault, confirmed by what actually opens the part — not a claim about ST's internal source. The proof is downstream: two pulses, in the right order, drop an in-field controller into serial mode. Repeatably.
What it takes to glitch an SPC58¶
A glitch is easy to describe and hard to land. You need the chip in a known state at a known instant, a trigger you can trust to within nanoseconds, a fault source powerful and repeatable enough to actually corrupt a computation, and — for electromagnetic injection — a way to put the probe over the exact spot on the die that matters. That is four separate jobs, and this bench splits them across four tools.

- ChipWhisperer-Husky — the brain (≈ €600). Does the math. Locks onto the reset-out edge, counts the exact delay from it, sequences the shots and fires the probe. Without timing this stable, none of the sequence above is repeatable.
- ChipShouter CW520 — the fault (≈ €4k vs ~€15k lab station). The reason it works. A high-voltage electromagnetic pulse, powerful and — crucially — repeatable. Same quality of fault as a laboratory EMFI station that costs roughly 4× as much. This is what turns "sometimes" into "reliably."
- Custom ESP32 power/CAN board — state (DIY). Switches ECU power up and down on demand, drives the reset line, and sends the CAN init message that asks the BAF whether the glitch landed. It puts the chip in exactly the right state at exactly the right moment — the trigger itself comes off the reset-out edge.
- CNC 1310 gantry — position (≈ €120). Carries the EMFI probe over the die and raster-scans XY (and Z height) to find the sensitive spot, feeding a position heat-map. EM faults are intensely local — a millimetre is the difference between a dead chip and an open door.
- Faulty Cat + homemade coils — the budget path (≈ €40). Electronic Cats' Faulty Cat and hand-wound coils do produce faults and are great for finding rough territory — but the pulse isn't stable enough to glitch reliably. They find the neighbourhood; they don't land the shot.
- Oscilloscope + fixturing. Scope to watch the trigger and the ECU's response so the delay can be dialled in; a CW308 breakout and a decapped / thinned package so the field actually couples into the die.

Signal map — who talks to whom: the ESP32 board powers the ECU and speaks CAN to it; the Husky senses the reset-out edge and fires the ChipShouter; the ChipShouter, positioned by the CNC over the die, delivers the EM pulse; the ECU's CAN reply goes back as the oracle.
The procedure: reset, wait, spark, ask¶
The trigger is not the CAN bus — it is the chip leaving reset. When ESR0 / reset-out goes high the CUP starts running and the BAF begins its boot; the Husky locks onto that rising edge and counts a fixed delay from it. From there the sequence always has the same shape:
Reset-out goes high → wait a set delay → fire the glitch while the BAF is doing its early boot check → wait a few milliseconds so the BAF is fully up → send the CAN init message and listen for a reply. On an in-field part, a second pulse goes in between the first glitch and the wait.
What you sweep¶
Four things decide whether a shot lands, and you search over all of them:
- When — the delay from the reset edge to the pulse, stepped finely until it lines up with the exact instruction doing the check.
- How hard — the pulse width and strength.
- Charge — the ChipShouter's voltage.
- Where — the spot on the die, moved by the CNC.
You raster position, and at each spot sweep the timing; an oracle scores every attempt into a heat-map so the sensitive spot rises out of the noise.
How fast, and how long¶
Each attempt is cheap. A full cycle — power-cycle the ECU, catch the reset edge, wait, fire, then ask over CAN — runs in about 40–60 ms, so the search rips through attempts and you can afford to move fast and hunt for perfect timing.
| Metric | Value | Notes |
|---|---|---|
| Per attempt | 40–60 ms | cycle → glitch → CAN check |
| OEM · 1 glitch | 10 s – 20 min | to jump into the BAF |
| In-field · 2 glitches | ~1 hour + | two aligned faults |
| Search space | time × XY | timing sweep + raster |
On an OEM part a single glitch usually falls into place somewhere between ten seconds and twenty minutes, timing luck depending. Two aligned glitches on an in-field controller is a different animal — usually an hour or more before both land clean on the same cycle.
What success looks like on the wire¶
There is no ambiguity when it lands. The controller stops behaving like a locked application and starts answering as a bootloader — it acknowledges tester-present, takes the ENABLE, and lets the loader unlock flash. Here is what the campaign log shows when it lands (tuning parameters trimmed):
===== attempt N [loop . place .]: armed on ESR0 reset-out ↑
>>> we are IN THE BOOTLOADER (triggered=True)
###### SECOND GLITCH
POWER-CYCLE tio4: OFF (pre-glitch reset-out LOW)
>>> we are IN THE BOOTLOADER (triggered=True)
>>> SUCCESS: uploading BAF stub -> SRAM
# then send CAN init -> got reply
# SBL-loader variant
OK: ENABLE keep-alive OK (triggered=True)
>>> SUCCESS: unlocking loader for flash read ...
loader unlock (CUP key) OK
Two IN THE BOOTLOADER hits on the same power cycle — the first past the header check, the second past the in-field watchdog — then the stub goes up to SRAM, the CAN init draws a reply, and the loader holds the session open. On the SBL variant the tell is a clean ENABLE followed by a live keep-alive: the loader answered tester-present after the glitch, which it only does if the fault corrupted the gate. From there, flash reads out.
- Trigger: ESR0 ↑ — reset-out high, CUP starts
- Oracle: CAN reply, asked after the pulse
- Glitches: 1 (OEM) or 2 (in-field)
- Outcome: OPEN — flash R / W
One door of ten¶
The header-then-watchdog path in this write-up is the one I documented end to end — but it is not the only way into this controller, and not even close. A modern automotive MCU makes dozens of trust decisions between power-on and a running, locked application, and fault injection doesn't care which one you attack. On this class of part there are easily ten or more distinct glitch routes, each landing on a different check:
- the boot header check shown here — jump-to-app vs. serial download;
- the life-cycle / in-field status gate — the watchdog reset;
- debug / JTAG re-enable — fault the fuse check and the port comes back;
- flash read-out protection — glitch the compare that says "you're not allowed to read this";
- CAN / UDS SecurityAccess — glitch the seed/key comparison instead of computing the key;
- checksum / signature verification — skip the "is this image authentic" branch;
- the key comparison itself — knock a single byte-compare and a wrong key passes.
They differ in where the pulse lands and what falls out, but underneath they are the same trick. A chip is a machine walking through decisions, and every security decision is, in the end, one branch: allowed, or not. Reach into the silicon at the instant that branch resolves — the right time, at the right place on the die — and you push it the way you want. The check still runs. It just comes out wrong, and the chip does what a passing check would have done: hands over the flash, opens the debug port, accepts the session, unlocks the loader.
That's the real takeaway. The specific offsets in this post open one gate. The method — precise timing, a repeatable fault, tight control of power and comms state, and a probe over the right spot — opens whichever gate you point it at. Find the instant a decision is made, be there with a pulse, and the controller gives you what that decision was protecting.
A repeatable break, not a lucky one¶
Plenty of glitches work once and never again. This one is worth writing down because it is reproducible: the same offsets, the same charge, the same probe spot, open the same class of part over and over. That reliability doesn't come from any single tool — it comes from the four jobs being done properly at once. Precise timing (Husky), a fault source strong and consistent enough to matter (ChipShouter, where the cheaper coils give up), tight control of power and CAN state (the ESP32 board), and repeatable positioning (the CNC).
Take any one of those away and you are back to guessing. Put them together and a locked automotive controller opens its own front door — first the header check, then the watchdog — and hands you the bootloader. That is why this sits near the top of the list of glitches that actually work in the field.
And yes — it works.
Authorized security research on hardware I own — ECU tuning and bootloader-key recovery. Target: a locked ECU built on the ST SPC58 (SPC58N) Power Architecture MCU. Tools: ChipWhisperer-Husky · ChipShouter CW520 · Electronic Cats Faulty Cat · custom ESP32 power/CAN board · CNC 1310. Parameters, addresses and log lines are from this specific part and are shared to document the technique, not as a recipe against anyone else's vehicle.
#spc58#st#emfi#fault-injection#chipshouter#chipwhisperer#bootloader#baf#reverse-engineering#security#can