mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 05:32:47 +00:00
Provide the tools for CTR transfers (A9LH only)
This commit is contained in:
parent
55e3da2e3c
commit
e502ad1d99
@ -48,7 +48,7 @@
|
||||
#endif
|
||||
|
||||
// GodMode9 version
|
||||
#define VERSION "1.0.3"
|
||||
#define VERSION "1.0.4"
|
||||
|
||||
// Maximum payload size (arbitrary value!)
|
||||
#define SELF_MAX_SIZE (320 * 1024) // 320kB
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "filetype.h"
|
||||
#include "fsutil.h"
|
||||
#include "fatmbr.h"
|
||||
#include "nand.h"
|
||||
#include "game.h"
|
||||
#include "chainload.h"
|
||||
|
||||
@ -26,8 +27,9 @@ u32 IdentifyFileType(const char* path) {
|
||||
} else if (ValidateMbrHeader((MbrHeader*) data) == 0) {
|
||||
MbrHeader* mbr = (MbrHeader*) data;
|
||||
MbrPartitionInfo* partition0 = mbr->partitions;
|
||||
bool ctr = (CheckNandMbr(data) & (NAND_TYPE_O3DS|NAND_TYPE_N3DS)); // is this a CTRNAND MBR?
|
||||
if ((partition0->sector + partition0->count) <= (fsize / 0x200)) // size check
|
||||
return IMG_FAT; // possibly an MBR -> also treat as FAT image
|
||||
return IMG_FAT | (ctr ? FLAG_CTR : 0); // possibly an MBR -> also treat as FAT image
|
||||
} else if (ValidateCiaHeader((CiaHeader*) data) == 0) {
|
||||
// this only works because these functions ignore CIA content index
|
||||
CiaInfo info;
|
||||
|
@ -20,6 +20,7 @@
|
||||
#define BIN_SUPPORT (1UL<<15)
|
||||
#define TYPE_BASE 0x00FFFFFF // 24 bit reserved for base types
|
||||
|
||||
#define FLAG_CTR (1UL<<29)
|
||||
#define FLAG_NUSCDN (1UL<<30)
|
||||
#define FLAG_CXI (1UL<<31)
|
||||
|
||||
@ -29,6 +30,7 @@
|
||||
#define FYTPE_ENCRYPTABLE(tp) (tp&(GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_BOSS))
|
||||
#define FTYPE_BUILDABLE(tp) (tp&(GAME_NCSD|GAME_NCCH|GAME_TMD))
|
||||
#define FTYPE_BUILDABLE_L(tp) (FTYPE_BUILDABLE(tp) && (tp&(GAME_TMD)))
|
||||
#define FTYPE_TRANSFERABLE(tp) ((u32) (tp&(IMG_FAT|FLAG_CTR)) == (u32) (IMG_FAT|FLAG_CTR))
|
||||
#define FTYPE_HSINJECTABLE(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))
|
||||
|
@ -866,7 +866,7 @@ bool PathDelete(const char* path) {
|
||||
char fpath[256]; // 256 is the maximum length of a full path
|
||||
if (!CheckDirWritePermissions(path)) return false;
|
||||
strncpy(fpath, path, 256);
|
||||
ShowString("Deleting files, please wait...");
|
||||
// ShowString("Deleting files, please wait..."); // handled elsewhere
|
||||
return PathDeleteWorker(fpath);
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "virtual.h"
|
||||
#include "vcart.h"
|
||||
#include "nandcmac.h"
|
||||
#include "ctrtransfer.h"
|
||||
#include "ncchinfo.h"
|
||||
#include "image.h"
|
||||
#include "chainload.h"
|
||||
@ -611,6 +612,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
||||
bool cryptable_inplace = ((encryptable||decryptable) && !in_output_path && (drvtype & DRV_FAT));
|
||||
bool buildable = (FTYPE_BUILDABLE(filetype));
|
||||
bool buildable_legit = (FTYPE_BUILDABLE_L(filetype));
|
||||
bool transferable = (FTYPE_TRANSFERABLE(filetype) && (drvtype & DRV_FAT));
|
||||
bool hsinjectable = (FTYPE_HSINJECTABLE(filetype));
|
||||
bool restorable = (FTYPE_RESTORABLE(filetype) && IS_A9LH && !(drvtype & DRV_SYSNAND));
|
||||
bool ebackupable = (FTYPE_EBACKUP(filetype));
|
||||
@ -643,7 +645,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
||||
int searchdrv = (DriveType(current_path) & DRV_SEARCH) ? ++n_opt : -1;
|
||||
if (special > 0) optionstr[special-1] =
|
||||
(filetype & IMG_NAND ) ? "NAND image options..." :
|
||||
(filetype & IMG_FAT ) ? "Mount as FAT image" :
|
||||
(filetype & IMG_FAT ) ? (transferable) ? "CTRNAND options..." : "Mount as FAT image" :
|
||||
(filetype & GAME_CIA ) ? "CIA image options..." :
|
||||
(filetype & GAME_NCSD ) ? "NCSD image options..." :
|
||||
(filetype & GAME_NCCH ) ? "NCCH image options..." :
|
||||
@ -774,6 +776,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
||||
int build = (buildable) ? ++n_opt : -1;
|
||||
int build_legit = (buildable_legit) ? ++n_opt : -1;
|
||||
int verify = (verificable) ? ++n_opt : -1;
|
||||
int ctradapt = (transferable) ? ++n_opt : -1;
|
||||
int hsinject = (hsinjectable) ? ++n_opt : -1;
|
||||
int xorpad = (xorpadable) ? ++n_opt : -1;
|
||||
int xorpad_inplace = (xorpadable) ? ++n_opt : -1;
|
||||
@ -786,6 +789,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
||||
if (build > 0) optionstr[build-1] = (build_legit < 0) ? "Build CIA from file" : "Build CIA (standard)";
|
||||
if (build_legit > 0) optionstr[build_legit-1] = "Build CIA (legit)";
|
||||
if (verify > 0) optionstr[verify-1] = "Verify file";
|
||||
if (ctradapt > 0) optionstr[ctradapt-1] = "Adapt image to SysNAND";
|
||||
if (hsinject > 0) optionstr[hsinject-1] = "Inject to H&S";
|
||||
if (xorpad > 0) optionstr[xorpad-1] = "Build XORpads (SD output)";
|
||||
if (xorpad_inplace > 0) optionstr[xorpad_inplace-1] = "Build XORpads (inplace)";
|
||||
@ -988,6 +992,10 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
||||
(InjectHealthAndSafety(curr_entry->path, destdrv[user_select-1]) == 0) ? "success" : "failed");
|
||||
}
|
||||
return 0;
|
||||
} else if (user_select == ctradapt) { // -> adapt CTRNAND image to SysNAND
|
||||
ShowPrompt(false, "%s\n%s", pathstr,
|
||||
(AdaptCtrNandImage(curr_entry->path) == 0) ? "Image adapted to SysNAND" : "Image modification failed");
|
||||
return 0;
|
||||
} else if (user_select == restore) { // -> restore SysNAND (A9LH preserving)
|
||||
ShowPrompt(false, "%s\nNAND restore %s", pathstr,
|
||||
(SafeRestoreNandDump(curr_entry->path) == 0) ? "success" : "failed");
|
||||
@ -1334,6 +1342,7 @@ u32 GodMode() {
|
||||
if (n_marked) {
|
||||
if (ShowPrompt(true, "Delete %u path(s)?", n_marked)) {
|
||||
u32 n_errors = 0;
|
||||
ShowString("Deleting files, please wait...");
|
||||
for (u32 c = 0; c < current_dir->n_entries; c++)
|
||||
if (current_dir->entry[c].marked && !PathDelete(current_dir->entry[c].path))
|
||||
n_errors++;
|
||||
@ -1344,6 +1353,7 @@ u32 GodMode() {
|
||||
char namestr[36+1];
|
||||
TruncateString(namestr, curr_entry->name, 28, 12);
|
||||
if (ShowPrompt(true, "Delete \"%s\"?", namestr)) {
|
||||
ShowString("Deleting files, please wait...");
|
||||
if (!PathDelete(curr_entry->path))
|
||||
ShowPrompt(false, "Failed deleting:\n%s", namestr);
|
||||
ClearScreenF(true, false, COLOR_STD_BG);
|
||||
|
76
source/nand/ctrtransfer.c
Normal file
76
source/nand/ctrtransfer.c
Normal file
@ -0,0 +1,76 @@
|
||||
#include "ctrtransfer.h"
|
||||
#include "nandcmac.h"
|
||||
#include "fsutil.h"
|
||||
#include "fsinit.h"
|
||||
#include "fsperm.h"
|
||||
#include "image.h"
|
||||
#include "essentials.h"
|
||||
#include "ui.h"
|
||||
|
||||
u32 AdaptCtrNandImage(const char* path) {
|
||||
if (!CheckWritePermissions(path)) return 1;
|
||||
|
||||
// a little warning...
|
||||
if (!ShowPrompt(true, "This will alter the provided image\nto make it transferable to your NAND."))
|
||||
return 1;
|
||||
|
||||
// backup current mount path, mount new path
|
||||
char path_store[256] = { 0 };
|
||||
char* path_bak = NULL;
|
||||
strncpy(path_store, GetMountPath(), 256);
|
||||
if (*path_store) path_bak = path_store;
|
||||
if (!InitImgFS(path)) {
|
||||
InitImgFS(path_bak);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// fixing CMACs
|
||||
ShowString("Fixing .db CMACs, please wait...");
|
||||
if ((FixFileCmac("7:/dbs/ticket.db") != 0) ||
|
||||
(FixFileCmac("7:/dbs/certs.db") != 0) ||
|
||||
(FixFileCmac("7:/dbs/title.db") != 0)) {
|
||||
ShowPrompt(false, "Error: .db file missing.");
|
||||
InitImgFS(path_bak);
|
||||
return 1;
|
||||
}
|
||||
FixFileCmac("7:/dbs/import.db");
|
||||
FixFileCmac("7:/dbs/tmp_t.db");
|
||||
FixFileCmac("7:/dbs/tmp_i.db");
|
||||
|
||||
// cleanup this image
|
||||
ShowString("Cleaning up image, please wait...");
|
||||
// special handling for out of region images
|
||||
SecureInfo* secnfo_img = (SecureInfo*) TEMP_BUFFER;
|
||||
SecureInfo* secnfo_loc = (SecureInfo*) (TEMP_BUFFER + 0x200);
|
||||
if (((FileGetData("7:/rw/sys/SecureInfo_A", (u8*) secnfo_img, sizeof(SecureInfo), 0) == sizeof(SecureInfo)) ||
|
||||
(FileGetData("7:/rw/sys/SecureInfo_B", (u8*) secnfo_img, sizeof(SecureInfo), 0) == sizeof(SecureInfo))) &&
|
||||
((FileGetData("1:/rw/sys/SecureInfo_A", (u8*) secnfo_loc, sizeof(SecureInfo), 0) == sizeof(SecureInfo)) ||
|
||||
(FileGetData("1:/rw/sys/SecureInfo_B", (u8*) secnfo_loc, sizeof(SecureInfo), 0) == sizeof(SecureInfo))) &&
|
||||
(secnfo_img->region != secnfo_loc->region)) {
|
||||
secnfo_loc->region = secnfo_img->region;
|
||||
FileSetData("1:/rw/sys/SecureInfo_C", (u8*) secnfo_loc, sizeof(SecureInfo), 0, true);
|
||||
}
|
||||
// actual cleanup
|
||||
PathDelete("7:/private/movable.sed");
|
||||
PathDelete("7:/rw/sys/LocalFriendCodeSeed_B");
|
||||
PathDelete("7:/rw/sys/LocalFriendCodeSeed_A");
|
||||
PathDelete("7:/rw/sys/SecureInfo_A");
|
||||
PathDelete("7:/rw/sys/SecureInfo_B");
|
||||
PathDelete("7:/data");
|
||||
|
||||
// inject all required files to image
|
||||
u32 flags = OVERWRITE_ALL;
|
||||
if (!PathCopy("7:/private", "1:/private/movable.sed", &flags) ||
|
||||
!(PathCopy("7:/rw/sys", "1:/rw/sys/LocalFriendCodeSeed_B", &flags) ||
|
||||
PathCopy("7:/rw/sys", "1:/rw/sys/LocalFriendCodeSeed_A", &flags)) ||
|
||||
!(PathCopy("7:/rw/sys", "1:/rw/sys/SecureInfo_A", &flags) ||
|
||||
PathCopy("7:/rw/sys", "1:/rw/sys/SecureInfo_B", &flags))) {
|
||||
ShowPrompt(false, "Error: Failed transfering data.");
|
||||
InitImgFS(path_bak);
|
||||
return 1;
|
||||
}
|
||||
PathCopy("7:", "1:/data", &flags);
|
||||
|
||||
InitImgFS(path_bak);
|
||||
return 0;
|
||||
}
|
5
source/nand/ctrtransfer.h
Normal file
5
source/nand/ctrtransfer.h
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
u32 AdaptCtrNandImage(const char* path);
|
@ -51,6 +51,22 @@ static const u8 twl_mbr[0x42] = { // encrypted version inside the NCSD NAND head
|
||||
0x55, 0xAA
|
||||
};
|
||||
|
||||
static const u8 ctr_mbr_o3ds[0x42] = { // found at the beginning of the CTRNAND partition (O3DS)
|
||||
0x00, 0x05, 0x2B, 0x00, 0x06, 0x02, 0x42, 0x80, 0x65, 0x01, 0x00, 0x00, 0x1B, 0x9F, 0x17, 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,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x55, 0xAA
|
||||
};
|
||||
|
||||
static const u8 ctr_mbr_n3ds[0x42] = { // found at the beginning of the CTRNAND partition (N3DS)
|
||||
0x00, 0x05, 0x1D, 0x00, 0x06, 0x02, 0x82, 0x17, 0x57, 0x01, 0x00, 0x00, 0x69, 0xE9, 0x20, 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,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x55, 0xAA
|
||||
};
|
||||
|
||||
static u8 CtrNandCtr[16];
|
||||
static u8 TwlNandCtr[16];
|
||||
static u8 OtpSha256[32] = { 0 };
|
||||
@ -352,13 +368,24 @@ int WriteNandSectors(const u8* buffer, u32 sector, u32 count, u32 keyslot, u32 n
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 CheckNandMbr(u8* mbr)
|
||||
{
|
||||
if (memcmp(mbr + (0x200 - sizeof(twl_mbr)), twl_mbr, sizeof(twl_mbr)) == 0)
|
||||
return NAND_TYPE_TWL; // TWLNAND MBR (included in NAND header)
|
||||
else if (memcmp(mbr + (0x200 - sizeof(ctr_mbr_o3ds)), ctr_mbr_o3ds, sizeof(ctr_mbr_o3ds)) == 0)
|
||||
return NAND_TYPE_O3DS; // CTRNAND MBR (@0x05C980)
|
||||
else if (memcmp(mbr + (0x200 - sizeof(ctr_mbr_n3ds)), ctr_mbr_n3ds, sizeof(ctr_mbr_n3ds)) == 0)
|
||||
return NAND_TYPE_N3DS; // CTRNAND MBR (@0x05C980)
|
||||
else return 0;
|
||||
}
|
||||
|
||||
u32 CheckNandHeader(u8* header)
|
||||
{
|
||||
// TWL MBR check
|
||||
u8 header_dec[0x200];
|
||||
memcpy(header_dec, header, 0x200);
|
||||
CryptNand(header_dec, 0, 1, 0x03);
|
||||
if (memcmp(header_dec + 0x1BE, twl_mbr, sizeof(twl_mbr)) != 0)
|
||||
if (CheckNandMbr(header_dec) != NAND_TYPE_TWL)
|
||||
return 0; // header does not belong to console
|
||||
|
||||
// header type check
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define NAND_TYPE_O3DS (1UL<<4)
|
||||
#define NAND_TYPE_N3DS (1UL<<5)
|
||||
#define NAND_TYPE_NO3DS (1UL<<6)
|
||||
#define NAND_TYPE_TWL (1UL<<7)
|
||||
|
||||
// minimum size of NAND memory
|
||||
#define NAND_MIN_SECTORS_O3DS 0x1D7800
|
||||
@ -47,6 +48,7 @@ int WriteNandSectors(const u8* buffer, u32 sector, u32 count, u32 keyslot, u32 d
|
||||
|
||||
u64 GetNandSizeSectors(u32 src);
|
||||
u64 GetNandUnusedSectors(u32 src);
|
||||
u32 CheckNandMbr(u8* mbr);
|
||||
u32 CheckNandHeader(u8* header);
|
||||
u32 CheckNandType(u32 src);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user