From 3aea9b5eb78eee2628ddaeb2a47f17a09a081978 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Fri, 13 Aug 2021 19:39:48 +0200 Subject: [PATCH] add some really evil code --- src/DSi.cpp | 2 + src/DSi_NAND.cpp | 229 ++++++++++++++++++++++++++++++++++++++++++++++- src/DSi_NAND.h | 2 + 3 files changed, 230 insertions(+), 3 deletions(-) diff --git a/src/DSi.cpp b/src/DSi.cpp index 47590dd5..b7056614 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -533,6 +533,8 @@ bool LoadNAND() DSi_NAND::Init(); DSi_NAND::PatchTSC(); + DSi_NAND::ImportTest(); + return true; } diff --git a/src/DSi_NAND.cpp b/src/DSi_NAND.cpp index d04e8502..a3c7c162 100644 --- a/src/DSi_NAND.cpp +++ b/src/DSi_NAND.cpp @@ -34,6 +34,8 @@ namespace DSi_NAND u8 FATIV[16]; u8 FATKey[16]; +u8 ESKey[16]; + void Init() { @@ -41,6 +43,7 @@ void Init() SHA1_CTX sha; u8 tmp[20]; + u8 keyX[16], keyY[16]; SHA1Init(&sha); SHA1Update(&sha, DSi::eMMC_CID, 16); @@ -48,13 +51,11 @@ void Init() DSi_AES::Swap16(FATIV, tmp); - u8 keyX[16]; *(u32*)&keyX[0] = (u32)DSi::ConsoleID; *(u32*)&keyX[4] = (u32)DSi::ConsoleID ^ 0x24EE6906; *(u32*)&keyX[8] = (u32)(DSi::ConsoleID >> 32) ^ 0xE65B601D; *(u32*)&keyX[12] = (u32)(DSi::ConsoleID >> 32); - u8 keyY[16]; *(u32*)&keyY[0] = 0x0AB9DC76; *(u32*)&keyY[4] = 0xBD4DC4D3; *(u32*)&keyY[8] = 0x202DDD1D; @@ -62,8 +63,20 @@ void Init() DSi_AES::DeriveNormalKey(keyX, keyY, 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) { u8 iv[16]; @@ -79,6 +92,11 @@ void SetupFATCrypto(AES_ctx* ctx, u32 ctr) res = iv[12] + (ctr >> 24) + (res >> 8); iv[12] = (res & 0xFF); 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); } @@ -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() { ff_disk_open(FF_ReadNAND, FF_WriteNAND); @@ -199,7 +324,6 @@ void PatchTSC() contents[0xC3] = 191; SHA1_CTX sha; - u8 datahash[20]; SHA1Init(&sha); SHA1Update(&sha, &contents[0x88], 0x128); SHA1Final(&contents[0], &sha); @@ -215,4 +339,103 @@ mount_fail: 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(); +} + } diff --git a/src/DSi_NAND.h b/src/DSi_NAND.h index 41d40b8b..1eb018b4 100644 --- a/src/DSi_NAND.h +++ b/src/DSi_NAND.h @@ -28,6 +28,8 @@ void Init(); void PatchTSC(); +void ImportTest(); + } #endif // DSI_NAND_H