Skip to content

Instantly share code, notes, and snippets.

@shuffle2
Created November 20, 2016 20:57
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save shuffle2/7a9c2f049be1efc06eb778ce0afb9605 to your computer and use it in GitHub Desktop.
Save shuffle2/7a9c2f049be1efc06eb778ce0afb9605 to your computer and use it in GitHub Desktop.
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <cstdint>
#include <memory>
#include <map>
#include <list>
#include <vector>
#include <set>
#include <algorithm>
#include "crypto.h"
static const u8 nes_classic_xts_key[]{
// :O
};
// Logical
#define BYTES_PER_SECTOR 512
// Physical
#define BYTES_PER_PAGE 0x1000
#define NUM_PLANES 2
#define BYTES_PER_PAGE_PER_PLANE (BYTES_PER_PAGE / NUM_PLANES)
#define PAGES_PER_BLOCK 64
#define BYTES_PER_BLOCK (BYTES_PER_PAGE * PAGES_PER_BLOCK)
/*
starting from 0x5a80000 there are 1686 blocks of 0x40000
*/
struct PageMapping
{
u64 block;
u64 page;
};
std::unique_ptr<u8[]> read_page(u8 *buf, const PageMapping &mapping)
{
size_t per_plane_len = BYTES_PER_PAGE_PER_PLANE;
size_t block_len = BYTES_PER_BLOCK;
auto page = std::make_unique<u8[]>(BYTES_PER_PAGE);
if (mapping.block == 0xffff || mapping.page == 0xffff)
{
memset(&page[0], 0xff, BYTES_PER_PAGE);
return page;
}
auto block = &buf[block_len * mapping.block];
for (int plane = 0; plane < NUM_PLANES; plane++)
{
auto page_src = &block[per_plane_len * (plane * PAGES_PER_BLOCK + mapping.page)];
memcpy(&page[plane * per_plane_len], page_src, per_plane_len);
}
return page;
}
void dump_logical(u8 *buf, u64 len) {
// should be (len - 0x5a80000) / 0x40000 * 64 == 0x1a580, but really 0x1b000, so rounded?
auto page_map = std::vector<PageMapping>(0x1b000, { 0xffff, 0xffff });
for (u64 pos = 0x5a80000, block = 0; pos < len; pos += BYTES_PER_BLOCK, block++)
{
// hack: don't translate, just directly read the sector containing logical map info
auto info = (u32 *)&buf[pos + 0x1f800];
for (u32 page = 0; page < PAGES_PER_BLOCK - 1; page++, info++)
{
auto existing = page_map[*info];
if (existing.block != 0xffff)
{
// TODO choose which to use
puts("logical dupe");
}
page_map[*info] = { block, page };
}
}
FILE *f = fopen("./logical.bin", "wb");
for (const auto &p : page_map)
{
auto page = read_page(&buf[0x5a80000], p);
fwrite(&page[0], BYTES_PER_PAGE, 1, f);
}
fclose(f);
}
void decrypt_file(const char *filename)
{
FILE *f = fopen(filename, "rb");
fseek(f, 0, SEEK_END);
auto f_len = ftell(f);
fseek(f, 0, SEEK_SET);
auto f_buf = std::make_unique<uint8_t[]>(f_len);
fread(&f_buf[0], f_len, 1, f);
fclose(f);
AesXts xts(BYTES_PER_SECTOR, &nes_classic_xts_key[0], &nes_classic_xts_key[0x10]);
xts.Decrypt(0, &f_buf[0], &f_buf[0], f_len);
f = fopen(filename, "wb");
fwrite(&f_buf[0], f_len, 1, f);
fclose(f);
}
int main(int argc, char **argv)
{
const char *fname = "./nand_fel_full.bin";
if (argc > 1 && argv[1])
{
fname = argv[1];
}
FILE *f = fopen(fname, "rb");
fseek(f, 0, SEEK_END);
auto f_len = ftell(f);
fseek(f, 0, SEEK_SET);
auto f_buf = std::make_unique<uint8_t[]>(f_len);
fread(f_buf.get(), f_len, 1, f);
fclose(f);
dump_logical(f_buf.get(), f_len);
//decrypt_file("./rootfs.bin");
return 0;
}
Copy link

ghost commented Dec 6, 2016

Can you post the missing AesXts class for this? Thanks!

@DeadlySystem
Copy link

Same question from my side... Also, this is giving me a segmentation fault after a few dozen "logical dupe"s. What is dump_logical actually doing? Seems like part of the NAND can be bad and there's a table in the beginning that maps the good blocks... Any documentation on this? I have a NAND dump made with the original hakchi but I am unable to decrypt it (tried using cryptsetup the same way the kernel does it... Also got the key from looking at the kernel). An help is appreciated.

@eisnerguy1
Copy link

Has anyone been able to actually compile this?

@DeadlySystem
Copy link

DeadlySystem commented Aug 23, 2017

Give the version from madmonkey1907 a try, you can download it here: https://www.dropbox.com/s/v4pnemkkt0zz1ei/nand.7z?dl=0
Originally obtained from comments on this commit, which also have some other helpful info: https://github.com/madmonkey1907/hakchi/commit/669a8ee56ba6d66a90126756cd84f52ae0a5bc83##commitcomment-20562669
I plan to release an all-in-one tool to decrypt NAND dumps based on this info. I've successfully decrypted my dump that I've obtained with hakchi.

@DeadlySystem
Copy link

DeadlySystem commented Aug 24, 2017

There you go: https://github.com/DeadlySystem/ninspect
EDIT: Now also with a hakchi Dockerfile allowing you to run latest hakchi with NAND dump ability on Windows.

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