Archives

Re-programming the 2Wire NAND flash IC

Californian hacker RyanC suggested another method for unlocking the 2Wires:  re-purposing a SmartMedia or xD-Picture card reader to program the NAND flash memory. [1]

The SmartMedia format uses the standard ONFI command set for reading and programming the NAND flash. The xD-Picture specs are slightly more involved, being a superset of ONFI.

Simple, so far?

2Wire, however, has its own flash translation layer (FTL) to hold the logical-to-physical block mapping.  This mapping data is stored in the out-of-band (OOB) area of the NAND page.  Unfortunately, the average flash card reader cannot program arbitrary data to the OOB area, so can’t be used to reprogram a 2Wire flash.  All is not lost though..

Aside the professional NAND programmers costing $2000 or more, there is one consumer-grade NAND controller IC which offers raw read and write access to all areas of the flash device. The IC, codenamed the Alauda, is something of a mystery. No one is even sure who developed it, but it was probably on behalf of Fuji and/or Olympus.

The Alauda IC has a USB peripheral controller to interface very simply with the PC. This allows easy transfer of control messages and page data to the raw NAND device.  And it doesn’t matter if the NAND chip is embedded in a camera card, or in a TSOP48 surface mount package, as in the case of the 2Wire.

It was perhaps BrendanU who first publicly documented the capabilities of Alauda-based card readers. [2] An open source kernel driver was then developed for the Alauda by legendary Linux hacker Daniel Drake.[3]   Cory1492, a well-known XBox and PSP hacker, ported Daniel’s code, and built it against the userspace USB library, libusb. [4]   Cory’s efforts have made the tool available for most Unix platforms and even for Microsoft Windows.

Alauda NAND flash controller harnessed to TSOP48 cradle
256Mbit NAND from 2Wire board loose beneath
(click to enlarge)

The Alauda NAND controller IC
(click to enlarge)

The plan to exploit this hack and hardware was described earlier.  Briefly:

  • Gently lift the NAND flash IC off the PCB with a hot-air gun;
  • Dump contents with a NAND reader. For reasons above, the Alauda IC is ideal;
  • Rewrite “initd” XML table to re-enable secure shell daemon. See: http://pastebin.com/ss8sqMdu
  • Rewrite “user” XML table with new root password. See: http://pastebin.com/gucCEM3H
  • Update ECC in OOB areas of all modified pages. See: http://hack..error-correcting-code-ecc/
  • Re-program the modified NAND pages;
  • Re-install NAND IC on the 2Wire PCB;
  • Fingers crossed and boot!

Userspace tool for Alauda NAND reader by Cory1492

UPDATE:

This method was just trialled several times. While the NAND reading and writing works fine, the 2Wire board still won’t boot with our modified firmware image. The device just hangs with a solid red LED.

The search for that elusive 2Wire hack continues!

As for the NAND hack in general, it could be very useful in a range of other applications. Whether for unlocking routers, digital TV set-top boxes, or for reflashing PC BIOS chips, etc.

EDIT:

There are some more notes in the comments below. In the dueness of time, it can be properly documented and referenced.  The beauty of this NAND reader is that it costs scarcely $10 to make.

[1] https://plus.google.com/102161594653790479451/posts
[2] http://www.uchobby.com/index.php/2007/05/05/read-embedded-flash-chips/
[3] http://www.reactivated.net/weblog/
[4] http://www.xboxhacker.org/index.php?action=profile;u=15891 DEAD LINK
Mirrored at http://docs.google.com/folder/d/0B6wW18mYskvBOWE2OGQ5NzAtZjc4ZS00MjNkLWE5ODAtMjZkMjYwZTZkMmVj/edit

2Wire’s NAND Flash Error Correcting Code (ECC)

Earlier we developed TriMedia code to dump the contents of the NAND flash device on the 2Wire boards. [1]

The diagram below illustrates the organisation of a NAND flash memory array. In addition to a main data page area (usually 512 bytes), NAND devices also have a small ‘Spare Area’ of extra bytes per flash page. In small NAND arrays, this ‘Spare Area’ typically holds 16 bytes.

NAND Memory Array Organisation

This is what that NAND flash Spare Area looks like in a 2Wire 2701HGV:

$ xxd -g4 2701HGV-C_6.3.9.41_nand_full_oob_dump_2.img | cut -c10-44 | ./parsehex
[...]
0199200: c0cf 3c55 24ff 69a5 00ff ff96 0600 ff99  ..<U$.i.........
0199400: 003f fcc0 24ff cc30 00ff ff96 0600 ff99  .?..$..0........
0199600: c3cc 0c3f 24ff c0c0 00ff ff96 0600 ff99  ...?$...........
0199800: a699 693f 24ff cf3c 00ff ff96 0600 ff99  ..i?$..<........
0199a00: 0030 0cfc 24ff c33c 00ff ff96 0600 ff99  .0..$..<........
[...]

The NAND Spare Area is also known as the redundancy area or the out-of-band (OOB) area of the flash page. Manufacturers use the area to store bad block information, to hold mapping data for the flash translation layer, and to store Error Correction Code (ECC)

The NAND spare area of the 2Wire 2701HGV router was found to include the check bits of ECC.

The ECC scheme used by 2Wire is based on a Hamming Code algorithm.

In a Hamming Code algorithm, the NAND page (aka the data block) is divided into various partitions – halves, quarters, eighths, even and odd rows and columns, and so on. Parity bits are calculated for each partition of the data block. These become the ECC bits.

The Hamming scheme allows an individual bit in error to be identified and corrected. The scheme can also detect (but not correct) a second errored bit in the same data block.

In 2Wire‘s modified Hamming Code algorithm, a data block of 256 bytes is used. This is half the size of a small NAND flash page (512 bytes).   22-bits are used for calculating the various row and column ECC parities for each 256 byte block. However, in 2Wire’s modified scheme, an additional check bit is used for the column parity ECC byte for each of those blocks. This means that for every 256 byte data block, the scheme uses 23 bits to hold all of the ECC parity bits. Three bytes are needed to store those 23 bits, leaving, it seems, one bit of those three bytes unused.

The 2Wire configuration of ECC requires in total six bytes from the out-of-band area for every 512 byte NAND page.

We examined ECC algorithms from NetBSD/Atmel, Numonyx/Micron and from Frans Meulenbroeks of Philips NV. However, no algorithm worked ‘out of the box’. Because of that extra bit for overall column parity, the ECC scheme used by 2Wire is slightly different to anything we could find published.  Instead, the existing ECC algorithms for calculation, detection and correction were slightly tweaked.

It was Meulenbroeks‘ code which we selected for tweaking, because of its simplicity and its elegance.[2]  Meulenbroeks uses this code as his foundation for discussing the speed optimisations of ECC algorithms. However, we chose to use his unoptimised algorithm because it is so easy to follow. And on a quad core AMD64 it’s not that slow either. The code takes a fraction of a second to calculate the ECCs for all the sectors in a 32MByte NAND image.

//  Modified from Linux kernel docs..  asbokid 2012
//  GPL v.3
//  Author: Frans Meulenbroeks
//  Copyright (C) 2008 Koninklijke Philips Electronics NV.

const char parity[256] = {
    0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
    0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
    0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
    0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
    0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
    0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
    0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
    0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0
};

void meul_ecc1_2wire(const unsigned char *buf, unsigned char *code)
{
    int i;
    const unsigned char *bp = buf;
    unsigned char cur, par;
    unsigned char rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7;
    unsigned char rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15;

    par = 0; rp0 = 0; rp1 = 0; rp2 = 0; rp3 = 0;
    rp4 = 0; rp5 = 0; rp6 = 0; rp7 = 0;
    rp8 = 0; rp9 = 0; rp10 = 0; rp11 = 0;
    rp12 = 0; rp13 = 0; rp14 = 0; rp15 = 0;

    for (i = 0; i < 256; i++) {
        cur = *bp++;
        par ^= cur;
        if (i & 0x01) rp1 ^= cur; else rp0 ^= cur;
        if (i & 0x02) rp3 ^= cur; else rp2 ^= cur;
        if (i & 0x04) rp5 ^= cur; else rp4 ^= cur;
        if (i & 0x08) rp7 ^= cur; else rp6 ^= cur;
        if (i & 0x10) rp9 ^= cur; else rp8 ^= cur;
        if (i & 0x20) rp11 ^= cur; else rp10 ^= cur;
        if (i & 0x40) rp13 ^= cur; else rp12 ^= cur;
        if (i & 0x80) rp15 ^= cur; else rp14 ^= cur;
    }
    code[0] =
        (parity[rp7] << 7) |
        (parity[rp6] << 6) |
        (parity[rp5] << 5) |
        (parity[rp4] << 4) |
        (parity[rp3] << 3) |
        (parity[rp2] << 2) |
        (parity[rp1] << 1) |
        (parity[rp0]);
    code[1] =
        (parity[rp15] << 7) |
        (parity[rp14] << 6) |
        (parity[rp13] << 5) |
        (parity[rp12] << 4) |
        (parity[rp11] << 3) |
        (parity[rp10] << 2) |
        (parity[rp9]  << 1) |
        (parity[rp8]);
    code[2] =
        (parity[par & 0xf0] << 7) |
        (parity[par & 0x0f] << 6) |
        (parity[par & 0xcc] << 5) |
        (parity[par & 0x33] << 4) |
        (parity[par & 0xaa] << 3) |
        (parity[par & 0x55] << 2) |
        (parity[par & 0x00] << 1) |
        (parity[par & 0xff]);       // asbokid added for 2wire

/*  code[0] = ~code[0];
    code[1] = ~code[1];             // asbokid removed for 2wire
    code[2] = ~code[2];  */
}

In tests the algorithm works fine on the 2Wire NAND contents. It correctly calculates the ECC for each data block and checks it against the stored ECC code in the out-of-band area of the NAND:

$ gcc -o nanddumpparse nanddumpparse.c 2wire_ecc.c

$ ./nanddumpparse
Usage: ./nanddumpparse nandimage.bin  nandimage.oob

$ ./nanddumpparse 2701HGV-C_6.3.9.41_nand_full_dump_2.img 2701HGV-C_6.3.9.41_nand_full_oob_dump_2.img

Read 33554432 bytes of NAND data from 2701HGV-C_6.3.9.41_nand_full_dump_2.img
Read 1048576 bytes of NAND OOB from 2701HGV-C_6.3.9.41_nand_full_oob_dump_2.img

[...]
Offset 0030000 - [bytes 000-255] : ECC1(stored) = c3:30:0c; ECC1(calc) = c3:30:0c;    ECC okay
Offset 0030100 - [bytes 256-511] : ECC2(stored) = 95:56:65; ECC2(calc) = 95:56:65;    ECC okay
Offset 0030200 - [bytes 000-255] : ECC1(stored) = fc:fc:f0; ECC1(calc) = fc:fc:f0;    ECC okay
Offset 0030300 - [bytes 256-511] : ECC2(stored) = a6:59:95; ECC2(calc) = a6:59:95;    ECC okay
Offset 0030400 - [bytes 000-255] : ECC1(stored) = 30:f0:3c; ECC1(calc) = 30:f0:3c;    ECC okay
Offset 0030500 - [bytes 256-511] : ECC2(stored) = fc:0f:00; ECC2(calc) = fc:0f:00;    ECC okay
Offset 0030600 - [bytes 000-255] : ECC1(stored) = 96:a9:55; ECC1(calc) = 96:a9:55;    ECC okay
Offset 0030700 - [bytes 256-511] : ECC2(stored) = a5:a6:65; ECC2(calc) = a5:a6:65;    ECC okay
Offset 0030800 - [bytes 000-255] : ECC1(stored) = 66:56:69; ECC1(calc) = 66:56:69;    ECC okay
Offset 0030900 - [bytes 256-511] : ECC2(stored) = f0:0f:fc; ECC2(calc) = f0:0f:fc;    ECC okay
Offset 0030a00 - [bytes 000-255] : ECC1(stored) = 99:56:69; ECC1(calc) = 99:56:69;    ECC okay
Offset 0030b00 - [bytes 256-511] : ECC2(stored) = 5a:56:59; ECC2(calc) = 5a:56:59;    ECC okay
Offset 0030c00 - [bytes 000-255] : ECC1(stored) = 3c:3f:00; ECC1(calc) = 3c:3f:00;    ECC okay
Offset 0030d00 - [bytes 256-511] : ECC2(stored) = 95:56:65; ECC2(calc) = 95:56:65;    ECC okay
Offset 0030e00 - [bytes 000-255] : ECC1(stored) = 65:69:95; ECC1(calc) = 65:69:95;    ECC okay
[...]
Offset 1ffbd00 - [bytes 256-511] : ECC2(stored) = 30:f0:30; ECC2(calc) = 30:f0:30;    ECC okay
Offset 1ffbe00 - [bytes 000-255] : ECC1(stored) = 6a:66:65; ECC1(calc) = 6a:66:65;    ECC okay
Offset 1ffbf00 - [bytes 256-511] : ECC2(stored) = 9a:66:95; ECC2(calc) = 9a:66:95;    ECC okay

ECC Errors: CORRECTABLE 0; UNCORRECTABLE 0
Page Utilisation: USED 30199; FREED 2979, ERASED 32347; TOTAL 65536
$

The ECC code patched for 2Wire flash contents can be downloaded from [3].

The 16-byte Spare Area is also safeguarded against corruption. This is achieved through a simple modulo-256 checksum which is performed on bytes [8:14] of the Spare Area.

Using the Spare Area excerpt below, the mod-256 checksum is (0×00+0xff+0xff+0×96+0×06+0×00+0xff) % 0×100 = 0×99, which is then stored in byte 15 of the Spare Area.

$ xxd -g4 2701HGV-C_6.3.9.41_nand_full_oob_dump_2.img | cut -c10-44 | ./parsehex
[...]
0199200: c0cf 3c55 24ff 69a5 00ff ff96 0600 ff99  ..<U$.i.........
[...]

It was important to discover and document the ECC scheme used by 2Wire. When the flash contents are modified, the ECC check bits must be re-calculated for every modified flash page. We can move on now to examine the other elements in the Out-of-Band flash area.

For those interested, more general information on Hamming Code for ECC in NAND Flash can be found in [4] [5] [6] [7] [8]

[1] http://hackingbtbusinesshub.wordpress.com/2012/01/14/the-flash-header-of-an-ares-based-2wire-2701hgv-c/
[2] http://lxr.linux.no/#linux+v3.2.9/Documentation/mtd/nand_ecc.txt
[3] http://docs.google.com/leaf?id=0B6wW18mYskvBX2JOenVYMVBUWDJYSGlVQ000UTBCQQ
[4] http://www.cypress.com/?docID=19134
[5] http://www.latticesemi.com/dynamic/view_document.cfm?document_id=9622
[6] http://www.elenota.pl/datasheet_download/44776/AN1823
[7] http://www.micron.com/~/media/Documents/Products/Technical%20Note/NAND%20Flash/tn2908_NAND_hamming_ECC_code.ashx
[8] http://www.elnec.com/sw/samsung_ecc_algorithm_for_256b.pdf