RELEASE: ROM DeScrambler for NES Classic Edition (Mini) NAND Dumps

Discussion in 'Underground Nintendo Scene' started by GaryOPA, Nov 20, 2016.

By GaryOPA on Nov 20, 2016 at 5:24 PM
  1. 23,144

    GaryOPA Master Phoenix Admin Staff Member Top-Dog Brass

    Mar 18, 2006
    Design Eng.
    Tropical Island
    Home Page:
    @qlutoo - Drops a nice hint with code on how to unscramble those 30 ROMs found inside the NES Classic (Mini)

    Work is moving along rapidly in ripping apart the NES Classic Edition (Mini) that Nintendo has been selling faster than they can produce them, now we can infact start unpacking the ROM's they included on the NAND flash for us to explore in more depth!


    Thanks the neat work of plutoo we now can play a bit more with our NES Mini, with a working U-Boot already done, and booting up alt. linux kernel via it, and dumping of the NAND, and now the unpacking of it, the final step is almost here, which will be repacking a new NAND with different set of 30 ROM's or better yet with more ROM's to enjoy, then what big 'N' decided to limit us to playing. :)

    Here is the neat code that plutoo wrote up, look how simple Nintendo thinks, they still have not learned from previous protection attempts:

      Scramble/descramble raw NAND dumps from the NES Classic.
      plutoo 2016
      Cheers to brizzo, derrek.
    #include <stdio.h>
    #include <string.h>
    #include <stdint.h>
    #include <stddef.h>
    static const uint16_t g_seed_table[] =
        0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72,
        0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436,
        0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d,
        0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130,
        0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56,
        0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55,
        0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb,
        0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17,
        0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62,
        0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064,
        0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126,
        0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e,
        0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3,
        0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b,
        0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d,
        0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db
    static const uint16_t g_boot0_seed = 0x4a80;
    #define PAGE_SIZE 0x400
    #define NAND_SIZE (512*1024*1024)
    #define BOOT0_END 0x100000
    static void lfsr_scramble(uint16_t seed, uint8_t page[PAGE_SIZE])
        uint16_t state = seed;
        size_t i;
        for (i=0; i<PAGE_SIZE; i++)
            size_t j;
            for (j=0; j<8; j++)
                state = (state >> 1) | (((state ^ (state >> 1)) & 1) << 14);
            page[i] ^= (uint8_t) (state >> 7);
    int main(int argc, char* argv[])
        int rc = 0;
        FILE* in  = NULL;
        FILE* out = NULL;
        if (argc != 3)
            fprintf(stderr, "Usage: %s <in.bin> <out.bin>\n", argv[0]);
            rc = 1;
            goto ret;
        in  = fopen(argv[1], "rb");
        out = fopen(argv[2], "wb");
        if (in == NULL || out == NULL)
            fprintf(stderr, "Failed to open file.\n");
            rc = 1;
            goto ret;
        size_t i;
        for (i=0; i<NAND_SIZE; i+=PAGE_SIZE)
            uint8_t page[PAGE_SIZE];
            if (fread(page, sizeof page, 1, in) != 1)
                fprintf(stderr, "Failed to read page %zu.. incomplete dump?", i);
                rc = 1;
                goto ret;
            uint16_t seed;
            // boot0 uses a fixed seed on every other page.
            if (i < BOOT0_END)
                seed = ((i % 2) == 0) ? g_boot0_seed : 0;
            // rest uses half of the seed_table, accidentally reusing same seed
            // twice in a row.
                seed = g_seed_table[(i / (2*PAGE_SIZE)) & 0x3F]; // wat
            lfsr_scramble(seed, page);
            if (fwrite(page, sizeof page, 1, out) != 1)
                fprintf(stderr, "Failed to write page %zu..", i);
                rc = 1;
                goto ret;
        if (in  != NULL) fclose(in);
        if (out != NULL) fclose(out);
        return rc;
    Stay Tuned as we bring you more Retro NES Mini hacking fun right here on MaxConsole UnderGround! :)


    NEWS SOURCE: @qlutoo (via) Twitter


Discussion in 'Underground Nintendo Scene' started by GaryOPA, Nov 20, 2016.

Share This Page