From 5b4712644a5a743042ac809fa8c86d665d9a0128 Mon Sep 17 00:00:00 2001 From: Aurora Date: Mon, 10 Oct 2016 01:34:53 +0200 Subject: [PATCH] Lots of refactoring, main() has its own file yet again, properly handle failed patches/decryption steps, support TWL and AGB FIRM since 3.0 --- source/3dsheaders.h | 161 ++++++++++++ source/config.c | 17 +- source/config.h | 13 +- source/crypto.c | 103 +++++--- source/crypto.h | 78 +----- source/emunand.c | 113 ++++++--- source/emunand.h | 6 +- source/exceptions.c | 21 +- source/exceptions.h | 2 +- source/firm.c | 395 +++++++---------------------- source/firm.h | 35 +-- source/fs.c | 4 +- source/fs.h | 2 - source/main.c | 249 +++++++++++++++++++ source/patches.c | 592 +++++++++++++++++++++++++++++++++----------- source/patches.h | 48 ++-- source/pin.h | 9 - source/screen.h | 4 +- source/types.h | 38 ++- source/utils.c | 6 +- source/utils.h | 2 - 21 files changed, 1187 insertions(+), 711 deletions(-) create mode 100644 source/3dsheaders.h create mode 100644 source/main.c 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/config.c b/source/config.c index 5487ce9..c609eff 100644 --- a/source/config.c +++ b/source/config.c @@ -29,6 +29,8 @@ #include "buttons.h" #include "pin.h" +CfgData configData; + bool readConfig(void) { bool ret; @@ -67,7 +69,7 @@ void writeConfig(ConfigurationStatus needConfig, u32 configTemp) } } -void configMenu(Fs fsStatus, bool oldPinStatus, u32 oldPinMode) +void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode) { const char *multiOptionsText[] = { "Default EmuNAND: 1( ) 2( ) 3( ) 4( )", "Screen brightness: 4( ) 3( ) 2( ) 1( )", @@ -116,7 +118,8 @@ void configMenu(Fs fsStatus, bool oldPinStatus, u32 oldPinMode) "games.", "Select the developer features.\n\n" - "\t* 'Off' disables exception handlers.\n" + "\t* 'Off' disables exception handlers\n" + "in FIRM.\n" "\t* 'ErrDisp' displays debug info\n" "on the 'An error has occurred' screen.\n" "\t* 'UNITINFO' makes the console be\n" @@ -194,11 +197,11 @@ void configMenu(Fs fsStatus, bool oldPinStatus, u32 oldPinMode) u32 enabled; bool visible; } multiOptions[] = { - { .posXs = {19, 24, 29, 34}, .visible = fsStatus == SD_CARD }, + { .posXs = {19, 24, 29, 34}, .visible = isSdMode }, { .posXs = {21, 26, 31, 36}, .visible = true }, { .posXs = {12, 22, 31, 0}, .visible = true }, { .posXs = {14, 19, 24, 29}, .visible = true }, - { .posXs = {17, 26, 32, 44}, .visible = isN3DS }, + { .posXs = {17, 26, 32, 44}, .visible = ISN3DS }, { .posXs = {19, 30, 42, 0}, .visible = true } }; @@ -207,10 +210,10 @@ void configMenu(Fs fsStatus, bool oldPinStatus, u32 oldPinMode) bool enabled; bool visible; } singleOptions[] = { - { .visible = fsStatus == SD_CARD }, - { .visible = fsStatus == SD_CARD }, + { .visible = isSdMode }, + { .visible = isSdMode }, { .visible = true }, - { .visible = fsStatus == SD_CARD }, + { .visible = isSdMode }, { .visible = true }, { .visible = true }, { .visible = true }, diff --git a/source/config.h b/source/config.h index d687bc1..a7fd02b 100644 --- a/source/config.h +++ b/source/config.h @@ -60,14 +60,6 @@ enum singleOptions PATCHACCESS }; -typedef struct __attribute__((packed)) -{ - char magic[4]; - u16 formatVersionMajor, formatVersionMinor; - - u32 config; -} CfgData; - typedef enum ConfigurationStatus { DONT_CONFIGURE = 0, @@ -75,9 +67,6 @@ typedef enum ConfigurationStatus CREATE_CONFIGURATION } ConfigurationStatus; -extern CfgData configData; -extern bool isN3DS; - bool readConfig(void); void writeConfig(ConfigurationStatus needConfig, u32 configTemp); -void configMenu(Fs fsStatus, bool oldPinStatus, u32 oldPinMode); \ No newline at end of file +void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode); \ No newline at end of file diff --git a/source/crypto.c b/source/crypto.c index ed0f3a7..f837cb5 100755 --- a/source/crypto.c +++ b/source/crypto.c @@ -24,11 +24,11 @@ * Crypto libs from http://github.com/b1l1s/ctr * 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 -* 3ds type structs adapted from 3DBrew and https://github.com/mid-kid/CakesForeveryWan/blob/master/source/headers.h */ #include "crypto.h" #include "memory.h" +#include "utils.h" #include "fatfs/sdmmc/sdmmc.h" /**************************************************************** @@ -257,6 +257,8 @@ static void sha_wait_idle() static void sha(void *res, const void *src, u32 size, u32 mode) { + backupAndRestoreShaHash(false); + sha_wait_idle(); *REG_SHA_CNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND; @@ -301,6 +303,8 @@ static u32 fatStart; static u8 __attribute__((aligned(4))) shaHashBackup[SHA_256_HASH_SIZE]; static bool didShaHashBackup = false; +FirmwareSource firmSource; + void ctrNandInit(void) { u8 __attribute__((aligned(4))) cid[AES_BLOCK_SIZE]; @@ -310,7 +314,7 @@ void ctrNandInit(void) sha(shaSum, cid, sizeof(cid), SHA_256_MODE); memcpy(nandCtr, shaSum, sizeof(nandCtr)); - 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); @@ -376,41 +380,59 @@ void set6x7xKeys(void) memset32((void *)0x01FFCD00, 0, 0x10); } -void decryptExeFs(Ncch *ncch) +bool decryptExeFs(Cxi *cxi) { - u8 *exeFsOffset = (u8 *)ncch + ncch->exeFsOffset * 0x200; - u32 exeFsSize = ncch->exeFsSize * 0x200; - u8 __attribute__((aligned(4))) ncchCtr[AES_BLOCK_SIZE] = {0}; + bool isCxi; - for(u32 i = 0; i < 8; i++) - ncchCtr[7 - i] = ncch->partitionId[i]; - ncchCtr[8] = 2; + if(memcmp(cxi->ncch.magic, "NCCH", 4) == 0) + { + isCxi = true; - 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_use_keyslot(0x2C); - aes(ncch, exeFsOffset + 0x200, exeFsSize / AES_BLOCK_SIZE, ncchCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); + u8 *exeFsOffset = (u8 *)cxi + cxi->ncch.exeFsOffset * 0x200; + u32 exeFsSize = cxi->ncch.exeFsSize * 0x200; + u8 __attribute__((aligned(4))) ncchCtr[AES_BLOCK_SIZE] = {0}; + + for(u32 i = 0; i < 8; i++) + ncchCtr[7 - i] = cxi->ncch.partitionId[i]; + ncchCtr[8] = 2; + + 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 + 0x200, exeFsSize / AES_BLOCK_SIZE, ncchCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); + } + else isCxi = false; + + return isCxi && memcmp(cxi, "FIRM", 4) == 0; } -void decryptNusFirm(const Ticket *ticket, Ncch *ncch, u32 ncchSize) +bool decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize) { - 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))) cetkIv[AES_BLOCK_SIZE] = {0}; - memcpy(titleKey, ticket->titleKey, sizeof(titleKey)); - memcpy(cetkIv, ticket->titleId, sizeof(ticket->titleId)); + bool isTicket; - aes_setkey(0x3D, keyY0x3D, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); - aes_use_keyslot(0x3D); - aes(titleKey, titleKey, 1, cetkIv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); + if(memcmp(ticket->sigIssuer, "Root", 4) == 0) + { + isTicket = true; - u8 __attribute__((aligned(4))) ncchIv[AES_BLOCK_SIZE] = {0}; + 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))) cetkIv[AES_BLOCK_SIZE] = {0}; + memcpy(titleKey, ticket->titleKey, sizeof(titleKey)); + memcpy(cetkIv, ticket->titleId, sizeof(ticket->titleId)); - aes_setkey(0x16, titleKey, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL); - aes_use_keyslot(0x16); - aes(ncch, ncch, ncchSize / AES_BLOCK_SIZE, ncchIv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); + aes_setkey(0x3D, keyY0x3D, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); + aes_use_keyslot(0x3D); + aes(titleKey, titleKey, 1, cetkIv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); - decryptExeFs(ncch); + u8 __attribute__((aligned(4))) ncchIv[AES_BLOCK_SIZE] = {0}; + + aes_setkey(0x16, titleKey, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL); + aes_use_keyslot(0x16); + aes(cxi, cxi, ncchSize / AES_BLOCK_SIZE, ncchIv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); + } + else isTicket = false; + + return isTicket && decryptExeFs(cxi); } void kernel9Loader(Arm9Bin *arm9Section) @@ -430,10 +452,10 @@ void kernel9Loader(Arm9Bin *arm9Section) break; } - u32 startOfArm9Bin = *(u32 *)((u8 *)arm9Section + 0x800); - bool needToDecrypt = startOfArm9Bin != 0x47704770 && startOfArm9Bin != 0xB0862000; + u32 *startOfArm9Bin = (u32 *)((u8 *)arm9Section + 0x800); + bool needToDecrypt = *startOfArm9Bin != 0x47704770 && *startOfArm9Bin != 0xB0862000; - if(!isDevUnit && (k9lVersion == 2 || (k9lVersion == 1 && needToDecrypt))) + if(!ISDEVUNIT && (k9lVersion == 2 || (k9lVersion == 1 && needToDecrypt))) { //Set 0x11 keyslot const u8 __attribute__((aligned(4))) key1[AES_BLOCK_SIZE] = {0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8}; @@ -474,7 +496,9 @@ void kernel9Loader(Arm9Bin *arm9Section) //Decrypt ARM9 binary aes_use_keyslot(arm9BinSlot); - aes((u8 *)arm9Section + 0x800, (u8 *)arm9Section + 0x800, arm9BinSize / AES_BLOCK_SIZE, arm9BinCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); + aes(startOfArm9Bin, startOfArm9Bin, arm9BinSize / AES_BLOCK_SIZE, arm9BinCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); + + if(*startOfArm9Bin != 0x47704770 && *startOfArm9Bin != 0xB0862000) error("Error decrypting New 3DS ARM9 Binary."); } //Set >=9.6 KeyXs @@ -498,19 +522,20 @@ void computePinHash(u8 *outbuf, const u8 *inbuf) u8 __attribute__((aligned(4))) cid[AES_BLOCK_SIZE]; u8 __attribute__((aligned(4))) cipherText[AES_BLOCK_SIZE]; - if(isA9lh && !didShaHashBackup) - { - memcpy(shaHashBackup, (void *)REG_SHA_HASH, sizeof(shaHashBackup)); - didShaHashBackup = true; - } - sdmmc_get_cid(1, (u32 *)cid); aes_use_keyslot(4); //Console-unique keyslot whose keys are set by the ARM9 bootROM aes(cipherText, inbuf, 1, cid, AES_CBC_ENCRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); sha(outbuf, cipherText, sizeof(cipherText), SHA_256_MODE); } -void restoreShaHashBackup(void) +void backupAndRestoreShaHash(bool isRestore) { - if(didShaHashBackup) memcpy((void *)REG_SHA_HASH, shaHashBackup, sizeof(shaHashBackup)); + if(ISA9LH) + { + if(isRestore) + { + if(didShaHashBackup) memcpy((void *)REG_SHA_HASH, shaHashBackup, sizeof(shaHashBackup)); + } + else if(!didShaHashBackup) memcpy(shaHashBackup, (void *)REG_SHA_HASH, sizeof(shaHashBackup)); + } } \ No newline at end of file diff --git a/source/crypto.h b/source/crypto.h index a3b958c..dd4cc3f 100755 --- a/source/crypto.h +++ b/source/crypto.h @@ -24,7 +24,6 @@ * Crypto libs from http://github.com/b1l1s/ctr * 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 -* 3ds type structs adapted from 3DBrew and https://github.com/mid-kid/CakesForeveryWan/blob/master/source/headers.h */ #pragma once @@ -102,86 +101,15 @@ #define SHA_224_HASH_SIZE (224 / 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]; - char 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 bool isN3DS, isDevUnit, isA9lh; extern FirmwareSource firmSource; void ctrNandInit(void); int ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf); int ctrNandWrite(u32 sector, u32 sectorCount, u8 *inbuf); void set6x7xKeys(void); -void decryptExeFs(Ncch *ncch); -void decryptNusFirm(const Ticket *ticket, Ncch *ncch, u32 ncchSize); +bool decryptExeFs(Cxi *cxi); +bool decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize); void kernel9Loader(Arm9Bin *arm9Section); void computePinHash(u8 *outbuf, const u8 *inbuf); -void restoreShaHashBackup(void); \ No newline at end of file +void backupAndRestoreShaHash(bool isRestore); \ No newline at end of file diff --git a/source/emunand.c b/source/emunand.c index c0a8e1c..67c888a 100644 --- a/source/emunand.c +++ b/source/emunand.c @@ -25,6 +25,8 @@ #include "fatfs/sdmmc/sdmmc.h" #include "../build/bundled.h" +u32 emuOffset; + void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType) { static u8 __attribute__((aligned(4))) temp[0x200]; @@ -50,7 +52,7 @@ void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType) nandOffset = ROUND_TO_4MB(nandSize + 1); //"Default" layout break; case 2: - nandOffset = roundedMinsizes[isN3DS ? 1 : 0]; //"Minsize" layout + nandOffset = roundedMinsizes[ISN3DS ? 1 : 0]; //"Minsize" layout break; default: nandOffset = *nandType == FIRMWARE_EMUNAND ? 0 : (nandSize > 0x200000 ? 0x400000 : 0x200000); //"Legacy" layout @@ -59,10 +61,10 @@ void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType) if(*nandType != FIRMWARE_EMUNAND) nandOffset *= ((u32)*nandType - 1); - if(fatStart >= nandOffset + roundedMinsizes[isN3DS ? 1 : 0]) + if(fatStart >= nandOffset + roundedMinsizes[ISN3DS ? 1 : 0]) { //Check for RedNAND - if(!sdmmc_sdcard_readsectors(nandOffset + 1, 1, temp) && *(u32 *)(temp + 0x100) == NCSD_MAGIC) + if(!sdmmc_sdcard_readsectors(nandOffset + 1, 1, temp) && memcmp(temp + 0x100, "NCSD", 4) == 0) { emuOffset = nandOffset + 1; *emuHeader = nandOffset + 1; @@ -70,7 +72,7 @@ void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType) } //Check for Gateway EmuNAND - else if(i != 2 && !sdmmc_sdcard_readsectors(nandOffset + nandSize, 1, temp) && *(u32 *)(temp + 0x100) == NCSD_MAGIC) + else if(i != 2 && !sdmmc_sdcard_readsectors(nandOffset + nandSize, 1, temp) && memcmp(temp + 0x100, "NCSD", 4) == 0) { emuOffset = nandOffset; *emuHeader = nandOffset + nandSize; @@ -93,68 +95,111 @@ void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType) } } -static inline u8 *getFreeK9Space(u8 *pos, u32 size) +static inline u32 getFreeK9Space(u8 *pos, u32 size, u8 **freeK9Space) { const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}; //Looking for the last free space before Process9 - return memsearch(pos + 0x13500, pattern, size - 0x13500, sizeof(pattern)) + 0x455; + *freeK9Space = memsearch(pos + 0x13500, pattern, size - 0x13500, sizeof(pattern)) + 0x455; + + return *freeK9Space == NULL ? 1 : 0; } -static inline u32 getSdmmc(u8 *pos, u32 size) +static inline u32 getSdmmc(u8 *pos, u32 size, u32 *sdmmc) { //Look for struct code const u8 pattern[] = {0x21, 0x20, 0x18, 0x20}; + u32 ret; + const u8 *off = memsearch(pos, pattern, size, sizeof(pattern)); - return *(u32 *)(off + 9) + *(u32 *)(off + 0xD); + if(off == NULL) ret = 1; + else + { + *sdmmc = *(u32 *)(off + 9) + *(u32 *)(off + 0xD); + ret = 0; + } + + return ret; } -static inline void patchNandRw(u8 *pos, u32 size, u32 branchOffset) +static inline u32 patchNandRw(u8 *pos, u32 size, u32 branchOffset) { //Look for read/write code const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05}; + u32 ret = 0; - u16 *readOffset = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)) - 3, - *writeOffset = (u16 *)memsearch((u8 *)(readOffset + 5), pattern, 0x100, sizeof(pattern)) - 3; + u16 *readOffset = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); - *readOffset = *writeOffset = 0x4C00; - readOffset[1] = writeOffset[1] = 0x47A0; - ((u32 *)writeOffset)[1] = ((u32 *)readOffset)[1] = branchOffset; + if(readOffset == NULL) ret = 1; + else + { + readOffset -= 3; + + u16 *writeOffset = (u16 *)memsearch((u8 *)(readOffset + 5), pattern, 0x100, sizeof(pattern)); + + if(writeOffset == NULL) ret = 1; + else + { + writeOffset -= 3; + *readOffset = *writeOffset = 0x4C00; + readOffset[1] = writeOffset[1] = 0x47A0; + ((u32 *)writeOffset)[1] = ((u32 *)readOffset)[1] = branchOffset; + } + } + + return ret; } -static inline void patchMpu(u8 *pos, u32 size) +static inline u32 patchMpu(u8 *pos, u32 size) { //Look for MPU pattern const u8 pattern[] = {0x03, 0x00, 0x24, 0x00}; + u32 ret; u32 *off = (u32 *)memsearch(pos, pattern, size, sizeof(pattern)); - off[0] = 0x00360003; - off[6] = 0x00200603; - off[9] = 0x001C0603; + if(off == NULL) ret = 1; + else + { + off[0] = 0x00360003; + off[6] = 0x00200603; + off[9] = 0x001C0603; + ret = 0; + } + + return ret; } -void patchEmuNand(u8 *arm9Section, u32 arm9SectionSize, u8 *process9Offset, u32 process9Size, u32 emuHeader, u32 branchAdditive) +u32 patchEmuNand(u8 *arm9Section, u8 *process9Offset, u32 process9Size, u32 emuHeader) { + u32 ret = 0; + //Copy EmuNAND code - u8 *freeK9Space = getFreeK9Space(arm9Section, arm9SectionSize); - memcpy(freeK9Space, emunand_bin, emunand_bin_size); + u8 *freeK9Space; + ret += getFreeK9Space(arm9Section, firm->section[2].size, &freeK9Space); + if(!ret) + { + memcpy(freeK9Space, emunand_bin, emunand_bin_size); - //Add the data of the found EmuNAND - u32 *posOffset = (u32 *)memsearch(freeK9Space, "NAND", emunand_bin_size, 4), - *posHeader = (u32 *)memsearch(freeK9Space, "NCSD", emunand_bin_size, 4); - *posOffset = emuOffset; - *posHeader = emuHeader; + //Add the data of the found EmuNAND + u32 *posOffset = (u32 *)memsearch(freeK9Space, "NAND", emunand_bin_size, 4), + *posHeader = (u32 *)memsearch(freeK9Space, "NCSD", emunand_bin_size, 4); + *posOffset = emuOffset; + *posHeader = emuHeader; - //Find and add the SDMMC struct - u32 *posSdmmc = (u32 *)memsearch(freeK9Space, "SDMC", emunand_bin_size, 4); - *posSdmmc = getSdmmc(process9Offset, process9Size); + //Find and add the SDMMC struct + u32 *posSdmmc = (u32 *)memsearch(freeK9Space, "SDMC", emunand_bin_size, 4); + u32 sdmmc; + ret += getSdmmc(process9Offset, process9Size, &sdmmc); + if(!ret) *posSdmmc = sdmmc; - //Add EmuNAND hooks - u32 branchOffset = (u32)freeK9Space - branchAdditive; - patchNandRw(process9Offset, process9Size, branchOffset); + //Add EmuNAND hooks + ret += patchNandRw(process9Offset, process9Size, (u32)(freeK9Space - arm9Section + firm->section[2].address)); - //Set MPU - patchMpu(arm9Section, arm9SectionSize); + //Set MPU + ret += patchMpu(arm9Section, firm->section[2].size); + } + + return ret; } \ No newline at end of file diff --git a/source/emunand.h b/source/emunand.h index 45032e9..70f41a2 100644 --- a/source/emunand.h +++ b/source/emunand.h @@ -24,11 +24,7 @@ #include "types.h" -#define NCSD_MAGIC 0x4453434E #define ROUND_TO_4MB(a) (((a) + 0x2000 - 1) & (~(0x2000 - 1))) -extern u32 emuOffset; -extern bool isN3DS; - void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType); -void patchEmuNand(u8 *arm9Section, u32 arm9SectionSize, u8 *process9Offset, u32 process9Size, u32 emuHeader, u32 branchAdditive); \ No newline at end of file +u32 patchEmuNand(u8 *arm9Section, u8 *process9Offset, u32 process9Size, u32 emuHeader); \ No newline at end of file diff --git a/source/exceptions.c b/source/exceptions.c index 99bbe3f..48b1828 100644 --- a/source/exceptions.c +++ b/source/exceptions.c @@ -45,17 +45,22 @@ void installArm9Handlers(void) } } -void installArm11Handlers(u32 *exceptionsPage, u32 stackAddress, u32 codeSetOffset) +u32 installArm11Handlers(u32 *exceptionsPage, u32 stackAddress, u32 codeSetOffset) { - u32 *initFPU; - for(initFPU = exceptionsPage; initFPU < (exceptionsPage + 0x400) && (initFPU[0] != 0xE59F0008 || initFPU[1] != 0xE5900000); initFPU++); + u32 ret = 0; - u32 *mcuReboot; - for(mcuReboot = exceptionsPage; mcuReboot < (exceptionsPage + 0x400) && (mcuReboot[0] != 0xE59F4104 || mcuReboot[1] != 0xE3A0A0C2); mcuReboot++); - mcuReboot--; + u32 *initFPU; + for(initFPU = exceptionsPage; initFPU < exceptionsPage + 0x400 && (initFPU[0] != 0xE59F0008 || initFPU[1] != 0xE5900000); initFPU++); + if(initFPU == exceptionsPage + 0x400) ret = 1; u32 *freeSpace; - for(freeSpace = initFPU; freeSpace < (exceptionsPage + 0x400) && (freeSpace[0] != 0xFFFFFFFF || freeSpace[1] != 0xFFFFFFFF); freeSpace++); + for(freeSpace = initFPU; freeSpace < exceptionsPage + 0x400 && (freeSpace[0] != 0xFFFFFFFF || freeSpace[1] != 0xFFFFFFFF); freeSpace++); + if(initFPU == exceptionsPage + 0x400) ret = 1; + + u32 *mcuReboot; + for(mcuReboot = exceptionsPage; mcuReboot < exceptionsPage + 0x400 && (mcuReboot[0] != 0xE59F4104 || mcuReboot[1] != 0xE3A0A0C2); mcuReboot++); + if(initFPU == exceptionsPage + 0x400) ret = 1; + mcuReboot--; memcpy(freeSpace, arm11_exceptions_bin + 32, arm11_exceptions_bin_size - 32); @@ -76,6 +81,8 @@ void installArm11Handlers(u32 *exceptionsPage, u32 stackAddress, u32 codeSetOffs default: break; } } + + return ret; } void detectAndProcessExceptionDumps(void) diff --git a/source/exceptions.h b/source/exceptions.h index 27e8a69..8be0806 100644 --- a/source/exceptions.h +++ b/source/exceptions.h @@ -43,5 +43,5 @@ typedef struct __attribute__((packed)) } ExceptionDumpHeader; void installArm9Handlers(void); -void installArm11Handlers(u32 *exceptionsPage, u32 stackAddress, u32 codeSetOffset); +u32 installArm11Handlers(u32 *exceptionsPage, u32 stackAddress, u32 codeSetOffset); void detectAndProcessExceptionDumps(void); \ No newline at end of file diff --git a/source/firm.c b/source/firm.c index 051d815..d626102 100755 --- a/source/firm.c +++ b/source/firm.c @@ -31,256 +31,11 @@ #include "cache.h" #include "emunand.h" #include "crypto.h" -#include "draw.h" #include "screen.h" -#include "buttons.h" -#include "pin.h" #include "../build/bundled.h" -extern u16 launchedFirmTidLow[8]; //Defined in start.s - -static firmHeader *firm = (firmHeader *)0x24000000; -static const firmSectionHeader *section; - -u32 emuOffset; -bool isN3DS, - isDevUnit, - isA9lh, - isFirmlaunch; -CfgData configData; -FirmwareSource firmSource; - -void main(void) +u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSdMode) { - u32 configTemp, - emuHeader; - FirmwareType firmType; - FirmwareSource nandType; - ConfigurationStatus needConfig; - - //Detect the console being used - isN3DS = PDN_MPCORE_CFG == 7; - - //Detect dev units - isDevUnit = CFG_UNITINFO != 0; - - //Mount SD or CTRNAND - Fs fsStatus; - if(mountFs(true)) fsStatus = SD_CARD; - else - { - firmSource = FIRMWARE_SYSNAND; - fsStatus = (mountFs(false) && switchToCtrNand()) ? CTRNAND : NONE; - } - - //Attempt to read the configuration file - needConfig = readConfig() ? MODIFY_CONFIGURATION : CREATE_CONFIGURATION; - - u32 devMode = MULTICONFIG(DEVOPTIONS); - - //Determine if this is a firmlaunch boot - if(launchedFirmTidLow[5] != 0) - { - isFirmlaunch = true; - - if(needConfig == CREATE_CONFIGURATION) mcuReboot(); - - //'0' = NATIVE_FIRM, '1' = TWL_FIRM, '2' = AGB_FIRM - firmType = launchedFirmTidLow[7] == u'3' ? SAFE_FIRM : (FirmwareType)(launchedFirmTidLow[5] - u'0'); - - nandType = (FirmwareSource)BOOTCFG_NAND; - firmSource = (FirmwareSource)BOOTCFG_FIRM; - isA9lh = BOOTCFG_A9LH != 0; - } - else - { - isFirmlaunch = false; - firmType = NATIVE_FIRM; - - //Determine if booting with A9LH - isA9lh = !PDN_SPI_CNT; - - if(fsStatus == NONE) error("Error mounting SD and CTRNAND."); - - if(devMode != 0 && isA9lh) detectAndProcessExceptionDumps(); - - //Get pressed buttons - u32 pressed = HID_PAD; - - //Save old options and begin saving the new boot configuration - configTemp = (configData.config & 0xFFFFFE00) | ((u32)isA9lh << 6); - - //If it's a MCU reboot, try to force boot options - if(isA9lh && CFG_BOOTENV) - { - //Always force a sysNAND boot when quitting AGB_FIRM - if(CFG_BOOTENV == 7) - { - nandType = FIRMWARE_SYSNAND; - firmSource = CONFIG(USESYSFIRM) ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCFG_FIRM; - needConfig = DONT_CONFIGURE; - - //Flag to prevent multiple boot options-forcing - configTemp |= 1 << 7; - } - - /* Else, force the last used boot options unless a button is pressed - or the no-forcing flag is set */ - else if(needConfig != CREATE_CONFIGURATION && !pressed && !BOOTCFG_NOFORCEFLAG) - { - nandType = (FirmwareSource)BOOTCFG_NAND; - firmSource = (FirmwareSource)BOOTCFG_FIRM; - needConfig = DONT_CONFIGURE; - } - } - - if(needConfig == DONT_CONFIGURE) - { - if(devMode != 0 && isA9lh) installArm9Handlers(); - } - - //Boot options aren't being forced - else - { - u32 pinMode = MULTICONFIG(PIN); - bool pinExists = pinMode != 0 && verifyPin(pinMode); - - //If no configuration file exists or SELECT is held, load configuration menu - bool shouldLoadConfigMenu = needConfig == CREATE_CONFIGURATION || ((pressed & BUTTON_SELECT) && !(pressed & BUTTON_L1)); - - if(shouldLoadConfigMenu) - { - configMenu(fsStatus, pinExists, pinMode); - - //Update pressed buttons - pressed = HID_PAD; - - devMode = MULTICONFIG(DEVOPTIONS); - } - - if(devMode != 0 && isA9lh) installArm9Handlers(); - - if(isA9lh && !CFG_BOOTENV && pressed == SAFE_MODE) - { - nandType = FIRMWARE_SYSNAND; - firmSource = FIRMWARE_SYSNAND; - - //Flag to tell loader to init SD - configTemp |= 1 << 8; - - //If the PIN has been verified, wait to make it easier to press the SAFE_MODE combo - if(pinExists && !shouldLoadConfigMenu) - { - while(HID_PAD & PIN_BUTTONS); - chrono(2); - } - } - else - { - u32 splashMode = MULTICONFIG(SPLASH); - - if(splashMode == 1 && loadSplash()) pressed = HID_PAD; - - /* If L and R/A/Select or one of the single payload buttons are pressed, - chainload an external payload */ - bool shouldLoadPayload = ((pressed & SINGLE_PAYLOAD_BUTTONS) && !(pressed & (BUTTON_L1 | BUTTON_R1 | BUTTON_A))) || - ((pressed & L_PAYLOAD_BUTTONS) && (pressed & BUTTON_L1)); - - if(shouldLoadPayload) loadPayload(pressed); - - if(splashMode == 2) loadSplash(); - - if(fsStatus == CTRNAND) nandType = FIRMWARE_SYSNAND; - - //If R is pressed, boot the non-updated NAND with the FIRM of the opposite one - else if(pressed & BUTTON_R1) - { - //Determine if the user chose to use the SysNAND FIRM as default for a R boot - bool useSysAsDefault = isA9lh ? CONFIG(USESYSFIRM) : false; - - nandType = useSysAsDefault ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND; - firmSource = useSysAsDefault ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND; - } - - /* Else, boot the NAND the user set to autoboot or the opposite one, depending on L, - with their own FIRM */ - else - { - nandType = (CONFIG(AUTOBOOTSYS) != !(pressed & BUTTON_L1)) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND; - firmSource = nandType; - } - - //If we're booting EmuNAND or using EmuNAND FIRM, determine which one from the directional pad buttons, or otherwise from the config - if(nandType == FIRMWARE_EMUNAND || firmSource == FIRMWARE_EMUNAND) - { - FirmwareSource temp; - switch(pressed & EMUNAND_BUTTONS) - { - case BUTTON_UP: - temp = FIRMWARE_EMUNAND; - break; - case BUTTON_RIGHT: - temp = FIRMWARE_EMUNAND2; - break; - case BUTTON_DOWN: - temp = FIRMWARE_EMUNAND3; - break; - case BUTTON_LEFT: - temp = FIRMWARE_EMUNAND4; - break; - default: - temp = (FirmwareSource)(1 + MULTICONFIG(DEFAULTEMU)); - break; - } - - if(nandType == FIRMWARE_EMUNAND) nandType = temp; - else firmSource = temp; - } - } - } - } - - //If we need to boot EmuNAND, make sure it exists - if(nandType != FIRMWARE_SYSNAND) - { - locateEmuNand(&emuHeader, &nandType); - if(nandType == FIRMWARE_SYSNAND) firmSource = FIRMWARE_SYSNAND; - } - - //Same if we're using EmuNAND as the FIRM source - else if(firmSource != FIRMWARE_SYSNAND) - locateEmuNand(&emuHeader, &firmSource); - - if(!isFirmlaunch) - { - configTemp |= (u32)nandType | ((u32)firmSource << 3); - writeConfig(needConfig, configTemp); - } - - bool loadFromStorage = CONFIG(LOADEXTFIRMSANDMODULES); - u32 firmVersion = loadFirm(&firmType, firmSource, loadFromStorage, fsStatus); - - switch(firmType) - { - case NATIVE_FIRM: - patchNativeFirm(firmVersion, nandType, emuHeader, devMode); - break; - case SAFE_FIRM: - case NATIVE_FIRM1X2X: - if(isA9lh) patch1x2xNativeAndSafeFirm(devMode); - break; - default: - patchLegacyFirm(firmType, firmVersion, devMode); - break; - } - - launchFirm(firmType, loadFromStorage); -} - -static inline u32 loadFirm(FirmwareType *firmType, FirmwareSource firmSource, bool loadFromStorage, Fs fsStatus) -{ - section = firm->section; - const char *firmwareFiles[] = { "luma/firmware.bin", "luma/firmware_twl.bin", @@ -294,7 +49,7 @@ static inline u32 loadFirm(FirmwareType *firmType, FirmwareSource firmSource, bo "luma/cetk_safe" }; - if(fsStatus == SD_CARD && !mountFs(false)) error("Error mounting CTRNAND."); + if(isSdMode && !mountFs(false)) error("Error mounting CTRNAND."); //Load FIRM from CTRNAND u32 firmVersion = firmRead(firm, (u32)*firmType); @@ -303,12 +58,12 @@ static inline u32 loadFirm(FirmwareType *firmType, FirmwareSource firmSource, bo bool mustLoadFromStorage = false; - if(!isN3DS && *firmType == NATIVE_FIRM) + if(!ISN3DS && *firmType == NATIVE_FIRM) { if(firmVersion < 0x18) { //We can't boot < 3.x EmuNANDs - if(firmSource != FIRMWARE_SYSNAND) + if(nandType != FIRMWARE_SYSNAND) error("An old unsupported EmuNAND has been detected.\nLuma3DS is unable to boot it."); if(BOOTCFG_SAFEMODE != 0) error("SAFE_MODE is not supported on 1.x/2.x FIRM."); @@ -324,19 +79,19 @@ static inline u32 loadFirm(FirmwareType *firmType, FirmwareSource firmSource, bo { u32 firmSize = fileRead(firm, *firmType == NATIVE_FIRM1X2X ? firmwareFiles[0] : firmwareFiles[(u32)*firmType], 0x400000); - if(firmSize > 0) + if(firmSize > sizeof(Cxi)) { if(memcmp(firm, "FIRM", 4) != 0) { u8 cetk[0xA50]; - if(fileRead(cetk, *firmType == NATIVE_FIRM1X2X ? cetkFiles[0] : cetkFiles[(u32)*firmType], sizeof(cetk)) == sizeof(cetk)) - decryptNusFirm((Ticket *)&cetk[0x140], (Ncch *)firm, firmSize); - else error("The firmware.bin in /luma is encrypted\nor corrupted."); + if(fileRead(cetk, *firmType == NATIVE_FIRM1X2X ? cetkFiles[0] : cetkFiles[(u32)*firmType], sizeof(cetk)) != sizeof(cetk) || + !decryptNusFirm((Ticket *)(cetk + 0x140), (Cxi *)firm, firmSize)) + error("The firmware.bin in /luma is encrypted\nor corrupted."); } //Check that the FIRM is right for the console from the ARM9 section address - if((section[3].offset ? section[3].address : section[2].address) != (isN3DS ? (u8 *)0x8006000 : (u8 *)0x8006800)) + if((firm->section[3].offset ? firm->section[3].address : firm->section[2].address) != (ISN3DS ? (u8 *)0x8006000 : (u8 *)0x8006800)) error("The firmware.bin in /luma is not valid for this\nconsole."); firmVersion = 0xFFFFFFFF; @@ -346,18 +101,18 @@ static inline u32 loadFirm(FirmwareType *firmType, FirmwareSource firmSource, bo if(firmVersion != 0xFFFFFFFF) { if(mustLoadFromStorage) error("An old unsupported FIRM has been detected.\nCopy a firmware.bin in /luma to boot."); - decryptExeFs((Ncch *)firm); + if(!decryptExeFs((Cxi *)firm)) error("The CTRNAND FIRM is corrupted."); } return firmVersion; } -static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, u32 devMode) +u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, u32 devMode) { - u8 *arm9Section = (u8 *)firm + section[2].offset, - *arm11Section1 = (u8 *)firm + section[1].offset; + u8 *arm9Section = (u8 *)firm + firm->section[2].offset, + *arm11Section1 = (u8 *)firm + firm->section[1].offset; - if(isN3DS) + if(ISN3DS) { //Decrypt ARM9Bin and patch ARM9 entrypoint to skip kernel9loader kernel9Loader((Arm9Bin *)arm9Section); @@ -365,41 +120,39 @@ static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 } //Sets the 7.x NCCH KeyX and the 6.x gamecard save data KeyY on >= 6.0 O3DS FIRMs, if not using A9LH or a dev unit - else if(!isA9lh && firmVersion >= 0x29 && !isDevUnit) set6x7xKeys(); + else if(!ISA9LH && !ISFIRMLAUNCH && firmVersion >= 0x29 && !ISDEVUNIT) set6x7xKeys(); //Find the Process9 .code location, size and memory address u32 process9Size, process9MemAddr; - u8 *process9Offset = getProcess9(arm9Section + 0x15000, section[2].size - 0x15000, &process9Size, &process9MemAddr); + u8 *process9Offset = getProcess9Info(arm9Section + 0x15000, firm->section[2].size - 0x15000, &process9Size, &process9MemAddr); - //Find Kernel11 SVC table and handler, exceptions page and free space locations + //Find the Kernel11 SVC table and handler, exceptions page and free space locations u32 baseK11VA; u8 *freeK11Space; u32 *arm11SvcHandler, *arm11ExceptionsPage, - *arm11SvcTable = getKernel11Info(arm11Section1, section[1].size, &baseK11VA, &freeK11Space, &arm11SvcHandler, &arm11ExceptionsPage); + *arm11SvcTable = getKernel11Info(arm11Section1, firm->section[1].size, &baseK11VA, &freeK11Space, &arm11SvcHandler, &arm11ExceptionsPage); + + u32 ret = 0; //Apply signature patches - patchSignatureChecks(process9Offset, process9Size); + ret += patchSignatureChecks(process9Offset, process9Size); //Apply EmuNAND patches - if(nandType != FIRMWARE_SYSNAND) - { - u32 branchAdditive = (u32)firm + section[2].offset - (u32)section[2].address; - patchEmuNand(arm9Section, section[2].size, process9Offset, process9Size, emuHeader, branchAdditive); - } + if(nandType != FIRMWARE_SYSNAND) ret += patchEmuNand(arm9Section, process9Offset, process9Size, emuHeader); //Apply FIRM0/1 writes patches on sysNAND to protect A9LH - else if(isA9lh) patchFirmWrites(process9Offset, process9Size); + else if(ISA9LH || (ISFIRMLAUNCH && BOOTCFG_A9LH != 0)) ret += patchFirmWrites(process9Offset, process9Size); //Apply firmlaunch patches - patchFirmlaunches(process9Offset, process9Size, process9MemAddr); + ret += patchFirmlaunches(process9Offset, process9Size, process9MemAddr); //11.0 FIRM patches - if(firmVersion >= (isN3DS ? 0x21 : 0x52)) + if(firmVersion >= (ISN3DS ? 0x21 : 0x52)) { //Apply anti-anti-DG patches - patchTitleInstallMinVersionCheck(process9Offset, process9Size); + ret += patchTitleInstallMinVersionChecks(process9Offset, process9Size, firmVersion); //Restore svcBackdoor reimplementSvcBackdoor(arm11Section1, arm11SvcTable, baseK11VA, &freeK11Space); @@ -408,69 +161,103 @@ static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 implementSvcGetCFWInfo(arm11Section1, arm11SvcTable, baseK11VA, &freeK11Space); //Apply UNITINFO patch - if(devMode == 2) patchUnitInfoValueSet(arm9Section, section[2].size); + if(devMode == 2) ret += patchUnitInfoValueSet(arm9Section, firm->section[2].size); - if(devMode != 0 && isA9lh) + if(devMode != 0 && ISA9LH) { //ARM11 exception handlers u32 codeSetOffset, - stackAddress = getInfoForArm11ExceptionHandlers(arm11Section1, section[1].size, &codeSetOffset); - installArm11Handlers(arm11ExceptionsPage, stackAddress, codeSetOffset); + stackAddress = getInfoForArm11ExceptionHandlers(arm11Section1, firm->section[1].size, &codeSetOffset); + ret += installArm11Handlers(arm11ExceptionsPage, stackAddress, codeSetOffset); patchSvcBreak11(arm11Section1, arm11SvcTable); - patchKernel11Panic(arm11Section1, section[1].size); + ret += patchKernel11Panic(arm11Section1, firm->section[1].size); //ARM9 exception handlers - patchArm9ExceptionHandlersInstall(arm9Section, section[2].size); - patchSvcBreak9(arm9Section, section[2].size, (u32)section[2].address); - patchKernel9Panic(arm9Section, section[2].size); + ret += patchArm9ExceptionHandlersInstall(arm9Section, firm->section[2].size); + ret += patchSvcBreak9(arm9Section, firm->section[2].size, (u32)firm->section[2].address); + ret += patchKernel9Panic(arm9Section, firm->section[2].size); } if(CONFIG(PATCHACCESS)) { - patchArm11SvcAccessChecks(arm11SvcHandler); - patchK11ModuleChecks(arm11Section1, section[1].size, &freeK11Space); - patchP9AccessChecks(process9Offset, process9Size); + ret += patchArm11SvcAccessChecks(arm11SvcHandler, (u32 *)(arm11Section1 + firm->section[1].size)); + ret += patchK11ModuleChecks(arm11Section1, firm->section[1].size, &freeK11Space); + ret += patchP9AccessChecks(process9Offset, process9Size); } + + return ret; } -static inline void patchLegacyFirm(FirmwareType firmType, u32 firmVersion, u32 devMode) +u32 patchTwlFirm(u32 firmVersion, u32 devMode) { - u8 *arm9Section = (u8 *)firm + section[3].offset; + u8 *arm9Section = (u8 *)firm + firm->section[3].offset; + u32 ret = 0; //On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip kernel9loader - if(isN3DS) + if(ISN3DS) { kernel9Loader((Arm9Bin *)arm9Section); firm->arm9Entry = (u8 *)0x801301C; } - if(isN3DS || firmVersion >= (firmType == TWL_FIRM ? 0x16 : 0xB)) - applyLegacyFirmPatches((u8 *)firm, firmType); + ret += patchLgySignatureChecks(arm9Section, firm->section[3].size); + ret += patchTwlInvalidSignatureChecks(arm9Section, firm->section[3].size); + ret += patchTwlNintendoLogoChecks(arm9Section, firm->section[3].size); + ret += patchTwlWhitelistChecks(arm9Section, firm->section[3].size); + if(!ISN3DS && firmVersion == 0x11) ret += patchOldTwlFlashcartChecks(arm9Section, firm->section[3].size); + else ret += patchTwlFlashcartChecks(arm9Section, firm->section[3].size, firmVersion); + ret += patchTwlShaHashChecks(arm9Section, firm->section[3].size); //Apply UNITINFO patch - if(devMode == 2) patchUnitInfoValueSet(arm9Section, section[3].size); + if(devMode == 2) ret += patchUnitInfoValueSet(arm9Section, firm->section[3].size); + + return ret; } -static inline void patch1x2xNativeAndSafeFirm(u32 devMode) +u32 patchAgbFirm(u32 devMode) { - u8 *arm9Section = (u8 *)firm + section[2].offset; + u8 *arm9Section = (u8 *)firm + firm->section[3].offset; + u32 ret = 0; + + //On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip kernel9loader + if(ISN3DS) + { + kernel9Loader((Arm9Bin *)arm9Section); + firm->arm9Entry = (u8 *)0x801301C; + } - if(isN3DS) + ret += patchLgySignatureChecks(arm9Section, firm->section[3].size); + if(CONFIG(SHOWGBABOOT)) ret += patchAgbBootSplash(arm9Section, firm->section[3].size); + + //Apply UNITINFO patch + if(devMode == 2) ret += patchUnitInfoValueSet(arm9Section, firm->section[3].size); + + return ret; +} + +u32 patch1x2xNativeAndSafeFirm(u32 devMode) +{ + u8 *arm9Section = (u8 *)firm + firm->section[2].offset; + u32 ret = 0; + + if(ISN3DS) { //Decrypt ARM9Bin and patch ARM9 entrypoint to skip kernel9loader kernel9Loader((Arm9Bin *)arm9Section); firm->arm9Entry = (u8 *)0x801B01C; - patchFirmWrites(arm9Section, section[2].size); + ret += patchFirmWrites(arm9Section, firm->section[2].size); } - else patchOldFirmWrites(arm9Section, section[2].size); + else ret += patchOldFirmWrites(arm9Section, firm->section[2].size); if(devMode != 0) { //ARM9 exception handlers - patchArm9ExceptionHandlersInstall(arm9Section, section[2].size); - patchSvcBreak9(arm9Section, section[2].size, (u32)section[2].address); + ret += patchArm9ExceptionHandlersInstall(arm9Section, firm->section[2].size); + ret += patchSvcBreak9(arm9Section, firm->section[2].size, (u32)firm->section[2].address); } + + return ret; } static inline void copySection0AndInjectSystemModules(FirmwareType firmType, bool loadFromStorage) @@ -478,11 +265,11 @@ static inline void copySection0AndInjectSystemModules(FirmwareType firmType, boo u32 srcModuleSize, dstModuleSize; - for(u8 *src = (u8 *)firm + section[0].offset, *srcEnd = src + section[0].size, *dst = section[0].address; + for(u8 *src = (u8 *)firm + firm->section[0].offset, *srcEnd = src + firm->section[0].size, *dst = firm->section[0].address; src < srcEnd; src += srcModuleSize, dst += dstModuleSize) { - srcModuleSize = ((Ncch *)src)->contentSize * 0x200; - const char *moduleName = (char *)(src + 0x200); + srcModuleSize = ((Cxi *)src)->ncch.contentSize * 0x200; + const char *moduleName = ((Cxi *)src)->exHeader.systemControlInfo.appTitle; u32 fileSize; @@ -520,7 +307,7 @@ static inline void copySection0AndInjectSystemModules(FirmwareType firmType, boo } } -static inline void launchFirm(FirmwareType firmType, bool loadFromStorage) +void launchFirm(FirmwareType firmType, bool loadFromStorage) { //Allow module injection and/or inject 3ds_injector on new NATIVE_FIRMs and LGY FIRMs u32 sectionNum; @@ -532,12 +319,12 @@ static inline void launchFirm(FirmwareType firmType, bool loadFromStorage) else sectionNum = 0; //Copy FIRM sections to respective memory locations - for(; sectionNum < 4 && section[sectionNum].size != 0; sectionNum++) - memcpy(section[sectionNum].address, (u8 *)firm + section[sectionNum].offset, section[sectionNum].size); + for(; sectionNum < 4 && firm->section[sectionNum].size != 0; sectionNum++) + memcpy(firm->section[sectionNum].address, (u8 *)firm + firm->section[sectionNum].offset, firm->section[sectionNum].size); //Determine the ARM11 entry to use vu32 *arm11; - if(isFirmlaunch) arm11 = (vu32 *)0x1FFFFFFC; + if(ISFIRMLAUNCH) arm11 = (vu32 *)0x1FFFFFFC; else { deinitScreens(); diff --git a/source/firm.h b/source/firm.h index 5a2dbb8..937dde6 100644 --- a/source/firm.h +++ b/source/firm.h @@ -24,32 +24,9 @@ #include "types.h" -#define CFG_BOOTENV (*(vu32 *)0x10010000) -#define CFG_UNITINFO (*(vu8 *)0x10010010) -#define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC) -#define PDN_SPI_CNT (*(vu32 *)0x101401C0) - -//FIRM Header layout -typedef struct firmSectionHeader { - u32 offset; - u8 *address; - u32 size; - u32 procType; - u8 hash[0x20]; -} firmSectionHeader; - -typedef struct firmHeader { - u32 magic; - u32 reserved1; - u8 *arm11Entry; - u8 *arm9Entry; - u8 reserved2[0x30]; - firmSectionHeader section[4]; -} firmHeader; - -static inline u32 loadFirm(FirmwareType *firmType, FirmwareSource firmSource, bool loadFromStorage, Fs fsStatus); -static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, u32 devMode); -static inline void patchLegacyFirm(FirmwareType firmType, u32 firmVersion, u32 devMode); -static inline void patch1x2xNativeAndSafeFirm(u32 devMode); -static inline void copySection0AndInjectSystemModules(FirmwareType firmType, bool loadFromSd); -static inline void launchFirm(FirmwareType firmType, bool loadFromStorage); \ No newline at end of file +u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSdMode); +u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, u32 devMode); +u32 patchTwlFirm(u32 firmVersion, u32 devMode); +u32 patchAgbFirm(u32 devMode); +u32 patch1x2xNativeAndSafeFirm(u32 devMode); +void launchFirm(FirmwareType firmType, bool loadFromStorage); \ No newline at end of file diff --git a/source/fs.c b/source/fs.c index 45f8271..ac1a270 100644 --- a/source/fs.c +++ b/source/fs.c @@ -144,7 +144,7 @@ void loadPayload(u32 pressed) { loaderAddress[1] = payloadSize; - if(isA9lh) restoreShaHashBackup(); + backupAndRestoreShaHash(true); initScreens(); flushDCacheRange(loaderAddress, loader_bin_size); @@ -163,7 +163,7 @@ u32 firmRead(void *dest, u32 firmType) { "00000003", "20000003" }}; char path[48] = "1:/title/00040138/"; - concatenateStrings(path, firmFolders[firmType][isN3DS ? 1 : 0]); + concatenateStrings(path, firmFolders[firmType][ISN3DS ? 1 : 0]); concatenateStrings(path, "/content"); DIR dir; diff --git a/source/fs.h b/source/fs.h index 2302164..3fbd87c 100644 --- a/source/fs.h +++ b/source/fs.h @@ -26,8 +26,6 @@ #define PATTERN(a) a "_*.bin" -extern bool isN3DS, isA9lh; - bool mountFs(bool isSd); bool switchToCtrNand(void); u32 fileRead(void *dest, const char *path, u32 maxSize); diff --git a/source/main.c b/source/main.c new file mode 100644 index 0000000..9156ce9 --- /dev/null +++ b/source/main.c @@ -0,0 +1,249 @@ +/* +* 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. +*/ + +#include "config.h" +#include "emunand.h" +#include "fs.h" +#include "firm.h" +#include "utils.h" +#include "exceptions.h" +#include "draw.h" +#include "buttons.h" +#include "pin.h" + +extern CfgData configData; +extern FirmwareSource firmSource; + +void main(void) +{ + u32 configTemp, + emuHeader; + FirmwareType firmType; + FirmwareSource nandType; + ConfigurationStatus needConfig; + + //Mount SD or CTRNAND + bool isSdMode; + if(mountFs(true)) isSdMode = true; + else + { + firmSource = FIRMWARE_SYSNAND; + if(!mountFs(false) || !switchToCtrNand()) error("Error mounting SD and CTRNAND."); + isSdMode = false; + } + + //Attempt to read the configuration file + needConfig = readConfig() ? MODIFY_CONFIGURATION : CREATE_CONFIGURATION; + + //Determine if this is a firmlaunch boot + if(ISFIRMLAUNCH) + { + if(needConfig == CREATE_CONFIGURATION) mcuReboot(); + + //'0' = NATIVE_FIRM, '1' = TWL_FIRM, '2' = AGB_FIRM + firmType = launchedFirmTidLow[7] == u'3' ? SAFE_FIRM : (FirmwareType)(launchedFirmTidLow[5] - u'0'); + + nandType = (FirmwareSource)BOOTCFG_NAND; + firmSource = (FirmwareSource)BOOTCFG_FIRM; + } + else + { + if(ISA9LH) + { + detectAndProcessExceptionDumps(); + installArm9Handlers(); + } + + firmType = NATIVE_FIRM; + + //Get pressed buttons + u32 pressed = HID_PAD; + + //Save old options and begin saving the new boot configuration + configTemp = (configData.config & 0xFFFFFE00) | ((u32)ISA9LH << 6); + + //If it's a MCU reboot, try to force boot options + if(ISA9LH && CFG_BOOTENV) + { + //Always force a SysNAND boot when quitting AGB_FIRM + if(CFG_BOOTENV == 7) + { + nandType = FIRMWARE_SYSNAND; + firmSource = CONFIG(USESYSFIRM) ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCFG_FIRM; + needConfig = DONT_CONFIGURE; + + //Flag to prevent multiple boot options-forcing + configTemp |= 1 << 7; + } + + /* Else, force the last used boot options unless a button is pressed + or the no-forcing flag is set */ + else if(needConfig != CREATE_CONFIGURATION && !pressed && !BOOTCFG_NOFORCEFLAG) + { + nandType = (FirmwareSource)BOOTCFG_NAND; + firmSource = (FirmwareSource)BOOTCFG_FIRM; + needConfig = DONT_CONFIGURE; + } + } + + //Boot options aren't being forced + if(needConfig != DONT_CONFIGURE) + { + u32 pinMode = MULTICONFIG(PIN); + bool pinExists = pinMode != 0 && verifyPin(pinMode); + + //If no configuration file exists or SELECT is held, load configuration menu + bool shouldLoadConfigMenu = needConfig == CREATE_CONFIGURATION || ((pressed & BUTTON_SELECT) && !(pressed & BUTTON_L1)); + + if(shouldLoadConfigMenu) + { + configMenu(isSdMode, pinExists, pinMode); + + //Update pressed buttons + pressed = HID_PAD; + } + + if(ISA9LH && !CFG_BOOTENV && pressed == SAFE_MODE) + { + nandType = FIRMWARE_SYSNAND; + firmSource = FIRMWARE_SYSNAND; + + //Flag to tell loader to init SD + configTemp |= 1 << 8; + + //If the PIN has been verified, wait to make it easier to press the SAFE_MODE combo + if(pinExists && !shouldLoadConfigMenu) + { + while(HID_PAD & PIN_BUTTONS); + chrono(2); + } + } + else + { + u32 splashMode = MULTICONFIG(SPLASH); + + if(splashMode == 1 && loadSplash()) pressed = HID_PAD; + + /* If L and R/A/Select or one of the single payload buttons are pressed, + chainload an external payload */ + bool shouldLoadPayload = ((pressed & SINGLE_PAYLOAD_BUTTONS) && !(pressed & (BUTTON_L1 | BUTTON_R1 | BUTTON_A))) || + ((pressed & L_PAYLOAD_BUTTONS) && (pressed & BUTTON_L1)); + + if(shouldLoadPayload) loadPayload(pressed); + + if(splashMode == 2) loadSplash(); + + //If booting from CTRNAND, always use SysNAND + if(!isSdMode) nandType = FIRMWARE_SYSNAND; + + //If R is pressed, boot the non-updated NAND with the FIRM of the opposite one + else if(pressed & BUTTON_R1) + { + //Determine if the user chose to use the SysNAND FIRM as default for a R boot + bool useSysAsDefault = ISA9LH ? CONFIG(USESYSFIRM) : false; + + nandType = useSysAsDefault ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND; + firmSource = useSysAsDefault ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND; + } + + /* Else, boot the NAND the user set to autoboot or the opposite one, depending on L, + with their own FIRM */ + else + { + nandType = (CONFIG(AUTOBOOTSYS) != !(pressed & BUTTON_L1)) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND; + firmSource = nandType; + } + + //If we're booting EmuNAND or using EmuNAND FIRM, determine which one from the directional pad buttons, or otherwise from the config + if(nandType == FIRMWARE_EMUNAND || firmSource == FIRMWARE_EMUNAND) + { + FirmwareSource temp; + switch(pressed & EMUNAND_BUTTONS) + { + case BUTTON_UP: + temp = FIRMWARE_EMUNAND; + break; + case BUTTON_RIGHT: + temp = FIRMWARE_EMUNAND2; + break; + case BUTTON_DOWN: + temp = FIRMWARE_EMUNAND3; + break; + case BUTTON_LEFT: + temp = FIRMWARE_EMUNAND4; + break; + default: + temp = (FirmwareSource)(1 + MULTICONFIG(DEFAULTEMU)); + break; + } + + if(nandType == FIRMWARE_EMUNAND) nandType = temp; + else firmSource = temp; + } + } + } + } + + //If we need to boot EmuNAND, make sure it exists + if(nandType != FIRMWARE_SYSNAND) + { + locateEmuNand(&emuHeader, &nandType); + if(nandType == FIRMWARE_SYSNAND) firmSource = FIRMWARE_SYSNAND; + } + + //Same if we're using EmuNAND as the FIRM source + else if(firmSource != FIRMWARE_SYSNAND) + locateEmuNand(&emuHeader, &firmSource); + + if(!ISFIRMLAUNCH) + { + configTemp |= (u32)nandType | ((u32)firmSource << 3); + writeConfig(needConfig, configTemp); + } + + bool loadFromStorage = CONFIG(LOADEXTFIRMSANDMODULES); + u32 firmVersion = loadFirm(&firmType, firmSource, loadFromStorage, isSdMode); + + u32 devMode = MULTICONFIG(DEVOPTIONS); + + u32 res; + switch(firmType) + { + case NATIVE_FIRM: + res = patchNativeFirm(firmVersion, nandType, emuHeader, devMode); + break; + case SAFE_FIRM: + case NATIVE_FIRM1X2X: + res = ISA9LH ? patch1x2xNativeAndSafeFirm(devMode) : 0; + break; + case TWL_FIRM: + res = patchTwlFirm(firmVersion, devMode); + break; + case AGB_FIRM: + res = patchAgbFirm(devMode); + break; + } + + if(res != 0) error("Error applying FIRM patches."); + + launchFirm(firmType, loadFromStorage); +} \ No newline at end of file diff --git a/source/patches.c b/source/patches.c index a4f119c..f4c4ef4 100644 --- a/source/patches.c +++ b/source/patches.c @@ -28,117 +28,179 @@ #include "fs.h" #include "memory.h" #include "config.h" +#include "utils.h" #include "../build/bundled.h" -u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr) +u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr) { - u8 *off = memsearch(pos, "ess9", size, 4); + u8 *temp = memsearch(pos, "NCCH", size, 4); - *process9Size = *(u32 *)(off - 0x60) * 0x200; - *process9MemAddr = *(u32 *)(off + 0xC); + if(temp == NULL) error("Error getting Process9 data."); - //Process9 code offset (start of NCCH + ExeFS offset + ExeFS header size) - return off - 0x204 + (*(u32 *)(off - 0x64) * 0x200) + 0x200; + Cxi *off = (Cxi *)(temp - 0x100); + + *process9Size = off->ncch.contentSize * 0x200; + *process9MemAddr = off->exHeader.systemControlInfo.textCodeSet.address; + + return (u8 *)off + (off->ncch.exeFsOffset * 0x200) + 0x200; } u32 *getKernel11Info(u8 *pos, u32 size, u32 *baseK11VA, u8 **freeK11Space, u32 **arm11SvcHandler, u32 **arm11ExceptionsPage) -{ +{ const u8 pattern[] = {0x00, 0xB0, 0x9C, 0xE5}; + bool ret = true; - *arm11ExceptionsPage = (u32 *)memsearch(pos, pattern, size, sizeof(pattern)) - 0xB; + *arm11ExceptionsPage = (u32 *)memsearch(pos, pattern, size, sizeof(pattern)); - u32 svcOffset = (-(((*arm11ExceptionsPage)[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch - u32 pointedInstructionVA = 0xFFFF0008 - svcOffset; - *baseK11VA = pointedInstructionVA & 0xFFFF0000; //This assumes that the pointed instruction has an offset < 0x10000, iirc that's always the case - u32 *arm11SvcTable = (u32 *)(pos + *(u32 *)(pos + pointedInstructionVA - *baseK11VA + 8) - *baseK11VA); //SVC handler address - *arm11SvcHandler = arm11SvcTable; - while(*arm11SvcTable) arm11SvcTable++; //Look for SVC0 (NULL) + u32 *arm11SvcTable; + + if(*arm11ExceptionsPage == NULL) ret = false; + else + { + *arm11ExceptionsPage -= 0xB; + u32 svcOffset = (-(((*arm11ExceptionsPage)[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch + u32 pointedInstructionVA = 0xFFFF0008 - svcOffset; + *baseK11VA = pointedInstructionVA & 0xFFFF0000; //This assumes that the pointed instruction has an offset < 0x10000, iirc that's always the case + arm11SvcTable = *arm11SvcHandler = (u32 *)(pos + *(u32 *)(pos + pointedInstructionVA - *baseK11VA + 8) - *baseK11VA); //SVC handler address + while(*arm11SvcTable) arm11SvcTable++; //Look for SVC0 (NULL) + } const u8 pattern2[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - *freeK11Space = memsearch(pos, pattern2, size, sizeof(pattern2)) + 1; + *freeK11Space = memsearch(pos, pattern2, size, sizeof(pattern2)); + + if(*freeK11Space == NULL) ret = false; + else (*freeK11Space)++; + + if(!ret) error("Error getting Kernel11 data."); return arm11SvcTable; } -void patchSignatureChecks(u8 *pos, u32 size) +u32 patchSignatureChecks(u8 *pos, u32 size) { //Look for signature checks const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7}, pattern2[] = {0xB5, 0x22, 0x4D, 0x0C}; + u32 ret; - u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)), - *off2 = (u16 *)(memsearch(pos, pattern2, size, sizeof(pattern2)) - 1); + u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); + u8 *temp = memsearch(pos, pattern2, size, sizeof(pattern2)); - *off = off2[0] = 0x2000; - off2[1] = 0x4770; + if(off == NULL || temp == NULL) ret = 1; + else + { + u16 *off2 = (u16 *)(temp - 1); + + *off = off2[0] = 0x2000; + off2[1] = 0x4770; + + ret = 0; + } + + return ret; } -void patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr) +u32 patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr) { //Look for firmlaunch code const u8 pattern[] = {0xE2, 0x20, 0x20, 0x90}; + u32 ret; - u8 *off = memsearch(pos, pattern, size, sizeof(pattern)) - 0x13; + u8 *off = memsearch(pos, pattern, size, sizeof(pattern)); - //Firmlaunch function offset - offset in BLX opcode (A4-16 - ARM DDI 0100E) + 1 - u32 fOpenOffset = (u32)(off + 9 - (-((*(u32 *)off & 0x00FFFFFF) << 2) & (0xFFFFFF << 2)) - pos + process9MemAddr); - - //Copy firmlaunch code - memcpy(off, reboot_bin, reboot_bin_size); - - //Put the fOpen offset in the right location - u32 *pos_fopen = (u32 *)memsearch(off, "OPEN", reboot_bin_size, 4); - *pos_fopen = fOpenOffset; - - if(CONFIG(USECUSTOMPATH)) + if(off == NULL) ret = 1; + else { - const char pathPath[] = "luma/path.txt"; + off -= 0x13; - u32 pathSize = getFileSize(pathPath); + //Firmlaunch function offset - offset in BLX opcode (A4-16 - ARM DDI 0100E) + 1 + u32 fOpenOffset = (u32)(off + 9 - (-((*(u32 *)off & 0x00FFFFFF) << 2) & (0xFFFFFF << 2)) - pos + process9MemAddr); - if(pathSize > 5 && pathSize < 58) + //Copy firmlaunch code + memcpy(off, reboot_bin, reboot_bin_size); + + //Put the fOpen offset in the right location + u32 *pos_fopen = (u32 *)memsearch(off, "OPEN", reboot_bin_size, 4); + *pos_fopen = fOpenOffset; + + ret = 0; + + if(CONFIG(USECUSTOMPATH)) { - u8 path[pathSize]; - fileRead(path, pathPath, pathSize); - if(path[pathSize - 1] == 0xA) pathSize--; - if(path[pathSize - 1] == 0xD) pathSize--; + const char pathPath[] = "luma/path.txt"; - if(pathSize > 5 && pathSize < 56 && path[0] == '/' && memcmp(&path[pathSize - 4], ".bin", 4) == 0) + u32 pathSize = getFileSize(pathPath); + + if(pathSize > 5 && pathSize < 58) { - u16 finalPath[pathSize + 1]; - for(u32 i = 0; i < pathSize; i++) - finalPath[i] = (u16)path[i]; - finalPath[pathSize] = 0; + u8 path[pathSize]; + fileRead(path, pathPath, pathSize); + if(path[pathSize - 1] == 0xA) pathSize--; + if(path[pathSize - 1] == 0xD) pathSize--; - u8 *pos_path = memsearch(off, u"sd", reboot_bin_size, 4) + 0xA; - memcpy(pos_path, finalPath, (pathSize + 1) * 2); + if(pathSize > 5 && pathSize < 56 && path[0] == '/' && memcmp(&path[pathSize - 4], ".bin", 4) == 0) + { + u16 finalPath[pathSize + 1]; + for(u32 i = 0; i < pathSize; i++) + finalPath[i] = (u16)path[i]; + finalPath[pathSize] = 0; + + u8 *pos_path = memsearch(off, u"sd", reboot_bin_size, 4) + 0xA; + memcpy(pos_path, finalPath, (pathSize + 1) * 2); + } } } } + + return ret; } -void patchFirmWrites(u8 *pos, u32 size) +u32 patchFirmWrites(u8 *pos, u32 size) { + u32 ret; + //Look for FIRM writing code - u8 *off1 = memsearch(pos, "exe:", size, 4); - const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA}; + u8 *off = memsearch(pos, "exe:", size, 4); - u16 *off2 = (u16 *)memsearch(off1 - 0x100, pattern, 0x100, sizeof(pattern)); + if(off == NULL) ret = 1; + else + { + const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA}; - off2[0] = 0x2000; - off2[1] = 0x46C0; + u16 *off2 = (u16 *)memsearch(off - 0x100, pattern, 0x100, sizeof(pattern)); + + if(off2 == NULL) ret = 1; + else + { + off2[0] = 0x2000; + off2[1] = 0x46C0; + + ret = 0; + } + } + + return ret; } -void patchOldFirmWrites(u8 *pos, u32 size) +u32 patchOldFirmWrites(u8 *pos, u32 size) { //Look for FIRM writing code const u8 pattern[] = {0x04, 0x1E, 0x1D, 0xDB}; + u32 ret; u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); - off[0] = 0x2400; - off[1] = 0xE01D; + if(off == NULL) ret = 1; + else + { + off[0] = 0x2400; + off[1] = 0xE01D; + + ret = 0; + } + + return ret; } void reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space) @@ -192,106 +254,109 @@ void implementSvcGetCFWInfo(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **fre *freeK11Space += svcGetCFWInfo_bin_size; } -void patchTitleInstallMinVersionCheck(u8 *pos, u32 size) +u32 patchTitleInstallMinVersionChecks(u8 *pos, u32 size, u32 firmVersion) { const u8 pattern[] = {0x0A, 0x81, 0x42, 0x02}; + u32 ret = 0; u8 *off = memsearch(pos, pattern, size, sizeof(pattern)); - if(off != NULL) off[4] = 0xE0; + if(off == NULL) + { + if(firmVersion != 0xFFFFFFFF) ret = 1; + } + else off[4] = 0xE0; + + return ret; } -void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType) +u32 patchArm9ExceptionHandlersInstall(u8 *pos, u32 size) { - const patchData twlPatches[] = { - {{0x1650C0, 0x165D64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0}, - {{0x173A0E, 0x17474A}, { .type1 = 0x2001 }, 1}, - {{0x174802, 0x17553E}, { .type1 = 0x2000 }, 2}, - {{0x174964, 0x1756A0}, { .type1 = 0x2000 }, 2}, - {{0x174D52, 0x175A8E}, { .type1 = 0x2001 }, 2}, - {{0x174D5E, 0x175A9A}, { .type1 = 0x2001 }, 2}, - {{0x174D6A, 0x175AA6}, { .type1 = 0x2001 }, 2}, - {{0x174E56, 0x175B92}, { .type1 = 0x2001 }, 1}, - {{0x174E58, 0x175B94}, { .type1 = 0x4770 }, 1} - }, - agbPatches[] = { - {{0x9D2A8, 0x9DF64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0}, - {{0xD7A12, 0xD8B8A}, { .type1 = 0xEF26 }, 1} - }; + const u8 pattern[] = {0x80, 0xE5, 0x40, 0x1C}; + u32 ret; - /* Calculate the amount of patches to apply. Only count the boot screen patch for AGB_FIRM - if the matching option was enabled (keep it as last) */ - u32 numPatches = firmType == TWL_FIRM ? (sizeof(twlPatches) / sizeof(patchData)) : - (sizeof(agbPatches) / sizeof(patchData) - !CONFIG(SHOWGBABOOT)); - const patchData *patches = firmType == TWL_FIRM ? twlPatches : agbPatches; + u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); - //Patch - for(u32 i = 0; i < numPatches; i++) + if(temp == NULL) ret = 1; + else { - switch(patches[i].type) + u32 *off = (u32 *)(temp - 0xA); + + for(u32 r0 = 0x08000000; *off != 0xE3A01040; off++) //Until mov r1, #0x40 { - case 0: - memcpy(pos + patches[i].offset[isN3DS ? 1 : 0], patches[i].patch.type0 + 1, patches[i].patch.type0[0]); - break; - case 2: - *(u16 *)(pos + patches[i].offset[isN3DS ? 1 : 0] + 2) = 0; - case 1: - *(u16 *)(pos + patches[i].offset[isN3DS ? 1 : 0]) = patches[i].patch.type1; - break; + //Discard everything that's not str rX, [r0, #imm](!) + if((*off & 0xFE5F0000) == 0xE4000000) + { + u32 rD = (*off >> 12) & 0xF, + offset = (*off & 0xFFF) * ((((*off >> 23) & 1) == 0) ? -1 : 1); + bool writeback = ((*off >> 21) & 1) != 0, + pre = ((*off >> 24) & 1) != 0; + + u32 addr = r0 + ((pre || !writeback) ? offset : 0); + if((addr & 7) != 0 && addr != 0x08000014 && addr != 0x08000004) *off = 0xE1A00000; //nop + else *off = 0xE5800000 | (rD << 12) | (addr & 0xFFF); //Preserve IRQ and SVC handlers + + if(!pre) addr += offset; + if(writeback) r0 = addr; + } } + + ret = 0; } -} -void patchArm9ExceptionHandlersInstall(u8 *pos, u32 size) -{ - const u8 pattern[] = {0x03, 0xA0, 0xE3, 0x18}; - - u32 *off = (u32 *)(memsearch(pos, pattern, size, sizeof(pattern)) + 0x13); - - for(u32 r0 = 0x08000000; *off != 0xE3A01040; off++) //Until mov r1, #0x40 - { - //Discard everything that's not str rX, [r0, #imm](!) - if((*off & 0xFE5F0000) != 0xE4000000) continue; - - u32 rD = (*off >> 12) & 0xF, - offset = (*off & 0xFFF) * ((((*off >> 23) & 1) == 0) ? -1 : 1); - bool writeback = ((*off >> 21) & 1) != 0, - pre = ((*off >> 24) & 1) != 0; - - u32 addr = r0 + ((pre || !writeback) ? offset : 0); - if((addr & 7) != 0 && addr != 0x08000014 && addr != 0x08000004) *off = 0xE1A00000; //nop - else *off = 0xE5800000 | (rD << 12) | (addr & 0xFFF); //Preserve IRQ and SVC handlers - - if(!pre) addr += offset; - if(writeback) r0 = addr; - } + return ret; } u32 getInfoForArm11ExceptionHandlers(u8 *pos, u32 size, u32 *codeSetOffset) { - const u8 pattern[] = {0xE3, 0xDC, 0x05, 0xC0}, //Get TitleID from CodeSet - pattern2[] = {0xE1, 0x0F, 0x00, 0xBD}; //Call exception dispatcher + const u8 pattern[] = {0x1B, 0x50, 0xA0, 0xE3}, //Get TitleID from CodeSet + pattern2[] = {0xE8, 0x13, 0x00, 0x02}; //Call exception dispatcher + bool ret = true; - u32 *loadCodeSet = (u32 *)(memsearch(pos, pattern, size, sizeof(pattern)) - 0xB); + u32 *loadCodeSet = (u32 *)memsearch(pos, pattern, size, sizeof(pattern)); - *codeSetOffset = *loadCodeSet & 0xFFF; + if(loadCodeSet == NULL) ret = false; + else + { + loadCodeSet -= 2; + *codeSetOffset = *loadCodeSet & 0xFFF; + } - return *(u32 *)(memsearch(pos, pattern2, size, sizeof(pattern2)) + 0xD); + u8 *temp = memsearch(pos, pattern2, size, sizeof(pattern2)); + + u32 stackAddress; + + if(temp == NULL) ret = false; + else stackAddress = *(u32 *)(temp + 9); + + if(!ret) error("Error getting ARM11 exception handlers data."); + + return stackAddress; } -void patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address) +u32 patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address) { /* Stub svcBreak with "bkpt 65535" so we can debug the panic. Thanks @yellows8 and others for mentioning this idea on #3dsdev */ //Look for the svc handler const u8 pattern[] = {0x00, 0xE0, 0x4F, 0xE1}; //mrs lr, spsr + u32 ret; u32 *arm9SvcTable = (u32 *)memsearch(pos, pattern, size, sizeof(pattern)); - while(*arm9SvcTable) arm9SvcTable++; //Look for SVC0 (NULL) - u32 *addr = (u32 *)(pos + arm9SvcTable[0x3C] - kernel9Address); - *addr = 0xE12FFF7F; + if(arm9SvcTable == NULL) ret = 1; + else + { + while(*arm9SvcTable) arm9SvcTable++; //Look for SVC0 (NULL) + + u32 *addr = (u32 *)(pos + arm9SvcTable[0x3C] - kernel9Address); + *addr = 0xE12FFF7F; + + ret = 0; + } + + return ret; } void patchSvcBreak11(u8 *pos, u32 *arm11SvcTable) @@ -301,68 +366,301 @@ void patchSvcBreak11(u8 *pos, u32 *arm11SvcTable) *addr = 0xE12FFF7F; } -void patchKernel9Panic(u8 *pos, u32 size) +u32 patchKernel9Panic(u8 *pos, u32 size) { const u8 pattern[] = {0xFF, 0xEA, 0x04, 0xD0}; + u32 ret; - u32 *off = (u32 *)(memsearch(pos, pattern, size, sizeof(pattern)) - 0x12); - *off = 0xE12FFF7E; + u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); + + if(temp == NULL) ret = 1; + else + { + u32 *off = (u32 *)(temp - 0x12); + *off = 0xE12FFF7E; + + ret = 0; + } + + return ret; } -void patchKernel11Panic(u8 *pos, u32 size) +u32 patchKernel11Panic(u8 *pos, u32 size) { const u8 pattern[] = {0x02, 0x0B, 0x44, 0xE2}; + u32 ret; u32 *off = (u32 *)memsearch(pos, pattern, size, sizeof(pattern)); - *off = 0xE12FFF7E; + + if(off == NULL) ret = 1; + else + { + *off = 0xE12FFF7E; + + ret = 0; + } + + return ret; } -void patchP9AccessChecks(u8 *pos, u32 size) +u32 patchP9AccessChecks(u8 *pos, u32 size) { - const u8 pattern[] = {0xE0, 0x00, 0x40, 0x39}; + const u8 pattern[] = {0x00, 0x08, 0x49, 0x68}; + u32 ret; - u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)) - 7; + u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); - off[0] = 0x2001; //mov r0, #1 - off[1] = 0x4770; //bx lr + if(temp == NULL) ret = 1; + else + { + u16 *off = (u16 *)(temp - 3); + + off[0] = 0x2001; //mov r0, #1 + off[1] = 0x4770; //bx lr + + ret = 0; + } + + return ret; } -void patchArm11SvcAccessChecks(u32 *arm11SvcHandler) +u32 patchArm11SvcAccessChecks(u32 *arm11SvcHandler, u32 *endPos) { - while(*arm11SvcHandler != 0xE11A0E1B) arm11SvcHandler++; //TST R10, R11,LSL LR - *arm11SvcHandler = 0xE3B0A001; //MOVS R10, #1 + u32 ret; + + while(*arm11SvcHandler != 0xE11A0E1B && arm11SvcHandler < endPos) arm11SvcHandler++; //TST R10, R11,LSL LR + + if(arm11SvcHandler == endPos) ret = 1; + else + { + *arm11SvcHandler = 0xE3B0A001; //MOVS R10, #1 + + ret = 0; + } + + return ret; } -void patchK11ModuleChecks(u8 *pos, u32 size, u8 **freeK11Space) +u32 patchK11ModuleChecks(u8 *pos, u32 size, u8 **freeK11Space) { /* We have to detour a function in the ARM11 kernel because builtin modules are compressed in memory and are only decompressed at runtime */ + u32 ret = 0; + //Check that we have enough free space if(*(u32 *)(*freeK11Space + k11modules_bin_size - 4) == 0xFFFFFFFF) { - //Inject our code into the free space - memcpy(*freeK11Space, k11modules_bin, k11modules_bin_size); - //Look for the code that decompresses the .code section of the builtin modules const u8 pattern[] = {0xE5, 0x48, 0x00, 0x9D}; - u32 *off = (u32 *)(memsearch(pos, pattern, size, sizeof(pattern)) - 0xB); + u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); - //Inject a jump (BL) instruction to our code at the offset we found - *off = 0xEB000000 | (((((u32)*freeK11Space) - ((u32)off + 8)) >> 2) & 0xFFFFFF); + if(temp == NULL) ret = 1; + else + { + //Inject our code into the free space + memcpy(*freeK11Space, k11modules_bin, k11modules_bin_size); - *freeK11Space += k11modules_bin_size; + u32 *off = (u32 *)(temp - 0xB); + + //Inject a jump (BL) instruction to our code at the offset we found + *off = 0xEB000000 | (((((u32)*freeK11Space) - ((u32)off + 8)) >> 2) & 0xFFFFFF); + + *freeK11Space += k11modules_bin_size; + } } + + return ret; } -void patchUnitInfoValueSet(u8 *pos, u32 size) +u32 patchUnitInfoValueSet(u8 *pos, u32 size) { //Look for UNITINFO value being set during kernel sync const u8 pattern[] = {0x01, 0x10, 0xA0, 0x13}; + u32 ret; u8 *off = memsearch(pos, pattern, size, sizeof(pattern)); - off[0] = isDevUnit ? 0 : 1; - off[3] = 0xE3; + if(off == NULL) ret = 1; + else + { + off[0] = ISDEVUNIT ? 0 : 1; + off[3] = 0xE3; + + ret = 0; + } + + return ret; +} + +u32 patchLgySignatureChecks(u8 *pos, u32 size) +{ + const u8 pattern[] = {0x47, 0xC1, 0x17, 0x49}; + u32 ret; + + u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); + + if(temp == NULL) ret = 1; + else + { + u16 *off = (u16 *)(temp + 1); + + off[0] = 0x2000; + off[1] = 0xB04E; + off[2] = 0xBD70; + + ret = 0; + } + + return ret; +} + +u32 patchTwlInvalidSignatureChecks(u8 *pos, u32 size) +{ + const u8 pattern[] = {0x20, 0xF6, 0xE7, 0x7F}; + u32 ret; + + u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); + + if(temp == NULL) ret = 1; + else + { + u16 *off = (u16 *)(temp - 1); + + *off = 0x2001; //mov r0, #1 + + ret = 0; + } + + return ret; +} + +u32 patchTwlNintendoLogoChecks(u8 *pos, u32 size) +{ + const u8 pattern[] = {0xC0, 0x30, 0x06, 0xF0}; + u32 ret; + + u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); + + if(temp == NULL) ret = 1; + else + { + u16 *off = (u16 *)temp + 1; + + off[0] = 0x2000; + off[1] = 0; + + ret = 0; + } + + return ret; +} + +u32 patchTwlWhitelistChecks(u8 *pos, u32 size) +{ + const u8 pattern[] = {0x22, 0x00, 0x20, 0x30}; + u32 ret; + + u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); + + if(temp == NULL) ret = 1; + else + { + u16 *off = (u16 *)temp + 2; + + off[0] = 0x2000; + off[1] = 0; + + ret = 0; + } + + return ret; +} + +u32 patchTwlFlashcartChecks(u8 *pos, u32 size, u32 firmVersion) +{ + const u8 pattern[] = {0x25, 0x20, 0x00, 0x0E}; + u32 ret; + + u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); + + if(temp == NULL) + { + if(firmVersion == 0xFFFFFFFF) ret = patchOldTwlFlashcartChecks(pos, size); + else ret = 1; + } + else + { + u16 *off = (u16 *)(temp + 3); + + off[0] = 0x2001; //mov r0, #1 + off[1] = 0; //nop + off[6] = 0x2001; //mov r0, #1 + off[7] = 0; //nop + off[0xC] = 0x2001; //mov r0, #1 + off[0xD] = 0; //nop + + ret = 0; + } + + return ret; +} + +u32 patchOldTwlFlashcartChecks(u8 *pos, u32 size) +{ + const u8 pattern[] = {0x06, 0xF0, 0xA0, 0xFD}; + u32 ret; + + u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); + + if(off == NULL) ret = 1; + else + { + off[0] = 0x2001; //mov r0, #1 + off[1] = 0; //nop + off[6] = 0x2001; //mov r0, #1 + off[7] = 0; //nop + + ret = 0; + } + + return ret; +} + +u32 patchTwlShaHashChecks(u8 *pos, u32 size) +{ + const u8 pattern[] = {0x10, 0xB5, 0x14, 0x22}; + u32 ret; + + u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); + + if(off == NULL) ret = 1; + else + { + off[0] = 0x2001; //mov r0, #1 + off[1] = 0x4770; + + ret = 0; + } + + return ret; +} + +u32 patchAgbBootSplash(u8 *pos, u32 size) +{ + const u8 pattern[] = {0x00, 0x00, 0x01, 0xEF}; + u32 ret; + + u8 *off = memsearch(pos, pattern, size, sizeof(pattern)); + + if(off == NULL) ret = 1; + else + { + *off = 0x26; + + ret = 0; + } + + return ret; } \ No newline at end of file diff --git a/source/patches.h b/source/patches.h index a7cebc7..dfa6c65 100644 --- a/source/patches.h +++ b/source/patches.h @@ -28,15 +28,6 @@ #include "types.h" -typedef struct patchData { - u32 offset[2]; - union { - u8 type0[8]; - u16 type1; - } patch; - u32 type; -} patchData; - typedef struct __attribute__((packed)) { char magic[4]; @@ -51,25 +42,32 @@ typedef struct __attribute__((packed)) u32 config; } CFWInfo; -extern bool isDevUnit; +extern CfgData configData; -u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr); +u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr); u32 *getKernel11Info(u8 *pos, u32 size, u32 *baseK11VA, u8 **freeK11Space, u32 **arm11SvcHandler, u32 **arm11ExceptionsPage); -void patchSignatureChecks(u8 *pos, u32 size); -void patchTitleInstallMinVersionCheck(u8 *pos, u32 size); -void patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr); -void patchFirmWrites(u8 *pos, u32 size); -void patchOldFirmWrites(u8 *pos, u32 size); +u32 patchSignatureChecks(u8 *pos, u32 size); +u32 patchTitleInstallMinVersionChecks(u8 *pos, u32 size, u32 firmVersion); +u32 patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr); +u32 patchFirmWrites(u8 *pos, u32 size); +u32 patchOldFirmWrites(u8 *pos, u32 size); void reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space); void implementSvcGetCFWInfo(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space); -void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType); -void patchArm9ExceptionHandlersInstall(u8 *pos, u32 size); +u32 patchArm9ExceptionHandlersInstall(u8 *pos, u32 size); u32 getInfoForArm11ExceptionHandlers(u8 *pos, u32 size, u32 *codeSetOffset); -void patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address); +u32 patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address); void patchSvcBreak11(u8 *pos, u32 *arm11SvcTable); -void patchKernel9Panic(u8 *pos, u32 size); -void patchKernel11Panic(u8 *pos, u32 size); -void patchP9AccessChecks(u8 *pos, u32 size); -void patchArm11SvcAccessChecks(u32 *arm11SvcHandler); -void patchK11ModuleChecks(u8 *pos, u32 size, u8 **freeK11Space); -void patchUnitInfoValueSet(u8 *pos, u32 size); \ No newline at end of file +u32 patchKernel9Panic(u8 *pos, u32 size); +u32 patchKernel11Panic(u8 *pos, u32 size); +u32 patchP9AccessChecks(u8 *pos, u32 size); +u32 patchArm11SvcAccessChecks(u32 *arm11SvcHandler, u32 *endPos); +u32 patchK11ModuleChecks(u8 *pos, u32 size, u8 **freeK11Space); +u32 patchUnitInfoValueSet(u8 *pos, u32 size); +u32 patchLgySignatureChecks(u8 *pos, u32 size); +u32 patchTwlInvalidSignatureChecks(u8 *pos, u32 size); +u32 patchTwlNintendoLogoChecks(u8 *pos, u32 size); +u32 patchTwlWhitelistChecks(u8 *pos, u32 size); +u32 patchTwlFlashcartChecks(u8 *pos, u32 size, u32 firmVersion); +u32 patchOldTwlFlashcartChecks(u8 *pos, u32 size); +u32 patchTwlShaHashChecks(u8 *pos, u32 size); +u32 patchAgbBootSplash(u8 *pos, u32 size); \ No newline at end of file diff --git a/source/pin.h b/source/pin.h index 4697d0a..456593e 100644 --- a/source/pin.h +++ b/source/pin.h @@ -32,14 +32,5 @@ #define PIN_VERSIONMAJOR 1 #define PIN_VERSIONMINOR 3 -typedef struct __attribute__((packed)) -{ - char magic[4]; - u16 formatVersionMajor, formatVersionMinor; - - u8 lengthHash[32]; - u8 hash[32]; -} PinData; - void newPin(bool allowSkipping, u32 pinMode); bool verifyPin(u32 pinMode); \ No newline at end of file diff --git a/source/screen.h b/source/screen.h index d7e5818..af0f6ad 100644 --- a/source/screen.h +++ b/source/screen.h @@ -44,7 +44,9 @@ static volatile struct fb { u8 *top_left; u8 *top_right; u8 *bottom; -} *const fbs = (volatile struct fb *)0x23FFFE00; +} __attribute__((packed)) *const fbs = (volatile struct fb *)0x23FFFE00; + +extern CfgData configData; void deinitScreens(void); void swapFramebuffers(bool isAlternate); diff --git a/source/types.h b/source/types.h index d31fae7..3992341 100644 --- a/source/types.h +++ b/source/types.h @@ -36,9 +36,37 @@ typedef volatile u16 vu16; typedef volatile u32 vu32; typedef volatile u64 vu64; -//Used by multiple files +#include "3dsheaders.h" + #define BRAHMA_ARM11_ENTRY 0x1FFFFFF8 +#define CFG_BOOTENV (*(vu32 *)0x10010000) +#define CFG_UNITINFO (*(vu8 *)0x10010010) +#define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC) +#define PDN_SPI_CNT (*(vu32 *)0x101401C0) + +#define ISN3DS (PDN_MPCORE_CFG == 7) +#define ISDEVUNIT (CFG_UNITINFO != 0) +#define ISA9LH (!PDN_SPI_CNT) +#define ISFIRMLAUNCH (launchedFirmTidLow[5] != 0) + +typedef struct __attribute__((packed)) +{ + char magic[4]; + u16 formatVersionMajor, formatVersionMinor; + + u32 config; +} CfgData; + +typedef struct __attribute__((packed)) +{ + char magic[4]; + u16 formatVersionMajor, formatVersionMinor; + + u8 lengthHash[32]; + u8 hash[32]; +} PinData; + typedef enum FirmwareSource { FIRMWARE_SYSNAND = 0, @@ -57,9 +85,5 @@ typedef enum FirmwareType NATIVE_FIRM1X2X } FirmwareType; -typedef enum Fs -{ - SD_CARD = 0, - CTRNAND, - NONE -} Fs; \ No newline at end of file +extern u16 launchedFirmTidLow[8]; //Defined in start.s +static Firm *const firm = (Firm *)0x24000000; \ No newline at end of file diff --git a/source/utils.c b/source/utils.c index e1325b0..edda2a7 100644 --- a/source/utils.c +++ b/source/utils.c @@ -56,7 +56,7 @@ u32 waitInput(void) void mcuReboot(void) { - if(!isFirmlaunch && PDN_GPU_CNT != 1) clearScreens(true, true, false); + if(ISFIRMLAUNCH && PDN_GPU_CNT != 1) clearScreens(true, true, false); //Ensure that all memory transfers have completed and that the data cache has been flushed flushEntireDCache(); @@ -67,7 +67,7 @@ void mcuReboot(void) void mcuPowerOff(void) { - if(!isFirmlaunch && PDN_GPU_CNT != 1) clearScreens(true, true, false); + if(ISFIRMLAUNCH && PDN_GPU_CNT != 1) clearScreens(true, true, false); //Ensure that all memory transfers have completed and that the data cache has been flushed flushEntireDCache(); @@ -112,7 +112,7 @@ void chrono(u32 seconds) void error(const char *message) { - if(isFirmlaunch) mcuReboot(); + if(ISFIRMLAUNCH) mcuReboot(); initScreens(); diff --git a/source/utils.h b/source/utils.h index 34b51eb..bf74e1c 100644 --- a/source/utils.h +++ b/source/utils.h @@ -28,8 +28,6 @@ #define REG_TIMER_CNT(i) *(vu16 *)(0x10003002 + 4 * i) #define REG_TIMER_VAL(i) *(vu16 *)(0x10003000 + 4 * i) -extern bool isFirmlaunch; - u32 waitInput(void); void mcuReboot(void); void mcuPowerOff(void);