Skip to content

Commit

Permalink
Allow fixing improperly decrypted NCSD/NCCH
Browse files Browse the repository at this point in the history
... use "verify" for this. Also, there's a hint now when trying to CIA convert such files.
  • Loading branch information
d0k3 committed Jan 2, 2020
1 parent 940284c commit 98c1b25
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 23 deletions.
13 changes: 12 additions & 1 deletion arm9/source/godmode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1524,12 +1524,23 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
else ShowPrompt(false, "%lu/%lu %ss built ok", n_success, n_marked, type);
if (n_success) ShowPrompt(false, "%lu files written to %s", n_success, OUTPUT_PATH);
if (n_success && in_output_path) GetDirContents(current_dir, current_path);
if (n_success != (n_marked - n_other)) {
ShowPrompt(false, "%lu file(s) failed conversion.\nVerification is recommended.",
n_marked - (n_success + n_other));
}
} else {
if (((user_select != cxi_dump) && (BuildCiaFromGameFile(file_path, force_legit) == 0)) ||
((user_select == cxi_dump) && (DumpCxiSrlFromTmdFile(file_path) == 0))) {
ShowPrompt(false, "%s\n%s built to %s", pathstr, type, OUTPUT_PATH);
if (in_output_path) GetDirContents(current_dir, current_path);
} else ShowPrompt(false, "%s\n%s build failed", pathstr, type);
} else {
ShowPrompt(false, "%s\n%s build failed", pathstr, type);
if ((filetype & (GAME_NCCH|GAME_NCSD)) &&
ShowPrompt(true, "%s\nfile failed conversion.\n \nVerify now?", pathstr)) {
ShowPrompt(false, "%s\nVerification %s", pathstr,
(VerifyGameFile(file_path) == 0) ? "success" : "failed");
}
}
}
return 0;
}
Expand Down
63 changes: 41 additions & 22 deletions arm9/source/utils/gameutil.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@
#define CRYPTO_DECRYPT NCCH_NOCRYPTO
#define CRYPTO_ENCRYPT NCCH_STDCRYPTO

u32 GetNcchHeaders(NcchHeader* ncch, NcchExtHeader* exthdr, ExeFsHeader* exefs, FIL* file) {
u32 GetNcchHeaders(NcchHeader* ncch, NcchExtHeader* exthdr, ExeFsHeader* exefs, FIL* file, bool nocrypto) {
u32 offset_ncch = fvx_tell(file);
UINT btr;

if ((fvx_read(file, ncch, sizeof(NcchHeader), &btr) != FR_OK) ||
(ValidateNcchHeader(ncch) != 0))
return 1;

if (fvx_read(file, ncch, sizeof(NcchHeader), &btr) != FR_OK) return 1;
if (nocrypto) {
ncch->flags[3] = 0x00;
ncch->flags[7] = (ncch->flags[7] & ~0x21) | 0x04;
}
if (ValidateNcchHeader(ncch) != 0) return 1;

if (exthdr) {
if (!ncch->size_exthdr) return 1;
Expand Down Expand Up @@ -71,7 +74,7 @@ u32 LoadNcchHeaders(NcchHeader* ncch, NcchExtHeader* exthdr, ExeFsHeader* exefs,
if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
return 1;
fvx_lseek(&file, offset);
if (GetNcchHeaders(ncch, exthdr, exefs, &file) != 0) {
if (GetNcchHeaders(ncch, exthdr, exefs, &file, false) != 0) {
fvx_close(&file);
return 1;
}
Expand Down Expand Up @@ -137,7 +140,7 @@ u32 LoadExeFsFile(void* data, const char* path, u32 offset, const char* name, u3
if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
return 1;
fvx_lseek(&file, offset);
if ((GetNcchHeaders(&ncch, NULL, &exefs, &file) != 0) ||
if ((GetNcchHeaders(&ncch, NULL, &exefs, &file, false) != 0) ||
(!ncch.size_exefs)) {
fvx_close(&file);
return 1;
Expand Down Expand Up @@ -304,6 +307,7 @@ u32 VerifyTmdContent(const char* path, u64 offset, TmdContentChunk* chunk, const
}

u32 VerifyNcchFile(const char* path, u32 offset, u32 size) {
bool cryptofix = false;
NcchHeader ncch;
NcchExtHeader exthdr;
ExeFsHeader exefs;
Expand All @@ -316,35 +320,49 @@ u32 VerifyNcchFile(const char* path, u32 offset, u32 size) {
if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
return 1;

// fetch and check NCCH header
fvx_lseek(&file, offset);
if (GetNcchHeaders(&ncch, NULL, NULL, &file) != 0) {
if (GetNcchHeaders(&ncch, NULL, NULL, &file, cryptofix) != 0) {
if (!offset) ShowPrompt(false, "%s\nError: Not a NCCH file", pathstr);
fvx_close(&file);
return 1;
}

fvx_lseek(&file, offset);
if (ncch.size_exthdr && (GetNcchHeaders(&ncch, &exthdr, NULL, &file) != 0)) {
if (!offset) ShowPrompt(false, "%s\nError: Missing ExtHeader", pathstr);

// check NCCH size
if (!size) size = fvx_size(&file) - offset;
if ((fvx_size(&file) < offset) || (size < ncch.size * NCCH_MEDIA_UNIT)) {
if (!offset) ShowPrompt(false, "%s\nError: File is too small", pathstr);
fvx_close(&file);
return 1;
}

// fetch and check ExeFS header
fvx_lseek(&file, offset);
if (ncch.size_exefs && (GetNcchHeaders(&ncch, NULL, &exefs, &file) != 0)) {
if (!offset) ShowPrompt(false, "%s\nError: Bad ExeFS header", pathstr);
fvx_close(&file);
return 1;
if (ncch.size_exefs && (GetNcchHeaders(&ncch, NULL, &exefs, &file, cryptofix) != 0)) {
bool borkedflags = false;
if (ncch.size_exefs && NCCH_ENCRYPTED(&ncch)) {
// disable crypto, try again
cryptofix = true;
fvx_lseek(&file, offset);
if ((GetNcchHeaders(&ncch, NULL, &exefs, &file, cryptofix) == 0) &&
ShowPrompt(true, "%s\nError: Bad crypto flags\n \nAttempt to fix?", pathstr))
borkedflags = true;
}
if (!borkedflags) {
if (!offset) ShowPrompt(false, "%s\nError: Bad ExeFS header", pathstr);
fvx_close(&file);
return 1;
}
}
// size checks
if (!size) size = fvx_size(&file) - offset;
if ((fvx_size(&file) < offset) || (size < ncch.size * NCCH_MEDIA_UNIT)) {
if (!offset) ShowPrompt(false, "%s\nError: File is too small", pathstr);

// fetch and check ExtHeader
fvx_lseek(&file, offset);
if (ncch.size_exthdr && (GetNcchHeaders(&ncch, &exthdr, NULL, &file, cryptofix) != 0)) {
if (!offset) ShowPrompt(false, "%s\nError: Missing ExtHeader", pathstr);
fvx_close(&file);
return 1;
}

// check / setup crypto
if (SetupNcchCrypto(&ncch, NCCH_NOCRYPTO) != 0) {
if (!offset) ShowPrompt(false, "%s\nError: Crypto not set up", pathstr);
Expand Down Expand Up @@ -481,6 +499,7 @@ u32 VerifyNcchFile(const char* path, u32 offset, u32 size) {
}

fvx_close(&file);
if (cryptofix) fvx_qwrite(path, &ncch, offset, sizeof(NcchHeader), NULL);
return ver_exthdr|ver_exefs|ver_romfs;
}

Expand Down

0 comments on commit 98c1b25

Please sign in to comment.