mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 13:42:47 +00:00
parent
f51a48c39e
commit
21fdb9543a
@ -98,10 +98,14 @@ u64 IdentifyFileType(const char* path) {
|
|||||||
} else if (memcmp(header, smdh_magic, sizeof(smdh_magic)) == 0) {
|
} else if (memcmp(header, smdh_magic, sizeof(smdh_magic)) == 0) {
|
||||||
return GAME_SMDH; // SMDH file
|
return GAME_SMDH; // SMDH file
|
||||||
} else if (ValidateTwlHeader((TwlHeader*) data) == 0) {
|
} else if (ValidateTwlHeader((TwlHeader*) data) == 0) {
|
||||||
if (((TwlHeader*)data)->ntr_rom_size <= fsize)
|
TwlHeader* twl = (TwlHeader*) data;
|
||||||
|
if (twl->ntr_rom_size <= fsize) { // NDS rom file
|
||||||
|
if ((twl->unit_code == 0x03) && !twl->twl_rom_region_start)
|
||||||
|
return GAME_NDS | FLAG_DSIW; // NDS DSiWare rom file
|
||||||
return GAME_NDS; // NDS rom file
|
return GAME_NDS; // NDS rom file
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (GetFontFromPbm(data, fsize, NULL, NULL)) {
|
if (GetFontFromPbm(data, fsize, NULL, NULL)) {
|
||||||
return FONT_PBM;
|
return FONT_PBM;
|
||||||
|
@ -35,8 +35,9 @@
|
|||||||
#define HDR_NAND (1ULL<<30)
|
#define HDR_NAND (1ULL<<30)
|
||||||
#define TYPE_BASE 0xFFFFFFFFULL // 32 bit reserved for base types
|
#define TYPE_BASE 0xFFFFFFFFULL // 32 bit reserved for base types
|
||||||
|
|
||||||
// #define FLAG_FIRM (1ULL<<58) // <--- for CXIs containing FIRMs
|
// #define FLAG_FIRM (1ULL<<57) // <--- for CXIs containing FIRMs
|
||||||
// #define FLAG_GBAVC (1ULL<<59) // <--- for GBAVC CXIs
|
// #define FLAG_GBAVC (1ULL<<58) // <--- for GBAVC CXIs
|
||||||
|
#define FLAG_DSIW (1ULL<<59)
|
||||||
#define FLAG_ENC (1ULL<<60)
|
#define FLAG_ENC (1ULL<<60)
|
||||||
#define FLAG_CTR (1ULL<<61)
|
#define FLAG_CTR (1ULL<<61)
|
||||||
#define FLAG_NUSCDN (1ULL<<62)
|
#define FLAG_NUSCDN (1ULL<<62)
|
||||||
@ -46,7 +47,7 @@
|
|||||||
#define FTYPE_VERIFICABLE(tp) (tp&(IMG_NAND|GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_TMD|GAME_BOSS|SYS_FIRM))
|
#define FTYPE_VERIFICABLE(tp) (tp&(IMG_NAND|GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_TMD|GAME_BOSS|SYS_FIRM))
|
||||||
#define FTYPE_DECRYPTABLE(tp) (tp&(GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_BOSS|GAME_NUSCDN|SYS_FIRM|BIN_KEYDB))
|
#define FTYPE_DECRYPTABLE(tp) (tp&(GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_BOSS|GAME_NUSCDN|SYS_FIRM|BIN_KEYDB))
|
||||||
#define FTYPE_ENCRYPTABLE(tp) (tp&(GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_BOSS|BIN_KEYDB))
|
#define FTYPE_ENCRYPTABLE(tp) (tp&(GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_BOSS|BIN_KEYDB))
|
||||||
#define FTYPE_CIABUILD(tp) (tp&(GAME_NCSD|GAME_NCCH|GAME_TMD))
|
#define FTYPE_CIABUILD(tp) ((tp&(GAME_NCSD|GAME_NCCH|GAME_TMD)) || ((tp&GAME_NDS)&&(tp&(FLAG_DSIW))))
|
||||||
#define FTYPE_CIABUILD_L(tp) (FTYPE_CIABUILD(tp) && (tp&(GAME_TMD)))
|
#define FTYPE_CIABUILD_L(tp) (FTYPE_CIABUILD(tp) && (tp&(GAME_TMD)))
|
||||||
#define FTYPE_CXIDUMP(tp) (tp&(GAME_TMD))
|
#define FTYPE_CXIDUMP(tp) (tp&(GAME_TMD))
|
||||||
#define FTYPE_TIKBUILD(tp) (tp&(GAME_TICKET|SYS_TICKDB|BIN_TIKDB))
|
#define FTYPE_TIKBUILD(tp) (tp&(GAME_TICKET|SYS_TICKDB|BIN_TIKDB))
|
||||||
|
@ -90,7 +90,11 @@ typedef struct {
|
|||||||
u64 secure_area_disable;
|
u64 secure_area_disable;
|
||||||
u32 ntr_rom_size; // in byte
|
u32 ntr_rom_size; // in byte
|
||||||
u32 header_size;
|
u32 header_size;
|
||||||
u8 reserved1[56];
|
u32 arm9_param_tbl_offset;
|
||||||
|
u32 arm7_param_tbl_offset;
|
||||||
|
u16 ntr_rom_region_end;
|
||||||
|
u16 twl_rom_region_start;
|
||||||
|
u8 reserved1[44];
|
||||||
u8 logo[156];
|
u8 logo[156];
|
||||||
u16 logo_crc;
|
u16 logo_crc;
|
||||||
u16 header_crc;
|
u16 header_crc;
|
||||||
|
@ -76,7 +76,7 @@ u32 FixTmdHashes(TitleMetaData* tmd) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 BuildFakeTmd(TitleMetaData* tmd, u8* title_id, u32 n_contents, u32 save_size) {
|
u32 BuildFakeTmd(TitleMetaData* tmd, u8* title_id, u32 n_contents, u32 save_size, u32 twl_privsave_size) {
|
||||||
const u8 sig_type[4] = { TMD_SIG_TYPE };
|
const u8 sig_type[4] = { TMD_SIG_TYPE };
|
||||||
// safety check: number of contents
|
// safety check: number of contents
|
||||||
if (n_contents > TMD_MAX_CONTENTS) return 1; // potential incompatibility here (!)
|
if (n_contents > TMD_MAX_CONTENTS) return 1; // potential incompatibility here (!)
|
||||||
@ -89,7 +89,8 @@ u32 BuildFakeTmd(TitleMetaData* tmd, u8* title_id, u32 n_contents, u32 save_size
|
|||||||
tmd->version = 0x01;
|
tmd->version = 0x01;
|
||||||
memcpy(tmd->title_id, title_id, 8);
|
memcpy(tmd->title_id, title_id, 8);
|
||||||
tmd->title_type[3] = 0x40; // whatever
|
tmd->title_type[3] = 0x40; // whatever
|
||||||
for (u32 i = 0; i < 4; i++) tmd->save_size[i] = (save_size >> (i*8)) & 0xFF; // little endian?
|
for (u32 i = 0; i < 4; i++) tmd->save_size[i] = (save_size >> (i*8)) & 0xFF; // le save size
|
||||||
|
for (u32 i = 0; i < 4; i++) tmd->twl_privsave_size[i] = (twl_privsave_size >> (i*8)) & 0xFF; // le privsave size
|
||||||
tmd->content_count[0] = (u8) ((n_contents >> 8) & 0xFF);
|
tmd->content_count[0] = (u8) ((n_contents >> 8) & 0xFF);
|
||||||
tmd->content_count[1] = (u8) (n_contents & 0xFF);
|
tmd->content_count[1] = (u8) (n_contents & 0xFF);
|
||||||
memset(tmd->contentinfo_hash, 0xFF, 0x20); // placeholder (hash)
|
memset(tmd->contentinfo_hash, 0xFF, 0x20); // placeholder (hash)
|
||||||
|
@ -62,5 +62,5 @@ u32 ValidateTmdSignature(TitleMetaData* tmd);
|
|||||||
u32 VerifyTmd(TitleMetaData* tmd);
|
u32 VerifyTmd(TitleMetaData* tmd);
|
||||||
u32 GetTmdCtr(u8* ctr, TmdContentChunk* chunk);
|
u32 GetTmdCtr(u8* ctr, TmdContentChunk* chunk);
|
||||||
u32 FixTmdHashes(TitleMetaData* tmd);
|
u32 FixTmdHashes(TitleMetaData* tmd);
|
||||||
u32 BuildFakeTmd(TitleMetaData* tmd, u8* title_id, u32 n_contents, u32 save_size);
|
u32 BuildFakeTmd(TitleMetaData* tmd, u8* title_id, u32 n_contents, u32 save_size, u32 twl_privsave_size);
|
||||||
u32 BuildTmdCert(u8* tmdcert);
|
u32 BuildTmdCert(u8* tmdcert);
|
||||||
|
@ -1453,7 +1453,7 @@ u32 BuildCiaFromNcchFile(const char* path_ncch, const char* path_cia) {
|
|||||||
if ((BuildCiaHeader(&(cia->header)) != 0) ||
|
if ((BuildCiaHeader(&(cia->header)) != 0) ||
|
||||||
(BuildCiaCert(cia->cert) != 0) ||
|
(BuildCiaCert(cia->cert) != 0) ||
|
||||||
(BuildFakeTicket(&(cia->ticket), title_id) != 0) ||
|
(BuildFakeTicket(&(cia->ticket), title_id) != 0) ||
|
||||||
(BuildFakeTmd(&(cia->tmd), title_id, 1, save_size)) ||
|
(BuildFakeTmd(&(cia->tmd), title_id, 1, save_size, 0)) ||
|
||||||
(FixCiaHeaderForTmd(&(cia->header), &(cia->tmd)) != 0) ||
|
(FixCiaHeaderForTmd(&(cia->header), &(cia->tmd)) != 0) ||
|
||||||
(WriteCiaStub(cia, path_cia) != 0)) {
|
(WriteCiaStub(cia, path_cia) != 0)) {
|
||||||
free(cia);
|
free(cia);
|
||||||
@ -1519,7 +1519,7 @@ u32 BuildCiaFromNcsdFile(const char* path_ncsd, const char* path_cia) {
|
|||||||
if ((BuildCiaHeader(&(cia->header)) != 0) ||
|
if ((BuildCiaHeader(&(cia->header)) != 0) ||
|
||||||
(BuildCiaCert(cia->cert) != 0) ||
|
(BuildCiaCert(cia->cert) != 0) ||
|
||||||
(BuildFakeTicket(&(cia->ticket), title_id) != 0) ||
|
(BuildFakeTicket(&(cia->ticket), title_id) != 0) ||
|
||||||
(BuildFakeTmd(&(cia->tmd), title_id, content_count, save_size)) ||
|
(BuildFakeTmd(&(cia->tmd), title_id, content_count, save_size, 0)) ||
|
||||||
(FixCiaHeaderForTmd(&(cia->header), &(cia->tmd)) != 0) ||
|
(FixCiaHeaderForTmd(&(cia->header), &(cia->tmd)) != 0) ||
|
||||||
(WriteCiaStub(cia, path_cia) != 0)) {
|
(WriteCiaStub(cia, path_cia) != 0)) {
|
||||||
free(cia);
|
free(cia);
|
||||||
@ -1562,6 +1562,69 @@ u32 BuildCiaFromNcsdFile(const char* path_ncsd, const char* path_cia) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 BuildCiaFromNdsFile(const char* path_nds, const char* path_cia) {
|
||||||
|
TwlHeader twl;
|
||||||
|
u8 title_id[8];
|
||||||
|
u32 save_size = 0;
|
||||||
|
u32 privsave_size = 0;
|
||||||
|
|
||||||
|
// Init progress bar
|
||||||
|
if (!ShowProgress(0, 0, path_nds)) return 1;
|
||||||
|
|
||||||
|
// load TWL header, get save sizes && title id
|
||||||
|
if (fvx_qread(path_nds, &twl, 0, sizeof(TwlHeader), NULL) != FR_OK)
|
||||||
|
return 1;
|
||||||
|
for (u32 i = 0; i < 8; i++)
|
||||||
|
title_id[i] = (twl.title_id >> ((7-i)*8)) & 0xFF;
|
||||||
|
save_size = twl.pubsav_size;
|
||||||
|
privsave_size = twl.prvsav_size;
|
||||||
|
|
||||||
|
// some basic sanity checks
|
||||||
|
// see: https://problemkaputt.de/gbatek.htm#dsicartridgeheader
|
||||||
|
// (gamecart dumps are not allowed)
|
||||||
|
u8 tidhigh_dsiware[4] = { 0x00, 0x03, 0x00, 0x04 };
|
||||||
|
if ((memcmp(title_id, tidhigh_dsiware, 3) != 0) || !title_id[3])
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// convert DSi title ID to 3DS title ID
|
||||||
|
u8 tidhigh_3ds[4] = { 0x00, 0x04, 0x80, 0x04 };
|
||||||
|
memcpy(title_id, tidhigh_3ds, 3);
|
||||||
|
|
||||||
|
// build the CIA stub
|
||||||
|
CiaStub* cia = (CiaStub*) malloc(sizeof(CiaStub));
|
||||||
|
if (!cia) return 1;
|
||||||
|
memset(cia, 0, sizeof(CiaStub));
|
||||||
|
if ((BuildCiaHeader(&(cia->header)) != 0) ||
|
||||||
|
(BuildCiaCert(cia->cert) != 0) ||
|
||||||
|
(BuildFakeTicket(&(cia->ticket), title_id) != 0) ||
|
||||||
|
(BuildFakeTmd(&(cia->tmd), title_id, 1, save_size, privsave_size)) ||
|
||||||
|
(FixCiaHeaderForTmd(&(cia->header), &(cia->tmd)) != 0) ||
|
||||||
|
(WriteCiaStub(cia, path_cia) != 0)) {
|
||||||
|
free(cia);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert NDS content
|
||||||
|
TmdContentChunk* chunk = cia->content_list;
|
||||||
|
memset(chunk, 0, sizeof(TmdContentChunk)); // nothing else to do
|
||||||
|
if (InsertCiaContent(path_cia, path_nds, 0, 0, chunk, NULL, false, false, false) != 0) {
|
||||||
|
free(cia);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the CIA stub (take #2)
|
||||||
|
FindTitleKey((&cia->ticket), title_id);
|
||||||
|
if ((FixTmdHashes(&(cia->tmd)) != 0) ||
|
||||||
|
(FixCiaHeaderForTmd(&(cia->header), &(cia->tmd)) != 0) ||
|
||||||
|
(WriteCiaStub(cia, path_cia) != 0)) {
|
||||||
|
free(cia);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(cia);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
u32 BuildCiaFromGameFile(const char* path, bool force_legit) {
|
u32 BuildCiaFromGameFile(const char* path, bool force_legit) {
|
||||||
u64 filetype = IdentifyFileType(path);
|
u64 filetype = IdentifyFileType(path);
|
||||||
char dest[256];
|
char dest[256];
|
||||||
@ -1596,6 +1659,8 @@ u32 BuildCiaFromGameFile(const char* path, bool force_legit) {
|
|||||||
ret = BuildCiaFromNcchFile(path, dest);
|
ret = BuildCiaFromNcchFile(path, dest);
|
||||||
else if (filetype & GAME_NCSD)
|
else if (filetype & GAME_NCSD)
|
||||||
ret = BuildCiaFromNcsdFile(path, dest);
|
ret = BuildCiaFromNcsdFile(path, dest);
|
||||||
|
else if ((filetype & GAME_NDS) && (filetype & FLAG_DSIW))
|
||||||
|
ret = BuildCiaFromNdsFile(path, dest);
|
||||||
else ret = 1;
|
else ret = 1;
|
||||||
|
|
||||||
if (ret != 0) // try to get rid of the borked file
|
if (ret != 0) // try to get rid of the borked file
|
||||||
|
Loading…
x
Reference in New Issue
Block a user