mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 21:52:48 +00:00
Enable direct decrypt of NUS / CDN content
This commit is contained in:
parent
faba2ebae5
commit
76cfc03a66
@ -38,7 +38,7 @@
|
||||
(((v) % (a)) ? ((v) + (a) - ((v) % (a))) : (v))
|
||||
|
||||
// GodMode9 version
|
||||
#define VERSION "0.9.7"
|
||||
#define VERSION "0.9.8"
|
||||
|
||||
// input / output paths
|
||||
#define INPUT_PATHS "0:", "0:/files9", "1:/rw/files9"
|
||||
|
@ -11,6 +11,7 @@ u32 IdentifyFileType(const char* path) {
|
||||
size_t fsize = FileGetSize(path);
|
||||
char* fname = strrchr(path, '/');
|
||||
char* ext = (fname) ? strrchr(++fname, '.') : NULL;
|
||||
u32 id = 0;
|
||||
if (ext) ext++;
|
||||
if (FileGetData(path, header, 0x200, 0) < ((fsize > 0x200) ? 0x200 : fsize)) return 0;
|
||||
|
||||
@ -49,6 +50,8 @@ u32 IdentifyFileType(const char* path) {
|
||||
return GAME_TMD | FLAG_NUSCDN; // TMD file from NUS/CDN
|
||||
else if (fsize >= TMD_SIZE_N(getbe16(header + 0x1DE)))
|
||||
return GAME_TMD; // TMD file
|
||||
} else if (ValidateTicket((Ticket*) data) == 0) {
|
||||
return GAME_TICKET; // Ticket file (not used for anything right now)
|
||||
} else if (ValidateFirmHeader((FirmHeader*) data, fsize) == 0) {
|
||||
return SYS_FIRM; // FIRM file
|
||||
}
|
||||
@ -60,6 +63,16 @@ u32 IdentifyFileType(const char* path) {
|
||||
(GetNcchInfoVersion((NcchInfoHeader*) data)) &&
|
||||
fname && (strncasecmp(fname, NCCHINFO_NAME, 32) == 0)) {
|
||||
return BIN_NCCHNFO; // ncchinfo.bin file
|
||||
} else if ((strnlen(fname, 16) == 8) && (sscanf(fname, "%08lx", &id) == 1)) {
|
||||
char path_cdn[256];
|
||||
char* name_cdn = path_cdn + (fname - path);
|
||||
strncpy(path_cdn, path, 256);
|
||||
strncpy(name_cdn, "tmd", 4);
|
||||
if (FileGetSize(path_cdn) > 0)
|
||||
return GAME_NUSCDN;
|
||||
strncpy(name_cdn, "cetk", 5);
|
||||
if (FileGetSize(path_cdn) > 0)
|
||||
return GAME_NUSCDN;
|
||||
#if PAYLOAD_MAX_SIZE <= TEMP_BUFFER_SIZE
|
||||
} else if ((fsize <= PAYLOAD_MAX_SIZE) && ext && (strncasecmp(ext, "bin", 4) == 0)) {
|
||||
return BIN_LAUNCH; // assume it's an ARM9 payload
|
||||
|
@ -11,9 +11,11 @@
|
||||
#define GAME_EXEFS (1<<6)
|
||||
#define GAME_ROMFS (1<<7)
|
||||
#define GAME_BOSS (1<<8)
|
||||
#define SYS_FIRM (1<<9)
|
||||
#define BIN_NCCHNFO (1<<10)
|
||||
#define BIN_LAUNCH (1<<11)
|
||||
#define GAME_NUSCDN (1<<9)
|
||||
#define GAME_TICKET (1<<10)
|
||||
#define SYS_FIRM (1<<11)
|
||||
#define BIN_NCCHNFO (1<<12)
|
||||
#define BIN_LAUNCH (1<<13)
|
||||
#define TYPE_BASE 0x00FFFFFF // 24 bit reserved for base types
|
||||
|
||||
#define FLAG_NUSCDN (1<<30)
|
||||
@ -21,7 +23,7 @@
|
||||
|
||||
#define FTYPE_MOUNTABLE(tp) (tp&(IMG_FAT|IMG_NAND|GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_EXEFS|GAME_ROMFS|SYS_FIRM))
|
||||
#define FYTPE_VERIFICABLE(tp) (tp&(IMG_NAND|GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_TMD|GAME_BOSS|SYS_FIRM))
|
||||
#define FYTPE_DECRYPTABLE(tp) (tp&(GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_BOSS|SYS_FIRM))
|
||||
#define FYTPE_DECRYPTABLE(tp) (tp&(GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_BOSS|GAME_NUSCDN|SYS_FIRM))
|
||||
#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)))
|
||||
|
@ -729,6 +729,8 @@ u32 CheckEncryptedGameFile(const char* path) {
|
||||
return CheckEncryptedBossFile(path);
|
||||
else if (filetype & SYS_FIRM)
|
||||
return CheckEncryptedFirmFile(path);
|
||||
else if (filetype & GAME_NUSCDN)
|
||||
return 0; // these should always be encrypted
|
||||
else return 1;
|
||||
}
|
||||
|
||||
@ -767,7 +769,8 @@ u32 CryptNcchNcsdBossFirmFile(const char* orig, const char* dest, u32 mode, u16
|
||||
}
|
||||
|
||||
fsize = fvx_size(ofp); // for progress bar
|
||||
if (!size) size = fsize;
|
||||
if (fsize < offset) return 1;
|
||||
if (!size) size = fsize - offset;
|
||||
|
||||
u32 ret = 0;
|
||||
if (!ShowProgress(offset, fsize, dest)) ret = 1;
|
||||
@ -786,7 +789,7 @@ u32 CryptNcchNcsdBossFirmFile(const char* orig, const char* dest, u32 mode, u16
|
||||
if ((read_bytes != bytes_read) || (bytes_read != bytes_written)) ret = 1;
|
||||
if (!ShowProgress(offset + i + read_bytes, fsize, dest)) ret = 1;
|
||||
}
|
||||
} else if (mode & GAME_CIA) { // for NCCHs inside CIAs
|
||||
} else if (mode & (GAME_CIA|GAME_NUSCDN)) { // for NCCHs inside CIAs
|
||||
bool cia_crypto = getbe16(chunk->type) & 0x1;
|
||||
bool ncch_crypto; // find out by decrypting the NCCH header
|
||||
UINT bytes_read, bytes_written;
|
||||
@ -920,6 +923,70 @@ u32 DecryptFirmFile(const char* orig, const char* dest) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 CryptCdnFile(const char* orig, const char* dest, u16 crypto) {
|
||||
bool inplace = (strncmp(orig, dest, 256) == 0);
|
||||
TitleMetaData* tmd = (TitleMetaData*) TEMP_BUFFER;
|
||||
TmdContentChunk* content_list = (TmdContentChunk*) (tmd + 1);
|
||||
Ticket* ticket = (Ticket*) (TEMP_BUFFER + TMD_SIZE_MAX);
|
||||
u8 titlekey[0x10] = { 0xFF };
|
||||
u32 cnt_id;
|
||||
|
||||
// try to load TMD file
|
||||
char path_tmd[256];
|
||||
char* name_tmd;
|
||||
strncpy(path_tmd, orig, 256);
|
||||
name_tmd = strrchr(path_tmd, '/');
|
||||
if (!name_tmd) return 1; // will not happen
|
||||
name_tmd++;
|
||||
snprintf(name_tmd, 256 - (name_tmd - path_tmd), "tmd");
|
||||
if (LoadTmdFile(tmd, path_tmd) != 0) tmd = NULL;
|
||||
|
||||
// load or build ticket
|
||||
if (LoadCdnTicketFile(ticket, orig) != 0) {
|
||||
if (!tmd || (BuildFakeTicket(ticket, tmd->title_id) != 0)) return 1;
|
||||
if (FindTitleKey(ticket, tmd->title_id) != 0) return 1;
|
||||
}
|
||||
|
||||
// get titlekey
|
||||
if (GetTitleKey(titlekey, ticket) != 0)
|
||||
return 1;
|
||||
|
||||
// get content id
|
||||
char* fname;
|
||||
fname = strrchr(orig, '/');
|
||||
if (!fname) return 1; // will not happen
|
||||
if (sscanf(++fname, "%08lx", &cnt_id) != 1)
|
||||
return 1; // this won't either
|
||||
|
||||
// find (build fake) content chunk
|
||||
TmdContentChunk* chunk = NULL;
|
||||
if (!tmd) {
|
||||
chunk = content_list;
|
||||
memset(chunk, 0, sizeof(TmdContentChunk));
|
||||
chunk->type[1] = 0x01; // encrypted
|
||||
} else {
|
||||
u32 content_count = getbe16(tmd->content_count);
|
||||
for (u32 i = 0; (i < content_count) && (i < TMD_MAX_CONTENTS); i++) {
|
||||
chunk = &(content_list[i]);
|
||||
if (getbe32(chunk->id) == cnt_id) break;
|
||||
chunk = NULL;
|
||||
}
|
||||
if (!chunk || !(getbe16(chunk->type) & 0x01)) return 1;
|
||||
}
|
||||
|
||||
// actual crypto
|
||||
if (CryptNcchNcsdBossFirmFile(orig, dest, GAME_NUSCDN, crypto, 0, 0, chunk, titlekey) != 0)
|
||||
return 1;
|
||||
|
||||
if (inplace && tmd) {
|
||||
UINT bw; // in that case, write the change to the TMD file, too
|
||||
u32 offset = ((u8*) chunk) - ((u8*) tmd);
|
||||
fvx_qwrite(path_tmd, chunk, offset, sizeof(TmdContentChunk), &bw);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 CryptGameFile(const char* path, bool inplace, bool encrypt) {
|
||||
u32 filetype = IdentifyFileType(path);
|
||||
u16 crypto = encrypt ? CRYPTO_ENCRYPT : CRYPTO_DECRYPT;
|
||||
@ -943,6 +1010,8 @@ u32 CryptGameFile(const char* path, bool inplace, bool encrypt) {
|
||||
|
||||
if (filetype & GAME_CIA)
|
||||
ret = CryptCiaFile(path, destptr, crypto);
|
||||
else if (filetype & GAME_NUSCDN)
|
||||
ret = CryptCdnFile(path, destptr, crypto);
|
||||
else if (filetype & SYS_FIRM)
|
||||
ret = DecryptFirmFile(path, destptr);
|
||||
else if (filetype & (GAME_NCCH|GAME_NCSD|GAME_BOSS))
|
||||
|
@ -627,6 +627,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
||||
(filetype & GAME_ROMFS) ? "Mount as ROMFS image" :
|
||||
(filetype & GAME_TMD) ? "TMD file options..." :
|
||||
(filetype & GAME_BOSS) ? "BOSS file options..." :
|
||||
(filetype & GAME_NUSCDN)? "Decrypt NUS/CDN file" :
|
||||
(filetype & SYS_FIRM) ? "FIRM image options..." :
|
||||
(filetype & BIN_NCCHNFO)? "NCCHinfo options..." :
|
||||
(filetype & BIN_LAUNCH) ? "Launch as arm9 payload" : "???";
|
||||
|
Loading…
x
Reference in New Issue
Block a user