mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 13:42:47 +00:00
Added BOSS file decryption & sverification
This commit is contained in:
parent
0ea8ac2ff1
commit
3f31807c75
@ -51,7 +51,10 @@ u32 IdentifyFileType(const char* path) {
|
|||||||
return SYS_FIRM; // FIRM file
|
return SYS_FIRM; // FIRM file
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((fsize > sizeof(NcchInfoHeader)) &&
|
if ((fsize > sizeof(BossHeader)) &&
|
||||||
|
(ValidateBossHeader((BossHeader*) (void*) header, fsize) == 0)) {
|
||||||
|
return GAME_BOSS; // BOSS (SpotPass) file
|
||||||
|
} else if ((fsize > sizeof(NcchInfoHeader)) &&
|
||||||
(GetNcchInfoVersion((NcchInfoHeader*) (void*) header)) &&
|
(GetNcchInfoVersion((NcchInfoHeader*) (void*) header)) &&
|
||||||
fname && (strncasecmp(fname, NCCHINFO_NAME, 32) == 0)) {
|
fname && (strncasecmp(fname, NCCHINFO_NAME, 32) == 0)) {
|
||||||
return BIN_NCCHNFO; // ncchinfo.bin file
|
return BIN_NCCHNFO; // ncchinfo.bin file
|
||||||
|
@ -10,16 +10,17 @@
|
|||||||
#define GAME_TMD (1<<5)
|
#define GAME_TMD (1<<5)
|
||||||
#define GAME_EXEFS (1<<6)
|
#define GAME_EXEFS (1<<6)
|
||||||
#define GAME_ROMFS (1<<7)
|
#define GAME_ROMFS (1<<7)
|
||||||
#define SYS_FIRM (1<<8)
|
#define GAME_BOSS (1<<8)
|
||||||
#define BIN_NCCHNFO (1<<9)
|
#define SYS_FIRM (1<<9)
|
||||||
#define BIN_LAUNCH (1<<10)
|
#define BIN_NCCHNFO (1<<10)
|
||||||
|
#define BIN_LAUNCH (1<<11)
|
||||||
|
|
||||||
#define FLAG_CXI (1<<30)
|
#define FLAG_CXI (1<<30)
|
||||||
#define FLAG_ENCRYPTED (1<<31)
|
#define FLAG_ENCRYPTED (1<<31)
|
||||||
|
|
||||||
#define FTYPE_MOUNTABLE(tp) (tp&(IMG_FAT|IMG_NAND|GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_EXEFS|GAME_ROMFS|SYS_FIRM))
|
#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|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|SYS_FIRM))
|
#define FYTPE_DECRYPTABLE(tp) (tp&(GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_BOSS|SYS_FIRM))
|
||||||
#define FTYPE_BUILDABLE(tp) (tp&(GAME_NCSD|GAME_NCCH|GAME_TMD))
|
#define FTYPE_BUILDABLE(tp) (tp&(GAME_NCSD|GAME_NCCH|GAME_TMD))
|
||||||
#define FTYPE_BUILDABLE_L(tp) (FTYPE_BUILDABLE(tp) && (tp&(GAME_TMD)))
|
#define FTYPE_BUILDABLE_L(tp) (FTYPE_BUILDABLE(tp) && (tp&(GAME_TMD)))
|
||||||
#define FTYPE_HSINJECTABLE(tp) ((tp&(GAME_NCCH|FLAG_CXI|FLAG_ENCRYPTED)) == (GAME_NCCH|FLAG_CXI))
|
#define FTYPE_HSINJECTABLE(tp) ((tp&(GAME_NCCH|FLAG_CXI|FLAG_ENCRYPTED)) == (GAME_NCCH|FLAG_CXI))
|
||||||
|
96
source/game/boss.c
Normal file
96
source/game/boss.c
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
#include "boss.h"
|
||||||
|
#include "sha.h"
|
||||||
|
#include "aes.h"
|
||||||
|
|
||||||
|
// http://3dbrew.org/wiki/SpotPass#Content_Header
|
||||||
|
u32 CheckBossHash(BossHeader* boss, bool encrypted) {
|
||||||
|
u8 hash_area[0x14] = { 0 };
|
||||||
|
u8 boss_sha256[0x20];
|
||||||
|
u8 l_sha256[0x20];
|
||||||
|
|
||||||
|
// calculate hash
|
||||||
|
memcpy(hash_area, ((u8*) boss) + 0x28, 0x12);
|
||||||
|
memcpy(boss_sha256, boss->hash_header, 0x20);
|
||||||
|
if (encrypted) {
|
||||||
|
CryptBoss(hash_area, 0x28, 0x12, boss);
|
||||||
|
CryptBoss(boss_sha256, 0x28 + 0x12, 0x20, boss);
|
||||||
|
}
|
||||||
|
sha_quick(l_sha256, hash_area, 0x14, SHA256_MODE);
|
||||||
|
|
||||||
|
return (memcmp(boss_sha256, l_sha256, 0x20) == 0) ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 ValidateBossHeader(BossHeader* header, u32 fsize) {
|
||||||
|
u8 boss_magic[] = { BOSS_MAGIC };
|
||||||
|
|
||||||
|
// base checks
|
||||||
|
if ((memcmp(header->magic, boss_magic, sizeof(boss_magic)) != 0) ||
|
||||||
|
(fsize && (fsize != getbe32(header->filesize))) ||
|
||||||
|
(getbe32(header->filesize) > BOSS_MAX_SIZE) ||
|
||||||
|
(getbe32(header->filesize) < sizeof(BossHeader)) ||
|
||||||
|
(getbe16(header->unknown0) != 0x0001) ||
|
||||||
|
(getbe16(header->cnthdr_hash_type) != 0x0002) ||
|
||||||
|
(getbe16(header->cnthdr_rsa_size) != 0x0002))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// hash check
|
||||||
|
if ((CheckBossHash(header, false) != 0) &&
|
||||||
|
(CheckBossHash(header, true) != 0))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 GetBossPayloadHashHeader(u8* header, BossHeader* boss) {
|
||||||
|
memset(header, 0, BOSS_SIZE_PAYLOAD_HEADER);
|
||||||
|
memcpy(header, ((u8*) boss) + 0x15A, 0x1C);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 CheckBossEncrypted(BossHeader* boss) {
|
||||||
|
return CheckBossHash(boss, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// on the fly de-/encryptor for BOSS
|
||||||
|
u32 CryptBoss(u8* data, u32 offset, u32 size, BossHeader* boss) {
|
||||||
|
// check data area (encrypted area starts @0x28)
|
||||||
|
if (offset + size < 0x28) return 0;
|
||||||
|
else if (offset < 0x28) {
|
||||||
|
data += 0x28 - offset;
|
||||||
|
size -= 0x28 - offset;
|
||||||
|
offset = 0x28;
|
||||||
|
}
|
||||||
|
|
||||||
|
// decrypt BOSS data
|
||||||
|
u8 ctr[16] = { 0 };
|
||||||
|
memcpy(ctr, boss->ctr12, 12);
|
||||||
|
ctr[15] = 0x01;
|
||||||
|
use_aeskey(0x38);
|
||||||
|
ctr_decrypt_byte(data, data, size, offset - 0x28, AES_CNT_CTRNAND_MODE, ctr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// on the fly de-/encryptor for BOSS - sequential
|
||||||
|
u32 CryptBossSequential(u8* data, u32 offset, u32 size) {
|
||||||
|
// warning: this will only work for sequential processing
|
||||||
|
// unexpected results otherwise
|
||||||
|
static BossHeader boss = { 0 };
|
||||||
|
static BossHeader* bossptr = NULL;
|
||||||
|
|
||||||
|
// fetch boss header from data
|
||||||
|
if ((offset == 0) && (size >= sizeof(BossHeader))) {
|
||||||
|
bossptr = NULL;
|
||||||
|
memcpy(&boss, data, sizeof(BossHeader));
|
||||||
|
if (((CheckBossEncrypted(&boss) == 0) &&
|
||||||
|
(CryptBoss((u8*) &boss, 0, sizeof(BossHeader), &boss) != 0)) ||
|
||||||
|
(ValidateBossHeader(&boss, 0) != 0))
|
||||||
|
return 1;
|
||||||
|
bossptr = &boss;
|
||||||
|
}
|
||||||
|
|
||||||
|
// safety check, boss pointer
|
||||||
|
if (!bossptr) return 1;
|
||||||
|
|
||||||
|
return CryptBoss(data, offset, size, bossptr);
|
||||||
|
}
|
45
source/game/boss.h
Normal file
45
source/game/boss.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#define BOSS_MAGIC 0x62, 0x6F, 0x73, 0x73, 0x00, 0x01, 0x00, 0x01
|
||||||
|
#define BOSS_MAX_SIZE 0xF0000 // 960 kB, should be more than enough
|
||||||
|
|
||||||
|
#define BOSS_OFFSET_PAYLOAD sizeof(BossHeader)
|
||||||
|
#define BOSS_SIZE_PAYLOAD_HEADER (0x1C + 2)
|
||||||
|
|
||||||
|
// see: http://3dbrew.org/wiki/SpotPass#BOSS_Header
|
||||||
|
// and: http://3dbrew.org/wiki/SpotPass#Content_Header
|
||||||
|
// and: http://3dbrew.org/wiki/SpotPass#Payload_Content_Header
|
||||||
|
// everything is in big endian
|
||||||
|
typedef struct {
|
||||||
|
// actual BOSS header
|
||||||
|
u8 magic[8]; // "boss" + 0x00010001, see above
|
||||||
|
u8 filesize[4]; // big endian
|
||||||
|
u8 release_date[8];
|
||||||
|
u8 unknown0[2]; // always 0x0001
|
||||||
|
u8 padding[2];
|
||||||
|
u8 cnthdr_hash_type[2]; // always 0x0002
|
||||||
|
u8 cnthdr_rsa_size[2]; // always 0x0002
|
||||||
|
u8 ctr12[12]; // first 12 byte of ctr
|
||||||
|
// content header, encryption starts here (0x28)
|
||||||
|
u8 unknown1[0x10]; // usually 0x80 followed by 0x00
|
||||||
|
u8 ext_info[2]; // for generating extdata filepath
|
||||||
|
u8 hash_header[0x20];
|
||||||
|
u8 signature_header[0x100];
|
||||||
|
// payload header, first 0x1C byte used for hash (0x15A)
|
||||||
|
u8 programId[8];
|
||||||
|
u8 unknown2[4]; // typically zero
|
||||||
|
u8 data_type[4];
|
||||||
|
u8 size_payload[4];
|
||||||
|
u8 ns_dataId[4];
|
||||||
|
u8 unknown3[4];
|
||||||
|
u8 hash_payload[0x20];
|
||||||
|
u8 signature_payload[0x100];
|
||||||
|
} __attribute__((packed)) BossHeader;
|
||||||
|
|
||||||
|
u32 ValidateBossHeader(BossHeader* header, u32 fsize);
|
||||||
|
u32 GetBossPayloadHashHeader(u8* header, BossHeader* boss);
|
||||||
|
u32 CheckBossEncrypted(BossHeader* boss);
|
||||||
|
u32 CryptBoss(u8* data, u32 offset, u32 size, BossHeader* boss);
|
||||||
|
u32 CryptBossSequential(u8* data, u32 offset, u32 size);
|
@ -6,4 +6,5 @@
|
|||||||
#include "exefs.h"
|
#include "exefs.h"
|
||||||
#include "romfs.h"
|
#include "romfs.h"
|
||||||
#include "firm.h"
|
#include "firm.h"
|
||||||
|
#include "boss.h"
|
||||||
#include "ncchinfo.h"
|
#include "ncchinfo.h"
|
||||||
|
@ -504,6 +504,48 @@ u32 VerifyFirmFile(const char* path) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 VerifyBossFile(const char* path) {
|
||||||
|
BossHeader* boss = (BossHeader*) TEMP_BUFFER;
|
||||||
|
u8* payload_hdr = MAIN_BUFFER;
|
||||||
|
u8* payload = MAIN_BUFFER + BOSS_SIZE_PAYLOAD_HEADER;
|
||||||
|
u32 payload_size;
|
||||||
|
bool encrypted = false;
|
||||||
|
|
||||||
|
char pathstr[32 + 1];
|
||||||
|
TruncateString(pathstr, path, 32, 8);
|
||||||
|
|
||||||
|
// read file header
|
||||||
|
UINT btr;
|
||||||
|
if ((fvx_qread(path, boss, 0, sizeof(BossHeader), &btr) != FR_OK) ||
|
||||||
|
(btr != sizeof(BossHeader)) || (ValidateBossHeader(boss, 0) != 0)) {
|
||||||
|
ShowPrompt(false, "%s\nError: Not a BOSS file", pathstr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get / check size
|
||||||
|
payload_size = getbe32(boss->filesize) - sizeof(BossHeader);
|
||||||
|
if ((payload_size + BOSS_SIZE_PAYLOAD_HEADER > MAIN_BUFFER_SIZE) || !payload_size)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// check if encrypted, decrypt if required
|
||||||
|
encrypted = (CheckBossEncrypted(boss) == 0);
|
||||||
|
if (encrypted) CryptBoss((u8*) boss, 0, sizeof(BossHeader), boss);
|
||||||
|
|
||||||
|
// actual hash calculation & compare
|
||||||
|
u8 hash[32];
|
||||||
|
memset(MAIN_BUFFER, 0, MAIN_BUFFER_SIZE);
|
||||||
|
GetBossPayloadHashHeader(payload_hdr, boss);
|
||||||
|
fvx_qread(path, payload, sizeof(BossHeader), payload_size, &btr);
|
||||||
|
if (encrypted) CryptBoss(payload, sizeof(BossHeader), payload_size, boss);
|
||||||
|
sha_quick(hash, MAIN_BUFFER, payload_size + BOSS_SIZE_PAYLOAD_HEADER, SHA256_MODE);
|
||||||
|
if (memcmp(hash, boss->hash_payload, 0x20) != 0) {
|
||||||
|
ShowPrompt(false, "%s\nBOSS payload hash mismatch", pathstr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
u32 VerifyGameFile(const char* path) {
|
u32 VerifyGameFile(const char* path) {
|
||||||
u32 filetype = IdentifyFileType(path);
|
u32 filetype = IdentifyFileType(path);
|
||||||
if (filetype & GAME_CIA)
|
if (filetype & GAME_CIA)
|
||||||
@ -514,6 +556,8 @@ u32 VerifyGameFile(const char* path) {
|
|||||||
return VerifyNcchFile(path, 0, 0);
|
return VerifyNcchFile(path, 0, 0);
|
||||||
else if (filetype & GAME_TMD)
|
else if (filetype & GAME_TMD)
|
||||||
return VerifyTmdFile(path);
|
return VerifyTmdFile(path);
|
||||||
|
else if (filetype & GAME_BOSS)
|
||||||
|
return VerifyBossFile(path);
|
||||||
else if (filetype & SYS_FIRM)
|
else if (filetype & SYS_FIRM)
|
||||||
return VerifyFirmFile(path);
|
return VerifyFirmFile(path);
|
||||||
else return 1;
|
else return 1;
|
||||||
@ -598,6 +642,19 @@ u32 CheckEncryptedFirmFile(const char* path) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 CheckEncryptedBossFile(const char* path) {
|
||||||
|
BossHeader* boss = (BossHeader*) TEMP_BUFFER;
|
||||||
|
UINT btr;
|
||||||
|
|
||||||
|
// get boss header
|
||||||
|
if ((fvx_qread(path, boss, 0, sizeof(BossHeader), &btr) != FR_OK) ||
|
||||||
|
(btr != sizeof(BossHeader))) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CheckBossEncrypted(boss);
|
||||||
|
}
|
||||||
|
|
||||||
u32 CheckEncryptedGameFile(const char* path) {
|
u32 CheckEncryptedGameFile(const char* path) {
|
||||||
u32 filetype = IdentifyFileType(path);
|
u32 filetype = IdentifyFileType(path);
|
||||||
if (filetype & GAME_CIA)
|
if (filetype & GAME_CIA)
|
||||||
@ -606,12 +663,14 @@ u32 CheckEncryptedGameFile(const char* path) {
|
|||||||
return CheckEncryptedNcsdFile(path);
|
return CheckEncryptedNcsdFile(path);
|
||||||
else if (filetype & GAME_NCCH)
|
else if (filetype & GAME_NCCH)
|
||||||
return CheckEncryptedNcchFile(path, 0);
|
return CheckEncryptedNcchFile(path, 0);
|
||||||
|
else if (filetype & GAME_BOSS)
|
||||||
|
return CheckEncryptedBossFile(path);
|
||||||
else if (filetype & SYS_FIRM)
|
else if (filetype & SYS_FIRM)
|
||||||
return CheckEncryptedFirmFile(path);
|
return CheckEncryptedFirmFile(path);
|
||||||
else return 1;
|
else return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 CryptNcchNcsdFirmFile(const char* orig, const char* dest, u32 mode, u16 crypto, // crypto only relevant for NCCH
|
u32 CryptNcchNcsdBossFirmFile(const char* orig, const char* dest, u32 mode, u16 crypto, // crypto only relevant for NCCH
|
||||||
u32 offset, u32 size, TmdContentChunk* chunk, const u8* titlekey) { // this line only for CIA contents
|
u32 offset, u32 size, TmdContentChunk* chunk, const u8* titlekey) { // this line only for CIA contents
|
||||||
// this will do a simple copy for unencrypted files
|
// this will do a simple copy for unencrypted files
|
||||||
bool inplace = (strncmp(orig, dest, 256) == 0);
|
bool inplace = (strncmp(orig, dest, 256) == 0);
|
||||||
@ -642,13 +701,14 @@ u32 CryptNcchNcsdFirmFile(const char* orig, const char* dest, u32 mode, u16 cryp
|
|||||||
|
|
||||||
u32 ret = 0;
|
u32 ret = 0;
|
||||||
if (!ShowProgress(offset, fsize, dest)) ret = 1;
|
if (!ShowProgress(offset, fsize, dest)) ret = 1;
|
||||||
if (mode & (GAME_NCCH|GAME_NCSD|SYS_FIRM)) { // for NCCH / NCSD / FIRM files
|
if (mode & (GAME_NCCH|GAME_NCSD|GAME_BOSS|SYS_FIRM)) { // for NCCH / NCSD / FIRM files
|
||||||
for (u32 i = 0; (i < size) && (ret == 0); i += MAIN_BUFFER_SIZE) {
|
for (u32 i = 0; (i < size) && (ret == 0); i += MAIN_BUFFER_SIZE) {
|
||||||
u32 read_bytes = min(MAIN_BUFFER_SIZE, (size - i));
|
u32 read_bytes = min(MAIN_BUFFER_SIZE, (size - i));
|
||||||
UINT bytes_read, bytes_written;
|
UINT bytes_read, bytes_written;
|
||||||
if (fvx_read(ofp, MAIN_BUFFER, read_bytes, &bytes_read) != FR_OK) ret = 1;
|
if (fvx_read(ofp, MAIN_BUFFER, read_bytes, &bytes_read) != FR_OK) ret = 1;
|
||||||
if (((mode & GAME_NCCH) && (CryptNcchSequential(MAIN_BUFFER, i, read_bytes, crypto) != 0)) ||
|
if (((mode & GAME_NCCH) && (CryptNcchSequential(MAIN_BUFFER, i, read_bytes, crypto) != 0)) ||
|
||||||
((mode & GAME_NCSD) && (DecryptNcsdSequential(MAIN_BUFFER, i, read_bytes) != 0)) ||
|
((mode & GAME_NCSD) && (DecryptNcsdSequential(MAIN_BUFFER, i, read_bytes) != 0)) ||
|
||||||
|
((mode & GAME_BOSS) && (CryptBossSequential(MAIN_BUFFER, i, read_bytes) != 0)) ||
|
||||||
((mode & SYS_FIRM) && (DecryptFirmSequential(MAIN_BUFFER, i, read_bytes) != 0)))
|
((mode & SYS_FIRM) && (DecryptFirmSequential(MAIN_BUFFER, i, read_bytes) != 0)))
|
||||||
ret = 1;
|
ret = 1;
|
||||||
if (inplace) fvx_lseek(ofp, fvx_tell(ofp) - read_bytes);
|
if (inplace) fvx_lseek(ofp, fvx_tell(ofp) - read_bytes);
|
||||||
@ -719,7 +779,7 @@ u32 DecryptCiaFile(const char* orig, const char* dest) {
|
|||||||
for (u32 i = 0; (i < content_count) && (i < TMD_MAX_CONTENTS); i++) {
|
for (u32 i = 0; (i < content_count) && (i < TMD_MAX_CONTENTS); i++) {
|
||||||
TmdContentChunk* chunk = &(cia->content_list[i]);
|
TmdContentChunk* chunk = &(cia->content_list[i]);
|
||||||
u64 size = getbe64(chunk->size);
|
u64 size = getbe64(chunk->size);
|
||||||
if (CryptNcchNcsdFirmFile(orig, dest, GAME_CIA, NCCH_NOCRYPTO, next_offset, size, chunk, titlekey) != 0)
|
if (CryptNcchNcsdBossFirmFile(orig, dest, GAME_CIA, NCCH_NOCRYPTO, next_offset, size, chunk, titlekey) != 0)
|
||||||
return 1;
|
return 1;
|
||||||
next_offset += size;
|
next_offset += size;
|
||||||
}
|
}
|
||||||
@ -738,7 +798,7 @@ u32 DecryptFirmFile(const char* orig, const char* dest) {
|
|||||||
UINT btr;
|
UINT btr;
|
||||||
|
|
||||||
// actual decryption
|
// actual decryption
|
||||||
if (CryptNcchNcsdFirmFile(orig, dest, SYS_FIRM, NCCH_NOCRYPTO, 0, 0, NULL, NULL) != 0)
|
if (CryptNcchNcsdBossFirmFile(orig, dest, SYS_FIRM, 0, 0, 0, NULL, NULL) != 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
// open destination file, get FIRM header
|
// open destination file, get FIRM header
|
||||||
@ -814,8 +874,8 @@ u32 DecryptGameFile(const char* path, bool inplace) {
|
|||||||
ret = DecryptCiaFile(path, destptr);
|
ret = DecryptCiaFile(path, destptr);
|
||||||
else if (filetype & SYS_FIRM)
|
else if (filetype & SYS_FIRM)
|
||||||
ret = DecryptFirmFile(path, destptr);
|
ret = DecryptFirmFile(path, destptr);
|
||||||
else if (filetype & (GAME_NCCH|GAME_NCSD))
|
else if (filetype & (GAME_NCCH|GAME_NCSD|GAME_BOSS))
|
||||||
ret = CryptNcchNcsdFirmFile(path, destptr, filetype, NCCH_NOCRYPTO, 0, 0, NULL, NULL);
|
ret = CryptNcchNcsdBossFirmFile(path, destptr, filetype, NCCH_NOCRYPTO, 0, 0, NULL, NULL);
|
||||||
else ret = 1;
|
else ret = 1;
|
||||||
|
|
||||||
if (!inplace && (ret != 0))
|
if (!inplace && (ret != 0))
|
||||||
@ -1239,9 +1299,9 @@ u32 InjectHealthAndSafety(const char* path, const char* destdrv) {
|
|||||||
if (f_rename(path_cxi, path_bak) != FR_OK) return 1;
|
if (f_rename(path_cxi, path_bak) != FR_OK) return 1;
|
||||||
} else f_unlink(path_cxi);
|
} else f_unlink(path_cxi);
|
||||||
|
|
||||||
// copy the source CXI
|
// copy / decrypt the source CXI
|
||||||
u32 ret = 0;
|
u32 ret = 0;
|
||||||
if (CryptNcchNcsdFirmFile(path, path_cxi, GAME_NCCH, NCCH_NOCRYPTO, 0, 0, NULL, NULL) != 0)
|
if (CryptNcchNcsdBossFirmFile(path, path_cxi, GAME_NCCH, NCCH_NOCRYPTO, 0, 0, NULL, NULL) != 0)
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
|
||||||
// fix up the injected H&S NCCH header (copy H&S signature, title ID)
|
// fix up the injected H&S NCCH header (copy H&S signature, title ID)
|
||||||
@ -1256,10 +1316,10 @@ u32 InjectHealthAndSafety(const char* path, const char* destdrv) {
|
|||||||
} else ret = 1;
|
} else ret = 1;
|
||||||
|
|
||||||
// encrypt the CXI in place
|
// encrypt the CXI in place
|
||||||
if (CryptNcchNcsdFirmFile(path_cxi, path_cxi, GAME_NCCH, crypto, 0, 0, NULL, NULL) != 0)
|
if (CryptNcchNcsdBossFirmFile(path_cxi, path_cxi, GAME_NCCH, crypto, 0, 0, NULL, NULL) != 0)
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
|
||||||
if (ret != 0) { // try recover
|
if (ret != 0) { // in case of failure: try recover
|
||||||
f_unlink(path_cxi);
|
f_unlink(path_cxi);
|
||||||
f_rename(path_bak, path_cxi);
|
f_rename(path_bak, path_cxi);
|
||||||
}
|
}
|
||||||
|
@ -625,8 +625,9 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
(filetype & GAME_EXEFS) ? "Mount as EXEFS image" :
|
(filetype & GAME_EXEFS) ? "Mount as EXEFS image" :
|
||||||
(filetype & GAME_ROMFS) ? "Mount as ROMFS image" :
|
(filetype & GAME_ROMFS) ? "Mount as ROMFS image" :
|
||||||
(filetype & GAME_TMD) ? "TMD file options..." :
|
(filetype & GAME_TMD) ? "TMD file options..." :
|
||||||
|
(filetype & GAME_BOSS) ? "BOSS file options..." :
|
||||||
(filetype & SYS_FIRM) ? "FIRM image options..." :
|
(filetype & SYS_FIRM) ? "FIRM image options..." :
|
||||||
(filetype & BIN_NCCHNFO) ? "NCCHinfo options..." :
|
(filetype & BIN_NCCHNFO)? "NCCHinfo options..." :
|
||||||
(filetype & BIN_LAUNCH) ? "Launch as arm9 payload" : "???";
|
(filetype & BIN_LAUNCH) ? "Launch as arm9 payload" : "???";
|
||||||
optionstr[hexviewer-1] = "Show in Hexeditor";
|
optionstr[hexviewer-1] = "Show in Hexeditor";
|
||||||
optionstr[calcsha-1] = "Calculate SHA-256";
|
optionstr[calcsha-1] = "Calculate SHA-256";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user