Learnings about SPI NAND

Background

I’m a member of the IoT Hacker Hangout discord group, and as part of looking into the security of an Internet-connected webcam, I removed a WSON8 SPI NAND from the unit, and wanted to dump its contents.

First Learnings

The BusPirate’s WSON8 plank made connecting it up really easy. :two_hearts: I then tried to use the firmware’s built-in CLI to read a few bytes, but the built-in support wasn’t working.

Turns out I have been “lucky” with all my prior SPI NAND … the W25N01GB was the first chip I messed with that didn’t have the same sequence for chip identification:

[0xFF] d:1000 [0x9F r:3]

Aka: Send the reset command, wait a second, then send the JEDEC ID command and read the three-byte response.

On this chip, however, the JEDEC ID isn’t reported immediately … it’s offset by a one-byte delay, shown as “Dummy” on the datasheet:

Digging deeper, I learned lots of unhappy things about the JEDED ID. It’s only “practical” use is to distinguish between a limited set of predetermined devices … not as a general identification technique. For example, there are subgroups for manufacturer ID … and the IDs themselves are not actually unique in the field.

So, I learned the “basic” identification flow is nowhere near sufficient for a general identification. I have some thoughts on improving this (including subgroups), but … I just needed to get the contents…

Second Learnings

Unfortunately, it turned out that a number of other key commands also needed delays, including reads. Thus, this wouldn’t be a simple change if I updated the core BusPirate firmware’s SPI NAND commands.

BPIO2 to the rescue!

But that’s OK! The BusPirate’s BPIO2 support allows prototyping in many languages!

Using the BPIO2 binary interface, I was able to quickly whip up some Python script which dumped the contents.

Interestingly, there was at least one other person on that project who also wanted to use the BusPirate for this, so I was able to shared my (hacked) Python script on that forum.

BusPirate is truly the swiss-army knife …

While I probably could have used some other program, the convenience of dropping the WSON8 chip into a well-made plank, and the simplicity of using the BPIO2 interface from host-side scripts, really showed off the power of the BusPirate!

2 Likes

Yeah this is the alpha and omega of the 9F command.

Yeah!

I’m glad it had a happy ending.

The weird bit is that the 9F “standard” is for NOR flash, winbonds major product. With this NAND chip it seems like they did a kind of loosely related interface so it would be familiar to existing NOR users getting into NAND.

How did the dump turn out? NAND is super messy (cheap = easy bad bits) and unreliable so generally there is a wear leveling system the same way we use dharma in the bus pirate. That makes decoding the contents extra challenging. You first have to decipher the wear leveling and then rebuild the contents and determine the file store method (eg fat).

1 Like
I have a structured way to handle it...

Don’t recall if I implemented it in the python script, but the general flow:

  1. Reset, wait, 0x9F, read bytes until top bit is not set, then read two more bytes.
    • Max bytes to read is N+2, where N is at least large enough to support all expected “pages” of manufacturer ID
    • Primarily to avoid infinite loops
    • Secondarily allows static sized buffer allocation in firmware
  2. Find “real” start of page increment / manufacturer ID by checking the checksum
    • 0xFF is not valid, for example, allowing detection of “dummy” bytes where device is not (yet) reporting data.
    • Can integrate into the read loop, between the start / stop, to discard dummy bytes and thus not even have a need to allocate for them.
  3. Count how many page increment values at the start of the data.
    • As above, can integrate into the read loop, between the start / stop, to discard these page increment values as they are read, and thus not need to allocate variable space for them.
  4. Rather than only three classes of information (manufacturer ID, product ID, product info / capacity), also report the Manufacturer Page value (… even though it’s typically zero …).

The dump turned out perfect. We each extracted the UBOOT binary (including its parameters blocks), extracted the various file system volume data, and then I could validate the file hashes matched other folks’ “pristine” dumps. This ensured we’re considering the same binaries (or highlighted what’s different).

Investigations are still ongoing, but … there are definitely flaws, and at least one that I found will likely require CVD. (PoC … when I get a moment to work on it … is in process…)

1 Like