mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 13:42:47 +00:00
Added ability to rebuild / fix NAND NCSD headers
This commit is contained in:
parent
343f1182b9
commit
cc31926a69
@ -23,9 +23,11 @@ u32 IdentifyFileType(const char* path) {
|
||||
|
||||
if (!fsize) return 0;
|
||||
if (fsize >= 0x200) {
|
||||
if ((getbe32(header + 0x100) == 0x4E435344) && (getbe64(header + 0x110) == (u64) 0x0104030301000000) &&
|
||||
(getbe64(header + 0x108) == (u64) 0) && (fsize >= 0x8FC8000)) {
|
||||
return IMG_NAND; // NAND image
|
||||
if (ValidateNandNcsdHeader((NandNcsdHeader*) data) == 0) {
|
||||
return (fsize >= GetNandNcsdMinSizeSectors((NandNcsdHeader*) data) * 0x200) ?
|
||||
IMG_NAND : (fsize == sizeof(NandNcsdHeader)) ? HDR_NAND : 0; // NAND image or just header
|
||||
} else if ((strncasecmp(path, "S:/nand.bin", 16) == 0) || (strncasecmp(path, "E:/nand.bin", 16) == 0)) {
|
||||
return NOIMG_NAND; // on NAND, but no proper NAND image
|
||||
} else if (ValidateFatHeader(header) == 0) {
|
||||
return IMG_FAT; // FAT image file
|
||||
} else if (ValidateMbrHeader((MbrHeader*) data) == 0) {
|
||||
|
@ -23,6 +23,8 @@
|
||||
#define BIN_LEGKEY (1UL<<18)
|
||||
#define TXT_SCRIPT (1UL<<19)
|
||||
#define TXT_GENERIC (1UL<<20)
|
||||
#define NOIMG_NAND (1UL<<21)
|
||||
#define HDR_NAND (1UL<<22)
|
||||
#define TYPE_BASE 0x00FFFFFF // 24 bit reserved for base types
|
||||
|
||||
#define FLAG_ENC (1UL<<28)
|
||||
@ -42,6 +44,7 @@
|
||||
#define FTYPE_TITLEINFO(tp) (tp&(GAME_SMDH|GAME_NCCH|GAME_NCSD|GAME_CIA|GAME_TMD|GAME_NDS))
|
||||
#define FTYPE_RENAMABLE(tp) (tp&(GAME_NCCH|GAME_NCSD|GAME_CIA|GAME_NDS))
|
||||
#define FTYPE_TRANSFERABLE(tp) ((u32) (tp&(IMG_FAT|FLAG_CTR)) == (u32) (IMG_FAT|FLAG_CTR))
|
||||
#define FTYPE_NCSDFIXABLE(tp) (tp&(HDR_NAND|NOIMG_NAND))
|
||||
#define FTYPE_HASCODE(tp) ((u32) (tp&(GAME_NCCH|FLAG_CXI)) == (u32) (GAME_NCCH|FLAG_CXI))
|
||||
#define FTYPE_RESTORABLE(tp) (tp&(IMG_NAND))
|
||||
#define FTYPE_EBACKUP(tp) (tp&(IMG_NAND))
|
||||
|
@ -713,12 +713,13 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
||||
bool extrcodeable = (FTYPE_HASCODE(filetype));
|
||||
bool restorable = (FTYPE_RESTORABLE(filetype) && IS_A9LH && !(drvtype & DRV_SYSNAND));
|
||||
bool ebackupable = (FTYPE_EBACKUP(filetype));
|
||||
bool ncsdfixable = (FTYPE_NCSDFIXABLE(filetype));
|
||||
bool xorpadable = (FTYPE_XORPAD(filetype));
|
||||
bool keyinitable = (FTYPE_KEYINIT(filetype));
|
||||
bool scriptable = (FTYPE_SCRIPT(filetype));
|
||||
bool bootable = (FTYPE_BOOTABLE(filetype) && !(drvtype & DRV_VIRTUAL));
|
||||
bool installable = (FTYPE_INSTALLABLE(filetype) && !(drvtype & DRV_VIRTUAL));
|
||||
bool special_opt = mountable || verificable || decryptable || encryptable || cia_buildable || cia_buildable_legit || cxi_dumpable || tik_buildable || key_buildable || titleinfo || renamable || transferable || hsinjectable || restorable || xorpadable || ebackupable || extrcodeable || keyinitable || bootable || scriptable || installable;
|
||||
bool special_opt = mountable || verificable || decryptable || encryptable || cia_buildable || cia_buildable_legit || cxi_dumpable || tik_buildable || key_buildable || titleinfo || renamable || transferable || hsinjectable || restorable || xorpadable || ebackupable || ncsdfixable || extrcodeable || keyinitable || bootable || scriptable || installable;
|
||||
|
||||
char pathstr[32+1];
|
||||
TruncateString(pathstr, curr_entry->path, 32, 8);
|
||||
@ -763,7 +764,9 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
||||
(filetype & BIN_KEYDB) ? "AESkeydb options..." :
|
||||
(filetype & BIN_LEGKEY) ? "Build " KEYDB_NAME :
|
||||
(filetype & BIN_NCCHNFO)? "NCCHinfo options..." :
|
||||
(filetype & TXT_SCRIPT) ? "Execute GM9 script" : "???";
|
||||
(filetype & TXT_SCRIPT) ? "Execute GM9 script" :
|
||||
(filetype & HDR_NAND) ? "Rebuild NCSD header" :
|
||||
(filetype & NOIMG_NAND) ? "Rebuild NCSD header" : "???";
|
||||
optionstr[hexviewer-1] = "Show in Hexeditor";
|
||||
optionstr[calcsha-1] = "Calculate SHA-256";
|
||||
if (textviewer > 0) optionstr[textviewer-1] = "Show in Textviewer";
|
||||
@ -776,6 +779,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
||||
"%s\n%(%lu files selected)" : "%s", pathstr, n_marked);
|
||||
if (user_select == hexviewer) { // -> show in hex viewer
|
||||
FileHexViewer(curr_entry->path);
|
||||
GetDirContents(current_dir, current_path);
|
||||
return 0;
|
||||
} else if (user_select == textviewer) { // -> show in text viewer
|
||||
FileTextViewer(curr_entry->path, scriptable);
|
||||
@ -859,6 +863,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
||||
int mount = (mountable) ? ++n_opt : -1;
|
||||
int restore = (restorable) ? ++n_opt : -1;
|
||||
int ebackup = (ebackupable) ? ++n_opt : -1;
|
||||
int ncsdfix = (ncsdfixable) ? ++n_opt : -1;
|
||||
int decrypt = (decryptable) ? ++n_opt : -1;
|
||||
int encrypt = (encryptable) ? ++n_opt : -1;
|
||||
int cia_build = (cia_buildable) ? ++n_opt : -1;
|
||||
@ -881,6 +886,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
||||
if (mount > 0) optionstr[mount-1] = "Mount image to drive";
|
||||
if (restore > 0) optionstr[restore-1] = "Restore SysNAND (safe)";
|
||||
if (ebackup > 0) optionstr[ebackup-1] = "Update embedded backup";
|
||||
if (ncsdfix > 0) optionstr[ncsdfix-1] = "Rebuild NCSD header";
|
||||
if (show_info > 0) optionstr[show_info-1] = "Show title info";
|
||||
if (decrypt > 0) optionstr[decrypt-1] = (cryptable_inplace) ? "Decrypt file (...)" : "Decrypt file (" OUTPUT_PATH ")";
|
||||
if (encrypt > 0) optionstr[encrypt-1] = (cryptable_inplace) ? "Encrypt file (...)" : "Encrypt file (" OUTPUT_PATH ")";
|
||||
@ -1216,7 +1222,13 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
||||
ShowPrompt(false, "%s\nNAND restore %s", pathstr,
|
||||
(SafeRestoreNandDump(curr_entry->path) == 0) ? "success" : "failed");
|
||||
return 0;
|
||||
} else if ((user_select == xorpad) || (user_select == xorpad_inplace)) {
|
||||
} else if (user_select == ncsdfix) { // -> inject sighaxed NCSD
|
||||
ShowPrompt(false, "%s\nRebuild NCSD %s", pathstr,
|
||||
(FixNandHeader(curr_entry->path, !(filetype == HDR_NAND)) == 0) ? "success" : "failed");
|
||||
GetDirContents(current_dir, current_path);
|
||||
InitExtFS(); // this might have fixed something, so try this
|
||||
return 0;
|
||||
} else if ((user_select == xorpad) || (user_select == xorpad_inplace)) { // -> build xorpads
|
||||
bool inplace = (user_select == xorpad_inplace);
|
||||
bool success = (BuildNcchInfoXorpads((inplace) ? current_path : OUTPUT_PATH, curr_entry->path) == 0);
|
||||
ShowPrompt(false, "%s\nNCCHinfo padgen %s%s", pathstr,
|
||||
@ -1232,7 +1244,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
||||
*cursor = 1;
|
||||
}
|
||||
return 0;
|
||||
} else if (user_select == ebackup) {
|
||||
} else if (user_select == ebackup) { // -> update embedded backup
|
||||
ShowString("%s\nUpdating embedded backup...", pathstr);
|
||||
bool required = (CheckEmbeddedBackup(curr_entry->path) != 0);
|
||||
bool success = (required && (EmbedEssentialBackup(curr_entry->path) == 0));
|
||||
@ -1240,11 +1252,11 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
||||
(success) ? "completed" : "failed!");
|
||||
GetDirContents(current_dir, current_path);
|
||||
return 0;
|
||||
} else if ((user_select == keyinit)) {
|
||||
} else if ((user_select == keyinit)) { // -> initialise keys from aeskeydb.bin
|
||||
if (ShowPrompt(true, "Warning: Keys are not verified.\nContinue on your own risk?"))
|
||||
ShowPrompt(false, "%s\nAESkeydb init %s", pathstr, (InitKeyDb(curr_entry->path) == 0) ? "success" : "failed");
|
||||
return 0;
|
||||
} else if ((user_select == install)) {
|
||||
} else if ((user_select == install)) { // -> install FIRM
|
||||
size_t firm_size = FileGetSize(curr_entry->path);
|
||||
u32 slots = 1;
|
||||
if (GetNandPartitionInfo(NULL, NP_TYPE_FIRM, NP_SUBTYPE_CTR, 1, NAND_SYSNAND) == 0) {
|
||||
@ -1257,7 +1269,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
||||
if (slots) ShowPrompt(false, "%s (%dkB)\nInstall %s", pathstr, firm_size / 1024,
|
||||
(SafeInstallFirm(curr_entry->path, slots) == 0) ? "success" : "failed!");
|
||||
return 0;
|
||||
} else if ((user_select == boot)) {
|
||||
} else if ((user_select == boot)) { // -> boot FIRM
|
||||
size_t firm_size = FileGetSize(curr_entry->path);
|
||||
if (firm_size > TEMP_BUFFER_SIZE) {
|
||||
ShowPrompt(false, "FIRM too big, can't launch"); // unlikely
|
||||
@ -1287,7 +1299,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
||||
} else ShowPrompt(false, "Not a bootable FIRM, can't boot");
|
||||
}
|
||||
return 0;
|
||||
} else if ((user_select == script)) {
|
||||
} else if ((user_select == script)) { // execute script
|
||||
if (ShowPrompt(true, "%s\nWarning: Do not run scripts\nfrom untrusted sources.\n \nExecute script?", pathstr))
|
||||
ShowPrompt(false, "%s\nScript execute %s", pathstr, ExecuteGM9Script(curr_entry->path) ? "success" : "failure");
|
||||
GetDirContents(current_dir, current_path);
|
||||
|
@ -13,6 +13,15 @@
|
||||
#include "vff.h"
|
||||
|
||||
|
||||
static const u8 twl_mbr_std[0x42] = {
|
||||
0x00, 0x04, 0x18, 0x00, 0x06, 0x01, 0xA0, 0x3F, 0x97, 0x00, 0x00, 0x00, 0xA9, 0x7D, 0x04, 0x00,
|
||||
0x00, 0x04, 0x8E, 0x40, 0x06, 0x01, 0xA0, 0xC3, 0x8D, 0x80, 0x04, 0x00, 0xB3, 0x05, 0x01, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x55, 0xAA
|
||||
};
|
||||
|
||||
|
||||
u32 ReadNandFile(FIL* file, void* buffer, u32 sector, u32 count, u32 keyslot) {
|
||||
u32 offset = sector * 0x200;
|
||||
u32 size = count * 0x200;
|
||||
@ -108,6 +117,76 @@ u32 EmbedEssentialBackup(const char* path) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 RebuildNandNcsdHeader(NandNcsdHeader* ncsd) {
|
||||
// signature (retail or dev)
|
||||
u8* signature = (IS_DEVKIT) ? sig_nand_ncsd_dev : sig_nand_ncsd_retail;
|
||||
|
||||
// encrypted TWL MBR
|
||||
u8 twl_mbr_data[0x200] = { 0 };
|
||||
u8* twl_mbr = twl_mbr_data + (0x200 - sizeof(twl_mbr_std));
|
||||
memcpy(twl_mbr, twl_mbr_std, sizeof(twl_mbr_std));
|
||||
CryptNand(twl_mbr_data, 0, 1, 0x03);
|
||||
|
||||
// rebuild NAND header for console
|
||||
memset(ncsd, 0x00, sizeof(NandNcsdHeader));
|
||||
memcpy(ncsd->signature, signature, 0x100); // signature
|
||||
memcpy(ncsd->twl_mbr, twl_mbr, 0x42); // TWL MBR
|
||||
memcpy(ncsd->magic, "NCSD", 0x4); // magic number
|
||||
ncsd->size = (IS_O3DS) ? 0x200000 : 0x280000; // total size
|
||||
|
||||
// TWL partition (0)
|
||||
ncsd->partitions_fs_type[0] = 0x01;
|
||||
ncsd->partitions_crypto_type[0] = 0x01;
|
||||
ncsd->partitions[0].offset = 0x000000;
|
||||
ncsd->partitions[0].size = 0x058800;
|
||||
|
||||
// AGBSAVE partition (1)
|
||||
ncsd->partitions_fs_type[1] = 0x04;
|
||||
ncsd->partitions_crypto_type[1] = 0x02;
|
||||
ncsd->partitions[1].offset = 0x058800;
|
||||
ncsd->partitions[1].size = 0x000180;
|
||||
|
||||
// FIRM0 partition (2)
|
||||
ncsd->partitions_fs_type[2] = 0x03;
|
||||
ncsd->partitions_crypto_type[2] = 0x02;
|
||||
ncsd->partitions[2].offset = 0x058980;
|
||||
ncsd->partitions[2].size = 0x002000;
|
||||
|
||||
// FIRM1 partition (3)
|
||||
ncsd->partitions_fs_type[3] = 0x03;
|
||||
ncsd->partitions_crypto_type[3] = 0x02;
|
||||
ncsd->partitions[3].offset = 0x05A980;
|
||||
ncsd->partitions[3].size = 0x002000;
|
||||
|
||||
// CTR partition (4)
|
||||
ncsd->partitions_fs_type[4] = 0x01;
|
||||
ncsd->partitions_crypto_type[4] = (IS_O3DS) ? 0x02 : 0x03;
|
||||
ncsd->partitions[4].offset = 0x05C980;
|
||||
ncsd->partitions[4].size = (IS_O3DS) ? 0x17AE80 : 0x20F680;
|
||||
|
||||
// unknown stuff - whatever this is ¯\_(ツ)_/¯
|
||||
ncsd->unknown[0x25] = 0x04;
|
||||
ncsd->unknown[0x2C] = 0x01;
|
||||
|
||||
// done
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 FixNandHeader(const char* path, bool check_size) {
|
||||
NandNcsdHeader ncsd;
|
||||
if (RebuildNandNcsdHeader(&ncsd) != 0) return 1;
|
||||
|
||||
// safety check
|
||||
FILINFO fno;
|
||||
FSIZE_t min_size = check_size ? GetNandNcsdMinSizeSectors(&ncsd) * 0x200 : 0x200;
|
||||
if ((fvx_stat(path, &fno) != FR_OK) || (min_size > fno.fsize))
|
||||
return 1;
|
||||
|
||||
// inject to path
|
||||
if (!CheckWritePermissions(path)) return 1;
|
||||
return (fvx_qwrite(path, &ncsd, 0x0, 0x200, NULL) == FR_OK) ? 0 : 1;
|
||||
}
|
||||
|
||||
u32 ValidateNandDump(const char* path) {
|
||||
NandPartitionInfo info;
|
||||
FIL file;
|
||||
@ -235,6 +314,7 @@ u32 SafeRestoreNandDump(const char* path) {
|
||||
}
|
||||
|
||||
// compare NCSD header partitioning
|
||||
// FIRMS must be at the same place for image and local NAND
|
||||
bool header_inject = false;
|
||||
if (memcmp(&ncsd_loc, &ncsd_img, sizeof(NandNcsdHeader)) != 0) {
|
||||
for (int p = -1; p <= 8; p++) {
|
||||
@ -246,7 +326,7 @@ u32 SafeRestoreNandDump(const char* path) {
|
||||
bool np_loc = (GetNandNcsdPartitionInfo(&info_loc, type, subtype, idx, &ncsd_loc) == 0);
|
||||
bool np_img = (GetNandNcsdPartitionInfo(&info_img, type, subtype, idx, &ncsd_img) == 0);
|
||||
if (!np_loc && !np_img) {
|
||||
if (p >= 1) header_inject = true;
|
||||
if (p >= 1) header_inject = true; // at least one matching FIRM found
|
||||
break;
|
||||
}
|
||||
if ((np_loc != np_img) || (memcmp(&info_loc, &info_img, sizeof(NandPartitionInfo)) != 0))
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
u32 CheckEmbeddedBackup(const char* path);
|
||||
u32 EmbedEssentialBackup(const char* path);
|
||||
u32 FixNandHeader(const char* path, bool check_size);
|
||||
u32 ValidateNandDump(const char* path);
|
||||
u32 SafeRestoreNandDump(const char* path);
|
||||
u32 SafeInstallFirm(const char* path, u32 slots);
|
||||
|
Loading…
x
Reference in New Issue
Block a user