mirror of
https://github.com/Scandal-UK/Incognito_RCM.git
synced 2024-12-22 18:32:03 +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
|
||||
LPVERSION_MAJOR := 1
|
||||
LPVERSION_MINOR := 5
|
||||
LPVERSION_MINOR := 0
|
||||
LPVERSION_BUGFX := 0
|
||||
|
||||
################################################################################
|
||||
|
||||
TARGET := Lockpick_RCM
|
||||
TARGET := Incognito_RCM
|
||||
BUILDDIR := build
|
||||
OUTPUTDIR := output
|
||||
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
|
||||
=
|
||||
* Launch Lockpick_RCM.bin using your favorite payload injector
|
||||
* Upon completion, keys will be saved to `/switch/prod.keys` on SD
|
||||
* 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)
|
||||
* Launch Incoginito_RCM.bin using your favorite payload injector
|
||||
* Use menu to make a backup! (Will be written to `sd:/prodinfo_sysnand.bin` and `sd:/prodinfo_emunand.bin` respectively)
|
||||
* 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
|
||||
=
|
||||
Install [devkitARM](https://devkitpro.org/) and run `make`.
|
||||
|
||||
Massive Thanks to CTCaer!
|
||||
=
|
||||
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.
|
||||
Massive Thanks to CTCaer, shchmue and blawar!
|
||||
|
||||
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()
|
||||
{
|
||||
u8 prevFontSize = gfx_con.fntsz;
|
||||
gfx_con.fntsz = 14;
|
||||
gfx_con.fntsz = 15;
|
||||
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", 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);
|
||||
gfx_con.fntsz = prevFontSize;
|
||||
}
|
||||
|
|
|
@ -47,8 +47,6 @@
|
|||
#include <string.h>
|
||||
#include "sha256.h"
|
||||
|
||||
#include "aes_xts.h"
|
||||
|
||||
extern bool sd_mount();
|
||||
extern void sd_unmount();
|
||||
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;
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
emmc_part_t *system_part;
|
||||
emmc_part_t *prodinfo_part;
|
||||
u32 start_time, end_time;
|
||||
|
||||
#define ENCRYPTED 1
|
||||
#define DECRYPTED 0
|
||||
|
||||
#define TPRINTF(text) \
|
||||
end_time = get_tmr_us(); \
|
||||
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_key[KB_FIRMWARE_VERSION_MAX + 1][0x10] = {0};
|
||||
|
||||
LIST_INIT(gpt);
|
||||
|
||||
// key functions
|
||||
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);
|
||||
|
@ -99,16 +103,17 @@ bool dump_keys()
|
|||
// 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);
|
||||
|
||||
gfx_printf("%kGetting bis_keys...\n", COLOR_YELLOW);
|
||||
|
||||
start_time = get_tmr_us();
|
||||
//u32 begin_time = get_tmr_us();
|
||||
u32 retries = 0;
|
||||
u32 color_idx = 0;
|
||||
// u32 color_idx = 0;
|
||||
|
||||
tsec_ctxt_t tsec_ctxt;
|
||||
sdmmc_t sdmmc;
|
||||
|
||||
emummc_storage_init_mmc(&storage, &sdmmc);
|
||||
TPRINTFARGS("%kMMC init... ", colors[(color_idx++) % 6]);
|
||||
// TPRINTFARGS("%kMMC init... ", colors[(color_idx++) % 6]);
|
||||
|
||||
// Read package1.
|
||||
u8 *pkg1 = (u8 *)malloc(0x40000);
|
||||
|
@ -183,10 +188,10 @@ bool dump_keys()
|
|||
if (res < 0)
|
||||
{
|
||||
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
|
||||
if (pkg1_id->kb == KB_FIRMWARE_VERSION_620 && _key_exists(tsec_keys + 0x10))
|
||||
|
@ -238,7 +243,7 @@ bool dump_keys()
|
|||
}
|
||||
free(keyblob_block);
|
||||
|
||||
TPRINTFARGS("%kMaster keys... ", colors[(color_idx++) % 6]);
|
||||
//TPRINTFARGS("%kMaster keys... ", colors[(color_idx++) % 6]);
|
||||
|
||||
u32 key_generation = 0;
|
||||
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_500)
|
||||
|
@ -275,7 +280,7 @@ bool dump_keys()
|
|||
|
||||
emummc_storage_set_mmc_partition(&storage, 0);
|
||||
// Parse eMMC GPT.
|
||||
LIST_INIT(gpt);
|
||||
|
||||
nx_emmc_gpt_parse(&gpt, &storage);
|
||||
|
||||
// Find PRODINFO partition.
|
||||
|
@ -283,148 +288,82 @@ bool dump_keys()
|
|||
if (!prodinfo_part)
|
||||
{
|
||||
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(9, bis_key[0] + 0x10, 0x10);
|
||||
|
||||
//u32 length = 0x18;
|
||||
// u8* buffer = (u8 *)malloc(NX_EMMC_BLOCKSIZE);
|
||||
// readData(buffer, 0, NX_EMMC_BLOCKSIZE);
|
||||
// gfx_hexdump(0, buffer, 0x08);
|
||||
gfx_printf("%kGot keys!\n", COLOR_GREEN);
|
||||
char serial[15];
|
||||
readData((u8 *)serial, 0x250, 15, ENCRYPTED);
|
||||
|
||||
// readData(buffer, NX_EMMC_BLOCKSIZE, NX_EMMC_BLOCKSIZE);
|
||||
// gfx_hexdump(0, buffer, 100);
|
||||
gfx_printf("%kCurrent serial:%s\n\n", COLOR_BLUE, serial);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
void erase(u32 offset, u32 length)
|
||||
{
|
||||
|
||||
void cleanUp(){
|
||||
|
||||
emummc_storage_end(&storage);
|
||||
u8 *tmp = (u8 *)calloc(length, sizeof(u8));
|
||||
writeData(tmp, offset, length, ENCRYPTED);
|
||||
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)
|
||||
|
@ -447,7 +386,7 @@ static inline u32 _read_le_u32(const void *buffer, u32 offset)
|
|||
(*(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);
|
||||
|
@ -492,16 +431,16 @@ bool readData(u8 *buffer, u32 offset, u32 length)
|
|||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
@ -539,9 +478,6 @@ bool writeData(u8 *buffer, u32 offset, u32 length)
|
|||
|
||||
// free(tmp);
|
||||
|
||||
|
||||
|
||||
|
||||
u32 sector = (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);
|
||||
|
||||
disk_read_prod(tmp, sector, sectorCount);
|
||||
disk_read_prod(tmp, sector, sectorCount, 1);
|
||||
|
||||
memcpy(tmp + newOffset, buffer, length);
|
||||
|
||||
disk_write_prod(tmp, sector, sectorCount);
|
||||
disk_write_prod(tmp, sector, sectorCount, enc);
|
||||
|
||||
free(tmp);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
u32 toRead = NX_EMMC_BLOCKSIZE - newOffset;
|
||||
readData(buffer, offset, toRead);
|
||||
readData(buffer, offset, toRead, ENCRYPTED);
|
||||
sha256_update(&ctx, buffer, toRead);
|
||||
|
||||
sz -= toRead;
|
||||
|
@ -583,7 +519,7 @@ bool writeHash(u32 hashOffset, u32 offset, u32 sz)
|
|||
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);
|
||||
|
||||
sz -= NX_EMMC_BLOCKSIZE;
|
||||
|
@ -593,13 +529,13 @@ bool writeHash(u32 hashOffset, u32 offset, u32 sz)
|
|||
if (sz > 0)
|
||||
{
|
||||
|
||||
readData(buffer, offset, sz);
|
||||
readData(buffer, offset, sz, ENCRYPTED);
|
||||
sha256_update(&ctx, buffer, sz);
|
||||
}
|
||||
u8 hash[0x20];
|
||||
sha256_final(&ctx, hash);
|
||||
|
||||
writeData(hash, hashOffset, 0x20);
|
||||
writeData(hash, hashOffset, 0x20, ENCRYPTED);
|
||||
|
||||
free(buffer);
|
||||
return true;
|
||||
|
@ -618,7 +554,7 @@ bool verifyHash(u32 hashOffset, u32 offset, u32 sz)
|
|||
if (newOffset > 0 && sz >= NX_EMMC_BLOCKSIZE)
|
||||
{
|
||||
u32 toRead = NX_EMMC_BLOCKSIZE - newOffset;
|
||||
readData(buffer, offset, toRead);
|
||||
readData(buffer, offset, toRead, ENCRYPTED);
|
||||
sha256_update(&ctx, buffer, toRead);
|
||||
|
||||
sz -= toRead;
|
||||
|
@ -628,7 +564,7 @@ bool verifyHash(u32 hashOffset, u32 offset, u32 sz)
|
|||
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);
|
||||
|
||||
sz -= NX_EMMC_BLOCKSIZE;
|
||||
|
@ -638,7 +574,7 @@ bool verifyHash(u32 hashOffset, u32 offset, u32 sz)
|
|||
if (sz > 0)
|
||||
{
|
||||
|
||||
readData(buffer, offset, sz);
|
||||
readData(buffer, offset, sz, ENCRYPTED);
|
||||
sha256_update(&ctx, buffer, sz);
|
||||
}
|
||||
u8 hash1[0x20];
|
||||
|
@ -646,20 +582,19 @@ bool verifyHash(u32 hashOffset, u32 offset, u32 sz)
|
|||
|
||||
u8 hash2[0x20];
|
||||
|
||||
readData(hash2, hashOffset, 0x20);
|
||||
readData(hash2, hashOffset, 0x20, ENCRYPTED);
|
||||
|
||||
if (memcmp(hash1, hash2, 0x20))
|
||||
{
|
||||
EPRINTF("error: hash verification failed\n");
|
||||
gfx_hexdump(0, hash1, 0x20);
|
||||
gfx_hexdump(0, hash2, 0x20);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
|
||||
gfx_hexdump(0, hash1, 0x20);
|
||||
gfx_hexdump(0, hash2, 0x20);
|
||||
|
||||
free(buffer);
|
||||
return result;
|
||||
}
|
||||
|
@ -667,14 +602,14 @@ bool verifyHash(u32 hashOffset, u32 offset, u32 sz)
|
|||
u32 certSize()
|
||||
{
|
||||
u32 buffer;
|
||||
readData((u8 *)&buffer, 0x0AD0, sizeof(buffer));
|
||||
readData((u8 *)&buffer, 0x0AD0, sizeof(buffer), ENCRYPTED);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
u32 calibrationDataSize()
|
||||
{
|
||||
u32 buffer;
|
||||
readData((u8 *)&buffer, 0x08, sizeof(buffer));
|
||||
readData((u8 *)&buffer, 0x08, sizeof(buffer), ENCRYPTED);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
@ -701,23 +636,54 @@ bool verifyClientCertHash()
|
|||
|
||||
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()
|
||||
{
|
||||
sd_mount();
|
||||
char* name;
|
||||
if (!emu_cfg.enabled || h_cfg.emummc_force_disable){
|
||||
char *name;
|
||||
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
|
||||
{
|
||||
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))
|
||||
{
|
||||
|
@ -725,48 +691,49 @@ bool backupProdinfo()
|
|||
}
|
||||
FIL fp;
|
||||
f_open(&fp, name, FA_CREATE_ALWAYS | FA_WRITE);
|
||||
u8 bufferNX[NX_EMMC_BLOCKSIZE];
|
||||
u8 *bufferNX = (u8 *)malloc(NX_EMMC_BLOCKSIZE);
|
||||
u32 size = 0x3FBC00;
|
||||
|
||||
u8 percentDone = 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)
|
||||
{
|
||||
readData(bufferNX, offset, NX_EMMC_BLOCKSIZE);
|
||||
readData(bufferNX, offset, NX_EMMC_BLOCKSIZE, ENCRYPTED);
|
||||
f_write(&fp, bufferNX, NX_EMMC_BLOCKSIZE, NULL);
|
||||
f_sync(&fp);
|
||||
|
||||
offset += 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)
|
||||
{
|
||||
readData(bufferNX, offset, size);
|
||||
readData(bufferNX, offset, size, ENCRYPTED);
|
||||
f_write(&fp, bufferNX, size, NULL);
|
||||
f_sync(&fp);
|
||||
|
||||
}
|
||||
|
||||
print_progress(100 / step, 100 / step);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -774,14 +741,18 @@ bool restoreProdinfo()
|
|||
{
|
||||
sd_mount();
|
||||
|
||||
char* name;
|
||||
if (!emu_cfg.enabled || h_cfg.emummc_force_disable){
|
||||
char *name;
|
||||
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
|
||||
{
|
||||
name = "sd:/prodinfo_sysnand.bin";
|
||||
} else {
|
||||
|
||||
name = "sd:/prodinfo_emunand.bin";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
name = "sd:/prodinfo_emunand.bin";
|
||||
}
|
||||
|
||||
gfx_printf("%kRestoring %s...\n", COLOR_YELLOW, name);
|
||||
|
||||
FIL fp;
|
||||
if (f_open(&fp, name, FA_READ) != FR_OK)
|
||||
|
@ -792,35 +763,41 @@ bool restoreProdinfo()
|
|||
u8 bufferNX[NX_EMMC_BLOCKSIZE];
|
||||
|
||||
u32 size = 0x3FBC00;
|
||||
|
||||
u8 percentDone = 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);
|
||||
writeData(bufferNX,offset,NX_EMMC_BLOCKSIZE);
|
||||
//nx_emmc_part_write(&storage, prodinfo_part, offset, 1, bufferNX);
|
||||
offset+= NX_EMMC_BLOCKSIZE;
|
||||
writeData(bufferNX, offset, NX_EMMC_BLOCKSIZE, ENCRYPTED);
|
||||
offset += 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){
|
||||
// f_read(&fp, bufferNX, size, NULL);
|
||||
// nx_emmc_part_write(&storage, prodinfo_part, offset, 1, bufferNX);
|
||||
// f_write(&fp, bufferNX, size, NULL);
|
||||
// }
|
||||
if (size > 0)
|
||||
{
|
||||
f_read(&fp, bufferNX, size, NULL);
|
||||
writeData(bufferNX, offset, size, ENCRYPTED);
|
||||
}
|
||||
print_progress(100 / step, 100 / step);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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"
|
||||
|
||||
bool dump_keys();
|
||||
void incognito();
|
||||
void cleanUp();
|
||||
bool readData(u8 *buffer, u32 offset, u32 length);
|
||||
bool writeData(u8 *buffer, u32 offset, u32 length);
|
||||
bool readData(u8 *buffer, u32 offset, u32 length, u8 enc);
|
||||
bool writeData(u8 *buffer, u32 offset, u32 length, u8 enc);
|
||||
bool writeClientCertHash();
|
||||
bool writeCal0Hash();
|
||||
bool verifyProdinfo();
|
||||
|
|
|
@ -133,10 +133,17 @@ DRESULT disk_read_prod (
|
|||
|
||||
BYTE *buff, /* Data buffer to store read data */
|
||||
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 u64 prev_cluster = -1;
|
||||
|
@ -171,10 +178,15 @@ DRESULT disk_write_prod (
|
|||
|
||||
BYTE *buff, /* Data buffer to store read data */
|
||||
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 u64 prev_cluster = -1;
|
||||
|
|
|
@ -33,8 +33,8 @@ typedef enum {
|
|||
DSTATUS disk_initialize (BYTE pdrv);
|
||||
DSTATUS disk_status (BYTE pdrv);
|
||||
DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
|
||||
DRESULT disk_read_prod (BYTE *buff, DWORD sector, UINT count);
|
||||
DRESULT disk_write_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, BYTE enc);
|
||||
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
|
||||
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_storage_t sd_storage;
|
||||
__attribute__ ((aligned (16))) FATFS sd_fs;
|
||||
__attribute__((aligned(16))) FATFS sd_fs;
|
||||
static bool sd_mounted;
|
||||
|
||||
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()
|
||||
{
|
||||
|
@ -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.
|
||||
#define RELOC_META_OFF 0x7C
|
||||
#define PATCHED_RELOC_SZ 0x94
|
||||
#define RELOC_META_OFF 0x7C
|
||||
#define PATCHED_RELOC_SZ 0x94
|
||||
#define PATCHED_RELOC_STACK 0x40007000
|
||||
#define COREBOOT_ADDR (0xD0000000 - 0x100000)
|
||||
#define CBFS_DRAM_EN_ADDR 0x4003e000
|
||||
#define CBFS_DRAM_MAGIC 0x4452414D // "DRAM"
|
||||
#define COREBOOT_ADDR (0xD0000000 - 0x100000)
|
||||
#define CBFS_DRAM_EN_ADDR 0x4003e000
|
||||
#define CBFS_DRAM_MAGIC 0x4452414D // "DRAM"
|
||||
|
||||
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->stack = PATCHED_RELOC_STACK;
|
||||
relocator->end = payload_dst + payload_size;
|
||||
relocator->ep = payload_dst;
|
||||
relocator->end = payload_dst + payload_size;
|
||||
relocator->ep = payload_dst;
|
||||
|
||||
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;
|
||||
b_cfg.extra_cfg &= ~EXTRA_CFG_DUMP_EMUMMC;
|
||||
dump_keys();
|
||||
if (!dump_keys())
|
||||
{
|
||||
cleanUp();
|
||||
return;
|
||||
}
|
||||
incognito();
|
||||
verifyProdinfo();
|
||||
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();
|
||||
}
|
||||
|
||||
void dump_emunand()
|
||||
void incognito_emunand()
|
||||
{
|
||||
if (h_cfg.emummc_force_disable)
|
||||
return;
|
||||
emu_cfg.enabled = 1;
|
||||
b_cfg.extra_cfg |= EXTRA_CFG_DUMP_EMUMMC;
|
||||
dump_keys();
|
||||
if (!dump_keys())
|
||||
{
|
||||
cleanUp();
|
||||
return;
|
||||
}
|
||||
incognito();
|
||||
verifyProdinfo();
|
||||
cleanUp();
|
||||
gfx_printf("\n%kPress any key to return to the main menu.", COLOR_GREEN);
|
||||
btn_wait();
|
||||
gfx_printf("\n%k---------------\n%kPress any key to return to the main menu.", COLOR_YELLOW, COLOR_ORANGE);
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void backup_sysnand(){
|
||||
h_cfg.emummc_force_disable = true;
|
||||
void backup_sysnand()
|
||||
{
|
||||
h_cfg.emummc_force_disable = true;
|
||||
b_cfg.extra_cfg &= ~EXTRA_CFG_DUMP_EMUMMC;
|
||||
dump_keys();
|
||||
|
||||
if (!dump_keys())
|
||||
{
|
||||
cleanUp();
|
||||
return;
|
||||
}
|
||||
backupProdinfo();
|
||||
verifyProdinfo();
|
||||
cleanUp();
|
||||
gfx_printf("\n%kPress any key to return to the main menu.", COLOR_GREEN);
|
||||
btn_wait();
|
||||
gfx_printf("\n%k---------------\n%kPress any key to return to the main menu.", COLOR_YELLOW, COLOR_ORANGE);
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void backup_emunand(){
|
||||
if (h_cfg.emummc_force_disable)
|
||||
void backup_emunand()
|
||||
{
|
||||
if (h_cfg.emummc_force_disable)
|
||||
return;
|
||||
emu_cfg.enabled = 1;
|
||||
b_cfg.extra_cfg |= EXTRA_CFG_DUMP_EMUMMC;
|
||||
dump_keys();
|
||||
if (!dump_keys())
|
||||
{
|
||||
cleanUp();
|
||||
return;
|
||||
}
|
||||
|
||||
backupProdinfo();
|
||||
verifyProdinfo();
|
||||
cleanUp();
|
||||
gfx_printf("\n%kPress any key to return to the main menu.", COLOR_GREEN);
|
||||
btn_wait();
|
||||
gfx_printf("\n%k---------------\n%kPress any key to return to the main menu.", COLOR_YELLOW, COLOR_ORANGE);
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void restore_sysnand(){
|
||||
h_cfg.emummc_force_disable = true;
|
||||
void restore_sysnand()
|
||||
{
|
||||
h_cfg.emummc_force_disable = true;
|
||||
b_cfg.extra_cfg &= ~EXTRA_CFG_DUMP_EMUMMC;
|
||||
dump_keys();
|
||||
if (!dump_keys())
|
||||
{
|
||||
cleanUp();
|
||||
return;
|
||||
}
|
||||
|
||||
restoreProdinfo();
|
||||
verifyProdinfo();
|
||||
verifyProdinfo();
|
||||
cleanUp();
|
||||
gfx_printf("\n%kPress any key to return to the main menu.", COLOR_GREEN);
|
||||
btn_wait();
|
||||
gfx_printf("\n%k---------------\n%kPress any key to return to the main menu.", COLOR_YELLOW, COLOR_ORANGE);
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void restore_emunand(){
|
||||
if (h_cfg.emummc_force_disable)
|
||||
void restore_emunand()
|
||||
{
|
||||
if (h_cfg.emummc_force_disable)
|
||||
return;
|
||||
emu_cfg.enabled = 1;
|
||||
b_cfg.extra_cfg |= EXTRA_CFG_DUMP_EMUMMC;
|
||||
|
||||
dump_keys();
|
||||
if (!dump_keys())
|
||||
{
|
||||
cleanUp();
|
||||
return;
|
||||
}
|
||||
|
||||
restoreProdinfo();
|
||||
verifyProdinfo();
|
||||
verifyProdinfo();
|
||||
cleanUp();
|
||||
gfx_printf("\n%kPress any key to return to the main menu.", COLOR_GREEN);
|
||||
btn_wait();
|
||||
gfx_printf("\n%k---------------\n%kPress any key to return to the main menu.", COLOR_YELLOW, COLOR_ORANGE);
|
||||
btn_wait();
|
||||
}
|
||||
ment_t ment_top[] = {
|
||||
MDEF_HANDLER("Incognito (SysNAND)", dump_sysnand, COLOR_ORANGE),
|
||||
MDEF_HANDLER("Incognito (emuMMC)", dump_emunand, COLOR_ORANGE),
|
||||
MDEF_HANDLER("Incognito (SysNAND)", incognito_sysnand, COLOR_ORANGE),
|
||||
MDEF_HANDLER("Incognito (emuMMC)", incognito_emunand, COLOR_ORANGE),
|
||||
MDEF_CAPTION("", COLOR_YELLOW),
|
||||
MDEF_HANDLER("Backup (SysNAND)", backup_sysnand, 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 (emuMMC)", restore_emunand, COLOR_ORANGE),
|
||||
MDEF_CAPTION("", COLOR_YELLOW),
|
||||
MDEF_CAPTION("---------------", COLOR_YELLOW),
|
||||
MDEF_HANDLER("Reboot (Normal)", reboot_normal, COLOR_GREEN),
|
||||
MDEF_HANDLER("Reboot (RCM)", reboot_rcm, COLOR_BLUE),
|
||||
MDEF_HANDLER("Power off", power_off, COLOR_VIOLET),
|
||||
MDEF_END()
|
||||
};
|
||||
MDEF_CAPTION("---------------", COLOR_YELLOW),
|
||||
MDEF_HANDLER("Reboot (Normal)", reboot_normal, COLOR_GREEN),
|
||||
MDEF_HANDLER("Reboot (RCM)", reboot_rcm, COLOR_BLUE),
|
||||
MDEF_HANDLER("Power off", power_off, COLOR_VIOLET),
|
||||
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
|
||||
|
||||
extern void pivot_stack(u32 stack_top);
|
||||
|
|
|
@ -47,6 +47,7 @@ bool emummc_load_cfg()
|
|||
emu_cfg.file_based_part_size = 0;
|
||||
emu_cfg.active_part = 0;
|
||||
emu_cfg.fs_ver = 0;
|
||||
free(emu_cfg.emummc_file_based_path);
|
||||
emu_cfg.emummc_file_based_path = (char *)malloc(0x80);
|
||||
|
||||
LIST_INIT(ini_sections);
|
||||
|
|
Loading…
Reference in a new issue