From 4ab5ad9a892667ba7000bb06299f4072147db13b Mon Sep 17 00:00:00 2001 From: Aurora Date: Sun, 16 Oct 2016 20:40:56 +0200 Subject: [PATCH] Replace the used key2 as the previous one was faulty (thanks @gemarcano), allow updating from every A9LH setup --- source/3dsheaders.h | 161 ++++++++++++++++++++++++++++++++++++++++++ source/crypto.c | 41 ++++++----- source/crypto.h | 5 +- source/fatfs/diskio.c | 8 +-- source/fs.c | 50 ++++++------- source/fs.h | 2 - source/installer.c | 106 ++++++++++++++++----------- source/installer.h | 4 +- source/screen.c | 2 +- source/screen.h | 2 + source/start.s | 6 +- source/strings.c | 2 - source/types.h | 10 ++- 13 files changed, 298 insertions(+), 101 deletions(-) create mode 100644 source/3dsheaders.h diff --git a/source/3dsheaders.h b/source/3dsheaders.h new file mode 100644 index 0000000..7e7bfd0 --- /dev/null +++ b/source/3dsheaders.h @@ -0,0 +1,161 @@ +/* +* This file is part of Luma3DS +* Copyright (C) 2016 Aurora Wright, TuxSH +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* +* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified +* reasonable legal notices or author attributions in that material or in the Appropriate Legal +* Notices displayed by works containing it. +*/ + +/* +* Adapted from 3DBrew and https://github.com/mid-kid/CakesForeveryWan/blob/master/source/headers.h +*/ + +typedef struct __attribute__((packed)) +{ + u32 address; + u32 phyRegionSize; + u32 size; +} CodeSetInfo; + +typedef struct __attribute__((packed)) +{ + u32 saveDataSize[2]; + u32 jumpID[2]; + u8 reserved[0x30]; +} SystemInfo; + +typedef struct __attribute__((packed)) +{ + char appTitle[8]; + u8 reserved1[5]; + u8 flag; + u8 remasterVersion[2]; + CodeSetInfo textCodeSet; + u32 stackSize; + CodeSetInfo roCodeSet; + u8 reserved2[4]; + CodeSetInfo dataCodeSet; + u32 bssSize; + char depends[0x180]; + SystemInfo systemInfo; +} SystemControlInfo; + +typedef struct __attribute__((packed)) +{ + SystemControlInfo systemControlInfo; + u8 aci[0x200]; + u8 accessDescSig[0x100]; + u8 ncchPubKey[0x100]; + u8 aciLim[0x200]; +} ExHeader; + +typedef struct __attribute__((packed)) +{ + u8 sig[0x100]; //RSA-2048 signature of the NCCH header, using SHA-256 + char magic[4]; //NCCH + u32 contentSize; //Media unit + u8 partitionId[8]; + u8 makerCode[2]; + u16 version; + u8 reserved1[4]; + u8 programID[8]; + u8 reserved2[0x10]; + u8 logoHash[0x20]; //Logo Region SHA-256 hash + char productCode[0x10]; + u8 exHeaderHash[0x20]; //Extended header SHA-256 hash + u32 exHeaderSize; //Extended header size + u32 reserved3; + u8 flags[8]; + u32 plainOffset; //Media unit + u32 plainSize; //Media unit + u32 logoOffset; //Media unit + u32 logoSize; //Media unit + u32 exeFsOffset; //Media unit + u32 exeFsSize; //Media unit + u32 exeFsHashSize; //Media unit + u32 reserved4; + u32 romFsOffset; //Media unit + u32 romFsSize; //Media unit + u32 romFsHashSize; //Media unit + u32 reserved5; + u8 exeFsHash[0x20]; //ExeFS superblock SHA-256 hash + u8 romFsHash[0x20]; //RomFS superblock SHA-256 hash +} Ncch; + +typedef struct __attribute__((packed)) +{ + Ncch ncch; + ExHeader exHeader; +} Cxi; + +typedef struct __attribute__((packed)) +{ + char sigIssuer[0x40]; + u8 eccPubKey[0x3C]; + u8 version; + u8 caCrlVersion; + u8 signerCrlVersion; + u8 titleKey[0x10]; + u8 reserved1; + u8 ticketId[8]; + u8 consoleId[4]; + u8 titleId[8]; + u8 reserved2[2]; + u16 ticketTitleVersion; + u8 reserved3[8]; + u8 licenseType; + u8 ticketCommonKeyYIndex; //Ticket common keyY index, usually 0x1 for retail system titles. + u8 reserved4[0x2A]; + u8 unk[4]; //eShop Account ID? + u8 reserved5; + u8 audit; + u8 reserved6[0x42]; + u8 limits[0x40]; + u8 contentIndex[0xAC]; +} Ticket; + +typedef struct __attribute__((packed)) +{ + u32 offset; + u8 *address; + u32 size; + u32 procType; + u8 hash[0x20]; +} FirmSection; + +typedef struct __attribute__((packed)) +{ + u32 magic; + u32 reserved1; + u8 *arm11Entry; + u8 *arm9Entry; + u8 reserved2[0x30]; + FirmSection section[4]; +} Firm; + +typedef struct __attribute__((packed)) +{ + u8 keyX[0x10]; + u8 keyY[0x10]; + u8 ctr[0x10]; + char size[8]; + u8 reserved[8]; + u8 ctlBlock[0x10]; + char magic[4]; + u8 reserved2[0xC]; + u8 slot0x16keyX[0x10]; +} Arm9Bin; \ No newline at end of file diff --git a/source/crypto.c b/source/crypto.c index 59a9d77..688c64f 100755 --- a/source/crypto.c +++ b/source/crypto.c @@ -275,10 +275,12 @@ static void sha(void *res, const void *src, u32 size, u32 mode) static u8 __attribute__((aligned(4))) nandCtr[AES_BLOCK_SIZE]; static u8 nandSlot; static u32 fatStart; -const u8 __attribute__((aligned(4))) key2s[3][AES_BLOCK_SIZE] = { +const u8 __attribute__((aligned(4))) key2s[5][AES_BLOCK_SIZE] = { {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0}, + {0x08, 0x24, 0xD3, 0xCB, 0x4A, 0xE9, 0x4D, 0x62, 0x4D, 0xAA, 0x52, 0x60, 0x47, 0xC5, 0x93, 0x94}, + {0x65, 0x29, 0x3E, 0x12, 0x56, 0x0C, 0x0B, 0xD1, 0xDD, 0xB5, 0x63, 0x1C, 0xB6, 0xD9, 0x52, 0x75}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3B, 0xF5, 0xF6}, - {0x65, 0x29, 0x3E, 0x12, 0x56, 0x0C, 0x0B, 0xD1, 0xDD, 0xB5, 0x63, 0x1C, 0xB6, 0xD9, 0x52, 0x75} + {0xA5, 0x25, 0x87, 0x11, 0x8F, 0x42, 0x9F, 0x3D, 0x65, 0x1D, 0xDD, 0x58, 0x0B, 0x6D, 0xF2, 0x17} }; void getNandCtr(void) @@ -295,7 +297,7 @@ void ctrNandInit(void) { getNandCtr(); - if(isN3DS) + if(ISN3DS) { u8 __attribute__((aligned(4))) keyY0x5[AES_BLOCK_SIZE] = {0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE}; aes_setkey(0x05, keyY0x5, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); @@ -382,7 +384,7 @@ void generateSector(u8 *keySector, u32 mode) memcpy(keySector + AES_BLOCK_SIZE, key2s[0], AES_BLOCK_SIZE); break; default: - memcpy(keySector + AES_BLOCK_SIZE, key2s[2], AES_BLOCK_SIZE); + memcpy(keySector + AES_BLOCK_SIZE, key2s[1], AES_BLOCK_SIZE); break; } @@ -417,20 +419,27 @@ bool verifyHash(const void *data, u32 size, const u8 *hash) return memcmp(shasum, hash, sizeof(shasum)) == 0; } -u32 decryptExeFs(u8 *inbuf) +u32 decryptExeFs(Cxi *cxi) { - u8 *exeFsOffset = inbuf + *(u32 *)(inbuf + 0x1A0) * 0x200; - u32 exeFsSize = *(u32 *)(inbuf + 0x1A4) * 0x200; - u8 __attribute__((aligned(4))) ncchCtr[AES_BLOCK_SIZE] = {0}; + u32 exeFsSize = 0; - for(u32 i = 0; i < 8; i++) - ncchCtr[7 - i] = *(inbuf + 0x108 + i); - ncchCtr[8] = 2; + if(memcmp(cxi->ncch.magic, "NCCH", 4) == 0) + { + u8 *exeFsOffset = (u8 *)cxi + (cxi->ncch.exeFsOffset + 1) * 0x200; + exeFsSize = (cxi->ncch.exeFsSize - 1) * 0x200; + u8 __attribute__((aligned(4))) ncchCtr[AES_BLOCK_SIZE] = {0}; - aes_setkey(0x2C, inbuf, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); - aes_advctr(ncchCtr, 0x200 / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL); - aes_use_keyslot(0x2C); - aes(inbuf, exeFsOffset + 0x200, exeFsSize / AES_BLOCK_SIZE, ncchCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); + for(u32 i = 0; i < 8; i++) + ncchCtr[7 - i] = cxi->ncch.partitionId[i]; + ncchCtr[8] = 2; - return exeFsSize - 0x200; + aes_setkey(0x2C, cxi, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); + aes_advctr(ncchCtr, 0x200 / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL); + aes_use_keyslot(0x2C); + aes(cxi, exeFsOffset, exeFsSize / AES_BLOCK_SIZE, ncchCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); + + if(memcmp(cxi, "FIRM", 4) != 0) exeFsSize = 0; + } + + return exeFsSize; } \ No newline at end of file diff --git a/source/crypto.h b/source/crypto.h index aa7224e..fd21e74 100755 --- a/source/crypto.h +++ b/source/crypto.h @@ -79,9 +79,6 @@ #define SHA_224_HASH_SIZE (224 / 8) #define SHA_1_HASH_SIZE (160 / 8) -extern bool isN3DS; -const u8 key2s[3][AES_BLOCK_SIZE]; - void getNandCtr(void); void ctrNandInit(void); int ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf); @@ -91,4 +88,4 @@ void setupKeyslot0x11(const void *otp, bool isA9lh); void generateSector(u8 *keySector, u32 mode); void getSector(u8 *keySector, bool isA9lh); bool verifyHash(const void *data, u32 size, const u8 *hash); -u32 decryptExeFs(u8 *inbuf); \ No newline at end of file +u32 decryptExeFs(Cxi *cxi); \ No newline at end of file diff --git a/source/fatfs/diskio.c b/source/fatfs/diskio.c index c9b5114..db917bb 100644 --- a/source/fatfs/diskio.c +++ b/source/fatfs/diskio.c @@ -39,7 +39,7 @@ DSTATUS disk_initialize ( { if(pdrv == CTRNAND) ctrNandInit(); - return RES_OK; + return 0; } @@ -55,8 +55,8 @@ DRESULT disk_read ( UINT count /* Number of sectors to read */ ) { - return ((pdrv == SDCARD && !sdmmc_sdcard_readsectors(sector, count, (BYTE *)buff)) || - (pdrv == CTRNAND && !ctrNandRead(sector, count, (BYTE *)buff))) ? RES_OK : RES_PARERR; + return ((pdrv == SDCARD && !sdmmc_sdcard_readsectors(sector, count, buff)) || + (pdrv == CTRNAND && !ctrNandRead(sector, count, buff))) ? RES_OK : RES_PARERR; } @@ -73,7 +73,7 @@ DRESULT disk_write ( UINT count /* Number of sectors to write */ ) { - return (pdrv == SDCARD && !sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff)) ? RES_OK : RES_PARERR; + return (pdrv == SDCARD && !sdmmc_sdcard_writesectors(sector, count, buff)) ? RES_OK : RES_PARERR; } #endif diff --git a/source/fs.c b/source/fs.c index 0cba911..ef3ee1c 100644 --- a/source/fs.c +++ b/source/fs.c @@ -53,32 +53,34 @@ bool fileWrite(const void *buffer, const char *path, u32 size) FIL file; bool ret; - FRESULT result = f_open(&file, path, FA_WRITE | FA_OPEN_ALWAYS); - - if(result == FR_OK) + switch(f_open(&file, path, FA_WRITE | FA_OPEN_ALWAYS)) { - unsigned int written; - f_write(&file, buffer, size, &written); - f_truncate(&file); - f_close(&file); + case FR_OK: + { + unsigned int written; + f_write(&file, buffer, size, &written); + f_truncate(&file); + f_close(&file); - ret = (u32)written == size; - } - else if(result == FR_NO_PATH) - { - for(u32 i = 1; path[i] != 0; i++) - if(path[i] == '/') - { - char folder[i + 1]; - memcpy(folder, path, i); - folder[i] = 0; - ret = f_mkdir(folder) == FR_OK; - if(!ret) break; - } + ret = (u32)written == size; + break; + } + case FR_NO_PATH: + for(u32 i = 1; path[i] != 0; i++) + if(path[i] == '/') + { + char folder[i + 1]; + memcpy(folder, path, i); + folder[i] = 0; + f_mkdir(folder); + } - if(ret) ret = fileWrite(buffer, path, size); + ret = fileWrite(buffer, path, size); + break; + default: + ret = false; + break; } - else ret = false; return ret; } @@ -87,7 +89,7 @@ u32 firmRead(void *dest) { const char *firmFolders[] = { "00000002", "20000002" }; char path[48] = "1:/title/00040138/"; - concatenateStrings(path, firmFolders[isN3DS ? 1 : 0]); + concatenateStrings(path, firmFolders[ISN3DS ? 1 : 0]); concatenateStrings(path, "/content"); DIR dir; @@ -116,7 +118,7 @@ u32 firmRead(void *dest) } //FIRM is equal or newer than 11.0 - if(tempVersion >= (isN3DS ? 0x21 : 0x52)) ret = 2; + if(tempVersion >= (ISN3DS ? 0x21 : 0x52)) ret = 2; //Found an older cxi if(tempVersion < firmVersion) firmVersion = tempVersion; diff --git a/source/fs.h b/source/fs.h index 5ac6902..5355a8b 100644 --- a/source/fs.h +++ b/source/fs.h @@ -24,8 +24,6 @@ #include "types.h" -extern bool isN3DS; - bool mountFs(bool isSd); u32 fileRead(void *dest, const char *path, u32 maxSize); bool fileWrite(const void *buffer, const char *path, u32 size); diff --git a/source/installer.c b/source/installer.c index bf03220..a32aa5f 100755 --- a/source/installer.c +++ b/source/installer.c @@ -2,7 +2,6 @@ * installer.c */ -#include "installer.h" #include "memory.h" #include "fs.h" #include "crypto.h" @@ -10,6 +9,7 @@ #include "draw.h" #include "utils.h" #include "types.h" +#include "installer.h" #include "fatfs/sdmmc/sdmmc.h" #include "../build/bundled.h" @@ -24,6 +24,10 @@ static const u8 sectorHash[SHA_256_HASH_SIZE] = { firm0A9lhHash[SHA_256_HASH_SIZE] = { 0x79, 0x3D, 0x35, 0x7B, 0x8F, 0xF1, 0xFC, 0xF0, 0x8F, 0xB6, 0xDB, 0x51, 0x31, 0xD4, 0xA7, 0x74, 0x8E, 0xF0, 0x4A, 0xB1, 0xA6, 0x7F, 0xCD, 0xAB, 0x0C, 0x0A, 0xC0, 0x69, 0xA7, 0x9D, 0xC5, 0x04 +}, + firm090A9lhHash[SHA_256_HASH_SIZE] = { + 0x68, 0x52, 0xCC, 0x21, 0x89, 0xAE, 0x28, 0x38, 0x1A, 0x75, 0x90, 0xE7, 0x38, 0x23, 0x48, 0x41, + 0x8E, 0x80, 0x78, 0x75, 0x27, 0x64, 0x04, 0xD6, 0x28, 0xD6, 0xFA, 0x39, 0xA8, 0x6F, 0xB0, 0x3F }, firm0100Hash[SHA_256_HASH_SIZE] = { 0xD8, 0x2D, 0xB7, 0xB4, 0x38, 0x2B, 0x07, 0x88, 0x99, 0x77, 0x91, 0x0C, 0xC6, 0xEC, 0x6D, 0x87, @@ -35,18 +39,11 @@ static const u8 sectorHash[SHA_256_HASH_SIZE] = { }; u32 posY; -bool isN3DS; void main(void) { - //Determine if booting with A9LH - bool isA9lh = !PDN_SPI_CNT; - - //Detect the console being used - isN3DS = PDN_MPCORE_CFG == 7; - vu32 *magic = (vu32 *)0x25000000; - bool isOtpless = isA9lh && magic[0] == 0xABADCAFE && magic[1] == 0xDEADCAFE; + bool isOtpless = ISA9LH && magic[0] == 0xABADCAFE && magic[1] == 0xDEADCAFE; initScreens(); @@ -60,7 +57,7 @@ void main(void) if(!isOtpless) { - posY = drawString(isA9lh ? "Press SELECT to update A9LH, START to uninstall" : "Press SELECT for a full install", 10, posY + SPACING_Y, COLOR_WHITE); + posY = drawString(ISA9LH ? "Press SELECT to update A9LH, START to uninstall" : "Press SELECT for a full install", 10, posY + SPACING_Y, COLOR_WHITE); posY = drawString("Press any other button to shutdown", 10, posY, COLOR_WHITE); pressed = waitInput(); } @@ -71,15 +68,17 @@ void main(void) pressed = 0; } - if(isOtpless || pressed == BUTTON_SELECT) installer(isA9lh, isOtpless); - if(pressed == BUTTON_START && isA9lh) uninstaller(); + if(isOtpless || pressed == BUTTON_SELECT) installer(isOtpless); + if(pressed == BUTTON_START && ISA9LH) uninstaller(); shutdown(0, NULL); } -static inline void installer(bool isA9lh, bool isOtpless) +static inline void installer(bool isOtpless) { - bool updateA9lh = false; + bool updateKey2 = false, + updateFirm0 = false, + updateFirm1 = false; u8 otp[256] = {0}, keySector[512]; @@ -87,7 +86,7 @@ static inline void installer(bool isA9lh, bool isOtpless) shutdown(1, "Error: failed to mount the SD card"); //If making a first install on O3DS, we need the OTP - if(!isA9lh && !isN3DS) + if(!ISA9LH && !ISN3DS) { const char otpPath[] = "a9lh/otp.bin"; @@ -107,7 +106,7 @@ static inline void installer(bool isA9lh, bool isOtpless) } //Setup the key sector de/encryption with the SHA register or otp.bin - if(isA9lh || !isN3DS) setupKeyslot0x11(otp, isA9lh); + if(ISA9LH || !ISN3DS) setupKeyslot0x11(otp, ISA9LH); //Calculate the CTR for the 3DS partitions getNandCtr(); @@ -121,7 +120,7 @@ static inline void installer(bool isA9lh, bool isOtpless) } //If booting from A9LH or on N3DS, we can use the key sector from NAND - if(isA9lh || isN3DS) getSector(keySector, isA9lh); + if(ISA9LH || ISN3DS) getSector(keySector, ISA9LH); else { //Read decrypted key sector @@ -131,19 +130,50 @@ static inline void installer(bool isA9lh, bool isOtpless) shutdown(1, "Error: secret_sector.bin is invalid or corrupted"); } - if(isA9lh && !isOtpless) + if(ISA9LH && !isOtpless) { - u32 i; - for(i = 1; i < 3; i++) - if(memcmp(keySector + AES_BLOCK_SIZE, key2s[i], AES_BLOCK_SIZE) == 0) break; + u32 i; + for(i = 1; i < 5; i++) + if(memcmp(keySector + AES_BLOCK_SIZE, key2s[i], AES_BLOCK_SIZE) == 0) break; - if(i == 3) shutdown(1, "Error: the OTP hash or the NAND key sector\nare invalid"); - if(i == 1) updateA9lh = true; + switch(i) + { + case 5: + shutdown(1, "Error: the OTP hash or the NAND key sector\nare invalid"); + break; + case 2: + case 3: + updateKey2 = true; + break; + case 4: + updateFirm1 = true; + updateKey2 = true; + break; + default: + break; + } + + if(!verifyHash((void *)FIRM0_OFFSET, SECTION2_POSITION, firm0A9lhHash)) + { + if(!verifyHash((void *)FIRM0_OFFSET, SECTION2_POSITION, firm090A9lhHash)) + shutdown(1, "Error: NAND FIRM0 is invalid"); + + updateFirm0 = true; + } } - if(!isA9lh || updateA9lh || isOtpless) generateSector(keySector, (!isA9lh && isN3DS) ? 1 : 0); + if(!ISA9LH || updateKey2 || isOtpless) generateSector(keySector, (!ISA9LH && ISN3DS) ? 1 : 0); - if(!isA9lh || updateA9lh) + if(!ISA9LH && ISN3DS) + { + //Read 10.0 FIRM0 + if(fileRead((void *)FIRM0_100_OFFSET, "a9lh/firm0_100.bin", FIRM0100_SIZE) != FIRM0100_SIZE) + shutdown(1, "Error: firm0_100.bin doesn't exist or has a wrong size"); + if(!verifyHash((void *)FIRM0_100_OFFSET, FIRM0100_SIZE, firm0100Hash)) + shutdown(1, "Error: firm0_100.bin is invalid or corrupted"); + } + + if(!ISA9LH || updateFirm0) { //Read FIRM0 if(fileRead((void *)FIRM0_OFFSET, "a9lh/firm0.bin", FIRM0_SIZE) != FIRM0_SIZE) @@ -151,20 +181,9 @@ static inline void installer(bool isA9lh, bool isOtpless) if(!verifyHash((void *)FIRM0_OFFSET, FIRM0_SIZE, firm0Hash)) shutdown(1, "Error: firm0.bin is invalid or corrupted"); } - else if(!isOtpless && !verifyHash((void *)FIRM0_OFFSET, SECTION2_POSITION, firm0A9lhHash)) - shutdown(1, "Error: NAND FIRM0 is invalid"); - if(!isA9lh) + if(!ISA9LH || updateFirm1) { - if(isN3DS) - { - //Read 10.0 FIRM0 - if(fileRead((void *)FIRM0_100_OFFSET, "a9lh/firm0_100.bin", FIRM0100_SIZE) != FIRM0100_SIZE) - shutdown(1, "Error: firm0_100.bin doesn't exist or has a wrong size"); - if(!verifyHash((void *)FIRM0_100_OFFSET, FIRM0100_SIZE, firm0100Hash)) - shutdown(1, "Error: firm0_100.bin is invalid or corrupted"); - } - //Read FIRM1 if(fileRead((void *)FIRM1_OFFSET, "a9lh/firm1.bin", FIRM1_SIZE) != FIRM1_SIZE) shutdown(1, "Error: firm1.bin doesn't exist or has a wrong size"); @@ -226,10 +245,10 @@ static inline void installer(bool isA9lh, bool isOtpless) sdmmc_nand_writesectors(0x5C000, MAX_STAGE2_SIZE / 0x200, (u8 *)STAGE2_OFFSET); } - if(!isA9lh) writeFirm((u8 *)FIRM1_OFFSET, true, FIRM1_SIZE); - if(!isA9lh || updateA9lh || isOtpless) sdmmc_nand_writesectors(0x96, 1, keySector); + if(!ISA9LH || updateFirm1) writeFirm((u8 *)FIRM1_OFFSET, true, FIRM1_SIZE); + if(!ISA9LH || updateKey2 || isOtpless) sdmmc_nand_writesectors(0x96, 1, keySector); - if(!isA9lh && isN3DS) + if(!ISA9LH && ISN3DS) { *(vu32 *)0x80FD0FC = 0xEAFFCBBF; //B 0x80F0000 memcpy((void *)0x80F0000, loader_bin, loader_bin_size); @@ -241,7 +260,7 @@ static inline void installer(bool isA9lh, bool isOtpless) writeFirm((u8 *)FIRM0_OFFSET, false, FIRM0_SIZE); - shutdown(2, isA9lh && !isOtpless ? "Update: success!" : "Full install: success!"); + shutdown(2, ISA9LH && !isOtpless ? "Update: success!" : "Full install: success!"); } static inline void uninstaller(void) @@ -253,7 +272,7 @@ static inline void uninstaller(void) inputSequence(); //New 3DSes need a key sector with a proper key2, Old 3DSes have a blank key sector - if(isN3DS) + if(ISN3DS) { setupKeyslot0x11(NULL, true); getSector(keySector, true); @@ -286,7 +305,8 @@ static inline void uninstaller(void) } //Decrypt it and get its size - u32 firmSize = decryptExeFs((u8 *)FIRM0_OFFSET); + u32 firmSize = decryptExeFs((Cxi *)FIRM0_OFFSET); + if(firmSize == 0) shutdown(1, "Error: couldn't decrypt the CTRNAND FIRM"); //writeFirm encrypts in-place, so we need two copies memcpy((void *)FIRM1_OFFSET, (void *)FIRM0_OFFSET, firmSize); diff --git a/source/installer.h b/source/installer.h index c7658e1..37bfe7e 100644 --- a/source/installer.h +++ b/source/installer.h @@ -23,5 +23,7 @@ #define MAX_STAGE1_SIZE 0x1E70 #define MAX_STAGE2_SIZE 0x89A00 -static inline void installer(bool isA9lh, bool isOtpless); +extern const u8 key2s[5][AES_BLOCK_SIZE]; + +static inline void installer(bool isOtpless); static inline void uninstaller(void); \ No newline at end of file diff --git a/source/screen.c b/source/screen.c index dbf9320..b2467ab 100644 --- a/source/screen.c +++ b/source/screen.c @@ -179,7 +179,7 @@ void initScreens(void) WAIT_FOR_ARM9(); } - if(PDN_GPU_CNT == 1) + if(!ARESCREENSINITED) { invokeArm11Function(initSequence); diff --git a/source/screen.h b/source/screen.h index ce8da5f..5f273b6 100644 --- a/source/screen.h +++ b/source/screen.h @@ -30,6 +30,8 @@ #define PDN_GPU_CNT (*(vu8 *)0x10141200) +#define ARESCREENSINITED (PDN_GPU_CNT != 1) + #define BRAHMA_ARM11_ENTRY 0x1FFFFFF8 #define WAIT_FOR_ARM9() *arm11Entry = 0; while(!*arm11Entry); ((void (*)())*arm11Entry)(); diff --git a/source/start.s b/source/start.s index 13e747d..d545d4d 100644 --- a/source/start.s +++ b/source/start.s @@ -24,14 +24,14 @@ .align 4 .global _start _start: - @ Change the stack pointer - mov sp, #0x27000000 - @ Disable interrupts mrs r0, cpsr orr r0, #0x1C0 msr cpsr_cx, r0 + @ Change the stack pointer + mov sp, #0x27000000 + @ Disable caches / MPU mrc p15, 0, r0, c1, c0, 0 @ read control register bic r0, #(1<<12) @ - instruction cache disable diff --git a/source/strings.c b/source/strings.c index 55fee26..5a63155 100644 --- a/source/strings.c +++ b/source/strings.c @@ -50,6 +50,4 @@ void hexItoa(u32 number, char *out, u32 digits) out[digits - 1 - i++] = hexDigits[number & 0xF]; number >>= 4; } - - while(i < digits) out[digits - 1 - i++] = '0'; } \ No newline at end of file diff --git a/source/types.h b/source/types.h index bce6f07..0ad40e7 100644 --- a/source/types.h +++ b/source/types.h @@ -16,4 +16,12 @@ typedef uint64_t u64; typedef volatile u8 vu8; typedef volatile u16 vu16; typedef volatile u32 vu32; -typedef volatile u64 vu64; \ No newline at end of file +typedef volatile u64 vu64; + +#define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC) +#define PDN_SPI_CNT (*(vu32 *)0x101401C0) + +#define ISN3DS (PDN_MPCORE_CFG == 7) +#define ISA9LH (!PDN_SPI_CNT) + +#include "3dsheaders.h" \ No newline at end of file