Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
/*
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.
else
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;
}
}
ret:
if (in != NULL) fclose(in);
if (out != NULL) fclose(out);
return rc;
}

Hi plutoo, I have a dump made with the original hakchi. I think it's already unscrambled but I'm not sure as I am currently unable to mount it anyway. How to tell?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment