Compare commits

...

9 Commits
v4.0 ... v4.1

12 changed files with 242 additions and 218 deletions

View File

@@ -5,6 +5,8 @@
You'll need armips and [bin2c](https://sourceforge.net/projects/bin2c/) added to your Path. [HERE](http://www91.zippyshare.com/v/ePGpjk9r/file.html) is a pre-compiled version of armips.
You also need to have a recent build of makerom in your path for the injector to be built.
Lastly, just run Make and everything should work!
Copy everything in 'out' folder to SD root and run!
@@ -30,3 +32,5 @@ A skilled reverser gave me the new reboot patch.
The screen init code is from dark_samus, bil1s, Normmatt, delebile and everyone who contributed.
The code for printing to the screen is from CakesFW.
ARM11 userland patching is only possible thanks to @yifanlu's 3ds_injector, which is bundled in the CFW.

View File

@@ -15,7 +15,7 @@ static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSiz
const u8 *patternc = (const u8 *)pattern;
//Preprocessing
int table[256];
u32 table[256];
for(u32 i = 0; i < 256; ++i)
table[i] = patternSize + 1;
@@ -70,7 +70,7 @@ static int file_open(IFile *file, FS_ArchiveID id, const char *path, int flags){
return IFile_Open(file, archive, ppath, flags);
}
static int patch_secureinfo(){
static int load_secureinfo(){
IFile file;
Result ret;
u64 total;
@@ -78,20 +78,6 @@ static int patch_secureinfo(){
if(secureinfo[0] == 0xFF)
return 0;
ret = file_open(&file, ARCHIVE_SDMC, "/SecureInfo_A", FS_OPEN_READ);
if(R_SUCCEEDED(ret)){
ret = IFile_Read(&file, &total, secureinfo, sizeof(secureinfo));
IFile_Close(&file);
if(R_SUCCEEDED(ret) && total == sizeof(secureinfo)){
ret = file_open(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_WRITE | FS_OPEN_CREATE);
if(R_SUCCEEDED(ret)){
ret = IFile_Write(&file, &total, secureinfo, sizeof(secureinfo), FS_WRITE_FLUSH);
IFile_Close(&file);
}
secureinfo[0] = 0xFF; // we repurpose this byte as status
}
}
else { // get file from NAND
ret = file_open(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_READ);
if(R_SUCCEEDED(ret)){
ret = IFile_Read(&file, &total, secureinfo, sizeof(secureinfo));
@@ -99,12 +85,11 @@ static int patch_secureinfo(){
if(R_SUCCEEDED(ret) && total == sizeof(secureinfo))
secureinfo[0] = 0xFF;
}
}
return ret;
}
static int open_config(){
static int load_config(){
IFile file;
Result ret;
u64 total;
@@ -122,13 +107,15 @@ static int open_config(){
}
u32 patch_code(u64 progid, u8 *code, u32 size){
if( progid == 0x0004003000008F02LL || // USA Menu
progid == 0x0004003000008202LL || // JPN Menu
progid == 0x0004003000009802LL || // EUR Menu
progid == 0x000400300000A102LL || // CHN Menu
progid == 0x000400300000A902LL || // KOR Menu
progid == 0x000400300000B102LL // TWN Menu
){
switch(progid){
case 0x0004003000008F02LL: // USA Menu
case 0x0004003000008202LL: // EUR Menu
case 0x0004003000009802LL: // JPN Menu
case 0x000400300000A102LL: // CHN Menu
case 0x000400300000A902LL: // KOR Menu
case 0x000400300000B102LL: // TWN Menu
{
static const u8 regionFreePattern[] = {
0x00, 0x00, 0x55, 0xE3, 0x01, 0x10, 0xA0, 0xE3
};
@@ -142,8 +129,11 @@ u32 patch_code(u64 progid, u8 *code, u32 size){
regionFreePatch,
sizeof(regionFreePatch), 1
);
break;
}
else if(progid == 0x0004013000002C02LL){ // NIM
case 0x0004013000002C02LL: // NIM
{
static const u8 blockAutoUpdatesPattern[] = {
0x25, 0x79, 0x0B, 0x99
};
@@ -156,15 +146,6 @@ u32 patch_code(u64 progid, u8 *code, u32 size){
static const u8 blockEShopUpdateCheckPatch[] = {
0x00, 0x20, 0x08, 0x60, 0x70, 0x47
};
static const u8 countryRespPattern[] = {
0x01, 0x20, 0x01, 0x90, 0x22, 0x46, 0x06, 0x9B
};
static const char countryRespPatchModel[] = {
0x06, 0x9A, 0x03, 0x20, 0x90, 0x47, 0x55, 0x21, 0x01, 0x70, 0x53, 0x21, 0x41, 0x70, 0x00, 0x21,
0x81, 0x70, 0x60, 0x61, 0x00, 0x20
};
const char *country;
char countryRespPatch[sizeof(countryRespPatchModel)];
patch_memory(code, size,
blockAutoUpdatesPattern,
@@ -178,7 +159,18 @@ u32 patch_code(u64 progid, u8 *code, u32 size){
blockEShopUpdateCheckPatch,
sizeof(blockEShopUpdateCheckPatch), 1
);
if(R_SUCCEEDED(patch_secureinfo())){
if(R_SUCCEEDED(load_secureinfo())){
static const char countryRespPattern[] = {
0x01, 0x20, 0x01, 0x90, 0x22, 0x46, 0x06, 0x9B
};
static const char countryRespPatchModel[] = {
0x06, 0x9A, 0x03, 0x20, 0x90, 0x47, 0x55, 0x21, 0x01, 0x70, 0x53, 0x21, 0x41, 0x70, 0x00, 0x21,
0x81, 0x70, 0x60, 0x61, 0x00, 0x20
};
const char *country;
char countryRespPatch[sizeof(countryRespPatchModel)];
switch(secureinfo[0x100]){
case 1: country = "US"; break;
case 2: country = "GB"; break; // sorry rest-of-Europe, you have to change this
@@ -188,7 +180,6 @@ u32 patch_code(u64 progid, u8 *code, u32 size){
case 6: country = "TW"; break;
default: case 0: country = "JP"; break;
}
// patch XML response Country
memcpy(countryRespPatch,
countryRespPatchModel,
@@ -203,30 +194,34 @@ u32 patch_code(u64 progid, u8 *code, u32 size){
sizeof(countryRespPatch), 1
);
}
break;
}
else if(
progid == 0x0004001000021000LL || // USA MSET
progid == 0x0004001000020000LL || // JPN MSET
progid == 0x0004001000022000LL || // EUR MSET
progid == 0x0004001000026000LL || // CHN MSET
progid == 0x0004001000027000LL || // KOR MSET
progid == 0x0004001000028000LL // TWN MSET
){
if(R_SUCCEEDED(open_config()) && ((config >> 5) & 0x1)){
static const u16 VerPattern[] = u"Ver.";
const u32 currentFirm = ((config >> 12) & 0x1);
const u32 currentNand = ((config >> 13) & 0x3);
case 0x0004001000021000LL: // USA MSET
case 0x0004001000020000LL: // JPN MSET
case 0x0004001000022000LL: // EUR MSET
case 0x0004001000026000LL: // CHN MSET
case 0x0004001000027000LL: // KOR MSET
case 0x0004001000028000LL: // TWN MSET
{
if(R_SUCCEEDED(load_config()) && ((config >> 5) & 1)){
static const u16 verPattern[] = u"Ver.";
const u32 currentFirm = ((config >> 12) & 1);
const u32 currentNand = ((config >> 13) & 3);
patch_memory(code, size,
VerPattern,
sizeof(VerPattern) - sizeof(u16), 0,
verPattern,
sizeof(verPattern) - sizeof(u16), 0,
currentNand ? ((currentNand == 1) ? ((currentFirm == 1) ? u" Emu" : u"Emu9") : u"Emu2") :
((currentFirm == 1) ? u" Sys" : u"Sys9"),
sizeof(VerPattern) - sizeof(u16), 1
sizeof(verPattern) - sizeof(u16), 1
);
}
break;
}
else if (progid == 0x0004013000008002LL){ // NS
case 0x0004013000008002LL: // NS
{
static const u8 stopCartUpdatesPattern[] = {
0x0C, 0x18, 0xE1, 0xD8
};
@@ -240,16 +235,17 @@ u32 patch_code(u64 progid, u8 *code, u32 size){
stopCartUpdatesPatch,
sizeof(stopCartUpdatesPatch), 2
);
break;
}
else if(progid == 0x0004013000001702LL){ // CFG
case 0x0004013000001702LL: // CFG
{
static const u8 secureinfoSigCheckPattern[] = {
0x06, 0x46, 0x10, 0x48, 0xFC
};
static const u8 secureinfoSigCheckPatch[] = {
0x00, 0x26
};
static const u16 secureinfoFilenamePattern[] = u"SecureInfo_";
static const u16 secureinfoFilenamePatch[] = u"C";
// disable SecureInfo signature check
patch_memory(code, size,
@@ -258,7 +254,11 @@ u32 patch_code(u64 progid, u8 *code, u32 size){
secureinfoSigCheckPatch,
sizeof(secureinfoSigCheckPatch), 1
);
if(R_SUCCEEDED(patch_secureinfo())){
if(R_SUCCEEDED(load_secureinfo())){
static const u16 secureinfoFilenamePattern[] = u"SecureInfo_";
static const u16 secureinfoFilenamePatch[] = u"C";
// use SecureInfo_C
patch_memory(code, size,
secureinfoFilenamePattern,
@@ -268,6 +268,8 @@ u32 patch_code(u64 progid, u8 *code, u32 size){
sizeof(secureinfoFilenamePatch) - sizeof(u16), 2
);
}
break;
}
}
return 0;

View File

@@ -3,7 +3,6 @@
#include "types.h"
#define HID_PAD (*(vu16 *)0x10146000 ^ 0xFFF)
#define BUTTON_B (1 << 1)
#define BUTTON_X (1 << 10)
#define BUTTON_Y (1 << 11)
#define BUTTON_SELECT (1 << 2)

View File

@@ -25,8 +25,7 @@ void main(void){
//Get pressed buttons
u16 pressed = HID_PAD;
if(((pressed & BUTTON_B) && loadPayload("/aurei/payloads/b.bin")) ||
((pressed & BUTTON_X) && loadPayload("/aurei/payloads/x.bin")) ||
if(((pressed & BUTTON_X) && loadPayload("/aurei/payloads/x.bin")) ||
((pressed & BUTTON_Y) && loadPayload("/aurei/payloads/y.bin")) ||
((pressed & BUTTON_SELECT) && loadPayload("/aurei/payloads/select.bin")) ||
((pressed & BUTTON_START) && loadPayload("/aurei/payloads/start.bin")) ||

View File

@@ -21,6 +21,6 @@
#define BUTTON_DOWN (1 << 7)
#define BUTTON_L1R1 ((1 << 8) | (1 << 9))
#define SAFE_MODE (BUTTON_L1R1 | BUTTON_A | BUTTON_UP)
#define OPTION_BUTTONS (BUTTON_L1R1 | BUTTON_A)
#define PAYLOAD_BUTTONS ((BUTTON_L1 | BUTTON_A) ^ 0xFFF)
#define OPTION_BUTTONS (BUTTON_L1R1 | BUTTON_A | BUTTON_SELECT)
#define PAYLOAD_BUTTONS ((BUTTON_L1 | BUTTON_A | BUTTON_B) ^ 0xFFF)
#define MENU_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_A | BUTTON_START)

View File

@@ -20,7 +20,7 @@ static const struct fb {
u8 *bottom;
} *const fb = (struct fb *)0x23FFFE00;
static int strlen(const char *string){
static inline int strlen(const char *string){
char *stringEnd = (char *)string;
while(*stringEnd) stringEnd++;
return stringEnd - string;

View File

@@ -8,11 +8,11 @@
#include "memory.h"
#include "fatfs/sdmmc/sdmmc.h"
void getEmunandSect(u32 *off, u32 *head, u32 emuNAND){
void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND){
u8 *const temp = (u8 *)0x24300000;
u32 nandSize = getMMCDevice(0)->total_size;
u32 nandOffset = emuNAND == 1 ? 0 :
const u32 nandSize = getMMCDevice(0)->total_size;
u32 nandOffset = *emuNAND == 1 ? 0 :
(nandSize > 0x200000 ? 0x400000 : 0x200000);
//Check for RedNAND
@@ -28,7 +28,11 @@ void getEmunandSect(u32 *off, u32 *head, u32 emuNAND){
*head = nandOffset + nandSize;
}
//Fallback to the first emuNAND if there's no second one
else if(emuNAND == 2) getEmunandSect(off, head, 1);
else if(*emuNAND == 2){
*emuNAND = 1;
getEmunandSect(off, head, emuNAND);
}
else *emuNAND = 0;
}
}
}

View File

@@ -10,7 +10,7 @@
#define NCSD_MAGIC (0x4453434E)
void getEmunandSect(u32 *off, u32 *head, u32 emuNAND);
void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND);
u32 getSDMMC(u8 *pos, u32 size);
void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff);
u32 *getMPU(u8 *pos, u32 size);

View File

@@ -18,7 +18,7 @@
#include "../build/patches.h"
//FIRM patches version
#define PATCH_VER 2
#define PATCH_VER 3
static firmHeader *const firm = (firmHeader *)0x24000000;
static const firmSectionHeader *section;
@@ -27,13 +27,16 @@ static const char *patchedFirms[] = { "/aurei/patched_firmware_sys.bin",
"/aurei/patched_firmware_emu.bin",
"/aurei/patched_firmware_em2.bin",
"/aurei/patched_firmware90.bin" };
static u32 firmSize,
console,
mode,
emuNAND,
a9lhSetup,
selectedFirm,
usePatchedFirm;
usePatchedFirm,
emuOffset,
emuHeader;
void setupCFW(void){
@@ -48,36 +51,41 @@ void setupCFW(void){
//Attempt to read the configuration file
const char configPath[] = "aurei/config.bin";
u32 config = 0;
u32 needConfig = fileRead(&config, configPath, 3) ? 1 : 2;
u32 config = 0,
needConfig = fileRead(&config, configPath, 3) ? 1 : 2;
//Determine if A9LH is installed and the user has an updated sysNAND
u32 updatedSys;
if(a9lhBoot || (config >> 2) & 0x1){
if(a9lhBoot || (config >> 2) & 1){
if(pressed == SAFE_MODE)
error("Using Safe Mode would brick you, or remove A9LH!");
a9lhSetup = 1;
//Check setting for > 9.2 sysNAND
updatedSys = config & 0x1;
updatedSys = config & 1;
} else{
a9lhSetup = 0;
updatedSys = 0;
}
u32 tempConfig = (PATCH_VER << 17) | (a9lhSetup << 16);
/* If booting with A9LH, it's a MCU reboot and a previous configuration exists,
try to force boot options */
if(a9lhBoot && previousFirm && needConfig == 1){
//Always force a sysNAND boot when quitting AGB_FIRM
if(previousFirm == 0x7){
if(!updatedSys) mode = (config >> 12) & 0x1;
if(previousFirm == 7){
mode = updatedSys ? 1 : (config >> 12) & 1;
emuNAND = 0;
//Flag to prevent multiple boot options-forcing
tempConfig |= 1 << 15;
needConfig = 0;
//Else, force the last used boot options unless A, L or R are pressed
} else if(!(pressed & OPTION_BUTTONS)){
mode = (config >> 12) & 0x1;
emuNAND = (config >> 13) & 0x3;
/* Else, force the last used boot options unless A, L or R are pressed
or the no-forcing flag is set */
} else if(!(pressed & OPTION_BUTTONS) && !((config >> 15) & 1)){
mode = (config >> 12) & 1;
emuNAND = (config >> 13) & 3;
needConfig = 0;
}
}
@@ -94,10 +102,10 @@ void setupCFW(void){
configureCFW(configPath, patchedFirms[3]);
//If screens are inited, load splash screen
if(PDN_GPU_CNT != 0x1) loadSplash();
if(PDN_GPU_CNT != 1) loadSplash();
/* If L is pressed, boot 9.0 FIRM */
mode = ((config >> 3) & 0x1) ? ((!(pressed & BUTTON_L1R1)) ? 0 : 1) :
mode = ((config >> 3) & 1) ? ((!(pressed & BUTTON_L1R1)) ? 0 : 1) :
((pressed & BUTTON_L1) ? 0 : 1);
/* If L or R aren't pressed on a 9.0/9.2 sysNAND, or the 9.0 FIRM is selected
@@ -105,33 +113,48 @@ void setupCFW(void){
if((updatedSys && (!mode || (pressed & BUTTON_R1))) ||
(!updatedSys && mode && !(pressed & BUTTON_R1))){
//If not 9.0 FIRM and B is pressed, attempt booting the second emuNAND
emuNAND = (mode && ((!(pressed & BUTTON_B)) == ((config >> 4) & 0x1))) ? 2 : 1;
emuNAND = (mode && ((!(pressed & BUTTON_B)) == ((config >> 4) & 1))) ? 2 : 1;
} else emuNAND = 0;
u32 tempConfig = (PATCH_VER << 17) | (a9lhSetup << 16) | (emuNAND << 13) | (mode << 12);
/* If tha FIRM patches version is different or user switched to/from A9LH,
delete all patched FIRMs */
if((tempConfig & 0xFF0000) != (config & 0xFF0000))
deleteFirms(patchedFirms, sizeof(patchedFirms) / sizeof(char *));
}
u32 usePatchedFirmSet = ((config >> 1) & 1);
while(1){
/* Determine which patched FIRM we need to write or attempt to use (if any).
Patched 9.0 FIRM is only needed if "Use pre-patched FIRMs" is set */
selectedFirm = mode ? (emuNAND ? (emuNAND == 1 ? 2 : 3) : 1) :
(usePatchedFirmSet ? 4 : 0);
//If "Use pre-patched FIRMs" is set and the appropriate FIRM exists, use it
if(usePatchedFirmSet && fileExists(patchedFirms[selectedFirm - 1]))
usePatchedFirm = 1;
//Detect EmuNAND
else if(emuNAND){
getEmunandSect(&emuOffset, &emuHeader, &emuNAND);
//If none exists, force SysNAND + 9.6/10.x FIRM and re-detect patched FIRMs
if(!emuNAND){
mode = 1;
continue;
}
}
break;
}
tempConfig |= (emuNAND << 13) | (mode << 12);
//If the boot configuration is different from previously, overwrite it
if((tempConfig & 0xFFF000) != (config & 0xFFF000)){
if(tempConfig != (config & 0xFFF000)){
//Preserve user settings (first 12 bits)
tempConfig |= config & 0xFFF;
fileWrite(&tempConfig, configPath, 3);
}
}
/* Determine which patched FIRM we need to write or attempt to use (if any).
Patched 9.0 FIRM is only needed if "Use pre-patched FIRMs" is set */
selectedFirm = mode ? (emuNAND ? (emuNAND == 1 ? 2 : 3) : 1) :
(((config >> 1) & 0x1) ? 4 : 0);
//If "Use pre-patched FIRMs" is set and the appropriate FIRM exists, use it
usePatchedFirm = (((config >> 1) & 0x1) && fileExists(patchedFirms[selectedFirm - 1])) ? 1 : 0;
}
//Load FIRM into FCRAM
void loadFirm(void){
@@ -165,18 +188,7 @@ void loadFirm(void){
}
//NAND redirection
static void loadEmu(u8 *proc9Offset){
u32 emuOffset,
emuHeader = 0,
emuRead,
emuWrite;
//Look for emuNAND
getEmunandSect(&emuOffset, &emuHeader, emuNAND);
//No emuNAND detected
if(!emuHeader) error("No emuNAND has been detected");
static inline void loadEmu(u8 *proc9Offset){
//Copy emuNAND code
void *emuCodeOffset = getEmuCode(proc9Offset);
@@ -197,6 +209,9 @@ static void loadEmu(u8 *proc9Offset){
section[2].offset + (u32)section[2].address;
//Add emunand hooks
u32 emuRead,
emuWrite;
getEmuRW(arm9Section, section[2].size, &emuRead, &emuWrite);
*(u16 *)emuRead = nandRedir[0];
*((u16 *)emuRead + 1) = nandRedir[1];
@@ -268,9 +283,11 @@ void patchFirm(void){
loaderSize;
getLoader((u8 *)firm + section[0].offset, section[0].size, &loaderOffset, &loaderSize);
//Check that the injector CXI isn't larger than the original
if(injector_size <= (int)loaderSize){
memset((void *)loaderOffset, 0, loaderSize);
memcpy((void *)loaderOffset, injector, injector_size);
//Patch content size and ExeFS size to match the repaced loader's ones
*((u32 *)loaderOffset + 0x41) = loaderSize / 0x200;
*((u32 *)loaderOffset + 0x69) = loaderSize / 0x200 - 5;
}

View File

@@ -41,7 +41,7 @@ u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize){
const u8 *patternc = (const u8 *)pattern;
//Preprocessing
int table[256];
u32 table[256];
for(u32 i = 0; i < 256; ++i)
table[i] = patternSize + 1;

View File

@@ -32,7 +32,7 @@ void deinitScreens(void){
((void (*)())*arm11)();
}
if(PDN_GPU_CNT != 0x1){
if(PDN_GPU_CNT != 1){
*arm11 = (u32)ARM11;
while(*arm11);
}
@@ -82,7 +82,7 @@ void initScreens(void){
*(vu32 *)0x1040049C = 0x00000000;
// Disco register
for(vu32 i = 0; i < 256; i++)
for(u32 i = 0; i < 256; i++)
*(vu32 *)0x10400484 = 0x10101 * i;
// Bottom screen
@@ -116,7 +116,7 @@ void initScreens(void){
*(vu32 *)0x1040059C = 0x00000000;
// Disco register
for(vu32 i = 0; i < 256; i++)
for(u32 i = 0; i < 256; i++)
*(vu32 *)0x10400584 = 0x10101 * i;
// Enable backlight
@@ -143,7 +143,7 @@ void initScreens(void){
((void (*)())*arm11)();
}
if(PDN_GPU_CNT == 0x1){
if(PDN_GPU_CNT == 1){
*arm11 = (u32)ARM11;
while(*arm11);
}

View File

@@ -63,7 +63,7 @@ void configureCFW(const char *configPath, const char *firm90Path){
u32 tempConfig = 0;
fileRead(&tempConfig, configPath, 3);
for(u32 i = 0; i < optionsAmount; i++)
options[i].enabled = (tempConfig >> i) & 0x1;
options[i].enabled = (tempConfig >> i) & 1;
//Pre-select the first configuration option
u32 selectedOption = 0;
@@ -102,8 +102,7 @@ void configureCFW(const char *configPath, const char *firm90Path){
}
//If the user has been using A9LH and the "Updated SysNAND" setting changed, delete the patched 9.0 FIRM
if(((tempConfig >> 16) & 0x1) && ((tempConfig & 0x1) != options[0].enabled))
fileDelete(firm90Path);
if(((tempConfig >> 16) & 1) && ((tempConfig & 1) != options[0].enabled)) fileDelete(firm90Path);
//Preserve the last-used boot options (last 12 bits)
tempConfig &= 0xFFF000;