mirror of
https://github.com/Scandal-UK/Incognito_RCM.git
synced 2024-11-22 20:06:42 +00:00
working
This commit is contained in:
parent
5f42d12184
commit
7b8946f6e0
9 changed files with 325 additions and 299 deletions
4
Makefile
4
Makefile
|
@ -10,12 +10,12 @@ include $(DEVKITARM)/base_rules
|
||||||
|
|
||||||
IPL_LOAD_ADDR := 0x40003000
|
IPL_LOAD_ADDR := 0x40003000
|
||||||
LPVERSION_MAJOR := 1
|
LPVERSION_MAJOR := 1
|
||||||
LPVERSION_MINOR := 5
|
LPVERSION_MINOR := 0
|
||||||
LPVERSION_BUGFX := 0
|
LPVERSION_BUGFX := 0
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
TARGET := Lockpick_RCM
|
TARGET := Incognito_RCM
|
||||||
BUILDDIR := build
|
BUILDDIR := build
|
||||||
OUTPUTDIR := output
|
OUTPUTDIR := output
|
||||||
SOURCEDIR = source
|
SOURCEDIR = source
|
||||||
|
|
30
README.md
30
README.md
|
@ -1,23 +1,33 @@
|
||||||
Lockpick_RCM
|
Incognito_RCM
|
||||||
=
|
=
|
||||||
Lockpick_RCM is a bare metal Nintendo Switch payload that derives encryption keys for use in Switch file handling software like hactool, hactoolnet/LibHac, ChoiDujour, etc. without booting Horizon OS.
|
Incognito_RCM is a bare metal Nintendo Switch payload that derives encryption keys for de- and encrypting PRODINFO partition (sysnand and emummc) and wiping personal information from your Nintendo Switch as to go online while worrying slightly less about a ban.
|
||||||
|
|
||||||
|
It is heavily based on [Lockpick_RCM](https://github.com/shchmue/Lockpick_RCM) and takes inspiration from [incognito](https://github.com/blawar/incognito).
|
||||||
|
|
||||||
Due to changes imposed by firmware 7.0.0, Lockpick homebrew can no longer derive the latest keys. In the boot-time environment however, there is no such limitation.
|
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
=
|
=
|
||||||
* Launch Lockpick_RCM.bin using your favorite payload injector
|
* Launch Incoginito_RCM.bin using your favorite payload injector
|
||||||
* Upon completion, keys will be saved to `/switch/prod.keys` on SD
|
* Use menu to make a backup! (Will be written to `sd:/prodinfo_sysnand.bin` and `sd:/prodinfo_emunand.bin` respectively)
|
||||||
* If the console has Firmware 7.x or higher, the `/sept/` folder from [Atmosphère](https://github.com/Atmosphere-NX/Atmosphere/releases) or [Kosmos](https://github.com/AtlasNX/Kosmos/releases) release zip must be present on SD or else only keyblob master key derivation is possible (ie. up to `master_key_05` only)
|
* Choose either Incognito (sysNAND) or Incognito (emuMMC) to wipe personal information
|
||||||
|
* If you ever want to revert, choose restore menu points
|
||||||
|
|
||||||
|
Keep in mind that backups will be overwritten, so don't backup after applying Incognito!
|
||||||
|
|
||||||
Building
|
Building
|
||||||
=
|
=
|
||||||
Install [devkitARM](https://devkitpro.org/) and run `make`.
|
Install [devkitARM](https://devkitpro.org/) and run `make`.
|
||||||
|
|
||||||
Massive Thanks to CTCaer!
|
Massive Thanks to CTCaer, shchmue and blawar!
|
||||||
=
|
|
||||||
This software is heavily based on [Hekate](https://github.com/CTCaer/hekate). Beyond that, CTCaer was exceptionally helpful in the development of this project, lending loads of advice, expertise, and humor.
|
|
||||||
|
|
||||||
Known Issues
|
Known Issues
|
||||||
=
|
=
|
||||||
* Chainloading from SX will hang immediately due to quirks in their hwinit code, please launch payload directly
|
* Chainloading from SX will hang immediately due to quirks in their hwinit code, please launch payload directly
|
||||||
|
|
||||||
|
Disclaimers
|
||||||
|
=
|
||||||
|
* This application does not remove all personal information from your Switch, and should not be treated as a true preventative measure against getting banned.
|
||||||
|
|
||||||
|
* ALWAYS have a NAND backup. I am not responsible for any bricks or bans. Use at your own risk, as this is an experimental program.
|
||||||
|
|
||||||
|
* This application backs up your PRODINFO to the SD card. You should keep this backup in a more secure location, and not leave it on the SD card where it could be subject to corruption or be read by malicious applications.
|
|
@ -400,14 +400,15 @@ void gfx_printf(const char *fmt, ...)
|
||||||
void gfx_print_header()
|
void gfx_print_header()
|
||||||
{
|
{
|
||||||
u8 prevFontSize = gfx_con.fntsz;
|
u8 prevFontSize = gfx_con.fntsz;
|
||||||
gfx_con.fntsz = 14;
|
gfx_con.fntsz = 15;
|
||||||
gfx_printf("%k ____ _ __ ____ ________ ___\n", colors[4]);
|
gfx_printf("%k ____ _ __ ____ ________ ___\n", colors[4]);
|
||||||
gfx_printf("%k / _/___ _________ ____ _____ (_) /_____ / __ \\/ ____/ |/ /\n", COLOR_GREEN);
|
gfx_printf("%k / _/___ _________ ____ _____ (_) /_____ / __ \\/ ____/ |/ /\n", COLOR_GREEN);
|
||||||
gfx_printf("%k / // __ \\/ ___/ __ \\/ __ `/ __ \\/ / __/ __ \\ / /_/ / / / /|_/ / \n", COLOR_GREEN);
|
gfx_printf("%k / // __ \\/ ___/ __ \\/ __ `/ __ \\/ / __/ __ \\ / /_/ / / / /|_/ / \n", COLOR_GREEN);
|
||||||
gfx_printf("%k _/ // / / / /__/ /_/ / /_/ / / / / / /_/ /_/ / / _, _/ /___/ / / / \n", COLOR_GREEN);
|
gfx_printf("%k _/ // / / / /__/ /_/ / /_/ / / / / / /_/ /_/ / / _, _/ /___/ / / / \n", COLOR_GREEN);
|
||||||
gfx_printf("%k/___/_/ /_/\\___/\\____/\\__, /_/ /_/_/\\__/\\____/____/_/ |_|\\____/_/ /_/ \n", colors[4]);
|
gfx_printf("%k/___/_/ /_/\\___/\\____/\\__, /_/ /_/_/\\__/\\____/____/_/ |_|\\____/_/ /_/ \n", colors[4]);
|
||||||
gfx_printf("%k /____/ /_____/ \n", colors[4]);
|
gfx_printf("%k /____/ /_____/ \n", colors[4]);
|
||||||
gfx_printf("%kv%d.%d.%d%k\n\n\n\n",
|
gfx_con.fntsz = 14;
|
||||||
|
gfx_printf("%kv%d.%d.%d - by jimzrt%k\n\n\n\n",
|
||||||
colors[4], LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC);
|
colors[4], LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC);
|
||||||
gfx_con.fntsz = prevFontSize;
|
gfx_con.fntsz = prevFontSize;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,8 +47,6 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "sha256.h"
|
#include "sha256.h"
|
||||||
|
|
||||||
#include "aes_xts.h"
|
|
||||||
|
|
||||||
extern bool sd_mount();
|
extern bool sd_mount();
|
||||||
extern void sd_unmount();
|
extern void sd_unmount();
|
||||||
extern int sd_save_to_file(void *buf, u32 size, const char *filename);
|
extern int sd_save_to_file(void *buf, u32 size, const char *filename);
|
||||||
|
@ -57,10 +55,14 @@ extern hekate_config h_cfg;
|
||||||
|
|
||||||
u32 _key_count = 0;
|
u32 _key_count = 0;
|
||||||
sdmmc_storage_t storage;
|
sdmmc_storage_t storage;
|
||||||
|
sdmmc_t sdmmc;
|
||||||
emmc_part_t *system_part;
|
emmc_part_t *system_part;
|
||||||
emmc_part_t *prodinfo_part;
|
emmc_part_t *prodinfo_part;
|
||||||
u32 start_time, end_time;
|
u32 start_time, end_time;
|
||||||
|
|
||||||
|
#define ENCRYPTED 1
|
||||||
|
#define DECRYPTED 0
|
||||||
|
|
||||||
#define TPRINTF(text) \
|
#define TPRINTF(text) \
|
||||||
end_time = get_tmr_us(); \
|
end_time = get_tmr_us(); \
|
||||||
gfx_printf(text " done in %d us\n", end_time - start_time); \
|
gfx_printf(text " done in %d us\n", end_time - start_time); \
|
||||||
|
@ -84,6 +86,8 @@ static u8 temp_key[0x10],
|
||||||
master_kek[KB_FIRMWARE_VERSION_MAX + 1][0x10] = {0},
|
master_kek[KB_FIRMWARE_VERSION_MAX + 1][0x10] = {0},
|
||||||
master_key[KB_FIRMWARE_VERSION_MAX + 1][0x10] = {0};
|
master_key[KB_FIRMWARE_VERSION_MAX + 1][0x10] = {0};
|
||||||
|
|
||||||
|
LIST_INIT(gpt);
|
||||||
|
|
||||||
// key functions
|
// key functions
|
||||||
static bool _key_exists(const void *data) { return memcmp(data, zeros, 0x10); };
|
static bool _key_exists(const void *data) { return memcmp(data, zeros, 0x10); };
|
||||||
static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed);
|
static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed);
|
||||||
|
@ -99,16 +103,17 @@ bool dump_keys()
|
||||||
// gfx_printf("[%kLo%kck%kpi%kck%k_R%kCM%k v%d.%d.%d%k]\n\n",
|
// gfx_printf("[%kLo%kck%kpi%kck%k_R%kCM%k v%d.%d.%d%k]\n\n",
|
||||||
// colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC);
|
// colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC);
|
||||||
|
|
||||||
|
gfx_printf("%kGetting bis_keys...\n", COLOR_YELLOW);
|
||||||
|
|
||||||
start_time = get_tmr_us();
|
start_time = get_tmr_us();
|
||||||
//u32 begin_time = get_tmr_us();
|
//u32 begin_time = get_tmr_us();
|
||||||
u32 retries = 0;
|
u32 retries = 0;
|
||||||
u32 color_idx = 0;
|
// u32 color_idx = 0;
|
||||||
|
|
||||||
tsec_ctxt_t tsec_ctxt;
|
tsec_ctxt_t tsec_ctxt;
|
||||||
sdmmc_t sdmmc;
|
|
||||||
|
|
||||||
emummc_storage_init_mmc(&storage, &sdmmc);
|
emummc_storage_init_mmc(&storage, &sdmmc);
|
||||||
TPRINTFARGS("%kMMC init... ", colors[(color_idx++) % 6]);
|
// TPRINTFARGS("%kMMC init... ", colors[(color_idx++) % 6]);
|
||||||
|
|
||||||
// Read package1.
|
// Read package1.
|
||||||
u8 *pkg1 = (u8 *)malloc(0x40000);
|
u8 *pkg1 = (u8 *)malloc(0x40000);
|
||||||
|
@ -183,10 +188,10 @@ bool dump_keys()
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
{
|
{
|
||||||
EPRINTFARGS("ERROR %x dumping TSEC.\n", res);
|
EPRINTFARGS("ERROR %x dumping TSEC.\n", res);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TPRINTFARGS("%kTSEC key(s)... ", colors[(color_idx++) % 6]);
|
//TPRINTFARGS("%kTSEC key(s)... ", colors[(color_idx++) % 6]);
|
||||||
|
|
||||||
// Master key derivation
|
// Master key derivation
|
||||||
if (pkg1_id->kb == KB_FIRMWARE_VERSION_620 && _key_exists(tsec_keys + 0x10))
|
if (pkg1_id->kb == KB_FIRMWARE_VERSION_620 && _key_exists(tsec_keys + 0x10))
|
||||||
|
@ -238,7 +243,7 @@ bool dump_keys()
|
||||||
}
|
}
|
||||||
free(keyblob_block);
|
free(keyblob_block);
|
||||||
|
|
||||||
TPRINTFARGS("%kMaster keys... ", colors[(color_idx++) % 6]);
|
//TPRINTFARGS("%kMaster keys... ", colors[(color_idx++) % 6]);
|
||||||
|
|
||||||
u32 key_generation = 0;
|
u32 key_generation = 0;
|
||||||
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_500)
|
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_500)
|
||||||
|
@ -275,7 +280,7 @@ bool dump_keys()
|
||||||
|
|
||||||
emummc_storage_set_mmc_partition(&storage, 0);
|
emummc_storage_set_mmc_partition(&storage, 0);
|
||||||
// Parse eMMC GPT.
|
// Parse eMMC GPT.
|
||||||
LIST_INIT(gpt);
|
|
||||||
nx_emmc_gpt_parse(&gpt, &storage);
|
nx_emmc_gpt_parse(&gpt, &storage);
|
||||||
|
|
||||||
// Find PRODINFO partition.
|
// Find PRODINFO partition.
|
||||||
|
@ -283,148 +288,82 @@ bool dump_keys()
|
||||||
if (!prodinfo_part)
|
if (!prodinfo_part)
|
||||||
{
|
{
|
||||||
EPRINTF("Failed to locate PRODINFO.");
|
EPRINTF("Failed to locate PRODINFO.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read in package2 header and get package2 real size.
|
|
||||||
|
|
||||||
// u8 *tmp_copy = (u8 *)malloc(NX_EMMC_BLOCKSIZE*2);
|
|
||||||
|
|
||||||
// nx_emmc_part_read(&storage, prodinfo_part, 0, 2, tmp);
|
|
||||||
|
|
||||||
// memcpy(tmp_copy, tmp, NX_EMMC_BLOCKSIZE*2);
|
|
||||||
// gfx_hexdump(0, tmp + 0x250, 0x18);
|
|
||||||
|
|
||||||
// aes_xtsn_decrypt(tmp_copy, NX_EMMC_BLOCKSIZE*2, bis_key[0], bis_key[0] + 0x10, pkg2_part->lba_end, pkg2_part->lba_start, NX_EMMC_BLOCKSIZE);
|
|
||||||
|
|
||||||
// gfx_hexdump(0, tmp_copy + 0x250, 0x18);
|
|
||||||
// memcpy(tmp_copy, tmp, NX_EMMC_BLOCKSIZE*2);
|
|
||||||
|
|
||||||
se_aes_key_set(8, bis_key[0] + 0x00, 0x10);
|
se_aes_key_set(8, bis_key[0] + 0x00, 0x10);
|
||||||
se_aes_key_set(9, bis_key[0] + 0x10, 0x10);
|
se_aes_key_set(9, bis_key[0] + 0x10, 0x10);
|
||||||
|
|
||||||
//u32 length = 0x18;
|
gfx_printf("%kGot keys!\n", COLOR_GREEN);
|
||||||
// u8* buffer = (u8 *)malloc(NX_EMMC_BLOCKSIZE);
|
char serial[15];
|
||||||
// readData(buffer, 0, NX_EMMC_BLOCKSIZE);
|
readData((u8 *)serial, 0x250, 15, ENCRYPTED);
|
||||||
// gfx_hexdump(0, buffer, 0x08);
|
|
||||||
|
|
||||||
// readData(buffer, NX_EMMC_BLOCKSIZE, NX_EMMC_BLOCKSIZE);
|
gfx_printf("%kCurrent serial:%s\n\n", COLOR_BLUE, serial);
|
||||||
// gfx_hexdump(0, buffer, 100);
|
|
||||||
|
|
||||||
// free(buffer);
|
|
||||||
|
|
||||||
//verify();
|
|
||||||
|
|
||||||
// const char junkSerial[] = "XAJ40030771137";
|
|
||||||
// // gfx_hexdump(0, (u8 *)junkSerial, strlen(junkSerial));
|
|
||||||
// writeData((u8 *)junkSerial, 0x250, strlen(junkSerial));
|
|
||||||
|
|
||||||
// writeClientCertHash();
|
|
||||||
// writeCal0Hash();
|
|
||||||
|
|
||||||
// // gfx_hexdump(0, buffer, sizeof(buffer));
|
|
||||||
// //free(buffer);
|
|
||||||
|
|
||||||
// // restore();
|
|
||||||
|
|
||||||
// // verify();
|
|
||||||
|
|
||||||
// // u8 *tmp = (u8 *)malloc(NX_EMMC_BLOCKSIZE);
|
|
||||||
// u8 *tmp_dec = (u8 *)malloc(NX_EMMC_BLOCKSIZE);
|
|
||||||
// // nx_emmc_part_read(&storage, prodinfo_part, 1, 1, tmp);
|
|
||||||
|
|
||||||
// // gfx_hexdump(0, tmp, 0x100);
|
|
||||||
// // aes_xts_ctxt_t context;
|
|
||||||
// // aes_xts_init(&context, AES_DECRYPT, bis_key[0], bis_key[0] + 0x10, 128);
|
|
||||||
// // // aes_xts_crypt(&context, 0, NX_EMMC_BLOCKSIZE, tmp, tmp_dec);
|
|
||||||
|
|
||||||
// // // gfx_hexdump(0, tmp_dec, 0x100);
|
|
||||||
|
|
||||||
// // aes_xts_crypt(&context, 1, NX_EMMC_BLOCKSIZE, tmp, tmp_dec);
|
|
||||||
|
|
||||||
// // gfx_hexdump(0, tmp_dec, 0x100);
|
|
||||||
|
|
||||||
// disk_read_prod(tmp_dec, 1, 1);
|
|
||||||
// //readData(tmp_dec, NX_EMMC_BLOCKSIZE, NX_EMMC_BLOCKSIZE);
|
|
||||||
|
|
||||||
// gfx_hexdump(0, tmp_dec, 0x100);
|
|
||||||
|
|
||||||
// // disk_write_prod(tmp_dec, 1, 1);
|
|
||||||
// // gfx_hexdump(0, tmp_dec, 0x100);
|
|
||||||
|
|
||||||
// //se_aes_xts_crypt_sec(9, 8, 1, 1, tmp, tmp_dec, NX_EMMC_BLOCKSIZE);
|
|
||||||
|
|
||||||
// //gfx_hexdump(0, tmp, 0x100);
|
|
||||||
|
|
||||||
// // se_aes_xts_crypt_sec(9, 8, 1, 0, tmp, tmp_dec, NX_EMMC_BLOCKSIZE);
|
|
||||||
|
|
||||||
// // se_aes_xts_crypt_sec(9, 8, 0, 0, tmp_dec, tmp, NX_EMMC_BLOCKSIZE);
|
|
||||||
|
|
||||||
// // gfx_hexdump(0, tmp_dec, 0x10);
|
|
||||||
|
|
||||||
// // free(tmp);
|
|
||||||
// free(tmp_dec);
|
|
||||||
|
|
||||||
// // writeClientCertHash();
|
|
||||||
// // writeCal0Hash();
|
|
||||||
|
|
||||||
// verify();
|
|
||||||
|
|
||||||
// // verify();
|
|
||||||
// // free(tmp_copy);
|
|
||||||
|
|
||||||
// // pkg2_done:
|
|
||||||
// // // free(pkg2);
|
|
||||||
// // // free(ki);
|
|
||||||
|
|
||||||
// // TPRINTFARGS("%kFS keys... ", colors[(color_idx++) % 6]);
|
|
||||||
|
|
||||||
// // // DIR dir;
|
|
||||||
// // // FILINFO fno;
|
|
||||||
// // // FIL fp;
|
|
||||||
|
|
||||||
// // // f_closedir(&dir);
|
|
||||||
|
|
||||||
// // // f_close(&fp);
|
|
||||||
|
|
||||||
// // TPRINTFARGS("%kSD Seed... ", colors[(color_idx++) % 6]);
|
|
||||||
|
|
||||||
// dismount:
|
|
||||||
// nx_emmc_gpt_free(&gpt);
|
|
||||||
// emummc_storage_end(&storage);
|
|
||||||
|
|
||||||
// end_time = get_tmr_us();
|
|
||||||
// gfx_printf("\n%kFound %d keys.", colors[(color_idx++) % 6], _key_count);
|
|
||||||
// _key_count = 0;
|
|
||||||
// gfx_printf("\n%kLockpick totally done in %d us", colors[(color_idx++) % 6], end_time - begin_time);
|
|
||||||
// gfx_printf("\n%kFound through master_key_%02x\n", colors[(color_idx++) % 6], MAX_KEY - 1);
|
|
||||||
|
|
||||||
// // f_mkdir("sd:/switch");
|
|
||||||
// // char keyfile_path[30] = "sd:/switch/";
|
|
||||||
// // if (!(fuse_read_odm(4) & 3))
|
|
||||||
// // sprintf(&keyfile_path[11], "prod.keys");
|
|
||||||
// // else
|
|
||||||
// // sprintf(&keyfile_path[11], "dev.keys");
|
|
||||||
// // if (sd_mount() && !sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) {
|
|
||||||
// // gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path);
|
|
||||||
// // } else
|
|
||||||
// // EPRINTF("Failed to save keys to SD.");
|
|
||||||
h_cfg.emummc_force_disable = emummc_load_cfg();
|
|
||||||
|
|
||||||
// out_wait:
|
|
||||||
// // sd_unmount();
|
|
||||||
// gfx_printf("\n%kPress any key to return to the main menu.", colors[(color_idx) % 6], colors[(color_idx + 1) % 6], colors[(color_idx + 2) % 6]);
|
|
||||||
|
|
||||||
// btn_wait();
|
|
||||||
// nx_emmc_gpt_free(&gpt);
|
|
||||||
gfx_printf("\n%kFound keys.\n\n", colors[(color_idx++) % 6]);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void erase(u32 offset, u32 length)
|
||||||
|
{
|
||||||
|
|
||||||
void cleanUp(){
|
u8 *tmp = (u8 *)calloc(length, sizeof(u8));
|
||||||
|
writeData(tmp, offset, length, ENCRYPTED);
|
||||||
emummc_storage_end(&storage);
|
free(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeSerial()
|
||||||
|
{
|
||||||
|
const char *junkSerial;
|
||||||
|
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
|
||||||
|
{
|
||||||
|
junkSerial = "XAW00000000000";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
junkSerial = "XAW00000000001";
|
||||||
|
}
|
||||||
|
|
||||||
|
writeData((u8 *)junkSerial, 0x250, 14, ENCRYPTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
void incognito()
|
||||||
|
{
|
||||||
|
|
||||||
|
gfx_printf("%kWriting junk serial...\n", COLOR_YELLOW);
|
||||||
|
|
||||||
|
writeSerial();
|
||||||
|
gfx_printf("%kErasing client cert...\n", COLOR_YELLOW);
|
||||||
|
erase(0x0AE0, 0x800); // client cert
|
||||||
|
gfx_printf("%kErasing private key...\n", COLOR_YELLOW);
|
||||||
|
erase(0x3AE0, 0x130); // private key
|
||||||
|
gfx_printf("%kErasing deviceId 1/2...\n", COLOR_YELLOW);
|
||||||
|
erase(0x35E1, 0x006); // deviceId
|
||||||
|
gfx_printf("%kErasing deviceId 2/2...\n", COLOR_YELLOW);
|
||||||
|
erase(0x36E1, 0x006); // deviceId
|
||||||
|
gfx_printf("%kErasing device cert 1/2...\n", COLOR_YELLOW);
|
||||||
|
erase(0x02B0, 0x180); // device cert
|
||||||
|
gfx_printf("%kErasing device cert 2/2...\n", COLOR_YELLOW);
|
||||||
|
erase(0x3D70, 0x240); // device cert
|
||||||
|
gfx_printf("%kErasing device key...\n", COLOR_YELLOW);
|
||||||
|
|
||||||
|
erase(0x3FC0, 0x240); // device key
|
||||||
|
|
||||||
|
gfx_printf("%kWriting client cert hash...\n", COLOR_YELLOW);
|
||||||
|
|
||||||
|
writeClientCertHash();
|
||||||
|
gfx_printf("%kWriting CAL0 hash...\n", COLOR_YELLOW);
|
||||||
|
|
||||||
|
writeCal0Hash();
|
||||||
|
|
||||||
|
gfx_printf("\n%kIncognito done!\n\n", COLOR_GREEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanUp()
|
||||||
|
{
|
||||||
|
|
||||||
|
h_cfg.emummc_force_disable = emummc_load_cfg();
|
||||||
|
//nx_emmc_gpt_free(&gpt);
|
||||||
|
// emummc_storage_end(&storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed)
|
static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed)
|
||||||
|
@ -447,7 +386,7 @@ static inline u32 _read_le_u32(const void *buffer, u32 offset)
|
||||||
(*(u8 *)(buffer + offset + 3) << 0x18);
|
(*(u8 *)(buffer + offset + 3) << 0x18);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool readData(u8 *buffer, u32 offset, u32 length)
|
bool readData(u8 *buffer, u32 offset, u32 length, u8 enc)
|
||||||
{
|
{
|
||||||
|
|
||||||
// u8 *tmp = (u8 *)malloc(NX_EMMC_BLOCKSIZE);
|
// u8 *tmp = (u8 *)malloc(NX_EMMC_BLOCKSIZE);
|
||||||
|
@ -492,16 +431,16 @@ bool readData(u8 *buffer, u32 offset, u32 length)
|
||||||
|
|
||||||
u8 *tmp = (u8 *)malloc(sectorCount * NX_EMMC_BLOCKSIZE);
|
u8 *tmp = (u8 *)malloc(sectorCount * NX_EMMC_BLOCKSIZE);
|
||||||
|
|
||||||
disk_read_prod(tmp, sector, sectorCount);
|
disk_read_prod(tmp, sector, sectorCount, enc);
|
||||||
|
|
||||||
memcpy(buffer, tmp + newOffset, length);
|
memcpy(buffer, tmp + newOffset, length);
|
||||||
|
|
||||||
free(tmp);
|
free(tmp);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool writeData(u8 *buffer, u32 offset, u32 length)
|
bool writeData(u8 *buffer, u32 offset, u32 length, u8 enc)
|
||||||
{
|
{
|
||||||
|
|
||||||
// u8 *tmp = (u8 *)malloc(NX_EMMC_BLOCKSIZE);
|
// u8 *tmp = (u8 *)malloc(NX_EMMC_BLOCKSIZE);
|
||||||
|
@ -539,9 +478,6 @@ bool writeData(u8 *buffer, u32 offset, u32 length)
|
||||||
|
|
||||||
// free(tmp);
|
// free(tmp);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
u32 sector = (offset / NX_EMMC_BLOCKSIZE);
|
u32 sector = (offset / NX_EMMC_BLOCKSIZE);
|
||||||
u32 newOffset = (offset % NX_EMMC_BLOCKSIZE);
|
u32 newOffset = (offset % NX_EMMC_BLOCKSIZE);
|
||||||
|
|
||||||
|
@ -549,15 +485,15 @@ bool writeData(u8 *buffer, u32 offset, u32 length)
|
||||||
|
|
||||||
u8 *tmp = (u8 *)malloc(sectorCount * NX_EMMC_BLOCKSIZE);
|
u8 *tmp = (u8 *)malloc(sectorCount * NX_EMMC_BLOCKSIZE);
|
||||||
|
|
||||||
disk_read_prod(tmp, sector, sectorCount);
|
disk_read_prod(tmp, sector, sectorCount, 1);
|
||||||
|
|
||||||
memcpy(tmp + newOffset, buffer, length);
|
memcpy(tmp + newOffset, buffer, length);
|
||||||
|
|
||||||
disk_write_prod(tmp, sector, sectorCount);
|
disk_write_prod(tmp, sector, sectorCount, enc);
|
||||||
|
|
||||||
free(tmp);
|
free(tmp);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool writeHash(u32 hashOffset, u32 offset, u32 sz)
|
bool writeHash(u32 hashOffset, u32 offset, u32 sz)
|
||||||
|
@ -573,7 +509,7 @@ bool writeHash(u32 hashOffset, u32 offset, u32 sz)
|
||||||
if (newOffset > 0 && newOffset + sz >= NX_EMMC_BLOCKSIZE)
|
if (newOffset > 0 && newOffset + sz >= NX_EMMC_BLOCKSIZE)
|
||||||
{
|
{
|
||||||
u32 toRead = NX_EMMC_BLOCKSIZE - newOffset;
|
u32 toRead = NX_EMMC_BLOCKSIZE - newOffset;
|
||||||
readData(buffer, offset, toRead);
|
readData(buffer, offset, toRead, ENCRYPTED);
|
||||||
sha256_update(&ctx, buffer, toRead);
|
sha256_update(&ctx, buffer, toRead);
|
||||||
|
|
||||||
sz -= toRead;
|
sz -= toRead;
|
||||||
|
@ -583,7 +519,7 @@ bool writeHash(u32 hashOffset, u32 offset, u32 sz)
|
||||||
while (sz > NX_EMMC_BLOCKSIZE)
|
while (sz > NX_EMMC_BLOCKSIZE)
|
||||||
{
|
{
|
||||||
|
|
||||||
readData(buffer, offset, NX_EMMC_BLOCKSIZE);
|
readData(buffer, offset, NX_EMMC_BLOCKSIZE, ENCRYPTED);
|
||||||
sha256_update(&ctx, buffer, NX_EMMC_BLOCKSIZE);
|
sha256_update(&ctx, buffer, NX_EMMC_BLOCKSIZE);
|
||||||
|
|
||||||
sz -= NX_EMMC_BLOCKSIZE;
|
sz -= NX_EMMC_BLOCKSIZE;
|
||||||
|
@ -593,13 +529,13 @@ bool writeHash(u32 hashOffset, u32 offset, u32 sz)
|
||||||
if (sz > 0)
|
if (sz > 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
readData(buffer, offset, sz);
|
readData(buffer, offset, sz, ENCRYPTED);
|
||||||
sha256_update(&ctx, buffer, sz);
|
sha256_update(&ctx, buffer, sz);
|
||||||
}
|
}
|
||||||
u8 hash[0x20];
|
u8 hash[0x20];
|
||||||
sha256_final(&ctx, hash);
|
sha256_final(&ctx, hash);
|
||||||
|
|
||||||
writeData(hash, hashOffset, 0x20);
|
writeData(hash, hashOffset, 0x20, ENCRYPTED);
|
||||||
|
|
||||||
free(buffer);
|
free(buffer);
|
||||||
return true;
|
return true;
|
||||||
|
@ -618,7 +554,7 @@ bool verifyHash(u32 hashOffset, u32 offset, u32 sz)
|
||||||
if (newOffset > 0 && sz >= NX_EMMC_BLOCKSIZE)
|
if (newOffset > 0 && sz >= NX_EMMC_BLOCKSIZE)
|
||||||
{
|
{
|
||||||
u32 toRead = NX_EMMC_BLOCKSIZE - newOffset;
|
u32 toRead = NX_EMMC_BLOCKSIZE - newOffset;
|
||||||
readData(buffer, offset, toRead);
|
readData(buffer, offset, toRead, ENCRYPTED);
|
||||||
sha256_update(&ctx, buffer, toRead);
|
sha256_update(&ctx, buffer, toRead);
|
||||||
|
|
||||||
sz -= toRead;
|
sz -= toRead;
|
||||||
|
@ -628,7 +564,7 @@ bool verifyHash(u32 hashOffset, u32 offset, u32 sz)
|
||||||
while (sz > NX_EMMC_BLOCKSIZE)
|
while (sz > NX_EMMC_BLOCKSIZE)
|
||||||
{
|
{
|
||||||
|
|
||||||
readData(buffer, offset, NX_EMMC_BLOCKSIZE);
|
readData(buffer, offset, NX_EMMC_BLOCKSIZE, ENCRYPTED);
|
||||||
sha256_update(&ctx, buffer, NX_EMMC_BLOCKSIZE);
|
sha256_update(&ctx, buffer, NX_EMMC_BLOCKSIZE);
|
||||||
|
|
||||||
sz -= NX_EMMC_BLOCKSIZE;
|
sz -= NX_EMMC_BLOCKSIZE;
|
||||||
|
@ -638,7 +574,7 @@ bool verifyHash(u32 hashOffset, u32 offset, u32 sz)
|
||||||
if (sz > 0)
|
if (sz > 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
readData(buffer, offset, sz);
|
readData(buffer, offset, sz, ENCRYPTED);
|
||||||
sha256_update(&ctx, buffer, sz);
|
sha256_update(&ctx, buffer, sz);
|
||||||
}
|
}
|
||||||
u8 hash1[0x20];
|
u8 hash1[0x20];
|
||||||
|
@ -646,20 +582,19 @@ bool verifyHash(u32 hashOffset, u32 offset, u32 sz)
|
||||||
|
|
||||||
u8 hash2[0x20];
|
u8 hash2[0x20];
|
||||||
|
|
||||||
readData(hash2, hashOffset, 0x20);
|
readData(hash2, hashOffset, 0x20, ENCRYPTED);
|
||||||
|
|
||||||
if (memcmp(hash1, hash2, 0x20))
|
if (memcmp(hash1, hash2, 0x20))
|
||||||
{
|
{
|
||||||
EPRINTF("error: hash verification failed\n");
|
EPRINTF("error: hash verification failed\n");
|
||||||
|
gfx_hexdump(0, hash1, 0x20);
|
||||||
|
gfx_hexdump(0, hash2, 0x20);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx_hexdump(0, hash1, 0x20);
|
|
||||||
gfx_hexdump(0, hash2, 0x20);
|
|
||||||
|
|
||||||
free(buffer);
|
free(buffer);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -667,14 +602,14 @@ bool verifyHash(u32 hashOffset, u32 offset, u32 sz)
|
||||||
u32 certSize()
|
u32 certSize()
|
||||||
{
|
{
|
||||||
u32 buffer;
|
u32 buffer;
|
||||||
readData((u8 *)&buffer, 0x0AD0, sizeof(buffer));
|
readData((u8 *)&buffer, 0x0AD0, sizeof(buffer), ENCRYPTED);
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 calibrationDataSize()
|
u32 calibrationDataSize()
|
||||||
{
|
{
|
||||||
u32 buffer;
|
u32 buffer;
|
||||||
readData((u8 *)&buffer, 0x08, sizeof(buffer));
|
readData((u8 *)&buffer, 0x08, sizeof(buffer), ENCRYPTED);
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -701,23 +636,54 @@ bool verifyClientCertHash()
|
||||||
|
|
||||||
bool verifyProdinfo()
|
bool verifyProdinfo()
|
||||||
{
|
{
|
||||||
return verifyClientCertHash() && verifyCal0Hash();
|
|
||||||
// bool r = verifyHash(0x12E0, 0xAE0, certSize()); // client cert hash
|
|
||||||
// r &= verifyHash(0x20, 0x40, calibrationDataSize()); // calibration hash
|
|
||||||
|
|
||||||
// return r;
|
gfx_printf("%kVerifying client cert hash and CAL0 hash...\n", COLOR_YELLOW);
|
||||||
|
|
||||||
|
if (verifyClientCertHash() && verifyCal0Hash())
|
||||||
|
{
|
||||||
|
char serial[15];
|
||||||
|
readData((u8 *)serial, 0x250, 15, ENCRYPTED);
|
||||||
|
gfx_printf("%kVerification successful!\n%kNew Serial:%s\n", COLOR_GREEN, COLOR_BLUE, serial);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
gfx_printf("%kVerification not successful!\nPlease restore backup!\n", COLOR_RED);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_progress(size_t count, size_t max)
|
||||||
|
{
|
||||||
|
const char prefix[] = "Progress: [";
|
||||||
|
const char suffix[] = "]";
|
||||||
|
const size_t prefix_length = sizeof(prefix) - 1;
|
||||||
|
const size_t suffix_length = sizeof(suffix) - 1;
|
||||||
|
char *buffer = calloc(max + prefix_length + suffix_length + 1, 1); // +1 for \0
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
strcpy(buffer, prefix);
|
||||||
|
for (; i < max; ++i)
|
||||||
|
{
|
||||||
|
buffer[prefix_length + i] = i < count ? '#' : ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(&buffer[prefix_length + i], suffix);
|
||||||
|
gfx_printf("%k%s %d%%\n", COLOR_BLUE, buffer, (100 / max) * count);
|
||||||
|
free(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool backupProdinfo()
|
bool backupProdinfo()
|
||||||
{
|
{
|
||||||
sd_mount();
|
char *name;
|
||||||
char* name;
|
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
|
||||||
if (!emu_cfg.enabled || h_cfg.emummc_force_disable){
|
{
|
||||||
name = "sd:/prodinfo_sysnand.bin";
|
name = "sd:/prodinfo_sysnand.bin";
|
||||||
} else {
|
|
||||||
|
|
||||||
name = "sd:/prodinfo_emunand.bin";
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
name = "sd:/prodinfo_emunand.bin";
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx_printf("%kBacking up %s...\n", COLOR_YELLOW, name);
|
||||||
|
|
||||||
if (f_stat(name, NULL))
|
if (f_stat(name, NULL))
|
||||||
{
|
{
|
||||||
|
@ -725,48 +691,49 @@ bool backupProdinfo()
|
||||||
}
|
}
|
||||||
FIL fp;
|
FIL fp;
|
||||||
f_open(&fp, name, FA_CREATE_ALWAYS | FA_WRITE);
|
f_open(&fp, name, FA_CREATE_ALWAYS | FA_WRITE);
|
||||||
u8 bufferNX[NX_EMMC_BLOCKSIZE];
|
u8 *bufferNX = (u8 *)malloc(NX_EMMC_BLOCKSIZE);
|
||||||
u32 size = 0x3FBC00;
|
u32 size = 0x3FBC00;
|
||||||
|
|
||||||
|
u8 percentDone = 0;
|
||||||
u32 offset = 0;
|
u32 offset = 0;
|
||||||
|
const u8 step = 5;
|
||||||
|
|
||||||
|
u32 iterations = size / NX_EMMC_BLOCKSIZE;
|
||||||
|
u32 printCount = iterations / (100 / step);
|
||||||
|
|
||||||
|
u32 x = gfx_con.x;
|
||||||
|
u32 y = gfx_con.y;
|
||||||
|
|
||||||
while (size > NX_EMMC_BLOCKSIZE)
|
while (size > NX_EMMC_BLOCKSIZE)
|
||||||
{
|
{
|
||||||
readData(bufferNX, offset, NX_EMMC_BLOCKSIZE);
|
readData(bufferNX, offset, NX_EMMC_BLOCKSIZE, ENCRYPTED);
|
||||||
f_write(&fp, bufferNX, NX_EMMC_BLOCKSIZE, NULL);
|
f_write(&fp, bufferNX, NX_EMMC_BLOCKSIZE, NULL);
|
||||||
f_sync(&fp);
|
f_sync(&fp);
|
||||||
|
|
||||||
offset += NX_EMMC_BLOCKSIZE;
|
offset += NX_EMMC_BLOCKSIZE;
|
||||||
size -= NX_EMMC_BLOCKSIZE;
|
size -= NX_EMMC_BLOCKSIZE;
|
||||||
|
if (iterations % printCount == 0)
|
||||||
|
{
|
||||||
|
print_progress(percentDone / step, 100 / step);
|
||||||
|
gfx_con.x = x;
|
||||||
|
gfx_con.y = y;
|
||||||
|
percentDone += step;
|
||||||
|
}
|
||||||
|
iterations--;
|
||||||
}
|
}
|
||||||
if (size > 0)
|
if (size > 0)
|
||||||
{
|
{
|
||||||
readData(bufferNX, offset, size);
|
readData(bufferNX, offset, size, ENCRYPTED);
|
||||||
f_write(&fp, bufferNX, size, NULL);
|
f_write(&fp, bufferNX, size, NULL);
|
||||||
f_sync(&fp);
|
f_sync(&fp);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print_progress(100 / step, 100 / step);
|
||||||
|
|
||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
|
free(bufferNX);
|
||||||
|
gfx_printf("%k\nBackup %s done!\n\n", COLOR_GREEN, name);
|
||||||
|
|
||||||
gfx_printf("%kBackup %s done!\n\n", COLOR_GREEN, name);
|
|
||||||
|
|
||||||
// if (f_stat("sd:/prodinfoENC.bin", NULL))
|
|
||||||
// {
|
|
||||||
// f_unlink("sd:/prodinfoENC.bin");
|
|
||||||
// }
|
|
||||||
|
|
||||||
// f_open(&fp, "sd:/prodinfoENC.bin", FA_CREATE_NEW | FA_WRITE);
|
|
||||||
// size = 0x3FBC00;
|
|
||||||
// offset = 0;
|
|
||||||
// while (size > 0)
|
|
||||||
// {
|
|
||||||
// nx_emmc_part_read(&storage, prodinfo_part, offset, 1, bufferNX);
|
|
||||||
// f_write(&fp, bufferNX, NX_EMMC_BLOCKSIZE, NULL);
|
|
||||||
// offset++;
|
|
||||||
// size -= NX_EMMC_BLOCKSIZE;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// f_close(&fp);
|
|
||||||
|
|
||||||
// gfx_printf("\n%kBackup encrypted done!", colors[4]);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -774,14 +741,18 @@ bool restoreProdinfo()
|
||||||
{
|
{
|
||||||
sd_mount();
|
sd_mount();
|
||||||
|
|
||||||
char* name;
|
char *name;
|
||||||
if (!emu_cfg.enabled || h_cfg.emummc_force_disable){
|
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
|
||||||
|
{
|
||||||
name = "sd:/prodinfo_sysnand.bin";
|
name = "sd:/prodinfo_sysnand.bin";
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
name = "sd:/prodinfo_emunand.bin";
|
{
|
||||||
|
|
||||||
|
name = "sd:/prodinfo_emunand.bin";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gfx_printf("%kRestoring %s...\n", COLOR_YELLOW, name);
|
||||||
|
|
||||||
FIL fp;
|
FIL fp;
|
||||||
if (f_open(&fp, name, FA_READ) != FR_OK)
|
if (f_open(&fp, name, FA_READ) != FR_OK)
|
||||||
|
@ -792,35 +763,41 @@ bool restoreProdinfo()
|
||||||
u8 bufferNX[NX_EMMC_BLOCKSIZE];
|
u8 bufferNX[NX_EMMC_BLOCKSIZE];
|
||||||
|
|
||||||
u32 size = 0x3FBC00;
|
u32 size = 0x3FBC00;
|
||||||
|
|
||||||
|
u8 percentDone = 0;
|
||||||
u32 offset = 0;
|
u32 offset = 0;
|
||||||
while (size > 0)
|
const u8 step = 5;
|
||||||
|
|
||||||
|
u32 iterations = size / NX_EMMC_BLOCKSIZE;
|
||||||
|
u32 printCount = iterations / (100 / step);
|
||||||
|
|
||||||
|
u32 x = gfx_con.x;
|
||||||
|
u32 y = gfx_con.y;
|
||||||
|
|
||||||
|
while (size > NX_EMMC_BLOCKSIZE)
|
||||||
{
|
{
|
||||||
f_read(&fp, bufferNX, NX_EMMC_BLOCKSIZE, NULL);
|
f_read(&fp, bufferNX, NX_EMMC_BLOCKSIZE, NULL);
|
||||||
writeData(bufferNX,offset,NX_EMMC_BLOCKSIZE);
|
writeData(bufferNX, offset, NX_EMMC_BLOCKSIZE, ENCRYPTED);
|
||||||
//nx_emmc_part_write(&storage, prodinfo_part, offset, 1, bufferNX);
|
offset += NX_EMMC_BLOCKSIZE;
|
||||||
offset+= NX_EMMC_BLOCKSIZE;
|
|
||||||
size -= NX_EMMC_BLOCKSIZE;
|
size -= NX_EMMC_BLOCKSIZE;
|
||||||
|
if (iterations % printCount == 0)
|
||||||
|
{
|
||||||
|
print_progress(percentDone / step, 100 / step);
|
||||||
|
gfx_con.x = x;
|
||||||
|
gfx_con.y = y;
|
||||||
|
percentDone += step;
|
||||||
|
}
|
||||||
|
iterations--;
|
||||||
}
|
}
|
||||||
// if(size > 0){
|
if (size > 0)
|
||||||
// f_read(&fp, bufferNX, size, NULL);
|
{
|
||||||
// nx_emmc_part_write(&storage, prodinfo_part, offset, 1, bufferNX);
|
f_read(&fp, bufferNX, size, NULL);
|
||||||
// f_write(&fp, bufferNX, size, NULL);
|
writeData(bufferNX, offset, size, ENCRYPTED);
|
||||||
// }
|
}
|
||||||
|
print_progress(100 / step, 100 / step);
|
||||||
|
|
||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
|
|
||||||
gfx_printf("%kRestore %s done!\n\n", COLOR_GREEN, name);
|
gfx_printf("%kRestore %s done!\n\n", COLOR_GREEN, name);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// bool erase(u32 offset, u32 sz)
|
|
||||||
// {
|
|
||||||
// u8 zero = 0;
|
|
||||||
|
|
||||||
// for (u64 i = 0; i < sz; i++)
|
|
||||||
// {
|
|
||||||
// fsStorageWrite(&m_sh, offset + i, &zero, 1);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
|
|
|
@ -20,9 +20,10 @@
|
||||||
#include "../utils/types.h"
|
#include "../utils/types.h"
|
||||||
|
|
||||||
bool dump_keys();
|
bool dump_keys();
|
||||||
|
void incognito();
|
||||||
void cleanUp();
|
void cleanUp();
|
||||||
bool readData(u8 *buffer, u32 offset, u32 length);
|
bool readData(u8 *buffer, u32 offset, u32 length, u8 enc);
|
||||||
bool writeData(u8 *buffer, u32 offset, u32 length);
|
bool writeData(u8 *buffer, u32 offset, u32 length, u8 enc);
|
||||||
bool writeClientCertHash();
|
bool writeClientCertHash();
|
||||||
bool writeCal0Hash();
|
bool writeCal0Hash();
|
||||||
bool verifyProdinfo();
|
bool verifyProdinfo();
|
||||||
|
|
|
@ -133,10 +133,17 @@ DRESULT disk_read_prod (
|
||||||
|
|
||||||
BYTE *buff, /* Data buffer to store read data */
|
BYTE *buff, /* Data buffer to store read data */
|
||||||
DWORD sector, /* Start sector in LBA */
|
DWORD sector, /* Start sector in LBA */
|
||||||
UINT count /* Number of sectors to read */
|
UINT count, /* Number of sectors to read */
|
||||||
|
BYTE enc
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if(enc == 0 ){
|
||||||
|
if (nx_emmc_part_read(&storage, prodinfo_part, sector, count, buff)) {
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
return RES_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
__attribute__ ((aligned (16))) static u8 tweak[0x10];
|
__attribute__ ((aligned (16))) static u8 tweak[0x10];
|
||||||
__attribute__ ((aligned (16))) static u64 prev_cluster = -1;
|
__attribute__ ((aligned (16))) static u64 prev_cluster = -1;
|
||||||
|
@ -171,10 +178,15 @@ DRESULT disk_write_prod (
|
||||||
|
|
||||||
BYTE *buff, /* Data buffer to store read data */
|
BYTE *buff, /* Data buffer to store read data */
|
||||||
DWORD sector, /* Start sector in LBA */
|
DWORD sector, /* Start sector in LBA */
|
||||||
UINT count /* Number of sectors to read */
|
UINT count, /* Number of sectors to read */
|
||||||
|
BYTE enc
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if(enc == 0){
|
||||||
|
nx_emmc_part_write(&storage, prodinfo_part, sector, count, buff);
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
__attribute__ ((aligned (16))) static u8 tweak[0x10];
|
__attribute__ ((aligned (16))) static u8 tweak[0x10];
|
||||||
__attribute__ ((aligned (16))) static u64 prev_cluster = -1;
|
__attribute__ ((aligned (16))) static u64 prev_cluster = -1;
|
||||||
|
|
|
@ -33,8 +33,8 @@ typedef enum {
|
||||||
DSTATUS disk_initialize (BYTE pdrv);
|
DSTATUS disk_initialize (BYTE pdrv);
|
||||||
DSTATUS disk_status (BYTE pdrv);
|
DSTATUS disk_status (BYTE pdrv);
|
||||||
DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
|
DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
|
||||||
DRESULT disk_read_prod (BYTE *buff, DWORD sector, UINT count);
|
DRESULT disk_read_prod (BYTE *buff, DWORD sector, UINT count, BYTE enc);
|
||||||
DRESULT disk_write_prod (BYTE *buff, DWORD sector, UINT count);
|
DRESULT disk_write_prod (BYTE *buff, DWORD sector, UINT count, BYTE enc);
|
||||||
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
|
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
|
||||||
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
|
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
|
||||||
|
|
||||||
|
|
132
source/main.c
132
source/main.c
|
@ -38,11 +38,11 @@
|
||||||
|
|
||||||
sdmmc_t sd_sdmmc;
|
sdmmc_t sd_sdmmc;
|
||||||
sdmmc_storage_t sd_storage;
|
sdmmc_storage_t sd_storage;
|
||||||
__attribute__ ((aligned (16))) FATFS sd_fs;
|
__attribute__((aligned(16))) FATFS sd_fs;
|
||||||
static bool sd_mounted;
|
static bool sd_mounted;
|
||||||
|
|
||||||
hekate_config h_cfg;
|
hekate_config h_cfg;
|
||||||
boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg;
|
boot_cfg_t __attribute__((section("._boot_cfg"))) b_cfg;
|
||||||
|
|
||||||
bool sd_mount()
|
bool sd_mount()
|
||||||
{
|
{
|
||||||
|
@ -124,12 +124,12 @@ int sd_save_to_file(void *buf, u32 size, const char *filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a safe and unused DRAM region for our payloads.
|
// This is a safe and unused DRAM region for our payloads.
|
||||||
#define RELOC_META_OFF 0x7C
|
#define RELOC_META_OFF 0x7C
|
||||||
#define PATCHED_RELOC_SZ 0x94
|
#define PATCHED_RELOC_SZ 0x94
|
||||||
#define PATCHED_RELOC_STACK 0x40007000
|
#define PATCHED_RELOC_STACK 0x40007000
|
||||||
#define COREBOOT_ADDR (0xD0000000 - 0x100000)
|
#define COREBOOT_ADDR (0xD0000000 - 0x100000)
|
||||||
#define CBFS_DRAM_EN_ADDR 0x4003e000
|
#define CBFS_DRAM_EN_ADDR 0x4003e000
|
||||||
#define CBFS_DRAM_MAGIC 0x4452414D // "DRAM"
|
#define CBFS_DRAM_MAGIC 0x4452414D // "DRAM"
|
||||||
|
|
||||||
void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size)
|
void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size)
|
||||||
{
|
{
|
||||||
|
@ -139,8 +139,8 @@ void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size)
|
||||||
|
|
||||||
relocator->start = payload_dst - ALIGN(PATCHED_RELOC_SZ, 0x10);
|
relocator->start = payload_dst - ALIGN(PATCHED_RELOC_SZ, 0x10);
|
||||||
relocator->stack = PATCHED_RELOC_STACK;
|
relocator->stack = PATCHED_RELOC_STACK;
|
||||||
relocator->end = payload_dst + payload_size;
|
relocator->end = payload_dst + payload_size;
|
||||||
relocator->ep = payload_dst;
|
relocator->ep = payload_dst;
|
||||||
|
|
||||||
if (payload_size == 0x7000)
|
if (payload_size == 0x7000)
|
||||||
{
|
{
|
||||||
|
@ -149,89 +149,114 @@ void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dump_sysnand()
|
void incognito_sysnand()
|
||||||
{
|
{
|
||||||
|
|
||||||
h_cfg.emummc_force_disable = true;
|
h_cfg.emummc_force_disable = true;
|
||||||
b_cfg.extra_cfg &= ~EXTRA_CFG_DUMP_EMUMMC;
|
b_cfg.extra_cfg &= ~EXTRA_CFG_DUMP_EMUMMC;
|
||||||
dump_keys();
|
if (!dump_keys())
|
||||||
|
{
|
||||||
|
cleanUp();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
incognito();
|
||||||
verifyProdinfo();
|
verifyProdinfo();
|
||||||
cleanUp();
|
cleanUp();
|
||||||
// verifyProdinfo();
|
|
||||||
|
|
||||||
gfx_printf("\n%kPress any key to return to the main menu.", COLOR_GREEN);
|
|
||||||
// cleanUp();
|
|
||||||
|
|
||||||
|
gfx_printf("\n%k---------------\n%kPress any key to return to the main menu.", COLOR_YELLOW, COLOR_ORANGE);
|
||||||
btn_wait();
|
btn_wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
void dump_emunand()
|
void incognito_emunand()
|
||||||
{
|
{
|
||||||
if (h_cfg.emummc_force_disable)
|
if (h_cfg.emummc_force_disable)
|
||||||
return;
|
return;
|
||||||
emu_cfg.enabled = 1;
|
emu_cfg.enabled = 1;
|
||||||
b_cfg.extra_cfg |= EXTRA_CFG_DUMP_EMUMMC;
|
b_cfg.extra_cfg |= EXTRA_CFG_DUMP_EMUMMC;
|
||||||
dump_keys();
|
if (!dump_keys())
|
||||||
|
{
|
||||||
|
cleanUp();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
incognito();
|
||||||
verifyProdinfo();
|
verifyProdinfo();
|
||||||
cleanUp();
|
cleanUp();
|
||||||
gfx_printf("\n%kPress any key to return to the main menu.", COLOR_GREEN);
|
gfx_printf("\n%k---------------\n%kPress any key to return to the main menu.", COLOR_YELLOW, COLOR_ORANGE);
|
||||||
btn_wait();
|
btn_wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
void backup_sysnand(){
|
void backup_sysnand()
|
||||||
h_cfg.emummc_force_disable = true;
|
{
|
||||||
|
h_cfg.emummc_force_disable = true;
|
||||||
b_cfg.extra_cfg &= ~EXTRA_CFG_DUMP_EMUMMC;
|
b_cfg.extra_cfg &= ~EXTRA_CFG_DUMP_EMUMMC;
|
||||||
dump_keys();
|
if (!dump_keys())
|
||||||
|
{
|
||||||
|
cleanUp();
|
||||||
|
return;
|
||||||
|
}
|
||||||
backupProdinfo();
|
backupProdinfo();
|
||||||
verifyProdinfo();
|
|
||||||
cleanUp();
|
cleanUp();
|
||||||
gfx_printf("\n%kPress any key to return to the main menu.", COLOR_GREEN);
|
gfx_printf("\n%k---------------\n%kPress any key to return to the main menu.", COLOR_YELLOW, COLOR_ORANGE);
|
||||||
btn_wait();
|
btn_wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
void backup_emunand(){
|
void backup_emunand()
|
||||||
if (h_cfg.emummc_force_disable)
|
{
|
||||||
|
if (h_cfg.emummc_force_disable)
|
||||||
return;
|
return;
|
||||||
emu_cfg.enabled = 1;
|
emu_cfg.enabled = 1;
|
||||||
b_cfg.extra_cfg |= EXTRA_CFG_DUMP_EMUMMC;
|
b_cfg.extra_cfg |= EXTRA_CFG_DUMP_EMUMMC;
|
||||||
dump_keys();
|
if (!dump_keys())
|
||||||
|
{
|
||||||
|
cleanUp();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
backupProdinfo();
|
backupProdinfo();
|
||||||
verifyProdinfo();
|
|
||||||
cleanUp();
|
cleanUp();
|
||||||
gfx_printf("\n%kPress any key to return to the main menu.", COLOR_GREEN);
|
gfx_printf("\n%k---------------\n%kPress any key to return to the main menu.", COLOR_YELLOW, COLOR_ORANGE);
|
||||||
btn_wait();
|
btn_wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
void restore_sysnand(){
|
void restore_sysnand()
|
||||||
h_cfg.emummc_force_disable = true;
|
{
|
||||||
|
h_cfg.emummc_force_disable = true;
|
||||||
b_cfg.extra_cfg &= ~EXTRA_CFG_DUMP_EMUMMC;
|
b_cfg.extra_cfg &= ~EXTRA_CFG_DUMP_EMUMMC;
|
||||||
dump_keys();
|
if (!dump_keys())
|
||||||
|
{
|
||||||
|
cleanUp();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
restoreProdinfo();
|
restoreProdinfo();
|
||||||
verifyProdinfo();
|
verifyProdinfo();
|
||||||
cleanUp();
|
cleanUp();
|
||||||
gfx_printf("\n%kPress any key to return to the main menu.", COLOR_GREEN);
|
gfx_printf("\n%k---------------\n%kPress any key to return to the main menu.", COLOR_YELLOW, COLOR_ORANGE);
|
||||||
btn_wait();
|
btn_wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
void restore_emunand(){
|
void restore_emunand()
|
||||||
if (h_cfg.emummc_force_disable)
|
{
|
||||||
|
if (h_cfg.emummc_force_disable)
|
||||||
return;
|
return;
|
||||||
emu_cfg.enabled = 1;
|
emu_cfg.enabled = 1;
|
||||||
b_cfg.extra_cfg |= EXTRA_CFG_DUMP_EMUMMC;
|
b_cfg.extra_cfg |= EXTRA_CFG_DUMP_EMUMMC;
|
||||||
|
|
||||||
dump_keys();
|
if (!dump_keys())
|
||||||
|
{
|
||||||
|
cleanUp();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
restoreProdinfo();
|
restoreProdinfo();
|
||||||
verifyProdinfo();
|
verifyProdinfo();
|
||||||
cleanUp();
|
cleanUp();
|
||||||
gfx_printf("\n%kPress any key to return to the main menu.", COLOR_GREEN);
|
gfx_printf("\n%k---------------\n%kPress any key to return to the main menu.", COLOR_YELLOW, COLOR_ORANGE);
|
||||||
btn_wait();
|
btn_wait();
|
||||||
}
|
}
|
||||||
ment_t ment_top[] = {
|
ment_t ment_top[] = {
|
||||||
MDEF_HANDLER("Incognito (SysNAND)", dump_sysnand, COLOR_ORANGE),
|
MDEF_HANDLER("Incognito (SysNAND)", incognito_sysnand, COLOR_ORANGE),
|
||||||
MDEF_HANDLER("Incognito (emuMMC)", dump_emunand, COLOR_ORANGE),
|
MDEF_HANDLER("Incognito (emuMMC)", incognito_emunand, COLOR_ORANGE),
|
||||||
MDEF_CAPTION("", COLOR_YELLOW),
|
MDEF_CAPTION("", COLOR_YELLOW),
|
||||||
MDEF_HANDLER("Backup (SysNAND)", backup_sysnand, COLOR_ORANGE),
|
MDEF_HANDLER("Backup (SysNAND)", backup_sysnand, COLOR_ORANGE),
|
||||||
MDEF_HANDLER("Backup (emuMMC)", backup_emunand, COLOR_ORANGE),
|
MDEF_HANDLER("Backup (emuMMC)", backup_emunand, COLOR_ORANGE),
|
||||||
|
@ -239,16 +264,15 @@ ment_t ment_top[] = {
|
||||||
MDEF_HANDLER("Restore (SysNAND)", restore_sysnand, COLOR_ORANGE),
|
MDEF_HANDLER("Restore (SysNAND)", restore_sysnand, COLOR_ORANGE),
|
||||||
MDEF_HANDLER("Restore (emuMMC)", restore_emunand, COLOR_ORANGE),
|
MDEF_HANDLER("Restore (emuMMC)", restore_emunand, COLOR_ORANGE),
|
||||||
MDEF_CAPTION("", COLOR_YELLOW),
|
MDEF_CAPTION("", COLOR_YELLOW),
|
||||||
MDEF_CAPTION("---------------", COLOR_YELLOW),
|
MDEF_CAPTION("---------------", COLOR_YELLOW),
|
||||||
MDEF_HANDLER("Reboot (Normal)", reboot_normal, COLOR_GREEN),
|
MDEF_HANDLER("Reboot (Normal)", reboot_normal, COLOR_GREEN),
|
||||||
MDEF_HANDLER("Reboot (RCM)", reboot_rcm, COLOR_BLUE),
|
MDEF_HANDLER("Reboot (RCM)", reboot_rcm, COLOR_BLUE),
|
||||||
MDEF_HANDLER("Power off", power_off, COLOR_VIOLET),
|
MDEF_HANDLER("Power off", power_off, COLOR_VIOLET),
|
||||||
MDEF_END()
|
MDEF_END()};
|
||||||
};
|
|
||||||
|
|
||||||
menu_t menu_top = { ment_top, NULL, 0, 0 };
|
menu_t menu_top = {ment_top, NULL, 0, 0};
|
||||||
|
|
||||||
#define IPL_STACK_TOP 0x4003F000
|
#define IPL_STACK_TOP 0x4003F000
|
||||||
#define IPL_HEAP_START 0x90020000
|
#define IPL_HEAP_START 0x90020000
|
||||||
|
|
||||||
extern void pivot_stack(u32 stack_top);
|
extern void pivot_stack(u32 stack_top);
|
||||||
|
|
|
@ -47,6 +47,7 @@ bool emummc_load_cfg()
|
||||||
emu_cfg.file_based_part_size = 0;
|
emu_cfg.file_based_part_size = 0;
|
||||||
emu_cfg.active_part = 0;
|
emu_cfg.active_part = 0;
|
||||||
emu_cfg.fs_ver = 0;
|
emu_cfg.fs_ver = 0;
|
||||||
|
free(emu_cfg.emummc_file_based_path);
|
||||||
emu_cfg.emummc_file_based_path = (char *)malloc(0x80);
|
emu_cfg.emummc_file_based_path = (char *)malloc(0x80);
|
||||||
|
|
||||||
LIST_INIT(ini_sections);
|
LIST_INIT(ini_sections);
|
||||||
|
|
Loading…
Reference in a new issue