Nandflash

The NAND flash is divided up into 0x1000 (4096) blocks of 64 pages; each page is 0x1000 (4096 bytes). More detailed information can be derived from the GPL spectra driver (Intel-13.11.232647-dist/BASE/GPL_LGPL_Dev/nandflash-linux-x86-None-SRC-13.11.10484.229643.br2.tar) available in the Intel SDK.

There's a freestanding piece of Go code which executes some of the basic ioctl's available in the nandflash driver which can be used to dump the full nandflash contents to an sdcard if you just want to get started. Note that reading data via the ioctl call is not the same as opening /dev/spectra as a file and reading its contents.

Intel FTL Lite

There are a couple of documents referencing the organization of the nandflash available from intel:
http://software.intel.com/sites/default/files/article/365160/w-jtag-release-install.pdf
http://software.intel.com/sites/products/documentation/hpc/atom/embedded/2.3/Release_Notes_JTAG.pdf
http://software.intel.com/sites/default/files/article/330802/w-jtag-release-install.pdf

From these we learn that blocks 0-65 are reserved for the "FTL Lite partition", with each block repeated 8 times per "DHG's spec". The data in these blocks are as follows:

Data Block#
Master Boot Header and Boot block table 0
Consumer Electronics Firmware Development Kit (CEFDK) 8
Redboot 40
Platform parameters 48

Note that on a regular boxeebox the Redboot blocks are filled with 0xff's and 0x00's so does not actually contain redboot.

Blocks 0-7

The first block has what looks a header with an unknown magic number (0xDEADB00B), and then at offset 0x20 a BOOT_BLOCKTABLE_INFO structure:

0000000: 0bb0adde 0f0001a9 00000000 00000000  ................  // 0xdeadb00b 0xa901000f
 0000010: 00000000 00000000 00000000 00000000  ................ 
 0000020: 474f4f44 00000008 40013000 70011000  GOOD....@.0.p... // BOOT_BLOCKTABLE_INFO{bt_sig:"GOOD" nSpareSkipByteInZone1:0 nSpareSkipByteInZone0:0 reserve3:0 btEntrySizeInBits:8 btEntryNum:320 btOffsetInBytes:48 md5OffsetInBytes:368 md5SizeInBytes:16}
 0000030: 00000000 00000000 00000000 00000000  ................
 *
 0000170: dac4b931 a719c49a 1c4bb6a8 09a93c0e  ...1.....K....<.  // MD5 hash of the BOOT_BLOCKTABLE_INFO.
 0000180: 00000000 00000000 00000000 00000000  ................

The BOOT_BLOCKTABLE_INFO basically states that each entry is 8 bits, there are 320 entries and the table starts at offset 48. In this example (and on my own box) all entries are 0 which is good as it means none of the boot blocks are marked as bad. After the table at offset 368 (0x170, or 320+48), follows a MD5 hash of the table header and data. If you've dumped this block to dump0.dat you can calculate the md5 hash as "dd if=dump0.dat bs=1 skip=0x20 count=0x0150 | md5". The same data is duplicated across blocks 0-7.

Blocks 8-15

These blocks contains the same duplicated data, with another header followed by an RSA signature, some more random data, some more structured data, and then some x86 code:

0000000: 06000000 a1000000 00000100 01000080 // 0x06 0xa1 0x10000 0x80000001
 0000010: 86800000 14050720 413f0000 40000000 // 0x8086 (architecture?) 0x20070514 (datestamp?) 0x3f41 0x40
 0000020: 40000000 01000000 80050000 80040000 // 0x40 0x01 0x0580 0x0480
 0000030: 00000000 00000000 00000000 00000000
 *
 0000090: 00000000 379505d3 01064677 8d59a9f1 // RSA sig
 00000a0: 56290727 e9f04be4 17d8a59e 887a9c58
 00000b0: 751da381 94135bb1 694be4f3 acf5eab3
 00000c0: e6cffe6c 1f519c7d d92c4260 246e6e06
 00000d0: aa2b3ac0 cd42d812 9eea8c0a 0d7481f8
 00000e0: 370cdd6a 854fca8f 75c1a113 ad48134f 
 00000f0: a6ea3fcb 7d335c88 f32ca9a9 43e861fb  
 0000100: 630e07b1 df5df24f 7fa69cc1 75be17af  
 0000110: 1ec00880 6c4572e8 5d9e8d4a 649d0907
 0000120: 185a64fe f34d3871 13c535c7 6ea13594  
 0000130: 33ea4c6f 86c30b60 9a47d98c e3ce2326 
 0000140: 6dd3c1ad fd2a42e1 a34e48ae 82e1a666 
 0000150: e159a18d 88cdb266 84e32ca9 396add2e
 0000160: ebd0993b f99b6e53 008928b2 ddd1cbe5
 0000170: 5d5f5f6d e81c98f6 e6c5a2f5 a2d28422 
 0000180: b33fca4b e4418fd6 30eaf1af dbd78414
 0000190: b18c9647 01000100 00000000 00000000 // modulus = 0x10001 (65537)
 00001a0: 00000000 00000000 00000000 00000000

Actual code appears to start at 0x60C. Strings towards the end of this code indicate that it verifies "Stage2", making this, presumably, Stage1 of the bootloader.

Blocks 16-23

Some more headers appear in this block group, along with some more executable code with some interesting strings:

seg000:00000140 aVerifyStage3Ke db 'Verify Stage3 Kernel...',0
 seg000:00000158 aFail           db 'fail',0
 seg000:0000015D aPass           db 'Pass',0
 seg000:00000162 aVerifyStage3Ra db 'Verify Stage3 RAM Disk...',0
 seg000:0000017C aFail_0         db 'Fail',0
 seg000:00000184 aVerifyStage3Pa db 'Verify stage 3 pass, try secure boot to Linux from NAND Flash ...'

Blocks 40-47

According to the intel documentation referenced earlier, this is where redboot should exist if it was flashed to the device. On a regular boxee box it's all filled with 0xff's and 0x00's.

Blocks 48-55

The "Platform parameters" are stored here

The output of running this block through the command

hexdump -C

follows:
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00007000  34 08 04 75 c5 4f 30 05  00 00 00 00 00 00 00 00  |4..u.O0.........|
00007010  00 00 00 00 0b 06 00 00  00 00 10 10 86 80 e8 34  |...............4|
00007020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00007040  0c c3 63 00 04 50 02 21  c8 00 00 00 00 00 00 00  |..c..P.!........|
00007050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 06 02  |................|
00007060  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00007070  00 00 00 00 00 00 00 00  00 00 00 00 00 00 c1 e5  |................|
00007080  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00042000

The first 6 bytes at 0x7000 configures the mac address of the linked network interface:

$ ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 34:08:04:75:C5:4F
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

Blocks 56-65

Unknown, all filled with 0xff's and 0x00's

Block 66-73

Contains the duplicated (start of the?) kernel.

Block 162-169

Contains the duplicated (start of the?) nandboot_v30 ramdisk.

Block 226-233

Contains data that is modified by the upgrade_flag tool.

Block 234~241

    # Widevine (block 234~241)
    echo -en "\n\n Verify Widevine Key...."
    START_BLOCK=234
    END_BLOCK=241
    for i in $(seq $START_BLOCK $END_BLOCK)
    do
        /usr/dtsbin/flash saveflash -type NAND -file /tmp/Widevine.bin -offset 0x00000 -startblock $i -length 192 > /tmp/flash.log 2>&1
        grep "FAILED" /tmp/flash.log > /dev/null 2>&1
        if [ $? == 0 ]; then
            if [ $i == $END_BLOCK ]; then
                EchoBox "Read Widevine Key Fail!"
                Wait_Enter_Key
                return
            fi
        else
            break
        fi
    done

    # Verify Widevine Key
    /hdisk1/wvverify /tmp/Widevine.bin > /dev/null 2>&1
    if [ $? != 0 ]; then
        EchoBox "Verify Widevine Key Fail!"
        Wait_Enter_Key
        return
    fi
    echo " OK"

Block 242~249

    # X.509 (block 242~249)
    echo -en "\n\n Verify X.509 Key...."
    START_BLOCK=242
    END_BLOCK=249
    for i in $(seq $START_BLOCK $END_BLOCK)
    do
        /usr/dtsbin/flash saveflash -type NAND -file /tmp/X509.bin -offset 0x00000 -startblock $i -length 880 > /tmp/flash.log 2>&1
        grep "FAILED" /tmp/flash.log > /dev/null 2>&1
        if [ $? == 0 ]; then
            if [ $i == $END_BLOCK ]; then
                EchoBox "Read X.509 Key Fail!"
                Wait_Enter_Key
                return
            fi
        else
            break
        fi
    done

    wget http://$SEVER_IP/DMS4110X509/$mac1/$mac2/$mac3/$mac4/$mac5/$mac6/dlink.dsm380_$mac1$mac2$mac3$mac4$mac5$mac6.crt.enc -P /tmp > /dev/null 2>&1
    if [ $? != 0 ]; then
        EchoBox "Wget dlink.dsm380_$mac1$mac2$mac3$mac4$mac5$mac6.crt.enc Fail!"
        Wait_Enter_Key
        return
    fi

    wget http://$SEVER_IP/DMS4110X509/$mac1/$mac2/$mac3/$mac4/$mac5/$mac6/dlink.dsm380_$mac1$mac2$mac3$mac4$mac5$mac6.crt.enc.md5 -P /tmp > /dev/null 2>&1
    if [ $? != 0 ]; then
        EchoBox "Wget dlink.dsm380_$mac1$mac2$mac3$mac4$mac5$mac6.crt.enc.md5 Fail!"
        Wait_Enter_Key
        return
    fi

    cd /tmp
    md5sum -c dlink.dsm380_$mac1$mac2$mac3$mac4$mac5$mac6.crt.enc.md5 > /dev/null 2>&1
    if [ $? != 0 ]; then
        EchoBox "X.509 Key Checksums did NOT match!"
        Wait_Enter_Key
        return
    fi
    cd /

    # Verify X.509 Key
    /hdisk1/x509verifier /tmp/dlink.dsm380_$mac1$mac2$mac3$mac4$mac5$mac6.crt.enc /tmp/X509.bin > /dev/null 2>&1
    if [ $? != 0 ]; then
        EchoBox "Verify X.509 Key Fail!"
        Wait_Enter_Key
        return
    fi
    echo " OK"

Block 250~273

    # Netflix
    echo -en "\n\n Verify Netflix Key...."
    # ESN (block 250~257)
    START_BLOCK=250
    END_BLOCK=257
    for i in $(seq $START_BLOCK $END_BLOCK)
    do
        /usr/dtsbin/flash saveflash -type NAND -file /tmp/ESN.bin -offset 0x00000 -startblock $i -length 64 > /tmp/flash.log 2>&1
        grep "FAILED" /tmp/flash.log > /dev/null 2>&1
        if [ $? == 0 ]; then
            if [ $i == $END_BLOCK ]; then
                EchoBox "Read Netflix(ESN) Key Fail!"
                Wait_Enter_Key
                return
            fi
        else
            break
        fi
    done
    # Kpe (block 258~265)
    START_BLOCK=258
    END_BLOCK=265
    for i in $(seq $START_BLOCK $END_BLOCK)
    do
        /usr/dtsbin/flash saveflash -type NAND -file /tmp/Kpe.bin -offset 0x00000 -startblock $i -length 48 > /tmp/flash.log 2>&1
        grep "FAILED" /tmp/flash.log > /dev/null 2>&1
        if [ $? == 0 ]; then
            if [ $i == $END_BLOCK ]; then
                EchoBox "Read Netflix(Kpe) Key Fail!"
                Wait_Enter_Key
                return
            fi
        else
            break
        fi
    done
    # Kph (block 266~273)
    START_BLOCK=266
    END_BLOCK=273
    for i in $(seq $START_BLOCK $END_BLOCK)
    do
        /usr/dtsbin/flash saveflash -type NAND -file /tmp/Kph.bin -offset 0x00000 -startblock $i -length 64 > /tmp/flash.log 2>&1
        grep "FAILED" /tmp/flash.log > /dev/null 2>&1
        if [ $? == 0 ]; then
            if [ $i == $END_BLOCK ]; then
                EchoBox "Read Netflix(Kph) Key Fail!"
                Wait_Enter_Key
                return
            fi
        else
            break
        fi
    done

    # wget Netflix key
    # ESN
    wget http://$SEVER_IP/DMS4110Netflix/$mac1/$mac2/$mac3/$mac4/$mac5/$mac6/esn_$mac1$mac2$mac3$mac4$mac5${mac6}_field_1.enc -P /tmp > /dev/null 2>&1
    if [ $? != 0 ]; then
        EchoBox "Wget esn_$mac1$mac2$mac3$mac4$mac5${mac6}_field_1.enc Fail!"
        Wait_Enter_Key
        return
    fi
    # Kpe
    wget http://$SEVER_IP/DMS4110Netflix/$mac1/$mac2/$mac3/$mac4/$mac5/$mac6/esn_$mac1$mac2$mac3$mac4$mac5${mac6}_field_2.enc -P /tmp > /dev/null 2>&1
    if [ $? != 0 ]; then
        EchoBox "Wget esn_$mac1$mac2$mac3$mac4$mac5${mac6}_field_2.enc Fail!"
        Wait_Enter_Key
        return
    fi
    # Kph
    wget http://$SEVER_IP/DMS4110Netflix/$mac1/$mac2/$mac3/$mac4/$mac5/$mac6/esn_$mac1$mac2$mac3$mac4$mac5${mac6}_field_3.enc -P /tmp > /dev/null 2>&1
    if [ $? != 0 ]; then
        EchoBox "Wget esn_$mac1$mac2$mac3$mac4$mac5${mac6}_field_3.enc Fail!"
        Wait_Enter_Key
        return
    fi

    # wget MD5 file
    # ESN
    wget http://$SEVER_IP/DMS4110Netflix/$mac1/$mac2/$mac3/$mac4/$mac5/$mac6/esn_$mac1$mac2$mac3$mac4$mac5${mac6}_field_1.enc.md5 -P /tmp > /dev/null 2>&1
    if [ $? != 0 ]; then
        EchoBox "Wget esn_$mac1$mac2$mac3$mac4$mac5${mac6}_field_1.enc.md5 Fail!"
        Wait_Enter_Key
        return
    fi
    # Kpe
    wget http://$SEVER_IP/DMS4110Netflix/$mac1/$mac2/$mac3/$mac4/$mac5/$mac6/esn_$mac1$mac2$mac3$mac4$mac5${mac6}_field_2.enc.md5 -P /tmp > /dev/null 2>&1
    if [ $? != 0 ]; then
        EchoBox "Wget esn_$mac1$mac2$mac3$mac4$mac5${mac6}_field_2.enc.md5 Fail!"
        Wait_Enter_Key
        return
    fi
    # Kph
    wget http://$SEVER_IP/DMS4110Netflix/$mac1/$mac2/$mac3/$mac4/$mac5/$mac6/esn_$mac1$mac2$mac3$mac4$mac5${mac6}_field_3.enc.md5 -P /tmp > /dev/null 2>&1
    if [ $? != 0 ]; then
        EchoBox "Wget esn_$mac1$mac2$mac3$mac4$mac5${mac6}_field_3.enc.md5 Fail!"
        Wait_Enter_Key
        return
    fi

    # check checksum
    cd /tmp
    # ESN
    md5sum -c esn_$mac1$mac2$mac3$mac4$mac5${mac6}_field_1.enc.md5 > /dev/null 2>&1
    if [ $? != 0 ]; then
        EchoBox "Netflix(ESN) Key Checksums did NOT match!"
        Wait_Enter_Key
        return
    fi
    # Kpe
    md5sum -c esn_$mac1$mac2$mac3$mac4$mac5${mac6}_field_2.enc.md5 > /dev/null 2>&1
    if [ $? != 0 ]; then
        EchoBox "Netflix(Kpe) Key Checksums did NOT match!"
        Wait_Enter_Key
        return
    fi
    # Kph
    md5sum -c esn_$mac1$mac2$mac3$mac4$mac5${mac6}_field_3.enc.md5 > /dev/null 2>&1
    if [ $? != 0 ]; then
        EchoBox "Netflix(Kph) Key Checksums did NOT match!"
        Wait_Enter_Key
        return
    fi
    cd /

    # Verify Netflix Key
    # ESN
    /hdisk1/verifier4netflix_f1 /tmp/esn_$mac1$mac2$mac3$mac4$mac5${mac6}_field_1.enc /tmp/ESN.bin > /dev/null 2>&1
    if [ $? != 0 ]; then
        EchoBox "Verify Netflix(ESN)Key Fail!"
        Wait_Enter_Key
        return
    fi
    # Kpe
    /hdisk1/verifier4netflix_f2 /tmp/esn_$mac1$mac2$mac3$mac4$mac5${mac6}_field_2.enc /tmp/Kpe.bin > /dev/null 2>&1
    if [ $? != 0 ]; then
        EchoBox "Verify Netflix(Kpe) Key Fail!"
        Wait_Enter_Key
        return
    fi
    # Kph
    /hdisk1/verifier4netflix_f3 /tmp/esn_$mac1$mac2$mac3$mac4$mac5${mac6}_field_3.enc /tmp/Kph.bin > /dev/null 2>&1
    if [ $? != 0 ]; then
        EchoBox "Verify Netflix(Kph) Key Fail!"
        Wait_Enter_Key
        return
    fi
    echo " OK"

Block 1723

Contains the start of the recovery_ramdisk (which is not duplicated across multiple blocks it seems).

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License