mirror of
https://github.com/rvtr/unlaunch-installer_dev.git
synced 2026-01-26 13:43:08 -05:00
Initial "safe" unlaunch installer attempt
This commit is contained in:
parent
35b8982442
commit
12cd316538
2
Makefile
2
Makefile
@ -5,7 +5,7 @@ ifeq ($(strip $(DEVKITARM)),)
|
|||||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||||
endif
|
endif
|
||||||
|
|
||||||
export TARGET := $(shell basename $(CURDIR))
|
export TARGET := NTM-unlaunch
|
||||||
export TOPDIR := $(CURDIR)
|
export TOPDIR := $(CURDIR)
|
||||||
|
|
||||||
# specify a directory which contains the nitro filesystem
|
# specify a directory which contains the nitro filesystem
|
||||||
|
|||||||
245
arm9/src/main.c
245
arm9/src/main.c
@ -4,11 +4,14 @@
|
|||||||
#include "nand/nandio.h"
|
#include "nand/nandio.h"
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
#include <errno.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
bool programEnd = false;
|
bool programEnd = false;
|
||||||
bool sdnandMode = true;
|
bool sdnandMode = true;
|
||||||
|
bool hasTitleTmdMatchingLauncher = true;
|
||||||
|
bool unlaunchInstallerFound = false;
|
||||||
bool unlaunchFound = false;
|
bool unlaunchFound = false;
|
||||||
bool unlaunchPatches = false;
|
bool unlaunchPatches = false;
|
||||||
bool devkpFound = false;
|
bool devkpFound = false;
|
||||||
@ -24,6 +27,8 @@ PrintConsole bottomScreen;
|
|||||||
enum {
|
enum {
|
||||||
MAIN_MENU_MODE,
|
MAIN_MENU_MODE,
|
||||||
MAIN_MENU_INSTALL,
|
MAIN_MENU_INSTALL,
|
||||||
|
MAIN_MENU_SAFE_UNLAUNCH_UNINSTALL,
|
||||||
|
MAIN_MENU_SAFE_UNLAUNCH_INSTALL,
|
||||||
MAIN_MENU_TITLES,
|
MAIN_MENU_TITLES,
|
||||||
MAIN_MENU_BACKUP,
|
MAIN_MENU_BACKUP,
|
||||||
MAIN_MENU_TEST,
|
MAIN_MENU_TEST,
|
||||||
@ -77,6 +82,8 @@ static int _mainMenu(int cursor)
|
|||||||
sprintf(launcherStr, "\x1B[%02omUninstall region mod", launcherDSiFound ? 047 : 037);
|
sprintf(launcherStr, "\x1B[%02omUninstall region mod", launcherDSiFound ? 047 : 037);
|
||||||
addMenuItem(m, modeStr, NULL, 0);
|
addMenuItem(m, modeStr, NULL, 0);
|
||||||
addMenuItem(m, "Install", NULL, 0);
|
addMenuItem(m, "Install", NULL, 0);
|
||||||
|
addMenuItem(m, "Safe unlaunch uninstall", NULL, 0);
|
||||||
|
addMenuItem(m, "Safe unlaunch install", NULL, 0);
|
||||||
addMenuItem(m, "Titles", NULL, 0);
|
addMenuItem(m, "Titles", NULL, 0);
|
||||||
addMenuItem(m, "Restore", NULL, 0);
|
addMenuItem(m, "Restore", NULL, 0);
|
||||||
addMenuItem(m, "Test", NULL, 0);
|
addMenuItem(m, "Test", NULL, 0);
|
||||||
@ -123,6 +130,52 @@ void fifoHandlerBattery(u32 value32, void* userdata)
|
|||||||
charging = (value32 & BIT(7)) != 0;
|
charging = (value32 & BIT(7)) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool checkIfUnlaunchHasPatches(const char* path)
|
||||||
|
{
|
||||||
|
//check if launcher patches are enabled
|
||||||
|
const static u32 tidValues[][2] = {
|
||||||
|
// {location, value}
|
||||||
|
{0xE439, 0x382E3176}, // 1.8
|
||||||
|
{0xB07C, 0x17484E41}, // 1.9
|
||||||
|
{0xB099, 0x17484E41}, // 2.0 (Normal)
|
||||||
|
{0xB079, 0x484E1841}, // 2.0 (Patched)
|
||||||
|
};
|
||||||
|
|
||||||
|
bool patched = false;
|
||||||
|
|
||||||
|
FILE *tmd = fopen(path, "rb");
|
||||||
|
if (tmd)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < sizeof(tidValues) / sizeof(tidValues[0]); i++)
|
||||||
|
{
|
||||||
|
if (fseek(tmd, tidValues[i][0], SEEK_SET) == 0)
|
||||||
|
{
|
||||||
|
u32 tidVal;
|
||||||
|
fread(&tidVal, sizeof(u32), 1, tmd);
|
||||||
|
if (tidVal == tidValues[i][1])
|
||||||
|
{
|
||||||
|
patched = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(tmd);
|
||||||
|
return patched;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool safeCreateDir(const char* path)
|
||||||
|
{
|
||||||
|
if (((mkdir(path, 0777) == 0) || errno == EEXIST))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
char errorStr[512];
|
||||||
|
sprintf(errorStr, "\x1B[31mError:\x1B[33m Failed to create directory (%s)\n", path);
|
||||||
|
|
||||||
|
messageBox(errorStr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
srand(time(0));
|
srand(time(0));
|
||||||
@ -153,7 +206,10 @@ int main(int argc, char **argv)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unlaunchInstallerFound = (access("sd:/unlaunch.dsi", F_OK) == 0);
|
||||||
|
|
||||||
//check for unlaunch and region
|
//check for unlaunch and region
|
||||||
|
char launcherTmdPath[64];
|
||||||
{
|
{
|
||||||
FILE *file = fopen("nand:/sys/HWINFO_S.dat", "rb");
|
FILE *file = fopen("nand:/sys/HWINFO_S.dat", "rb");
|
||||||
if (file)
|
if (file)
|
||||||
@ -165,37 +221,26 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
region = launcherTid & 0xFF;
|
region = launcherTid & 0xFF;
|
||||||
|
|
||||||
char path[64];
|
sprintf(launcherTmdPath, "nand:/title/00030017/%08lx/content/title.tmd", launcherTid);
|
||||||
sprintf(path, "nand:/title/00030017/%08lx/content/title.tmd", launcherTid);
|
unsigned long long tmdSize = getFileSizePath(launcherTmdPath);
|
||||||
unsigned long long tmdSize = getFileSizePath(path);
|
if(tmdSize != 520)
|
||||||
if (tmdSize > 520)
|
|
||||||
unlaunchFound = true;
|
|
||||||
|
|
||||||
//check if launcher patches are enabled
|
|
||||||
const static u32 tidValues[][2] = {
|
|
||||||
// {location, value}
|
|
||||||
{0xE439, 0x382E3176}, // 1.8
|
|
||||||
{0xB07C, 0x17484E41}, // 1.9
|
|
||||||
{0xB099, 0x17484E41}, // 2.0 (Normal)
|
|
||||||
{0xB079, 0x484E1841}, // 2.0 (Patched)
|
|
||||||
};
|
|
||||||
|
|
||||||
FILE *tmd = fopen(path, "rb");
|
|
||||||
if (tmd)
|
|
||||||
{
|
{
|
||||||
for (int i = 0; i < sizeof(tidValues) / sizeof(tidValues[0]); i++)
|
hasTitleTmdMatchingLauncher = false;
|
||||||
{
|
}
|
||||||
if (fseek(file, tidValues[i][0], SEEK_SET) == 0)
|
else if (tmdSize > 520)
|
||||||
{
|
{
|
||||||
u32 tidVal;
|
unlaunchFound = true;
|
||||||
fread(&tidVal, sizeof(u32), 1, file);
|
unlaunchPatches = checkIfUnlaunchHasPatches(launcherTmdPath);
|
||||||
if (tidVal == tidValues[i][1])
|
}
|
||||||
{
|
}
|
||||||
unlaunchPatches = true;
|
|
||||||
break;
|
if (!unlaunchFound)
|
||||||
}
|
{
|
||||||
}
|
unsigned long long tmdSize = getFileSizePath("nand:/title/00030017/484e4141/content/title.tmd");
|
||||||
}
|
if (tmdSize > 520)
|
||||||
|
{
|
||||||
|
unlaunchFound = true;
|
||||||
|
unlaunchPatches = checkIfUnlaunchHasPatches("nand:/title/00030017/484e4141/content/title.tmd");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,6 +281,146 @@ int main(int argc, char **argv)
|
|||||||
installMenu();
|
installMenu();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MAIN_MENU_SAFE_UNLAUNCH_INSTALL:
|
||||||
|
if (unlaunchInstallerFound && (choiceBox("Install unlaunch?") == YES)
|
||||||
|
&& (hasTitleTmdMatchingLauncher || (choiceBox("There doesn't seem to be a launcher.tmd\nfile matcing the hwinfo file\nKeep installing?") == YES))
|
||||||
|
&& nandio_unlock_writing())
|
||||||
|
{
|
||||||
|
|
||||||
|
FILE* unlaunchInstaller = fopen("sd:/unlaunch.dsi", "rb");
|
||||||
|
if (!unlaunchInstaller)
|
||||||
|
{
|
||||||
|
messageBox("\x1B[31mError:\x1B[33m Failed to open unlaunch installer\n");
|
||||||
|
nandio_lock_writing();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//Create HNAA launcher folder
|
||||||
|
if (!safeCreateDir("nand:/title/00030017")
|
||||||
|
|| !safeCreateDir("nand:/title/00030017/484e4141")
|
||||||
|
|| !safeCreateDir("nand:/title/00030017/484e4141/content")) {
|
||||||
|
nandio_lock_writing();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE* targetTmd = fopen("nand:/title/00030017/484e4141/content/title.tmd", "wb");
|
||||||
|
if (!targetTmd)
|
||||||
|
{
|
||||||
|
fclose(unlaunchInstaller);
|
||||||
|
messageBox("\x1B[31mError:\x1B[33m Failed to open target unlaunch tmd\n");
|
||||||
|
rmdir("nand:/title/00030017/484e4141/content");
|
||||||
|
rmdir("nand:/title/00030017/484e4141");
|
||||||
|
nandio_lock_writing();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char buffer[512] = {0};
|
||||||
|
//write the first 512 bytes as 0, as that's the size of a tmd, but it can be whatever
|
||||||
|
if (fwrite(buffer, sizeof(char), 512, targetTmd) != 512)
|
||||||
|
{
|
||||||
|
fclose(unlaunchInstaller);
|
||||||
|
fclose(targetTmd);
|
||||||
|
messageBox("\x1B[31mError:\x1B[33m Failed write to target unlaunch tmd\n");
|
||||||
|
remove("nand:/title/00030017/484e4141/content/title.tmd");
|
||||||
|
rmdir("nand:/title/00030017/484e4141/content");
|
||||||
|
rmdir("nand:/title/00030017/484e4141");
|
||||||
|
nandio_lock_writing();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t n;
|
||||||
|
bool failed = false;
|
||||||
|
|
||||||
|
while ((n = fread(buffer, sizeof(char), sizeof(buffer), unlaunchInstaller)) > 0)
|
||||||
|
{
|
||||||
|
if (fwrite(buffer, sizeof(char), n, targetTmd) != n)
|
||||||
|
{
|
||||||
|
fclose(unlaunchInstaller);
|
||||||
|
fclose(targetTmd);
|
||||||
|
messageBox("\x1B[31mError:\x1B[33m Failed write to target unlaunch tmd\n");
|
||||||
|
remove("nand:/title/00030017/484e4141/content/title.tmd");
|
||||||
|
rmdir("nand:/title/00030017/484e4141/content");
|
||||||
|
rmdir("nand:/title/00030017/484e4141");
|
||||||
|
nandio_lock_writing();
|
||||||
|
failed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (failed)
|
||||||
|
break;
|
||||||
|
if (!feof(unlaunchInstaller) || ferror(unlaunchInstaller))
|
||||||
|
{
|
||||||
|
fclose(unlaunchInstaller);
|
||||||
|
fclose(targetTmd);
|
||||||
|
messageBox("\x1B[31mError:\x1B[33m Failed read unlaunch installer\n");
|
||||||
|
remove("nand:/title/00030017/484e4141/content/title.tmd");
|
||||||
|
rmdir("nand:/title/00030017/484e4141/content");
|
||||||
|
rmdir("nand:/title/00030017/484e4141");
|
||||||
|
nandio_lock_writing();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(unlaunchInstaller);
|
||||||
|
fclose(targetTmd);
|
||||||
|
|
||||||
|
//Mark the tmd as readonly
|
||||||
|
int fatAttributes = FAT_getAttr("nand:/title/00030017/484e4141/content/title.tmd");
|
||||||
|
if(!FAT_setAttr("nand:/title/00030017/484e4141/content/title.tmd", fatAttributes | ATTR_READONLY) != 0)
|
||||||
|
{
|
||||||
|
messageBox("\x1B[31mError:\x1B[33m Failed to mark unlaunch's title.tmd as read only\n");
|
||||||
|
remove("nand:/title/00030017/484e4141/content/title.tmd");
|
||||||
|
rmdir("nand:/title/00030017/484e4141/content");
|
||||||
|
rmdir("nand:/title/00030017/484e4141");
|
||||||
|
nandio_lock_writing();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Finally patch the default launcher tmd to be invalid
|
||||||
|
|
||||||
|
//If there isn't a title.tmd matching the language region in the hwinfo
|
||||||
|
// nothing else has to be done, could be a language patch, or a dev system, the user will know what they have done
|
||||||
|
if (hasTitleTmdMatchingLauncher)
|
||||||
|
{
|
||||||
|
FILE* launcherTmd = fopen(launcherTmdPath, "rb");
|
||||||
|
if(!launcherTmd)
|
||||||
|
{
|
||||||
|
messageBox("\x1B[31mError:\x1B[33m Failed to open default launcher's title.tmd\n");
|
||||||
|
remove("nand:/title/00030017/484e4141/content/title.tmd");
|
||||||
|
rmdir("nand:/title/00030017/484e4141/content");
|
||||||
|
rmdir("nand:/title/00030017/484e4141");
|
||||||
|
nandio_lock_writing();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
FILE * f = fopen("title.tmd", "r+b");
|
||||||
|
// Patches the title.tmd's title id from HNXX to GNXX
|
||||||
|
fseek(launcherTmd, 0x190, SEEK_SET);
|
||||||
|
char c;
|
||||||
|
fread(&c, 1, 1, launcherTmd);
|
||||||
|
//if byte is not already
|
||||||
|
if(c == 0x48)
|
||||||
|
{
|
||||||
|
fseek(launcherTmd, -1, SEEK_CUR);
|
||||||
|
c = 0x47;
|
||||||
|
fwrite(&launcherTmd, 1, 1, f);
|
||||||
|
}
|
||||||
|
else if(c != 0x47)
|
||||||
|
{
|
||||||
|
messageBox("\x1B[31mError:\x1B[33m Default launcher's title.tmd was tamprered with, aborting\n");
|
||||||
|
remove("nand:/title/00030017/484e4141/content/title.tmd");
|
||||||
|
rmdir("nand:/title/00030017/484e4141/content");
|
||||||
|
rmdir("nand:/title/00030017/484e4141");
|
||||||
|
nandio_lock_writing();
|
||||||
|
fclose(launcherTmd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fclose(launcherTmd);
|
||||||
|
}
|
||||||
|
nandio_lock_writing();
|
||||||
|
unlaunchFound = true;
|
||||||
|
messageBox("Unlaunch has been installed.\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case MAIN_MENU_TITLES:
|
case MAIN_MENU_TITLES:
|
||||||
titleMenu();
|
titleMenu();
|
||||||
break;
|
break;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user