Switch to structs where possible
This commit is contained in:
parent
b575ee9e28
commit
50b24bf6c2
@ -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
|
||||||
|
@ -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);
|
@ -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;
|
||||||
|
Reference in New Issue
Block a user