forked from Mirror/GodMode9
parent
af14376c84
commit
8ebb74b0bc
@ -15,5 +15,5 @@ void NTR_CmdEnter16ByteMode(void);
|
|||||||
void NTR_CmdReadHeader (u8* buffer);
|
void NTR_CmdReadHeader (u8* buffer);
|
||||||
void NTR_CmdReadData (u32 offset, void* buffer);
|
void NTR_CmdReadData (u32 offset, void* buffer);
|
||||||
|
|
||||||
bool NTR_Secure_Init (u8* buffer, u32 CartID, int iCardDevice);
|
bool NTR_Secure_Init (u8* buffer, u8* sa_copy, u32 CartID, int iCardDevice);
|
||||||
|
|
||||||
|
@ -33,8 +33,7 @@ typedef struct {
|
|||||||
TwlHeader ntr_header;
|
TwlHeader ntr_header;
|
||||||
u8 ntr_padding[0x3000]; // 0x00
|
u8 ntr_padding[0x3000]; // 0x00
|
||||||
u8 secure_area[0x4000];
|
u8 secure_area[0x4000];
|
||||||
TwlHeader twl_header;
|
u8 secure_area_enc[0x4000];
|
||||||
u8 twl_padding[0x3000]; // 0x00
|
|
||||||
u8 modcrypt_area[0x4000];
|
u8 modcrypt_area[0x4000];
|
||||||
u32 cart_type;
|
u32 cart_type;
|
||||||
u32 cart_id;
|
u32 cart_id;
|
||||||
@ -45,7 +44,8 @@ typedef struct {
|
|||||||
u32 arm9i_rom_offset;
|
u32 arm9i_rom_offset;
|
||||||
} PACKED_ALIGN(16) CartDataNtrTwl;
|
} PACKED_ALIGN(16) CartDataNtrTwl;
|
||||||
|
|
||||||
DsTime init_time;
|
static DsTime init_time;
|
||||||
|
static bool encrypted_sa = false;
|
||||||
|
|
||||||
u32 GetCartName(char* name, CartData* cdata) {
|
u32 GetCartName(char* name, CartData* cdata) {
|
||||||
if (cdata->cart_type & CART_CTR) {
|
if (cdata->cart_type & CART_CTR) {
|
||||||
@ -86,8 +86,14 @@ u32 GetCartInfoString(char* info, CartData* cdata) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 SetSecureAreaEncryption(bool encrypted) {
|
||||||
|
encrypted_sa = encrypted;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
u32 InitCartRead(CartData* cdata) {
|
u32 InitCartRead(CartData* cdata) {
|
||||||
get_dstime(&init_time);
|
get_dstime(&init_time);
|
||||||
|
encrypted_sa = false;
|
||||||
memset(cdata, 0x00, sizeof(CartData));
|
memset(cdata, 0x00, sizeof(CartData));
|
||||||
cdata->cart_type = CART_NONE;
|
cdata->cart_type = CART_NONE;
|
||||||
if (!CART_INSERTED) return 1;
|
if (!CART_INSERTED) return 1;
|
||||||
@ -153,9 +159,11 @@ u32 InitCartRead(CartData* cdata) {
|
|||||||
} else { // NTR/TWL cartridges
|
} else { // NTR/TWL cartridges
|
||||||
// NTR header
|
// NTR header
|
||||||
TwlHeader* nds_header = (void*)cdata->header;
|
TwlHeader* nds_header = (void*)cdata->header;
|
||||||
|
u8 secure_area_enc[0x4000];
|
||||||
NTR_CmdReadHeader(cdata->header);
|
NTR_CmdReadHeader(cdata->header);
|
||||||
if (!(*(cdata->header))) return 1; // error reading the header
|
if (!(*(cdata->header))) return 1; // error reading the header
|
||||||
if (!NTR_Secure_Init(cdata->header, Cart_GetID(), 0)) return 1;
|
if (!NTR_Secure_Init(cdata->header, secure_area_enc, Cart_GetID(), 0)) return 1;
|
||||||
|
|
||||||
|
|
||||||
// cartridge size, trimmed size, twl presets
|
// cartridge size, trimmed size, twl presets
|
||||||
if (nds_header->device_capacity >= 15) return 1; // too big, not valid
|
if (nds_header->device_capacity >= 15) return 1; // too big, not valid
|
||||||
@ -177,11 +185,14 @@ u32 InitCartRead(CartData* cdata) {
|
|||||||
// We'll only want to use TWL secure init if this is a TWL cartridge.
|
// We'll only want to use TWL secure init if this is a TWL cartridge.
|
||||||
if (cdata->cart_id & 0x40000000U) { // TWL cartridge
|
if (cdata->cart_id & 0x40000000U) { // TWL cartridge
|
||||||
Cart_Init();
|
Cart_Init();
|
||||||
NTR_CmdReadHeader(cdata->twl_header);
|
NTR_CmdReadHeader(cdata->storage);
|
||||||
if (!NTR_Secure_Init(cdata->twl_header, Cart_GetID(), 1)) return 1;
|
if (!NTR_Secure_Init(cdata->storage, NULL, Cart_GetID(), 1)) return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// store encrypted secure area
|
||||||
|
memcpy(cdata->storage, secure_area_enc, 0x4000);
|
||||||
|
|
||||||
// last safety check
|
// last safety check
|
||||||
if (cdata->data_size > cdata->cart_size) return 1;
|
if (cdata->data_size > cdata->cart_size) return 1;
|
||||||
|
|
||||||
@ -199,7 +210,7 @@ u32 ReadCartSectors(void* buffer, u32 sector, u32 count, CartData* cdata) {
|
|||||||
u8* buffer8 = (u8*) buffer;
|
u8* buffer8 = (u8*) buffer;
|
||||||
if (!CART_INSERTED) return 1;
|
if (!CART_INSERTED) return 1;
|
||||||
// header
|
// header
|
||||||
u32 header_sectors = (cdata->cart_type & CART_CTR) ? 0x4000/0x200 : 0x8000/0x200;
|
const u32 header_sectors = 0x4000/0x200;
|
||||||
if (sector < header_sectors) {
|
if (sector < header_sectors) {
|
||||||
u32 header_count = (sector + count > header_sectors) ? header_sectors - sector : count;
|
u32 header_count = (sector + count > header_sectors) ? header_sectors - sector : count;
|
||||||
memcpy(buffer8, cdata->header + (sector * 0x200), header_count * 0x200);
|
memcpy(buffer8, cdata->header + (sector * 0x200), header_count * 0x200);
|
||||||
@ -219,6 +230,7 @@ u32 ReadCartSectors(void* buffer, u32 sector, u32 count, CartData* cdata) {
|
|||||||
CTR_CmdReadData(sector + i, 0x200, min(max_read, count - i), buff);
|
CTR_CmdReadData(sector + i, 0x200, min(max_read, count - i), buff);
|
||||||
buff += max_read * 0x200;
|
buff += max_read * 0x200;
|
||||||
}
|
}
|
||||||
|
|
||||||
// overwrite the card2 savegame with 0xFF
|
// overwrite the card2 savegame with 0xFF
|
||||||
u32 card2_offset = getle32(cdata->header + 0x200);
|
u32 card2_offset = getle32(cdata->header + 0x200);
|
||||||
if ((card2_offset != 0xFFFFFFFF) &&
|
if ((card2_offset != 0xFFFFFFFF) &&
|
||||||
@ -231,9 +243,24 @@ u32 ReadCartSectors(void* buffer, u32 sector, u32 count, CartData* cdata) {
|
|||||||
}
|
}
|
||||||
} else if (cdata->cart_type & CART_NTR) {
|
} else if (cdata->cart_type & CART_NTR) {
|
||||||
u8* buff = buffer8;
|
u8* buff = buffer8;
|
||||||
|
|
||||||
|
// secure area handling
|
||||||
|
const u32 sa_sector_end = 0x8000/0x200;
|
||||||
|
if (sector < sa_sector_end) {
|
||||||
|
CartDataNtrTwl* cdata_twl = (CartDataNtrTwl*) cdata;
|
||||||
|
u8* sa = encrypted_sa ? cdata_twl->secure_area_enc : cdata_twl->secure_area;
|
||||||
|
u32 count_sa = ((sector + count) > sa_sector_end) ? sa_sector_end - sector : count;
|
||||||
|
memcpy(buff, sa + ((sector - header_sectors) * 0x200), count_sa * 0x200);
|
||||||
|
buff += count_sa * 0x200;
|
||||||
|
sector += count_sa;
|
||||||
|
count -= count_sa;
|
||||||
|
}
|
||||||
|
|
||||||
|
// regular cart data
|
||||||
u32 off = sector * 0x200;
|
u32 off = sector * 0x200;
|
||||||
for (u32 i = 0; i < count; i++, off += 0x200, buff += 0x200)
|
for (u32 i = 0; i < count; i++, off += 0x200, buff += 0x200)
|
||||||
NTR_CmdReadData(off, buff);
|
NTR_CmdReadData(off, buff);
|
||||||
|
|
||||||
// modcrypt area handling
|
// modcrypt area handling
|
||||||
if ((cdata->cart_type & CART_TWL) &&
|
if ((cdata->cart_type & CART_TWL) &&
|
||||||
((sector+count) * 0x200 > cdata->arm9i_rom_offset) &&
|
((sector+count) * 0x200 > cdata->arm9i_rom_offset) &&
|
||||||
@ -248,7 +275,7 @@ u32 ReadCartSectors(void* buffer, u32 sector, u32 count, CartData* cdata) {
|
|||||||
size_i = MODC_AREA_SIZE - offset_i;
|
size_i = MODC_AREA_SIZE - offset_i;
|
||||||
if (size_i > (count * 0x200) - (buffer_arm9i - buffer8))
|
if (size_i > (count * 0x200) - (buffer_arm9i - buffer8))
|
||||||
size_i = (count * 0x200) - (buffer_arm9i - buffer8);
|
size_i = (count * 0x200) - (buffer_arm9i - buffer8);
|
||||||
if (size_i) memcpy(buffer_arm9i, cdata->twl_header + 0x4000 + offset_i, size_i);
|
if (size_i) memcpy(buffer_arm9i, cdata->storage + 0x4000 + offset_i, size_i);
|
||||||
}
|
}
|
||||||
} else return 1;
|
} else return 1;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u8 header[0x8000]; // NTR header + secure area / CTR header + private header
|
u8 header[0x8000]; // NTR header + secure area / CTR header + private header
|
||||||
u8 twl_header[0x8000]; // TWL header + modcrypt area / unused
|
u8 storage[0x8000]; // encrypted secure area + modcrypt area / unused
|
||||||
u32 cart_type;
|
u32 cart_type;
|
||||||
u32 cart_id;
|
u32 cart_id;
|
||||||
u64 cart_size;
|
u64 cart_size;
|
||||||
@ -26,6 +26,7 @@ typedef struct {
|
|||||||
|
|
||||||
u32 GetCartName(char* name, CartData* cdata);
|
u32 GetCartName(char* name, CartData* cdata);
|
||||||
u32 GetCartInfoString(char* info, CartData* cdata);
|
u32 GetCartInfoString(char* info, CartData* cdata);
|
||||||
|
u32 SetSecureAreaEncryption(bool encrypted);
|
||||||
u32 InitCartRead(CartData* cdata);
|
u32 InitCartRead(CartData* cdata);
|
||||||
u32 ReadCartSectors(void* buffer, u32 sector, u32 count, CartData* cdata);
|
u32 ReadCartSectors(void* buffer, u32 sector, u32 count, CartData* cdata);
|
||||||
u32 ReadCartBytes(void* buffer, u64 offset, u64 count, CartData* cdata);
|
u32 ReadCartBytes(void* buffer, u64 offset, u64 count, CartData* cdata);
|
||||||
|
@ -231,7 +231,7 @@ void NTR_CmdSecure (u32 flags, void* buffer, u32 length, u8* pcmd)
|
|||||||
cardPolledTransfer (flags, buffer, length, pcmd);
|
cardPolledTransfer (flags, buffer, length, pcmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NTR_Secure_Init (u8* header, u32 CartID, int iCardDevice)
|
bool NTR_Secure_Init (u8* header, u8* sa_copy, u32 CartID, int iCardDevice)
|
||||||
{
|
{
|
||||||
u32 iGameCode;
|
u32 iGameCode;
|
||||||
u32 iCardHash[0x412] = {0};
|
u32 iCardHash[0x412] = {0};
|
||||||
@ -329,6 +329,7 @@ bool NTR_Secure_Init (u8* header, u32 CartID, int iCardDevice)
|
|||||||
NTR_CmdSecure (flagsKey1, NULL, 0, cmdData);
|
NTR_CmdSecure (flagsKey1, NULL, 0, cmdData);
|
||||||
|
|
||||||
//CycloDS doesn't like the dsi secure area being decrypted
|
//CycloDS doesn't like the dsi secure area being decrypted
|
||||||
|
if (sa_copy) memcpy(sa_copy, secureArea, 0x4000);
|
||||||
if(!iCardDevice && ((nds9Offset != 0x4000) || secureArea[0] || secureArea[1]))
|
if(!iCardDevice && ((nds9Offset != 0x4000) || secureArea[0] || secureArea[1]))
|
||||||
{
|
{
|
||||||
NTR_DecryptSecureArea (iGameCode, iCardHash, nCardHash, iKeyCode, secureArea, iCardDevice);
|
NTR_DecryptSecureArea (iGameCode, iCardHash, nCardHash, iKeyCode, secureArea, iCardDevice);
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "gamecart.h"
|
#include "gamecart.h"
|
||||||
|
|
||||||
#define FAT_LIMIT 0x100000000
|
#define FAT_LIMIT 0x100000000
|
||||||
|
#define VFLAG_SECURE_AREA_ENC (1UL<<27)
|
||||||
#define VFLAG_GAMECART_NFO (1UL<<28)
|
#define VFLAG_GAMECART_NFO (1UL<<28)
|
||||||
#define VFLAG_JEDECID_AND_SRFG (1UL<<29)
|
#define VFLAG_JEDECID_AND_SRFG (1UL<<29)
|
||||||
#define VFLAG_SAVEGAME (1UL<<30)
|
#define VFLAG_SAVEGAME (1UL<<30)
|
||||||
@ -34,7 +35,7 @@ bool ReadVCartDir(VirtualFile* vfile, VirtualDir* vdir) {
|
|||||||
vfile->keyslot = 0xFF; // unused
|
vfile->keyslot = 0xFF; // unused
|
||||||
vfile->flags = VFLAG_READONLY;
|
vfile->flags = VFLAG_READONLY;
|
||||||
|
|
||||||
while (++vdir->index <= 8) {
|
while (++vdir->index <= 9) {
|
||||||
if ((vdir->index == 0) && (cdata->data_size < FAT_LIMIT)) { // standard full rom
|
if ((vdir->index == 0) && (cdata->data_size < FAT_LIMIT)) { // standard full rom
|
||||||
snprintf(vfile->name, 32, "%s.%s", name, ext);
|
snprintf(vfile->name, 32, "%s.%s", name, ext);
|
||||||
vfile->size = cdata->cart_size;
|
vfile->size = cdata->cart_size;
|
||||||
@ -53,24 +54,31 @@ bool ReadVCartDir(VirtualFile* vfile, VirtualDir* vdir) {
|
|||||||
vfile->size = (FAT_LIMIT / 2);
|
vfile->size = (FAT_LIMIT / 2);
|
||||||
vfile->offset = (FAT_LIMIT / 2);
|
vfile->offset = (FAT_LIMIT / 2);
|
||||||
return true;
|
return true;
|
||||||
} else if ((vdir->index == 5) && (cdata->cart_type & CART_CTR)) { // private header
|
} else if ((vdir->index == 5) && (cdata->data_size < FAT_LIMIT) &&
|
||||||
|
(cdata->cart_type & CART_NTR)) { // encrypted secure area
|
||||||
|
snprintf(vfile->name, 32, "%s.nds.enc", name);
|
||||||
|
vfile->size = cdata->cart_size;
|
||||||
|
if (vfile->size == FAT_LIMIT) vfile->size--;
|
||||||
|
vfile->flags = VFLAG_SECURE_AREA_ENC;
|
||||||
|
return true;
|
||||||
|
} else if ((vdir->index == 6) && (cdata->cart_type & CART_CTR)) { // private header
|
||||||
snprintf(vfile->name, 32, "%s-priv.bin", name);
|
snprintf(vfile->name, 32, "%s-priv.bin", name);
|
||||||
vfile->size = PRIV_HDR_SIZE;
|
vfile->size = PRIV_HDR_SIZE;
|
||||||
vfile->flags |= VFLAG_PRIV_HDR;
|
vfile->flags |= VFLAG_PRIV_HDR;
|
||||||
return true;
|
return true;
|
||||||
} else if ((vdir->index == 6) && (cdata->save_size > 0)) { // savegame
|
} else if ((vdir->index == 7) && (cdata->save_size > 0)) { // savegame
|
||||||
snprintf(vfile->name, 32, "%s.sav", name);
|
snprintf(vfile->name, 32, "%s.sav", name);
|
||||||
vfile->size = cdata->save_size;
|
vfile->size = cdata->save_size;
|
||||||
vfile->flags = VFLAG_SAVEGAME;
|
vfile->flags = VFLAG_SAVEGAME;
|
||||||
return true;
|
return true;
|
||||||
} else if (vdir->index == 7) { // gamecart info
|
} else if (vdir->index == 8) { // gamecart info
|
||||||
char info[256];
|
char info[256];
|
||||||
GetCartInfoString(info, cdata);
|
GetCartInfoString(info, cdata);
|
||||||
snprintf(vfile->name, 32, "%s.txt", name);
|
snprintf(vfile->name, 32, "%s.txt", name);
|
||||||
vfile->size = strnlen(info, 255);
|
vfile->size = strnlen(info, 255);
|
||||||
vfile->flags |= VFLAG_GAMECART_NFO;
|
vfile->flags |= VFLAG_GAMECART_NFO;
|
||||||
return true;
|
return true;
|
||||||
} else if ((vdir->index == 8) && cdata->save_type.chip) { // JEDEC id and status register
|
} else if ((vdir->index == 9) && cdata->save_type.chip) { // JEDEC id and status register
|
||||||
strcpy(vfile->name, "jedecid_and_sreg.bin");
|
strcpy(vfile->name, "jedecid_and_sreg.bin");
|
||||||
vfile->size = JEDECID_AND_SREG_SIZE;
|
vfile->size = JEDECID_AND_SREG_SIZE;
|
||||||
vfile->flags |= VFLAG_JEDECID_AND_SRFG;
|
vfile->flags |= VFLAG_JEDECID_AND_SRFG;
|
||||||
@ -84,6 +92,7 @@ bool ReadVCartDir(VirtualFile* vfile, VirtualDir* vdir) {
|
|||||||
int ReadVCartFile(const VirtualFile* vfile, void* buffer, u64 offset, u64 count) {
|
int ReadVCartFile(const VirtualFile* vfile, void* buffer, u64 offset, u64 count) {
|
||||||
u32 foffset = vfile->offset + offset;
|
u32 foffset = vfile->offset + offset;
|
||||||
if (!cdata) return -1;
|
if (!cdata) return -1;
|
||||||
|
|
||||||
if (vfile->flags & VFLAG_PRIV_HDR)
|
if (vfile->flags & VFLAG_PRIV_HDR)
|
||||||
return ReadCartPrivateHeader(buffer, foffset, count, cdata);
|
return ReadCartPrivateHeader(buffer, foffset, count, cdata);
|
||||||
else if (vfile->flags & VFLAG_SAVEGAME)
|
else if (vfile->flags & VFLAG_SAVEGAME)
|
||||||
@ -92,7 +101,9 @@ int ReadVCartFile(const VirtualFile* vfile, void* buffer, u64 offset, u64 count)
|
|||||||
return ReadCartInfo(buffer, foffset, count, cdata);
|
return ReadCartInfo(buffer, foffset, count, cdata);
|
||||||
else if (vfile->flags & VFLAG_JEDECID_AND_SRFG)
|
else if (vfile->flags & VFLAG_JEDECID_AND_SRFG)
|
||||||
return ReadCartSaveJedecId(buffer, foffset, count, cdata);
|
return ReadCartSaveJedecId(buffer, foffset, count, cdata);
|
||||||
else return ReadCartBytes(buffer, foffset, count, cdata);
|
|
||||||
|
SetSecureAreaEncryption(vfile->flags & VFLAG_SECURE_AREA_ENC);
|
||||||
|
return ReadCartBytes(buffer, foffset, count, cdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
int WriteVCartFile(const VirtualFile* vfile, const void* buffer, u64 offset, u64 count) {
|
int WriteVCartFile(const VirtualFile* vfile, const void* buffer, u64 offset, u64 count) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user