Handle nocash footer embedding into nand

Another step the unlaunch installer does but wasn't being handled yet
This commit is contained in:
Edoardo Lolletti 2024-04-27 23:34:13 +02:00
parent bfdd89218d
commit 351d4547b3
5 changed files with 170 additions and 8 deletions

View File

@ -8,6 +8,7 @@
#include "unlaunch.h"
#include "nitrofs.h"
#include "deviceList.h"
#include "nocashFooter.h"
volatile bool programEnd = false;
static volatile bool arm7Exiting = false;
@ -22,7 +23,9 @@ static const char* splashSoundBinaryPatchPath = NULL;
static const char* customBgPath = NULL;
volatile bool charging = false;
volatile u8 batteryLevel = 0;
static bool wantsUnsafeUnlaunchUninstall = false;
static bool advancedOptionsUnlocked = false;
static bool needsNocashFooterToBeWritten = false;
static NocashFooter computedNocashFooter;
PrintConsole topScreen;
PrintConsole bottomScreen;
@ -35,6 +38,7 @@ enum {
MAIN_MENU_SAFE_UNLAUNCH_INSTALL,
MAIN_MENU_EXIT,
MAIN_MENU_SAFE_UNLAUNCH_UNINSTALL_NO_BACKUP,
MAIN_MENU_WRITE_NOCASH_FOOTER_ONLY,
};
static void setupScreens()
@ -94,8 +98,11 @@ static int mainMenu(int cursor)
addMenuItem(m, soundPatchesStr, NULL, foundUnlaunchInstallerVersion == v2_0 && !disableAllPatches && splashSoundBinaryPatchPath != NULL, false);
addMenuItem(m, installUnlaunchStr, NULL, foundUnlaunchInstallerVersion != INVALID && !unlaunchFound, false);
addMenuItem(m, "Exit", NULL, true, false);
if(wantsUnsafeUnlaunchUninstall)
if(advancedOptionsUnlocked)
{
addMenuItem(m, "Uninstall unlaunch no backup", NULL, unlaunchFound, false);
addMenuItem(m, "Write nocash footer", NULL, needsNocashFooterToBeWritten, false);
}
m->cursor = cursor;
@ -116,7 +123,7 @@ static int mainMenu(int cursor)
if (keysDown() & KEY_A)
break;
if(wantsUnsafeUnlaunchUninstall)
if(advancedOptionsUnlocked)
continue;
int held = keysHeld();
@ -135,8 +142,9 @@ static int mainMenu(int cursor)
}
if (konamiCode == 5)
{
wantsUnsafeUnlaunchUninstall = true;
advancedOptionsUnlocked = true;
addMenuItem(m, "Uninstall unlaunch no backup", NULL, unlaunchFound, false);
addMenuItem(m, "Write nocash footer", NULL, needsNocashFooterToBeWritten, false);
}
}
@ -189,6 +197,25 @@ int main(int argc, char **argv)
return 0;
}
NocashFooter footer;
nandio_read_nocash_footer(&footer);
nandio_construct_nocash_footer(&computedNocashFooter);
if(!(needsNocashFooterToBeWritten = !isFooterValid(&footer)))
{
if(memcmp(&footer, &computedNocashFooter, sizeof(footer)) != 0)
{
messageBox("\x1B[31mError:\x1B[33m This console has a\n"
"nocash footer embedded in its\n"
"nand that doesn't match the one\n"
"generated.\n"
"The footer already present will\n"
"be overwritten.");
needsNocashFooterToBeWritten = true;
}
}
while (batteryLevel < 7 && !charging)
{
if (choiceBox("\x1B[47mBattery is too low!\nPlease plug in the console.\n\nContinue?") == NO)
@ -292,7 +319,18 @@ int main(int argc, char **argv)
case MAIN_MENU_SAFE_UNLAUNCH_UNINSTALL:
case MAIN_MENU_SAFE_UNLAUNCH_UNINSTALL_NO_BACKUP:
if(unlaunchFound && nandio_unlock_writing()) {
bool unsafeUninstall = wantsUnsafeUnlaunchUninstall && cursor == MAIN_MENU_SAFE_UNLAUNCH_UNINSTALL_NO_BACKUP;
bool unsafeUninstall = advancedOptionsUnlocked && cursor == MAIN_MENU_SAFE_UNLAUNCH_UNINSTALL_NO_BACKUP;
printf("Uninstalling");
if(needsNocashFooterToBeWritten)
{
printf("Writing nocash footer\n");
if(!nandio_write_nocash_footer(&computedNocashFooter))
{
messageBox("Failed to write nocash footer");
break;
}
needsNocashFooterToBeWritten = false;
}
if(uninstallUnlaunch(retailConsole, hnaaUnlaunchFound, retailLauncherTmdPath, unsafeUninstall))
{
messageBox("Uninstall successful!\n");
@ -340,6 +378,16 @@ int main(int argc, char **argv)
&& nandio_unlock_writing())
{
printf("Installing\n");
if(needsNocashFooterToBeWritten)
{
printf("Writing nocash footer\n");
if(!nandio_write_nocash_footer(&computedNocashFooter))
{
messageBox("Failed to write nocash footer");
break;
}
needsNocashFooterToBeWritten = false;
}
if(installUnlaunch(retailConsole,
retailLauncherTmdPresentAndToBePatched ? retailLauncherTmdPath : NULL,
disableAllPatches,
@ -357,6 +405,18 @@ int main(int argc, char **argv)
}
break;
case MAIN_MENU_WRITE_NOCASH_FOOTER_ONLY:
if(needsNocashFooterToBeWritten)
{
if(!nandio_write_nocash_footer(&computedNocashFooter))
{
messageBox("Failed to write nocash footer");
break;
}
needsNocashFooterToBeWritten = false;
}
break;
case MAIN_MENU_EXIT:
programEnd = true;
break;

View File

@ -10,6 +10,8 @@
#include "nandio.h"
#include "u128_math.h"
#define NOCASH_FOOTER_SECTOR 2044
/************************ Function Protoypes **********************************/
static bool nandio_startup();
@ -51,7 +53,16 @@ void nandio_set_fat_sig_fix(u32 offset)
fat_sig_fix_offset = offset;
}
static void getConsoleID(u8 *consoleID)
void getCID(u8 *CID)
{
vu8* CIDbuff = (vu8*)0x2FFD7BC;
for(int i = 0; i < 16; ++i)
{
CID[i] = CIDbuff[i];
}
}
void getConsoleID(u8 *consoleID)
{
vu8 *fifo=(vu8*)0x02300000; //shared mem address that has our computed key3 stuff
u8 key[16]; //key3 normalkey - keyslot 3 is used for DSi/twln NAND crypto
@ -89,6 +100,7 @@ static bool nandio_startup()
u8 consoleID[8];
u8 consoleIDfixed[8];
u8 CID[16];
// Get ConsoleID
getConsoleID(consoleID);
@ -97,8 +109,10 @@ static bool nandio_startup()
consoleIDfixed[i] = consoleID[7-i];
}
getCID(CID);
// iprintf("sector 0 is %s\n", is3DS ? "3DS" : "DSi");
dsi_crypt_init((const u8*)consoleIDfixed, (const u8*)0x2FFD7BC, is3DS);
dsi_crypt_init((const u8*)consoleIDfixed, (const u8*)CID, is3DS);
dsi_nand_crypt(sector_buf, sector_buf, 0, SECTOR_SIZE / AES_BLOCK_SIZE);
parse_mbr(sector_buf, is3DS);
@ -144,6 +158,49 @@ static bool read_sectors(sec_t start, sec_t len, void *buffer)
}
}
void nandio_construct_nocash_footer(NocashFooter* footer)
{
u8 CID[16];
u8 consoleID[8];
getCID(CID);
getConsoleID(consoleID);
constructNocashFooter(footer, CID, consoleID);
}
bool nandio_read_nocash_footer(NocashFooter* footer)
{
if(!nand_ReadSectors(NOCASH_FOOTER_SECTOR, 1, crypt_buf))
{
return false;
}
memcpy(footer, crypt_buf, sizeof(NocashFooter));
return true;
}
bool nandio_write_nocash_footer(NocashFooter* footer)
{
if (writingLocked)
return false;
if(!nand_ReadSectors(NOCASH_FOOTER_SECTOR, 1, crypt_buf))
{
return false;
}
memcpy(crypt_buf, footer, sizeof(NocashFooter));
if(!nand_WriteSectors(NOCASH_FOOTER_SECTOR, 1, crypt_buf))
{
return false;
}
return true;
}
// len is guaranteed <= CRYPT_BUF_LEN
static bool write_sectors(sec_t start, sec_t len, const void *buffer)
{

View File

@ -2,6 +2,7 @@
#include <stdint.h>
#include <nds/disc_io.h>
#include "../nocashFooter.h"
#ifdef __cplusplus
extern "C" {
@ -26,6 +27,10 @@ extern bool nandio_unlock_writing();
extern bool nandio_force_fat_fix();
extern void nandio_synchronize_fats();
extern void nandio_construct_nocash_footer(NocashFooter* footer);
extern bool nandio_read_nocash_footer(NocashFooter* footer);
extern bool nandio_write_nocash_footer(NocashFooter* footer);
#ifdef __cplusplus
}
#endif

17
arm9/src/nocashFooter.c Normal file
View File

@ -0,0 +1,17 @@
#include "nocashFooter.h"
#include <string.h>
static const char* nocashMagicString = "DSi eMMC CID/CPU";
bool isFooterValid(const NocashFooter* footer)
{
return memcmp(nocashMagicString, footer->footerID, sizeof(footer->footerID)) == 0;
}
void constructNocashFooter(NocashFooter* footer, const u8* CID, const u8* consoleID)
{
memset(footer, 0, sizeof(NocashFooter));
memcpy(footer->footerID, nocashMagicString, sizeof(footer->footerID));
memcpy(footer->CID, CID, sizeof(footer->CID));
memcpy(footer->consoleId, consoleID, sizeof(footer->consoleId));
}

23
arm9/src/nocashFooter.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef NOCASH_FOOTER_H
#define NOCASH_FOOTER_H
#include <nds/ndstypes.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct NocashFooter {
char footerID[16]; //DSi eMMC CID/CPU
u8 CID[16];
u8 consoleId[8];
u8 pad[0x18];
} NocashFooter;
bool isFooterValid(const NocashFooter* footer);
void constructNocashFooter(NocashFooter* footer, const u8* CID, const u8* consoleID);
#ifdef __cplusplus
}
#endif
#endif