mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 21:52:48 +00:00
Added CMAC and GBA VC inject support for SD AGBSAVEs
This commit is contained in:
parent
9dc8105e9c
commit
c24a654cb9
@ -860,7 +860,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
bool bootable = (FTYPE_BOOTABLE(filetype));
|
bool bootable = (FTYPE_BOOTABLE(filetype));
|
||||||
bool installable = (FTYPE_INSTALLABLE(filetype));
|
bool installable = (FTYPE_INSTALLABLE(filetype));
|
||||||
bool agbexportable = (FTPYE_AGBSAVE(filetype));
|
bool agbexportable = (FTPYE_AGBSAVE(filetype));
|
||||||
bool agbimportable = (FTPYE_AGBSAVE(filetype) && (drvtype & DRV_VIRTUAL) && (drvtype & DRV_SYSNAND));
|
bool agbimportable = (FTPYE_AGBSAVE(filetype));
|
||||||
bool special_opt = mountable || verificable || decryptable || encryptable || cia_buildable || cia_buildable_legit || cxi_dumpable || tik_buildable || key_buildable || titleinfo || renamable || transferable || hsinjectable || restorable || xorpadable || ebackupable || ncsdfixable || extrcodeable || keyinitable || bootable || scriptable || installable || agbexportable || agbimportable;
|
bool special_opt = mountable || verificable || decryptable || encryptable || cia_buildable || cia_buildable_legit || cxi_dumpable || tik_buildable || key_buildable || titleinfo || renamable || transferable || hsinjectable || restorable || xorpadable || ebackupable || ncsdfixable || extrcodeable || keyinitable || bootable || scriptable || installable || agbexportable || agbimportable;
|
||||||
|
|
||||||
char pathstr[32+1];
|
char pathstr[32+1];
|
||||||
@ -1771,7 +1771,7 @@ u32 GodMode(bool is_b9s) {
|
|||||||
// bootloader handler
|
// bootloader handler
|
||||||
if (bootloader) {
|
if (bootloader) {
|
||||||
const char* bootfirm_paths[] = { BOOTFIRM_PATHS };
|
const char* bootfirm_paths[] = { BOOTFIRM_PATHS };
|
||||||
if (IsBootableFirm(firm_in_mem, FIRM_MAX_SIZE)) BootFirm(firm_in_mem, "0:/bootonce.firm");
|
if (IsBootableFirm(firm_in_mem, FIRM_MAX_SIZE)) BootFirm(firm_in_mem, "sdmc:/bootonce.firm");
|
||||||
for (u32 i = 0; i < sizeof(bootfirm_paths) / sizeof(char*); i++) {
|
for (u32 i = 0; i < sizeof(bootfirm_paths) / sizeof(char*); i++) {
|
||||||
BootFirmHandler(bootfirm_paths[i], false, (BOOTFIRM_TEMPS >> i) & 0x1);
|
BootFirmHandler(bootfirm_paths[i], false, (BOOTFIRM_TEMPS >> i) & 0x1);
|
||||||
}
|
}
|
||||||
|
@ -19,12 +19,13 @@
|
|||||||
#define CMAC_TITLEDB_SD 8
|
#define CMAC_TITLEDB_SD 8
|
||||||
#define CMAC_MOVABLE 9
|
#define CMAC_MOVABLE 9
|
||||||
#define CMAC_AGBSAVE 10
|
#define CMAC_AGBSAVE 10
|
||||||
|
#define CMAC_AGBSAVE_SD 11
|
||||||
|
|
||||||
// see: https://www.3dbrew.org/wiki/Savegames#AES_CMAC_header
|
// see: https://www.3dbrew.org/wiki/Savegames#AES_CMAC_header
|
||||||
#define CMAC_SAVETYPE NULL, "CTR-EXT0", "CTR-EXT0", "CTR-SYS0", "CTR-NOR0", "CTR-SAV0", "CTR-SIGN", "CTR-9DB0", "CTR-9DB0", NULL, NULL
|
#define CMAC_SAVETYPE NULL, "CTR-EXT0", "CTR-EXT0", "CTR-SYS0", "CTR-NOR0", "CTR-SAV0", "CTR-SIGN", "CTR-9DB0", "CTR-9DB0", NULL, NULL, NULL
|
||||||
|
|
||||||
// see: http://3dbrew.org/wiki/AES_Registers#Keyslots
|
// see: http://3dbrew.org/wiki/AES_Registers#Keyslots
|
||||||
#define CMAC_KEYSLOT 0xFF, 0x30 /*0x3A?*/, 0x30, 0x30, 0x33 /*0x19*/, 0xFF, 0x30, 0x0B, 0x30, 0x0B, 0x24
|
#define CMAC_KEYSLOT 0xFF, 0x30 /*0x3A?*/, 0x30, 0x30, 0x33 /*0x19*/, 0xFF, 0x30, 0x0B, 0x30, 0x0B, 0x24, 0x30
|
||||||
|
|
||||||
// see: https://www.3dbrew.org/wiki/Title_Database
|
// see: https://www.3dbrew.org/wiki/Title_Database
|
||||||
#define SYS_DB_NAMES "ticket.db", "certs.db", "title.db", "import.db", "tmp_t.db", "tmp_i.db"
|
#define SYS_DB_NAMES "ticket.db", "certs.db", "title.db", "import.db", "tmp_t.db", "tmp_i.db"
|
||||||
@ -47,6 +48,16 @@
|
|||||||
// "%c:/agbsave.bin" virtual AGBSAVE file
|
// "%c:/agbsave.bin" virtual AGBSAVE file
|
||||||
|
|
||||||
|
|
||||||
|
u32 CheckAgbSaveHeader(const char* path) {
|
||||||
|
AgbSaveHeader agbsave;
|
||||||
|
UINT br;
|
||||||
|
|
||||||
|
if ((fvx_qread(path, &agbsave, 0, 0x200, &br) != FR_OK) || (br != 0x200))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return ValidateAgbSaveHeader(&agbsave);
|
||||||
|
}
|
||||||
|
|
||||||
u32 CheckCmacHeader(const char* path) {
|
u32 CheckCmacHeader(const char* path) {
|
||||||
u8 cmac_hdr[0x100];
|
u8 cmac_hdr[0x100];
|
||||||
UINT br;
|
UINT br;
|
||||||
@ -70,7 +81,7 @@ u32 ReadFileCmac(const char* path, u8* cmac) {
|
|||||||
|
|
||||||
if (!cmac_type) return 1;
|
if (!cmac_type) return 1;
|
||||||
else if (cmac_type == CMAC_MOVABLE) offset = 0x130;
|
else if (cmac_type == CMAC_MOVABLE) offset = 0x130;
|
||||||
else if (cmac_type == CMAC_AGBSAVE) offset = 0x010;
|
else if ((cmac_type == CMAC_AGBSAVE) || (cmac_type == CMAC_AGBSAVE_SD)) offset = 0x010;
|
||||||
else offset = 0x000;
|
else offset = 0x000;
|
||||||
|
|
||||||
return ((fvx_qread(path, cmac, offset, 0x10, &br) != FR_OK) || (br != 0x10)) ? 1 : 0;
|
return ((fvx_qread(path, cmac, offset, 0x10, &br) != FR_OK) || (br != 0x10)) ? 1 : 0;
|
||||||
@ -83,7 +94,7 @@ u32 WriteFileCmac(const char* path, u8* cmac) {
|
|||||||
|
|
||||||
if (!cmac_type) return 1;
|
if (!cmac_type) return 1;
|
||||||
else if (cmac_type == CMAC_MOVABLE) offset = 0x130;
|
else if (cmac_type == CMAC_MOVABLE) offset = 0x130;
|
||||||
else if (cmac_type == CMAC_AGBSAVE) offset = 0x010;
|
else if ((cmac_type == CMAC_AGBSAVE) || (cmac_type == CMAC_AGBSAVE_SD)) offset = 0x010;
|
||||||
else offset = 0x000;
|
else offset = 0x000;
|
||||||
|
|
||||||
if (!CheckWritePermissions(path)) return 1;
|
if (!CheckWritePermissions(path)) return 1;
|
||||||
@ -111,8 +122,8 @@ u32 CalculateFileCmac(const char* path, u8* cmac) {
|
|||||||
sid = 1;
|
sid = 1;
|
||||||
cmac_type = CMAC_EXTDATA_SD;
|
cmac_type = CMAC_EXTDATA_SD;
|
||||||
} else if ((sscanf(path, "%c:/title/%08lx/%08lx/data/%08lx.sav", &drv, &tid_high, &tid_low, &sid) == 4) &&
|
} else if ((sscanf(path, "%c:/title/%08lx/%08lx/data/%08lx.sav", &drv, &tid_high, &tid_low, &sid) == 4) &&
|
||||||
ext && (strncmp(ext, "sav", 4) == 0) && (CheckCmacHeader(path) == 0)) {
|
ext && (strncasecmp(ext, "sav", 4) == 0)) {
|
||||||
cmac_type = CMAC_SAVEDATA_SD;
|
cmac_type = (CheckCmacHeader(path) == 0) ? CMAC_SAVEDATA_SD : (CheckAgbSaveHeader(path) == 0) ? CMAC_AGBSAVE_SD : 0;
|
||||||
}
|
}
|
||||||
} else if ((drv == '1') || (drv == '4') || (drv == '7')) { // data on CTRNAND
|
} else if ((drv == '1') || (drv == '4') || (drv == '7')) { // data on CTRNAND
|
||||||
u64 id0_high, id0_low; // ID0
|
u64 id0_high, id0_low; // ID0
|
||||||
@ -162,14 +173,29 @@ u32 CalculateFileCmac(const char* path, u8* cmac) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// build hash data block, get size
|
// build hash data block, get size
|
||||||
if (cmac_type == CMAC_AGBSAVE) { // agbsaves
|
if ((cmac_type == CMAC_AGBSAVE) || (cmac_type == CMAC_AGBSAVE_SD)) { // agbsaves
|
||||||
// see: https://www.3dbrew.org/wiki/Savegames#AES_CMAC_header
|
|
||||||
AgbSaveHeader* agbsave = (AgbSaveHeader*) (void*) data;
|
AgbSaveHeader* agbsave = (AgbSaveHeader*) (void*) data;
|
||||||
if ((TEMP_BUFFER_SIZE < AGBSAVE_MAX_SIZE) || (fvx_qread(path, agbsave, 0, AGBSAVE_MAX_SIZE, &br) != FR_OK) ||
|
if ((TEMP_BUFFER_SIZE < AGBSAVE_MAX_SIZE) || (fvx_qread(path, agbsave, 0, AGBSAVE_MAX_SIZE, &br) != FR_OK) ||
|
||||||
(br < 0x200) || (ValidateAgbSaveHeader(agbsave) != 0) || (0x200 + agbsave->save_size > br))
|
(br < 0x200) || (ValidateAgbSaveHeader(agbsave) != 0) || (0x200 + agbsave->save_size > br))
|
||||||
return 1;
|
return 1;
|
||||||
hashsize = (0x200 - 0x30) + agbsave->save_size;
|
hashsize = (0x200 - 0x30) + agbsave->save_size;
|
||||||
hashdata = data + 0x30;
|
hashdata = data + 0x30;
|
||||||
|
if (cmac_type == CMAC_AGBSAVE_SD) {
|
||||||
|
// see: https://www.3dbrew.org/wiki/Savegames#AES_CMAC_header
|
||||||
|
// thanks to TuxSH, AuroraWright and Wolfvak for helping me
|
||||||
|
// reverse engineering P9 and figuring out AGBSAVE on SD CMACs
|
||||||
|
// this won't work on devkits(!!!)
|
||||||
|
const char* cmac_savetype[] = { CMAC_SAVETYPE };
|
||||||
|
u8* hashdata0 = data + AGBSAVE_MAX_SIZE;
|
||||||
|
memcpy(hashdata0 + 0x00, cmac_savetype[CMAC_SAVEGAME], 8);
|
||||||
|
sha_quick(hashdata0 + 0x08, hashdata, hashsize, SHA256_MODE);
|
||||||
|
|
||||||
|
hashdata = data;
|
||||||
|
memcpy(hashdata + 0x00, cmac_savetype[CMAC_SAVEDATA_SD], 8);
|
||||||
|
memcpy(hashdata + 0x08, &(agbsave->title_id), 8);
|
||||||
|
sha_quick(hashdata + 0x10, hashdata0, 0x28, SHA256_MODE);
|
||||||
|
hashsize = 0x30;
|
||||||
|
}
|
||||||
} else if (cmac_type == CMAC_MOVABLE) { // movable.sed
|
} else if (cmac_type == CMAC_MOVABLE) { // movable.sed
|
||||||
// see: https://3dbrew.org/wiki/Nand/private/movable.sed
|
// see: https://3dbrew.org/wiki/Nand/private/movable.sed
|
||||||
if ((fvx_qread(path, data, 0, 0x140, &br) != FR_OK) || (br != 0x140))
|
if ((fvx_qread(path, data, 0, 0x140, &br) != FR_OK) || (br != 0x140))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user