From b6aa3e1fd1569e6dd362900f3659a75a2567e97f Mon Sep 17 00:00:00 2001 From: Aurora Date: Fri, 25 Mar 2016 04:47:07 +0100 Subject: [PATCH] Removed stage2-only install, added A9LH update which only needs the stage1 and 2 payloads to update A9LH. Also, secret_sector.bin is never needed on New 3DS anymore --- source/crypto.c | 11 ++-- source/fs.c | 5 -- source/fs.h | 1 - source/installer.c | 145 ++++++++++++++++++-------------------------- source/installer.h | 5 +- source/main.c | 2 + source/screeninit.c | 3 + source/utils.c | 10 +-- source/utils.h | 8 --- 9 files changed, 74 insertions(+), 116 deletions(-) diff --git a/source/crypto.c b/source/crypto.c index 119f668..b22bc2f 100755 --- a/source/crypto.c +++ b/source/crypto.c @@ -349,16 +349,17 @@ void generateSector(u8 *keySector){ } //Test the OTP to be correct by verifying key2 -u32 testOtp(u32 a9lhBoot, u8 *tempOffset){ +u32 testOtp(u32 a9lhBoot, u8 *keySector){ //Read keysector from NAND - sdmmc_nand_readsectors(0x96, 1, tempOffset); + sdmmc_nand_readsectors(0x96, 1, keySector); - //Decrypt key2 + //Decrypt keys (we need just key2 on A9LH) aes_use_keyslot(0x11); - aes(tempOffset + 0x10, tempOffset + 0x10, 1, NULL, AES_ECB_DECRYPT_MODE, 0); + for(u32 i = 0, keysAmount = a9lhBoot ? 2 : 32; i < keysAmount; i++) + aes(keySector + (0x10 * i), keySector + (0x10 * i), 1, NULL, AES_ECB_DECRYPT_MODE, 0); //Test key2 - if(memcmp(tempOffset + 0x10, a9lhBoot ? a9lhKey2 : key2, 0x10) != 0) return 0; + if(memcmp(keySector + 0x10, a9lhBoot ? a9lhKey2 : key2, 0x10) != 0) return 0; return 1; } diff --git a/source/fs.c b/source/fs.c index 33f17b1..7a490ce 100644 --- a/source/fs.c +++ b/source/fs.c @@ -12,11 +12,6 @@ u32 mountSD(void){ return 1; } -u32 unmountSD(void){ - if(f_mount(NULL, "0:", 1) != FR_OK) return 0; - return 1; -} - u32 fileRead(void *dest, const char *path, u32 size){ FRESULT fr; FIL fp; diff --git a/source/fs.h b/source/fs.h index cc0f3ff..a02ffc0 100644 --- a/source/fs.h +++ b/source/fs.h @@ -7,6 +7,5 @@ #include "types.h" u32 mountSD(void); -u32 unmountSD(void); u32 fileRead(void *dest, const char *path, u32 size); u32 fileSize(const char *path); \ No newline at end of file diff --git a/source/installer.c b/source/installer.c index 10d452b..2d38efd 100755 --- a/source/installer.c +++ b/source/installer.c @@ -16,6 +16,11 @@ static const u8 firm0Hash[0x20] = { 0x95, 0x47, 0x61, 0xA1, 0xD5, 0xEA, 0x03, 0xB5, 0xEB, 0x50, 0x47, 0xAC, 0x63, 0xAC, 0x5D, 0x6B }; +static const u8 firm0A9lhHash[0x20] = { + 0xFC, 0x7C, 0xC7, 0x2D, 0xA3, 0x0A, 0xDE, 0x3A, 0xE2, 0xFE, 0x7D, 0x79, 0xA3, 0xC2, 0x6C, 0x82, + 0xB8, 0xA3, 0xDB, 0xC4, 0x46, 0x22, 0xB4, 0x61, 0x8D, 0xDC, 0x73, 0x90, 0x50, 0x5D, 0x40, 0x11 +}; + static const u8 firm1Hash[0x20] = { 0xD2, 0x53, 0xC1, 0xCC, 0x0A, 0x5F, 0xFA, 0xC6, 0xB3, 0x83, 0xDA, 0xC1, 0x82, 0x7C, 0xFB, 0x3B, 0x2D, 0x3D, 0x56, 0x6C, 0x6A, 0x1A, 0x8E, 0x52, 0x54, 0xE3, 0x89, 0xC2, 0x95, 0x06, 0x23, 0xE5 @@ -23,65 +28,18 @@ static const u8 firm1Hash[0x20] = { int pos_y; -static void installStage2(u32 mode){ - if(!mode){ - pos_y = drawString("You are about to update stage2 only", 10, pos_y + 10, COLOR_RED); - pos_y = drawString("Doing this could brick your console!", 10, pos_y, COLOR_RED); - pos_y = drawString("If you would like to continue, press:", 10, pos_y, COLOR_WHITE); - pos_y = drawString("Up, Down, Left, Right, B, A, START, SELECT", 10, pos_y, COLOR_WHITE); - - u16 unlockSequence[] = { BUTTON_UP, BUTTON_DOWN, BUTTON_LEFT, BUTTON_RIGHT, BUTTON_B, BUTTON_A, BUTTON_START, BUTTON_SELECT }; - u32 sequenceSize = sizeof(unlockSequence) / sizeof(u16); - - for(u32 correctPresses = 0; correctPresses < sequenceSize; correctPresses++){ - if(waitInput() != unlockSequence[correctPresses]) - shutdown(1, "Button sequence not entered correctly"); - } - - //Mount the SD card - mountSD(); - } - - //Read stage2 - const char path[] = "a9lh/payload_stage2.bin"; - u32 size = fileSize(path); - if(!size || size > MAX_STAGE2_SIZE) - shutdown(1, "Error: stage2.bin doesn't exist or exceeds\nmax size"); - memset((void *)STAGE2_OFFSET, 0, MAX_STAGE2_SIZE); - fileRead((void *)STAGE2_OFFSET, path, size); - - if(mode) return; - - sdmmc_nand_writesectors(0x5C000, 0x20, (vu8 *)STAGE2_OFFSET); - - //Unmount the SD card - unmountSD(); - shutdown(2, "Stage2 update: success!"); -} - void installer(void){ //Determine if booting with A9LH u32 a9lhBoot = (PDN_SPI_CNT == 0x0) ? 1 : 0; //Detect the console being used u32 console = (PDN_MPCORE_CFG == 1) ? 0 : 1; - while(1){ - clearScreens(); - drawString("Safe A9LH Installer v1.4", 10, 10, COLOR_TITLE); - pos_y = drawString("Thanks to delebile, #cakey and StandardBus", 10, 40, COLOR_WHITE); - pos_y = drawString("Press SELECT for a full install", 10, pos_y + SPACING_VERT, COLOR_WHITE); - if(a9lhBoot){ pos_y = drawString("Press START to only update stage2", 10, pos_y, COLOR_WHITE); - pos_y = drawString("(Only do stage2 updates from the fork you use!)", 10, pos_y, COLOR_RED); } - pos_y = drawString("Press any other button to shutdown", 10, pos_y, COLOR_WHITE); + drawString("Safe A9LH Installer v1.5", 10, 10, COLOR_TITLE); + pos_y = drawString("Thanks to delebile, #cakey and StandardBus", 10, 40, COLOR_WHITE); + pos_y = drawString(a9lhBoot ? "Press SELECT to update A9LH" : "Press SELECT for a full install", 10, pos_y, COLOR_WHITE); + pos_y = drawString("Press any other button to shutdown", 10, pos_y, COLOR_WHITE); - u16 pressed = waitInput(); - if(a9lhBoot && pressed == BUTTON_START) installStage2(0); - else if(pressed == BUTTON_SELECT) break; - else shutdown(0, NULL); - } - - //Mount the SD card - mountSD(); + if(waitInput() != BUTTON_SELECT) shutdown(0, NULL); const char *path; @@ -97,65 +55,78 @@ void installer(void){ //Setup the key sector de/encryption with the SHA register or otp.bin setupKeyslot0x11(a9lhBoot, (void *)OTP_OFFSET); - if(a9lhBoot && !testOtp(a9lhBoot, (u8 *)TEMP_OFFSET)) + if(a9lhBoot && !testOtp(a9lhBoot, (u8 *)SECTOR_OFFSET)) shutdown(1, "Error: the OTP hash is invalid"); - if(!a9lhBoot && console && !testOtp(a9lhBoot, (u8 *)TEMP_OFFSET)) + if(!a9lhBoot && console && !testOtp(a9lhBoot, (u8 *)SECTOR_OFFSET)) shutdown(1, "Error: otp.bin is invalid or corrupted"); //Calculate the CTR for the 3DS partitions getNandCTR(); - //Test that the CTR is correct - readFirm0((u8 *)TEMP_OFFSET, 0x200); - if(memcmp((void *)TEMP_OFFSET, "FIRM", 4) != 0) + //Get NAND FIRM0 and test that the CTR is correct + readFirm0((u8 *)FIRM0_OFFSET, FIRM_SIZE); + if(memcmp((void *)FIRM0_OFFSET, "FIRM", 4) != 0) shutdown(1, "Error: failed to setup FIRM encryption"); - //Read decrypted key sector - path = "a9lh/secret_sector.bin"; - if(fileSize(path) != 0x200) - shutdown(1, "Error: secret_sector.bin doesn't exist or has\na wrong size"); - fileRead((void *)SECTOR_OFFSET, path, 0x200); - if(!verifyHash((void *)SECTOR_OFFSET, 0x200, sectorHash)) - shutdown(1, "Error: secret_sector.bin is invalid or corrupted"); + if(!a9lhBoot){ + if(!console){ + //Read decrypted key sector + path = "a9lh/secret_sector.bin"; + if(fileSize(path) != 0x200) + shutdown(1, "Error: secret_sector.bin doesn't exist or has\na wrong size"); + fileRead((void *)SECTOR_OFFSET, path, 0x200); + if(!verifyHash((void *)SECTOR_OFFSET, 0x200, sectorHash)) + shutdown(1, "Error: secret_sector.bin is invalid or corrupted"); + } + else if(!verifyHash((void *)SECTOR_OFFSET, 0x200, sectorHash)) + shutdown(1, "Error: the NAND key sector is invalid"); - //Generate and encrypt a per-console A9LH key sector - generateSector((u8 *)SECTOR_OFFSET); + //Generate and encrypt a per-console A9LH key sector + generateSector((u8 *)SECTOR_OFFSET); - //Read FIRM0 - path = "a9lh/firm0.bin"; - u32 firm0Size = fileSize(path); - if(!firm0Size) - shutdown(1, "Error: firm0.bin doesn't exist"); - fileRead((void *)FIRM0_OFFSET, path, firm0Size); - if(!verifyHash((void *)FIRM0_OFFSET, firm0Size, firm0Hash)) - shutdown(1, "Error: firm0.bin is invalid or corrupted"); + //Read FIRM0 + path = "a9lh/firm0.bin"; + if(fileSize(path) != FIRM_SIZE) + shutdown(1, "Error: firm0.bin doesn't exist or has a wrong size"); + fileRead((void *)FIRM0_OFFSET, path, FIRM_SIZE); + if(!verifyHash((void *)FIRM0_OFFSET, FIRM_SIZE, firm0Hash)) + shutdown(1, "Error: firm0.bin is invalid or corrupted"); - //Read FIRM1 - path = "a9lh/firm1.bin"; - u32 firm1Size = fileSize(path); - if(!firm1Size) - shutdown(1, "Error: firm1.bin doesn't exist"); - fileRead((void *)FIRM1_OFFSET, path, firm1Size); - if(!verifyHash((void *)FIRM1_OFFSET, firm1Size, firm1Hash)) - shutdown(1, "Error: firm1.bin is invalid or corrupted"); + //Read FIRM1 + path = "a9lh/firm1.bin"; + if(fileSize(path) != FIRM_SIZE) + shutdown(1, "Error: firm1.bin doesn't exist or has a wrong size"); + fileRead((void *)FIRM1_OFFSET, path, FIRM_SIZE); + if(!verifyHash((void *)FIRM1_OFFSET, FIRM_SIZE, firm1Hash)) + shutdown(1, "Error: firm1.bin is invalid or corrupted"); + } + else if(!verifyHash((void *)FIRM0_OFFSET, STAGE1_POSITION, firm0A9lhHash)) + shutdown(1, "Error: NAND FIRM0 is invalid"); //Inject stage1 path = "a9lh/payload_stage1.bin"; u32 size = fileSize(path); if(!size || size > MAX_STAGE1_SIZE) shutdown(1, "Error: stage1.bin doesn't exist or exceeds\nmax size"); + memset((void *)STAGE1_OFFSET, 0, MAX_STAGE1_SIZE); fileRead((void *)STAGE1_OFFSET, path, size); - installStage2(1); + //Read stage2 + path = "a9lh/payload_stage2.bin"; + size = fileSize(path); + if(!size || size > MAX_STAGE2_SIZE) + shutdown(1, "Error: stage2.bin doesn't exist or exceeds\nmax size"); + memset((void *)STAGE2_OFFSET, 0, MAX_STAGE2_SIZE); + fileRead((void *)STAGE2_OFFSET, path, size); pos_y = drawString("All checks passed, installing...", 10, pos_y + SPACING_VERT, COLOR_WHITE); //Point of no return, install stuff in the safest order sdmmc_nand_writesectors(0x5C000, 0x20, (vu8 *)STAGE2_OFFSET); - writeFirm((u8 *)FIRM1_OFFSET, 1, firm1Size); - writeFirm((u8 *)FIRM0_OFFSET, 0, firm0Size); - sdmmc_nand_writesectors(0x96, 0x1, (vu8 *)SECTOR_OFFSET); + if(!a9lhBoot){ writeFirm((u8 *)FIRM1_OFFSET, 1, FIRM_SIZE); + sdmmc_nand_writesectors(0x96, 1, (vu8 *)SECTOR_OFFSET); } + writeFirm((u8 *)FIRM0_OFFSET, 0, FIRM_SIZE); - shutdown(1, "Full install: success!"); + shutdown(1, a9lhBoot ? "Update: success!" : "Full install: success!"); } \ No newline at end of file diff --git a/source/installer.h b/source/installer.h index 4106716..75d0770 100644 --- a/source/installer.h +++ b/source/installer.h @@ -9,10 +9,11 @@ #define SECTOR_OFFSET 0x24100000 #define FIRM0_OFFSET 0x24200000 #define FIRM1_OFFSET 0x24300000 -#define STAGE1_OFFSET FIRM0_OFFSET + 0xF0400 +#define FIRM_SIZE 0xF2000 +#define STAGE1_POSITION 0xF0400 +#define STAGE1_OFFSET FIRM0_OFFSET + STAGE1_POSITION #define STAGE2_OFFSET 0x24400000 #define MAX_STAGE1_SIZE 0x1C00 #define MAX_STAGE2_SIZE 0x2800 -#define TEMP_OFFSET 0x24500000 void installer(void); \ No newline at end of file diff --git a/source/main.c b/source/main.c index 0b852ea..704df83 100644 --- a/source/main.c +++ b/source/main.c @@ -1,8 +1,10 @@ #include "installer.h" +#include "fs.h" #include "screeninit.h" #include "types.h" void main(void){ + mountSD(); initScreens(); installer(); } \ No newline at end of file diff --git a/source/screeninit.c b/source/screeninit.c index 99d3e7f..4456880 100644 --- a/source/screeninit.c +++ b/source/screeninit.c @@ -1,4 +1,5 @@ #include "screeninit.h" +#include "draw.h" #include "i2c.h" void initScreens(void){ @@ -107,4 +108,6 @@ void initScreens(void){ *arm11 = (u32)ARM11; while(*arm11); } + + clearScreens(); } \ No newline at end of file diff --git a/source/utils.c b/source/utils.c index de2c171..1656378 100755 --- a/source/utils.c +++ b/source/utils.c @@ -28,14 +28,8 @@ u16 waitInput(void){ void shutdown(u32 mode, char *message){ if(mode){ pos_y = drawString(message, 10, pos_y + SPACING_VERT, COLOR_WHITE); - if(mode == 1) drawString("Press any button to shutdown", 10, pos_y, COLOR_WHITE); - else { - pos_y = drawString("Press START or SELECT to return to menu", 10, pos_y, COLOR_RED); - pos_y = drawString("(SD will be unmounted until the next install)", 10, pos_y, COLOR_RED); - pos_y = drawString("Press any other button to shutdown", 10, pos_y, COLOR_WHITE); - } - u16 pressed = waitInput(); - if(mode == 2 && (pressed & (BUTTON_START | BUTTON_SELECT))) return; + drawString("Press any button to shutdown", 10, pos_y, COLOR_WHITE); + waitInput(); } i2cWriteRegister(I2C_DEV_MCU, 0x20, 1); while(1); diff --git a/source/utils.h b/source/utils.h index 7569bbd..3d28cb3 100644 --- a/source/utils.h +++ b/source/utils.h @@ -3,17 +3,9 @@ #include "types.h" #define HID_PAD (*(vu16 *)0x10146000 ^ 0xFFF) -#define BUTTON_START (1 << 3) #define BUTTON_SELECT (1 << 2) -#define BUTTON_A 1 -#define BUTTON_B (1 << 1) -#define BUTTON_RIGHT (1 << 4) -#define BUTTON_LEFT (1 << 5) -#define BUTTON_UP (1 << 6) -#define BUTTON_DOWN (1 << 7) #define COLOR_TITLE 0xFF9900 -#define COLOR_WHITE 0xFFFFFF #define COLOR_RED 0x0000FF extern int pos_y;