mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-07-27 00:00:07 -06:00
add some really evil code
This commit is contained in:
@ -533,6 +533,8 @@ bool LoadNAND()
|
|||||||
DSi_NAND::Init();
|
DSi_NAND::Init();
|
||||||
DSi_NAND::PatchTSC();
|
DSi_NAND::PatchTSC();
|
||||||
|
|
||||||
|
DSi_NAND::ImportTest();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
229
src/DSi_NAND.cpp
229
src/DSi_NAND.cpp
@ -34,6 +34,8 @@ namespace DSi_NAND
|
|||||||
u8 FATIV[16];
|
u8 FATIV[16];
|
||||||
u8 FATKey[16];
|
u8 FATKey[16];
|
||||||
|
|
||||||
|
u8 ESKey[16];
|
||||||
|
|
||||||
|
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
@ -41,6 +43,7 @@ void Init()
|
|||||||
|
|
||||||
SHA1_CTX sha;
|
SHA1_CTX sha;
|
||||||
u8 tmp[20];
|
u8 tmp[20];
|
||||||
|
u8 keyX[16], keyY[16];
|
||||||
|
|
||||||
SHA1Init(&sha);
|
SHA1Init(&sha);
|
||||||
SHA1Update(&sha, DSi::eMMC_CID, 16);
|
SHA1Update(&sha, DSi::eMMC_CID, 16);
|
||||||
@ -48,13 +51,11 @@ void Init()
|
|||||||
|
|
||||||
DSi_AES::Swap16(FATIV, tmp);
|
DSi_AES::Swap16(FATIV, tmp);
|
||||||
|
|
||||||
u8 keyX[16];
|
|
||||||
*(u32*)&keyX[0] = (u32)DSi::ConsoleID;
|
*(u32*)&keyX[0] = (u32)DSi::ConsoleID;
|
||||||
*(u32*)&keyX[4] = (u32)DSi::ConsoleID ^ 0x24EE6906;
|
*(u32*)&keyX[4] = (u32)DSi::ConsoleID ^ 0x24EE6906;
|
||||||
*(u32*)&keyX[8] = (u32)(DSi::ConsoleID >> 32) ^ 0xE65B601D;
|
*(u32*)&keyX[8] = (u32)(DSi::ConsoleID >> 32) ^ 0xE65B601D;
|
||||||
*(u32*)&keyX[12] = (u32)(DSi::ConsoleID >> 32);
|
*(u32*)&keyX[12] = (u32)(DSi::ConsoleID >> 32);
|
||||||
|
|
||||||
u8 keyY[16];
|
|
||||||
*(u32*)&keyY[0] = 0x0AB9DC76;
|
*(u32*)&keyY[0] = 0x0AB9DC76;
|
||||||
*(u32*)&keyY[4] = 0xBD4DC4D3;
|
*(u32*)&keyY[4] = 0xBD4DC4D3;
|
||||||
*(u32*)&keyY[8] = 0x202DDD1D;
|
*(u32*)&keyY[8] = 0x202DDD1D;
|
||||||
@ -62,8 +63,20 @@ void Init()
|
|||||||
|
|
||||||
DSi_AES::DeriveNormalKey(keyX, keyY, tmp);
|
DSi_AES::DeriveNormalKey(keyX, keyY, tmp);
|
||||||
DSi_AES::Swap16(FATKey, tmp);
|
DSi_AES::Swap16(FATKey, tmp);
|
||||||
|
|
||||||
|
|
||||||
|
*(u32*)&keyX[0] = 0x4E00004A;
|
||||||
|
*(u32*)&keyX[4] = 0x4A00004E;
|
||||||
|
*(u32*)&keyX[8] = (u32)(DSi::ConsoleID >> 32) ^ 0xC80C4B72;
|
||||||
|
*(u32*)&keyX[12] = (u32)DSi::ConsoleID;
|
||||||
|
|
||||||
|
memcpy(keyY, &DSi::ARM7iBIOS[0x8308], 16);
|
||||||
|
|
||||||
|
DSi_AES::DeriveNormalKey(keyX, keyY, tmp);
|
||||||
|
DSi_AES::Swap16(ESKey, tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SetupFATCrypto(AES_ctx* ctx, u32 ctr)
|
void SetupFATCrypto(AES_ctx* ctx, u32 ctr)
|
||||||
{
|
{
|
||||||
u8 iv[16];
|
u8 iv[16];
|
||||||
@ -79,6 +92,11 @@ void SetupFATCrypto(AES_ctx* ctx, u32 ctr)
|
|||||||
res = iv[12] + (ctr >> 24) + (res >> 8);
|
res = iv[12] + (ctr >> 24) + (res >> 8);
|
||||||
iv[12] = (res & 0xFF);
|
iv[12] = (res & 0xFF);
|
||||||
iv[11] += (res >> 8);
|
iv[11] += (res >> 8);
|
||||||
|
for (int i = 10; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (iv[i+1] == 0) iv[i]++;
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
|
||||||
AES_init_ctx_iv(ctx, FATKey, iv);
|
AES_init_ctx_iv(ctx, FATKey, iv);
|
||||||
}
|
}
|
||||||
@ -157,6 +175,113 @@ UINT FF_WriteNAND(BYTE* buf, LBA_t sector, UINT num)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool ESDecrypt(u8* data, u32 len)
|
||||||
|
{
|
||||||
|
AES_ctx ctx;
|
||||||
|
u8 iv[16];
|
||||||
|
u8 mac[16];
|
||||||
|
|
||||||
|
iv[0] = 0x02;
|
||||||
|
for (int i = 0; i < 12; i++) iv[1+i] = data[len+0x1C-i];
|
||||||
|
iv[13] = 0x00;
|
||||||
|
iv[14] = 0x00;
|
||||||
|
iv[15] = 0x01;
|
||||||
|
|
||||||
|
AES_init_ctx_iv(&ctx, ESKey, iv);
|
||||||
|
|
||||||
|
u32 blklen = (len + 0xF) & ~0xF; printf("blk=%x\n", blklen);
|
||||||
|
mac[0] = 0x3A;
|
||||||
|
for (int i = 1; i < 13; i++) mac[i] = iv[i];
|
||||||
|
mac[13] = (blklen >> 16) & 0xFF;
|
||||||
|
mac[14] = (blklen >> 8) & 0xFF;
|
||||||
|
mac[15] = blklen & 0xFF;
|
||||||
|
|
||||||
|
AES_ECB_encrypt(&ctx, mac);
|
||||||
|
|
||||||
|
u32 coarselen = len & ~0xF;
|
||||||
|
for (u32 i = 0; i < coarselen; i += 16)
|
||||||
|
{
|
||||||
|
u8 tmp[16];
|
||||||
|
|
||||||
|
DSi_AES::Swap16(tmp, &data[i]);
|
||||||
|
|
||||||
|
AES_CTR_xcrypt_buffer(&ctx, tmp, 16);
|
||||||
|
for (int i = 0; i < 16; i++) mac[i] ^= tmp[i];
|
||||||
|
AES_ECB_encrypt(&ctx, mac);
|
||||||
|
|
||||||
|
DSi_AES::Swap16(&data[i], tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 remlen = len - coarselen;
|
||||||
|
if (remlen)
|
||||||
|
{
|
||||||
|
u8 rem[16];
|
||||||
|
|
||||||
|
u32 ivnum = (coarselen >> 4) + 1;
|
||||||
|
iv[13] = (ivnum >> 16) & 0xFF;
|
||||||
|
iv[14] = (ivnum >> 8) & 0xFF;
|
||||||
|
iv[15] = ivnum & 0xFF;
|
||||||
|
|
||||||
|
memset(rem, 0, 16);
|
||||||
|
AES_ctx_set_iv(&ctx, iv);
|
||||||
|
AES_CTR_xcrypt_buffer(&ctx, rem, 16);
|
||||||
|
|
||||||
|
for (int i = 0; i < remlen; i++)
|
||||||
|
rem[15-i] = data[coarselen+i];
|
||||||
|
|
||||||
|
AES_ctx_set_iv(&ctx, iv);
|
||||||
|
AES_CTR_xcrypt_buffer(&ctx, rem, 16);
|
||||||
|
for (int i = 0; i < 16; i++) mac[i] ^= rem[i];
|
||||||
|
AES_ECB_encrypt(&ctx, mac);
|
||||||
|
|
||||||
|
for (int i = 0; i < remlen; i++)
|
||||||
|
data[coarselen+i] = rem[15-i];
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Iv[13] = 0x00;
|
||||||
|
ctx.Iv[14] = 0x00;
|
||||||
|
ctx.Iv[15] = 0x00;
|
||||||
|
AES_CTR_xcrypt_buffer(&ctx, mac, 16);
|
||||||
|
|
||||||
|
u8 footer[16];
|
||||||
|
|
||||||
|
iv[0] = 0x00;
|
||||||
|
iv[1] = 0x00;
|
||||||
|
iv[2] = 0x00;
|
||||||
|
for (int i = 0; i < 12; i++) iv[3+i] = data[len+0x1C-i];
|
||||||
|
iv[15] = 0x00;
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
footer[15-i] = data[len+0x10+i];
|
||||||
|
|
||||||
|
AES_ctx_set_iv(&ctx, iv);
|
||||||
|
AES_CTR_xcrypt_buffer(&ctx, footer, 16);
|
||||||
|
|
||||||
|
data[len+0x10] = footer[15];
|
||||||
|
data[len+0x1D] = footer[2];
|
||||||
|
data[len+0x1E] = footer[1];
|
||||||
|
data[len+0x1F] = footer[0];
|
||||||
|
|
||||||
|
u32 footerlen = footer[0] | (footer[1] << 8) | (footer[2] << 16);
|
||||||
|
if (footerlen != len)
|
||||||
|
{
|
||||||
|
printf("ESDecrypt: bad length %d (expected %d)\n", len, footerlen);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
if (data[len+i] != mac[15-i])
|
||||||
|
{
|
||||||
|
printf("ESDecrypt: bad MAC\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PatchTSC()
|
void PatchTSC()
|
||||||
{
|
{
|
||||||
ff_disk_open(FF_ReadNAND, FF_WriteNAND);
|
ff_disk_open(FF_ReadNAND, FF_WriteNAND);
|
||||||
@ -199,7 +324,6 @@ void PatchTSC()
|
|||||||
contents[0xC3] = 191;
|
contents[0xC3] = 191;
|
||||||
|
|
||||||
SHA1_CTX sha;
|
SHA1_CTX sha;
|
||||||
u8 datahash[20];
|
|
||||||
SHA1Init(&sha);
|
SHA1Init(&sha);
|
||||||
SHA1Update(&sha, &contents[0x88], 0x128);
|
SHA1Update(&sha, &contents[0x88], 0x128);
|
||||||
SHA1Final(&contents[0], &sha);
|
SHA1Final(&contents[0], &sha);
|
||||||
@ -215,4 +339,103 @@ mount_fail:
|
|||||||
ff_disk_close();
|
ff_disk_close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ImportTest()
|
||||||
|
{
|
||||||
|
char* tmdfile = "cavestory.tmd";
|
||||||
|
char* appfile = "cavestory.nds";
|
||||||
|
|
||||||
|
ff_disk_open(FF_ReadNAND, FF_WriteNAND);
|
||||||
|
|
||||||
|
FRESULT res;
|
||||||
|
FATFS fs;
|
||||||
|
res = f_mount(&fs, "0:", 0);
|
||||||
|
if (res != FR_OK)
|
||||||
|
{
|
||||||
|
printf("NAND mounting failed: %d\n", res);
|
||||||
|
f_unmount("0:");
|
||||||
|
ff_disk_close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 tmd[0x208];
|
||||||
|
{
|
||||||
|
FILE* f = fopen(tmdfile, "rb");
|
||||||
|
fread(tmd, 0x208, 1, f);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 version = tmd[0x1E7];
|
||||||
|
printf(".app version: %08x\n", version);
|
||||||
|
|
||||||
|
{
|
||||||
|
DIR ticketdir;
|
||||||
|
FILINFO info;
|
||||||
|
FRESULT res;
|
||||||
|
|
||||||
|
res = f_opendir(&ticketdir, "0:/ticket/00030004");
|
||||||
|
printf("dir res: %d\n", res);
|
||||||
|
|
||||||
|
res = f_readdir(&ticketdir, &info);
|
||||||
|
if (res)
|
||||||
|
{
|
||||||
|
printf("bad read res: %d\n", res);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info.fname[0])
|
||||||
|
{
|
||||||
|
printf("VERY BAD!! DIR IS EMPTY\n");
|
||||||
|
// TODO ERROR MANAGEMENT!!
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("- %s\n", info.fname);
|
||||||
|
char ticketfname[128];
|
||||||
|
sprintf(ticketfname, "0:/ticket/00030004/%s", info.fname);
|
||||||
|
|
||||||
|
f_closedir(&ticketdir);
|
||||||
|
|
||||||
|
FIL ticketfile;
|
||||||
|
res = f_open(&ticketfile, ticketfname, FA_OPEN_EXISTING | FA_READ);
|
||||||
|
//
|
||||||
|
|
||||||
|
u8 ticket[708];
|
||||||
|
u32 nread;
|
||||||
|
f_read(&ticketfile, ticket, 708, &nread);
|
||||||
|
//
|
||||||
|
|
||||||
|
f_close(&ticketfile);
|
||||||
|
|
||||||
|
// DECRYPT!!
|
||||||
|
/*{
|
||||||
|
u8 iv[16];
|
||||||
|
|
||||||
|
iv[0] = 0x02;
|
||||||
|
for (int i = 0; i < 12; i++) iv[1+i] = ticket[0x2A4 + 0x1C - i];
|
||||||
|
iv[13] = 0x00;
|
||||||
|
iv[14] = 0x00;
|
||||||
|
iv[15] = 0x01;
|
||||||
|
|
||||||
|
AES_ctx aes;
|
||||||
|
AES_init_ctx_iv(&aes, ESKey, iv);
|
||||||
|
|
||||||
|
for (u32 i = 0; i < 0x290; i += 16)
|
||||||
|
{
|
||||||
|
u8 tmp[16];
|
||||||
|
|
||||||
|
DSi_AES::Swap16(tmp, &ticket[i]);
|
||||||
|
AES_CTR_xcrypt_buffer(&aes, tmp, 16);
|
||||||
|
DSi_AES::Swap16(&ticket[i], tmp);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
ESDecrypt(ticket, 0x2A4);
|
||||||
|
|
||||||
|
FILE* dorp = fopen("assticket.bin", "wb");
|
||||||
|
fwrite(ticket, 708, 1, dorp);
|
||||||
|
fclose(dorp);
|
||||||
|
}
|
||||||
|
|
||||||
|
f_unmount("0:");
|
||||||
|
ff_disk_close();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,8 @@ void Init();
|
|||||||
|
|
||||||
void PatchTSC();
|
void PatchTSC();
|
||||||
|
|
||||||
|
void ImportTest();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // DSI_NAND_H
|
#endif // DSI_NAND_H
|
||||||
|
Reference in New Issue
Block a user