Switch to structs where possible

This commit is contained in:
Aurora 2016-10-08 14:23:08 +02:00
parent b575ee9e28
commit 50b24bf6c2
3 changed files with 100 additions and 28 deletions

View File

@ -24,6 +24,7 @@
* Crypto libs from http://github.com/b1l1s/ctr * Crypto libs from http://github.com/b1l1s/ctr
* kernel9Loader code originally adapted from https://github.com/Reisyukaku/ReiNand/blob/228c378255ba693133dec6f3368e14d386f2cde7/source/crypto.c#L233 * kernel9Loader code originally adapted from https://github.com/Reisyukaku/ReiNand/blob/228c378255ba693133dec6f3368e14d386f2cde7/source/crypto.c#L233
* decryptNusFirm code adapted from https://github.com/mid-kid/CakesForeveryWan/blob/master/source/firm.c * decryptNusFirm code adapted from https://github.com/mid-kid/CakesForeveryWan/blob/master/source/firm.c
* 3ds type structs adapted from 3DBrew and https://github.com/mid-kid/CakesForeveryWan/blob/master/source/headers.h
*/ */
#include "crypto.h" #include "crypto.h"
@ -375,29 +376,29 @@ void set6x7xKeys(void)
memset32((void *)0x01FFCD00, 0, 0x10); memset32((void *)0x01FFCD00, 0, 0x10);
} }
void decryptExeFs(u8 *inbuf) void decryptExeFs(Ncch *ncch)
{ {
u8 *exeFsOffset = inbuf + *(u32 *)(inbuf + 0x1A0) * 0x200; u8 *exeFsOffset = (u8 *)ncch + ncch->exeFsOffset * 0x200;
u32 exeFsSize = *(u32 *)(inbuf + 0x1A4) * 0x200; u32 exeFsSize = ncch->exeFsSize * 0x200;
u8 __attribute__((aligned(4))) ncchCtr[AES_BLOCK_SIZE] = {0}; u8 __attribute__((aligned(4))) ncchCtr[AES_BLOCK_SIZE] = {0};
for(u32 i = 0; i < 8; i++) for(u32 i = 0; i < 8; i++)
ncchCtr[7 - i] = *(inbuf + 0x108 + i); ncchCtr[7 - i] = ncch->partitionId[i];
ncchCtr[8] = 2; ncchCtr[8] = 2;
aes_setkey(0x2C, inbuf, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(0x2C, ncch, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_advctr(ncchCtr, 0x200 / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL); aes_advctr(ncchCtr, 0x200 / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x2C); aes_use_keyslot(0x2C);
aes(inbuf, exeFsOffset + 0x200, exeFsSize / AES_BLOCK_SIZE, ncchCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); aes(ncch, exeFsOffset + 0x200, exeFsSize / AES_BLOCK_SIZE, ncchCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
} }
void decryptNusFirm(const u8 *inbuf, u8 *outbuf, u32 ncchSize) void decryptNusFirm(const Ticket *ticket, Ncch *ncch, u32 ncchSize)
{ {
const u8 keyY0x3D[AES_BLOCK_SIZE] = {0x0C, 0x76, 0x72, 0x30, 0xF0, 0x99, 0x8F, 0x1C, 0x46, 0x82, 0x82, 0x02, 0xFA, 0xAC, 0xBE, 0x4C}; const u8 keyY0x3D[AES_BLOCK_SIZE] = {0x0C, 0x76, 0x72, 0x30, 0xF0, 0x99, 0x8F, 0x1C, 0x46, 0x82, 0x82, 0x02, 0xFA, 0xAC, 0xBE, 0x4C};
u8 __attribute__((aligned(4))) titleKey[AES_BLOCK_SIZE]; u8 __attribute__((aligned(4))) titleKey[AES_BLOCK_SIZE];
u8 __attribute__((aligned(4))) cetkIv[AES_BLOCK_SIZE] = {0}; u8 __attribute__((aligned(4))) cetkIv[AES_BLOCK_SIZE] = {0};
memcpy(titleKey, inbuf + 0x1BF, sizeof(titleKey)); memcpy(titleKey, ticket->titleKey, sizeof(titleKey));
memcpy(cetkIv, inbuf + 0x1DC, 8); memcpy(cetkIv, ticket->titleId, sizeof(ticket->titleId));
aes_setkey(0x3D, keyY0x3D, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(0x3D, keyY0x3D, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x3D); aes_use_keyslot(0x3D);
@ -407,16 +408,16 @@ void decryptNusFirm(const u8 *inbuf, u8 *outbuf, u32 ncchSize)
aes_setkey(0x16, titleKey, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(0x16, titleKey, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x16); aes_use_keyslot(0x16);
aes(outbuf, outbuf, ncchSize / AES_BLOCK_SIZE, ncchIv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); aes(ncch, ncch, ncchSize / AES_BLOCK_SIZE, ncchIv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
decryptExeFs(outbuf); decryptExeFs(ncch);
} }
void kernel9Loader(u8 *arm9Section) void kernel9Loader(Arm9Bin *arm9Section)
{ {
//Determine the kernel9loader version //Determine the kernel9loader version
u32 k9lVersion; u32 k9lVersion;
switch(arm9Section[0x53]) switch(arm9Section->magic[3])
{ {
case 0xFF: case 0xFF:
k9lVersion = 0; k9lVersion = 0;
@ -429,7 +430,7 @@ void kernel9Loader(u8 *arm9Section)
break; break;
} }
u32 startOfArm9Bin = *(u32 *)(arm9Section + 0x800); u32 startOfArm9Bin = *(u32 *)((u8 *)arm9Section + 0x800);
bool needToDecrypt = startOfArm9Bin != 0x47704770 && startOfArm9Bin != 0xB0862000; bool needToDecrypt = startOfArm9Bin != 0x47704770 && startOfArm9Bin != 0xB0862000;
if(!isDevUnit && (k9lVersion == 2 || (k9lVersion == 1 && needToDecrypt))) if(!isDevUnit && (k9lVersion == 2 || (k9lVersion == 1 && needToDecrypt)))
@ -452,28 +453,28 @@ void kernel9Loader(u8 *arm9Section)
//Set keyX //Set keyX
u8 __attribute__((aligned(4))) keyX[AES_BLOCK_SIZE]; u8 __attribute__((aligned(4))) keyX[AES_BLOCK_SIZE];
aes_use_keyslot(0x11); aes_use_keyslot(0x11);
aes(keyX, arm9Section + 0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0); aes(keyX, arm9Section->slot0x16keyX, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
aes_setkey(0x16, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(0x16, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
} }
//Set keyY //Set keyY
u8 __attribute__((aligned(4))) keyY[AES_BLOCK_SIZE]; u8 __attribute__((aligned(4))) keyY[AES_BLOCK_SIZE];
memcpy(keyY, arm9Section + 0x10, sizeof(keyY)); memcpy(keyY, arm9Section->keyY, sizeof(keyY));
aes_setkey(arm9BinSlot, keyY, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(arm9BinSlot, keyY, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
//Set CTR //Set CTR
u8 __attribute__((aligned(4))) arm9BinCtr[AES_BLOCK_SIZE]; u8 __attribute__((aligned(4))) arm9BinCtr[AES_BLOCK_SIZE];
memcpy(arm9BinCtr, arm9Section + 0x20, sizeof(arm9BinCtr)); memcpy(arm9BinCtr, arm9Section->ctr, sizeof(arm9BinCtr));
//Calculate the size of the ARM9 binary //Calculate the size of the ARM9 binary
u32 arm9BinSize = 0; u32 arm9BinSize = 0;
//http://stackoverflow.com/questions/12791077/atoi-implementation-in-c //http://stackoverflow.com/questions/12791077/atoi-implementation-in-c
for(u8 *tmp = arm9Section + 0x30; *tmp != 0; tmp++) for(u8 *tmp = arm9Section->size; *tmp != 0; tmp++)
arm9BinSize = (arm9BinSize << 3) + (arm9BinSize << 1) + *tmp - '0'; arm9BinSize = (arm9BinSize << 3) + (arm9BinSize << 1) + *tmp - '0';
//Decrypt ARM9 binary //Decrypt ARM9 binary
aes_use_keyslot(arm9BinSlot); aes_use_keyslot(arm9BinSlot);
aes(arm9Section + 0x800, arm9Section + 0x800, arm9BinSize / AES_BLOCK_SIZE, arm9BinCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); aes((u8 *)arm9Section + 0x800, (u8 *)arm9Section + 0x800, arm9BinSize / AES_BLOCK_SIZE, arm9BinCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
} }
//Set >=9.6 KeyXs //Set >=9.6 KeyXs

View File

@ -24,6 +24,7 @@
* Crypto libs from http://github.com/b1l1s/ctr * Crypto libs from http://github.com/b1l1s/ctr
* kernel9Loader code originally adapted from https://github.com/Reisyukaku/ReiNand/blob/228c378255ba693133dec6f3368e14d386f2cde7/source/crypto.c#L233 * kernel9Loader code originally adapted from https://github.com/Reisyukaku/ReiNand/blob/228c378255ba693133dec6f3368e14d386f2cde7/source/crypto.c#L233
* decryptNusFirm code adapted from https://github.com/mid-kid/CakesForeveryWan/blob/master/source/firm.c * decryptNusFirm code adapted from https://github.com/mid-kid/CakesForeveryWan/blob/master/source/firm.c
* 3ds type structs adapted from 3DBrew and https://github.com/mid-kid/CakesForeveryWan/blob/master/source/headers.h
*/ */
#pragma once #pragma once
@ -101,6 +102,76 @@
#define SHA_224_HASH_SIZE (224 / 8) #define SHA_224_HASH_SIZE (224 / 8)
#define SHA_1_HASH_SIZE (160 / 8) #define SHA_1_HASH_SIZE (160 / 8)
typedef struct Ncch {
uint8_t sig[0x100]; //RSA-2048 signature of the NCCH header, using SHA-256
char magic[4]; //NCCH
uint32_t contentSize; //Media unit
uint8_t partitionId[8];
uint8_t makerCode[2];
uint16_t version;
uint8_t reserved1[4];
uint8_t programID[8];
uint8_t reserved2[0x10];
uint8_t logoHash[0x20]; //Logo Region SHA-256 hash
char productCode[0x10];
uint8_t exHeaderHash[0x20]; //Extended header SHA-256 hash
uint32_t exHeaderSize; //Extended header size
uint32_t reserved3;
uint8_t flags[8];
uint32_t plainOffset; //Media unit
uint32_t plainSize; //Media unit
uint32_t logoOffset; //Media unit
uint32_t logoSize; //Media unit
uint32_t exeFsOffset; //Media unit
uint32_t exeFsSize; //Media unit
uint32_t exeFsHashSize; //Media unit
uint32_t reserved4;
uint32_t romFsOffset; //Media unit
uint32_t romFsSize; //Media unit
uint32_t romFsHashSize; //Media unit
uint32_t reserved5;
uint8_t exeFsHash[0x20]; //ExeFS superblock SHA-256 hash
uint8_t romFsHash[0x20]; //RomFS superblock SHA-256 hash
} Ncch;
typedef struct Ticket
{
char sigIssuer[0x40];
uint8_t eccPubKey[0x3C];
uint8_t version;
uint8_t caCrlVersion;
uint8_t signerCrlVersion;
uint8_t titleKey[0x10];
uint8_t reserved1;
uint8_t ticketId[8];
uint8_t consoleId[4];
uint8_t titleId[8];
uint8_t reserved2[2];
uint16_t ticketTitleVersion;
uint8_t reserved3[8];
uint8_t licenseType;
uint8_t ticketCommonKeyYIndex; //Ticket common keyY index, usually 0x1 for retail system titles.
uint8_t reserved4[0x2A];
uint8_t unk[4]; //eShop Account ID?
uint8_t reserved5;
uint8_t audit;
uint8_t reserved6[0x42];
uint8_t limits[0x40];
uint8_t contentIndex[0xAC];
} Ticket;
typedef struct Arm9Bin {
uint8_t keyX[0x10];
uint8_t keyY[0x10];
uint8_t ctr[0x10];
uint8_t size[8];
uint8_t reserved[8];
uint8_t ctlBlock[0x10];
char magic[4];
uint8_t reserved2[0xC];
uint8_t slot0x16keyX[0x10];
} Arm9Bin;
extern u32 emuOffset; extern u32 emuOffset;
extern bool isN3DS, isDevUnit, isA9lh; extern bool isN3DS, isDevUnit, isA9lh;
extern FirmwareSource firmSource; extern FirmwareSource firmSource;
@ -109,8 +180,8 @@ void ctrNandInit(void);
int ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf); int ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
int ctrNandWrite(u32 sector, u32 sectorCount, u8 *inbuf); int ctrNandWrite(u32 sector, u32 sectorCount, u8 *inbuf);
void set6x7xKeys(void); void set6x7xKeys(void);
void decryptExeFs(u8 *inbuf); void decryptExeFs(Ncch *ncch);
void decryptNusFirm(const u8 *inbuf, u8 *outbuf, u32 ncchSize); void decryptNusFirm(const Ticket *ticket, Ncch *ncch, u32 ncchSize);
void kernel9Loader(u8 *arm9Section); void kernel9Loader(Arm9Bin *arm9Section);
void computePinHash(u8 *outbuf, const u8 *inbuf); void computePinHash(u8 *outbuf, const u8 *inbuf);
void restoreShaHashBackup(void); void restoreShaHashBackup(void);

View File

@ -331,7 +331,7 @@ static inline u32 loadFirm(FirmwareType *firmType, FirmwareSource firmSource, bo
u8 cetk[0xA50]; u8 cetk[0xA50];
if(fileRead(cetk, *firmType == NATIVE_FIRM1X2X ? cetkFiles[0] : cetkFiles[(u32)*firmType], sizeof(cetk)) == sizeof(cetk)) if(fileRead(cetk, *firmType == NATIVE_FIRM1X2X ? cetkFiles[0] : cetkFiles[(u32)*firmType], sizeof(cetk)) == sizeof(cetk))
decryptNusFirm(cetk, (u8 *)firm, firmSize); decryptNusFirm((Ticket *)&cetk[0x140], (Ncch *)firm, firmSize);
else error("The firmware.bin in /luma is encrypted\nor corrupted."); else error("The firmware.bin in /luma is encrypted\nor corrupted.");
} }
@ -346,7 +346,7 @@ static inline u32 loadFirm(FirmwareType *firmType, FirmwareSource firmSource, bo
if(firmVersion != 0xFFFFFFFF) if(firmVersion != 0xFFFFFFFF)
{ {
if(mustLoadFromStorage) error("An old unsupported FIRM has been detected.\nCopy a firmware.bin in /luma to boot."); if(mustLoadFromStorage) error("An old unsupported FIRM has been detected.\nCopy a firmware.bin in /luma to boot.");
decryptExeFs((u8 *)firm); decryptExeFs((Ncch *)firm);
} }
return firmVersion; return firmVersion;
@ -360,7 +360,7 @@ static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32
if(isN3DS) if(isN3DS)
{ {
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip kernel9loader //Decrypt ARM9Bin and patch ARM9 entrypoint to skip kernel9loader
kernel9Loader(arm9Section); kernel9Loader((Arm9Bin *)arm9Section);
firm->arm9Entry = (u8 *)0x801B01C; firm->arm9Entry = (u8 *)0x801B01C;
} }
@ -440,7 +440,7 @@ static inline void patchLegacyFirm(FirmwareType firmType, u32 firmVersion, u32 d
//On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip kernel9loader //On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip kernel9loader
if(isN3DS) if(isN3DS)
{ {
kernel9Loader(arm9Section); kernel9Loader((Arm9Bin *)arm9Section);
firm->arm9Entry = (u8 *)0x801301C; firm->arm9Entry = (u8 *)0x801301C;
} }
@ -458,7 +458,7 @@ static inline void patch1x2xNativeAndSafeFirm(u32 devMode)
if(isN3DS) if(isN3DS)
{ {
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip kernel9loader //Decrypt ARM9Bin and patch ARM9 entrypoint to skip kernel9loader
kernel9Loader(arm9Section); kernel9Loader((Arm9Bin *)arm9Section);
firm->arm9Entry = (u8 *)0x801B01C; firm->arm9Entry = (u8 *)0x801B01C;
patchFirmWrites(arm9Section, section[2].size); patchFirmWrites(arm9Section, section[2].size);
@ -481,7 +481,7 @@ static inline void copySection0AndInjectSystemModules(FirmwareType firmType, boo
for(u8 *src = (u8 *)firm + section[0].offset, *srcEnd = src + section[0].size, *dst = section[0].address; for(u8 *src = (u8 *)firm + section[0].offset, *srcEnd = src + section[0].size, *dst = section[0].address;
src < srcEnd; src += srcModuleSize, dst += dstModuleSize) src < srcEnd; src += srcModuleSize, dst += dstModuleSize)
{ {
srcModuleSize = *(u32 *)(src + 0x104) * 0x200; srcModuleSize = ((Ncch *)src)->contentSize * 0x200;
const char *moduleName = (char *)(src + 0x200); const char *moduleName = (char *)(src + 0x200);
u32 fileSize; u32 fileSize;