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

This commit is contained in:
Aurora 2016-03-25 04:47:07 +01:00
parent 9c7e70bb81
commit b6aa3e1fd1
9 changed files with 74 additions and 116 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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!");
}

View File

@ -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);

View File

@ -1,8 +1,10 @@
#include "installer.h"
#include "fs.h"
#include "screeninit.h"
#include "types.h"
void main(void){
mountSD();
initScreens();
installer();
}

View File

@ -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();
}

View File

@ -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);

View File

@ -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;