courses

SPI

Why this matters

SPI is where the firmware lives.

I2C’s two-wire economy costs speed, so bulk storage went to SPI, and that decision is the single most consequential fact in hardware security. The 8-pin part sitting beside the SoC on almost every embedded board is SPI-NOR flash holding the entire firmware image, and it speaks a command set that is close to universal across manufacturers. Read that chip and you have the device’s code, its filesystem, its credentials, and its keys.

Everything in Dumping flash depends on what is on this page.

The four wires

Line Also called Direction
SCK CLK, SCLK Controller → target
MOSI SDI, DI, COPI Controller → target
MISO SDO, DO, CIPO Target → controller
CS SS, CE, NSS Controller → target, active low

Plus one CS per additional device. SCK, MOSI, and MISO are shared; chip select is what picks who is listening.

SPI is full duplex: every clock edge shifts one bit out on MOSI and one bit in on MISO, simultaneously. There is no idle direction. When the controller sends a command and expects a reply, it clocks out dummy bytes to generate the clock the target needs to reply on — which is why you see 9F 00 00 00 going out while -- EF 40 18 comes back.

The consequence that matters for capture

Chip select is out of band. A capture of SCK, MOSI, and MISO alone cannot tell you which device was being addressed, because the addressing information is on a wire you did not capture.

⚠️ Always capture CS. On a multi-device bus a capture without it is nearly worthless: your decoder cannot find transaction boundaries and you cannot attribute any byte to any device. This is the most common mistake in SPI analysis and it costs an entire lab session.

Clock polarity and phase

SPI has no single standard for when data is valid. Two bits define four modes:

Mode CPOL CPHA Clock idles Data sampled on
0 0 0 Low Rising edge
1 0 1 Low Falling edge
2 1 0 High Falling edge
3 1 1 High Rising edge

Mode 0 is overwhelmingly the most common and the right first guess. Mode 3 is second. Modes 1 and 2 are rare enough that if your decode fails in mode 0, try 3 before either of them.

Determining the mode from a capture takes one look: note whether the clock idles high or low between transactions (that is CPOL), then try both phases. The wrong phase produces bytes shifted by one bit, which reads as plausible garbage rather than obvious nonsense — so verify against something you can recognise, like a JEDEC ID.

The SPI-NOR flash command set

This is the payoff. Flash parts from Winbond, Macronix, Micron, GigaDevice, ISSI and others share a command set that is close enough to identical that one set of tools reads all of them.

Command Name What it does
0x9F Read JEDEC ID Returns 3 bytes identifying the part
0x03 Read Data Read from a 24-bit address, unlimited length
0x0B Fast Read As above with a dummy byte, higher clock
0x05 Read Status Register Busy bit, write-enable latch, protection bits
0x06 Write Enable Required before any write or erase
0x02 Page Program Write up to one page (usually 256 bytes)
0x20 Sector Erase Erase 4 KB
0xD8 Block Erase Erase 64 KB
0xC7 Chip Erase Erase everything
0x5A Read SFDP Read the parameter table — see below

For reading firmware you need exactly two: 0x9F to identify the part and 0x03 to read it.

Decoding a JEDEC ID

The three bytes are manufacturer, memory type, and capacity:

CS   ‾‾‾\_______________________________/‾‾‾
MOSI     9F 00 00 00
MISO     -- EF 40 18
Byte Value Meaning
Manufacturer 0xEF Winbond (JEDEC JEP106)
Memory type 0x40 SPI NOR, W25Q series
Capacity 0x18 2^0x18 = 16 MiB = 128 Mbit

So: a Winbond W25Q128, 16 MiB. The capacity byte is a power of two, which makes the arithmetic trivial once you notice it — 0x17 is 8 MiB, 0x18 is 16 MiB, 0x19 is 32 MiB.

Manufacturer codes worth recognising:

Code Manufacturer
0xEF Winbond
0xC2 Macronix
0x20 Micron / ST
0xC8 GigaDevice
0x9D ISSI
0x01 Spansion / Cypress / Infineon
0xBF SST / Microchip

SFDP: the part describing itself

0x5A reads the Serial Flash Discoverable Parameters table, standardised as JEDEC JESD216 (current revision JESD216F, December 2021). It is a structured description of the part’s own geometry, command set, and timing — address width, erase sizes and their opcodes, supported read modes.

This is why modern tools can handle a flash part they have never heard of: they ask it. When flashrom reports a chip it does not have in its database but still reads it correctly, SFDP is why.

For an assessment it is a shortcut: if the JEDEC ID is unfamiliar, read SFDP rather than hunting for a datasheet.

Sniffing a live bus

Capture SCK, MOSI, MISO, and CS, then power-cycle the board. Nearly every bootloader begins by identifying the flash, so the first few milliseconds contain the JEDEC exchange and the start of the firmware read.

What to look for, in order:

  1. 0x9F near the start. Decode the reply, identify the part, and you now know the size of the dump you are about to take.
  2. 0x03 followed by three address bytes. The bootloader reading. The first bytes returned are the start of whatever is at that address — often a recognisable magic number.
  3. 0x05 polling. Status register reads in a tight loop mean the host is waiting for a write or erase to finish. If you see this on a device that should not be writing, that is interesting.

Worked example: reading the boot sequence

t=0.4ms   CS↓  MOSI: 9F 00 00 00   MISO: -- EF 40 18   CS↑
t=0.6ms   CS↓  MOSI: 03 00 00 00   MISO: -- 27 05 19 56 ...   CS↑

The first transaction identifies a W25Q128. The second reads from address 0x000000, and the first four bytes returned are 27 05 19 56 — the U-Boot legacy image magic. So the bootloader is checking for a valid uImage header at the start of flash before deciding whether to boot it.

That single observation tells you the image format, which tells you what binwalk will find, before you have dumped anything.

Bus contention, and why sniffing is not enough

To read the flash yourself you must become the controller — and the SoC already is one.

If both drive SCK or MOSI simultaneously in opposite directions, you have a low-impedance path between the supply rails through two output drivers. The mild outcome is a corrupted transaction. The severe one is a destroyed driver.

Remedies, in order of preference:

Method Risk
Hold the SoC in reset (assert NRST) Some SoCs do not tri-state pins on reset; a watchdog may release reset mid-read
Power the flash from the programmer, board unpowered Back-powering through the SoC’s ESD diodes: partially powers the SoC, which may then drive the bus, and can damage it
Desolder the flash Thermal damage, pad lift, and rework afterwards

If you spend more than an hour fighting contention, desolder. It is faster than being clever, and Dumping flash covers the mechanics.

Other things on the SPI bus

Flash is the prize, but not the only occupant:

A radio on SPI is worth noting: it means you can read plaintext before it is encrypted and after it is decrypted, without touching the crypto at all.

Key takeaways

References


Related course pages: Protocols · Schedule · I2C · UART · Dumping flash · Tools of the Trade

🛠️ Maintenance note: the flash command set is stable and the JEDEC manufacturer codes change only by addition. What moves is flashrom’s supported-chip list and the SFDP revision (JESD216F, December 2021, at time of writing). Re-check the manufacturer code table if a new vendor appears in the course stock — GigaDevice and ISSI parts have become much more common in cost-reduced consumer gear.