Merge pull request #1 from rvtr/TwlArchiveData

TAD support
This commit is contained in:
Lillian Skinner 2024-04-05 01:54:20 -04:00 committed by GitHub
commit 0ebb1eda5e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 560 additions and 258 deletions

View File

@ -1,4 +1,4 @@
name: Build NAND Title Manager name: Build TAD Delivery Tool
on: on:
push: push:
@ -22,7 +22,7 @@ jobs:
uses: actions/checkout@v1 uses: actions/checkout@v1
- name: Setup environment - name: Setup environment
run: git config --global safe.directory '*' run: git config --global safe.directory '*'
- name: Build NAND Title Manager - name: Build TAD Delivery Tool
run: make run: make
- name: Publish build to GH Actions - name: Publish build to GH Actions
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2

1
.gitignore vendored
View File

@ -1,6 +1,7 @@
*.o *.o
*.d *.d
*.nds *.nds
*.tad
*.dsi *.dsi
*.elf *.elf
*.map *.map

View File

@ -13,11 +13,11 @@ export TOPDIR := $(CURDIR)
NITRO_FILES := NITRO_FILES :=
# These set the information text in the nds file # These set the information text in the nds file
GAME_TITLE := NAND Title Manager GAME_TITLE := TAD Delivery Tool
GAME_SUBTITLE1 := JeffRuLz, Pk11 GAME_SUBTITLE1 := JeffRuLz, Pk11, rmc
GAME_CODE := HTMA GAME_CODE := 4TDA
GAME_LABEL := NANDTM GAME_LABEL := TAD_DELIVERY
include $(DEVKITARM)/ds_rules include $(DEVKITARM)/ds_rules
@ -49,7 +49,7 @@ checkarm9:
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
$(TARGET).dsi : $(NITRO_FILES) arm7/$(TARGET).elf arm9/$(TARGET).elf $(TARGET).dsi : $(NITRO_FILES) arm7/$(TARGET).elf arm9/$(TARGET).elf
ndstool -c $(TARGET).dsi -7 arm7/$(TARGET).elf -9 arm9/$(TARGET).elf \ ndstool -c $(TARGET).dsi -7 arm7/$(TARGET).elf -9 arm9/$(TARGET).elf \
-u "00030004" \ -u "00030015" \
-g "$(GAME_CODE)" "00" "$(GAME_LABEL)" \ -g "$(GAME_CODE)" "00" "$(GAME_LABEL)" \
-b $(GAME_ICON) "$(GAME_TITLE);$(GAME_SUBTITLE1)" \ -b $(GAME_ICON) "$(GAME_TITLE);$(GAME_SUBTITLE1)" \
$(_ADDFILES) $(_ADDFILES)

View File

@ -1,5 +1,6 @@
# NAND Title Manager # NAND Title Manager
A basic title manager for the Nintendo DSi supporting both hiyaCFW's SDNAND and SysNAND, modified from JeffRuLz's Title Manager for HiyaCFW. A basic title manager for the Nintendo DSi supporting both hiyaCFW's SDNAND and SysNAND, modified from JeffRuLz's Title Manager for HiyaCFW.
This fork has been modified to allow installing TADs, the DSi's version of a WAD. These are typically signed and encrypted for development units. This makes them impossible to install on a retail unit. My NTM fork should let dev TADs install on retail, retail TADs install on dev, etc.
## WARNING ## WARNING
This can modify your internal system NAND! There is *always* a risk of **bricking**, albeit small, when you modify NAND. Please proceed with caution. Having Unlaunch installed is also strongly recommended as it will likely protect you if something manages to go wrong. This can modify your internal system NAND! There is *always* a risk of **bricking**, albeit small, when you modify NAND. Please proceed with caution. Having Unlaunch installed is also strongly recommended as it will likely protect you if something manages to go wrong.
@ -30,4 +31,4 @@ This can modify your internal system NAND! There is *always* a risk of **brickin
- [Martin Korth (nocash)](https://problemkaputt.de): [GBATEK](https://problemkaputt.de/gbatek.htm) - [Martin Korth (nocash)](https://problemkaputt.de): [GBATEK](https://problemkaputt.de/gbatek.htm)
- [JeffRuLz](https://github.com/JeffRuLz): [TMFH](https://github.com/JeffRuLz/TMFH) (what this is a fork of) - [JeffRuLz](https://github.com/JeffRuLz): [TMFH](https://github.com/JeffRuLz/TMFH) (what this is a fork of)
- [DesperateProgrammer](https://github.com/DesperateProgrammer): [DSi Language Patcher](https://github.com/DesperateProgrammer/DSiLanguagePacher) (working NAND writing code) - [DesperateProgrammer](https://github.com/DesperateProgrammer): [DSi Language Patcher](https://github.com/DesperateProgrammer/DSiLanguagePacher) (working NAND writing code)
- [rvtr](https://github.com/rvtr): Adding support for installing dev titles - [rvtr](https://github.com/rvtr): Adding support for installing TADs and dev titles

View File

@ -157,12 +157,7 @@ static void generateList(Menu* m)
} }
else else
{ {
if (strcasecmp(strrchr(ent->d_name, '.'), ".nds") == 0 || if (strcasecmp(strrchr(ent->d_name, '.'), ".tad") == 0)
strcasecmp(strrchr(ent->d_name, '.'), ".app") == 0 ||
strcasecmp(strrchr(ent->d_name, '.'), ".dsi") == 0 ||
strcasecmp(strrchr(ent->d_name, '.'), ".ids") == 0 ||
strcasecmp(strrchr(ent->d_name, '.'), ".srl") == 0 ||
strcasecmp(strrchr(ent->d_name, '.'), ".cia") == 0)
{ {
if (count < m->page * ITEMS_PER_PAGE) if (count < m->page * ITEMS_PER_PAGE)
count += 1; count += 1;

View File

@ -8,6 +8,7 @@
#include "nand/ticket0.h" #include "nand/ticket0.h"
#include "rom.h" #include "rom.h"
#include "storage.h" #include "storage.h"
#include "tad.h"
#include <dirent.h> #include <dirent.h>
#include <errno.h> #include <errno.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -351,7 +352,7 @@ static void _createTicket(tDSiHeader *h, char* ticketPath)
} }
} }
bool install(char* fpath, bool systemTitle) bool install(char* tadPath, bool systemTitle)
{ {
bool result = false; bool result = false;
@ -364,6 +365,7 @@ bool install(char* fpath, bool systemTitle)
//start installation //start installation
clearScreen(&bottomScreen); clearScreen(&bottomScreen);
char* fpath = openTad(tadPath);
tDSiHeader* h = getRomHeader(fpath); tDSiHeader* h = getRomHeader(fpath);
@ -372,7 +374,7 @@ bool install(char* fpath, bool systemTitle)
iprintf("\x1B[31m"); //red iprintf("\x1B[31m"); //red
iprintf("Error: "); iprintf("Error: ");
iprintf("\x1B[33m"); //yellow iprintf("\x1B[33m"); //yellow
iprintf("Could not open file.\n"); iprintf("Could not decrypt TAD.\n");
iprintf("\x1B[47m"); //white iprintf("\x1B[47m"); //white
goto error; goto error;
} }
@ -385,35 +387,25 @@ bool install(char* fpath, bool systemTitle)
//title id must be one of these //title id must be one of these
if (h->tid_high == 0x00030004 || // DSiWare if (h->tid_high == 0x00030004 || // DSiWare
h->tid_high == 0x00030005 || // "unimportant" system titles h->tid_high == 0x00030005 || // "Unimportant" system titles
h->tid_high == 0x00030011 || // SRLs in the TWL SDK h->tid_high == 0x0003000f || // Data titles
h->tid_high == 0x00030015 || // system titles h->tid_high == 0x00030015 || // System titles
h->tid_high == 0x00030017) // Launcher h->tid_high == 0x00030017) // Launcher
{} {}
else else
{ {
iprintf("\x1B[31m"); //red iprintf("\x1B[31m"); //red
iprintf("Error: "); iprintf("TID Error: ");
iprintf("\x1B[33m"); //yellow iprintf("\x1B[33m"); //yellow
iprintf("This is not a DSi rom.\n"); iprintf("Could not decrypt TAD.\n%s", fpath);
iprintf("\x1B[47m"); //white iprintf("\x1B[47m"); //white
goto error; goto error;
} }
// I am going to remove patching because it results in bad TMDs that the launcher auto deletes.
//patch dev titles to system titles on SysNAND. // Comment these back in if you really want, but know that 99% of dev apps will not install right with patching.
//
//software released through the TWL SDK usually comes as a TAD and an SRL
//things like NandFiler have a TAD with a TID of 0x00030015 and an SRL with 0x00030011
//the TAD is the installable version, so I'm assuming that 0x00030015 is what the console wants to see on NAND
//this changes the SRL TID accordingly
//not entirely sure why there's even any difference. I think the installed TAD and SRL the same as each other (minus the TID)
if(!sdnandMode && h->tid_high == 0x00030011)
{
h->tid_high = 0x00030015;
fixHeader = true;
}
//offer to patch system titles to normal DSiWare on SysNAND //offer to patch system titles to normal DSiWare on SysNAND
/*
if(!sdnandMode && h->tid_high != 0x00030004 && h->tid_high != 0x00030017) //do not allow patching home menus to be normal DSiWare! This will trigger "ERROR! - 0x0000000000000008 HWINFO_SECURE" on prototype launchers. May also cause issues on the prod versions. if(!sdnandMode && h->tid_high != 0x00030004 && h->tid_high != 0x00030017) //do not allow patching home menus to be normal DSiWare! This will trigger "ERROR! - 0x0000000000000008 HWINFO_SECURE" on prototype launchers. May also cause issues on the prod versions.
{ {
if(choiceBox("This is set as a system/dev\ntitle, would you like to patch\nit to be a normal DSiWare?\n\nThis is safer, but invalidates\nRSA checks and may not work.\n\nIf the title is homebrew this isstrongly recommended.") == YES) if(choiceBox("This is set as a system/dev\ntitle, would you like to patch\nit to be a normal DSiWare?\n\nThis is safer, but invalidates\nRSA checks and may not work.\n\nIf the title is homebrew this isstrongly recommended.") == YES)
@ -422,8 +414,10 @@ bool install(char* fpath, bool systemTitle)
fixHeader = true; fixHeader = true;
} }
} }
*/
//offer to patch home menus to be system titles on SysNAND //offer to patch home menus to be system titles on SysNAND
/*
if(!sdnandMode && h->tid_high == 0x00030017) if(!sdnandMode && h->tid_high == 0x00030017)
{ {
if(choiceBox("This title is a home menu.\nWould you like to patch it to bea system title?\n\nThis is safer and prevents your\nhome menu from being hidden.") == YES) if(choiceBox("This title is a home menu.\nWould you like to patch it to bea system title?\n\nThis is safer and prevents your\nhome menu from being hidden.") == YES)
@ -432,6 +426,7 @@ bool install(char* fpath, bool systemTitle)
fixHeader = true; fixHeader = true;
} }
} }
*/
//no system titles without Unlaunch //no system titles without Unlaunch
if (!unlaunchFound && h->tid_high != 0x00030004) if (!unlaunchFound && h->tid_high != 0x00030004)
@ -450,28 +445,17 @@ bool install(char* fpath, bool systemTitle)
u32 tidLow = (h->tid_low & 0xFFFFFF00); u32 tidLow = (h->tid_low & 0xFFFFFF00);
if (!sdnandMode && ( if (!sdnandMode && (
(h->tid_high == 0x00030005 && ( (h->tid_high == 0x00030005 && (
tidLow == 0x484e4400 || // DS Download Play
tidLow == 0x484e4500 || // PictoChat
tidLow == 0x484e4900 || // Nintendo DSi Camera tidLow == 0x484e4900 || // Nintendo DSi Camera
tidLow == 0x484e4a00 || // Nintendo Zone tidLow == 0x484e4a00 || // Nintendo Zone
tidLow == 0x484e4b00 // Nintendo DSi Sound tidLow == 0x484e4b00 // Nintendo DSi Sound
)) || (h->tid_high == 0x00030011 && (
tidLow == 0x30535500 || // Twl SystemUpdater
tidLow == 0x34544e00 || // TwlNmenu
tidLow == 0x54574c00 // TWL EVA
)) || (h->tid_high == 0x00030015 && ( )) || (h->tid_high == 0x00030015 && (
tidLow == 0x484e4200 || // System Settings tidLow == 0x484e4200 || // System Settings
tidLow == 0x484e4600 || // Nintendo DSi Shop tidLow == 0x484e4600 // Nintendo DSi Shop
tidLow == 0x34544e00 // TwlNmenu
)) || (h->tid_high == 0x00030017 && ( )) || (h->tid_high == 0x00030017 && (
tidLow == 0x484e4100 // Launcher tidLow == 0x484e4100 // Launcher
))) && ( ))) && (
(h->tid_low & 0xFF) == region || // Only blacklist console region, or the following programs that have all-region codes: (h->tid_low & 0xFF) == region || // Only blacklist console region, or the following programs that have all-region codes:
h->tid_low == 0x484e4541 || // PictoChat
h->tid_low == 0x484e4441 || // Download Play
h->tid_low == 0x30535541 || // Twl SystemUpdater (iirc one version fits in NAND)
h->tid_low == 0x34544e41 || // TwlNmenu (blocking due to potential to uninstall system titles) h->tid_low == 0x34544e41 || // TwlNmenu (blocking due to potential to uninstall system titles)
h->tid_low == 0x54574c41 || // TWL EVA
region == 0 //if the region check failed somehow, blacklist everything region == 0 //if the region check failed somehow, blacklist everything
)) ))
{ {
@ -495,6 +479,9 @@ bool install(char* fpath, bool systemTitle)
{ {
const char system[] = "\x1B[41mWARNING:\x1B[47m This is a system app,\ninstalling it is potentially\nmore risky than regular DSiWare.\n\x1B[33m"; const char system[] = "\x1B[41mWARNING:\x1B[47m This is a system app,\ninstalling it is potentially\nmore risky than regular DSiWare.\n\x1B[33m";
const char areYouSure[] = "Are you sure you want to install\n"; const char areYouSure[] = "Are you sure you want to install\n";
clearScreen(&topScreen); // Top screen breaks after this for some reason.
printTadInfo(tadPath);
clearScreen(&bottomScreen);
char* msg = (char*)malloc(strlen(system) + strlen(areYouSure) + strlen(fpath) + 2); char* msg = (char*)malloc(strlen(system) + strlen(areYouSure) + strlen(fpath) + 2);
if (sdnandMode || h->tid_high == 0x00030004) if (sdnandMode || h->tid_high == 0x00030004)
sprintf(msg, "%s%s?\n", areYouSure, fpath); sprintf(msg, "%s%s?\n", areYouSure, fpath);
@ -556,6 +543,7 @@ bool install(char* fpath, bool systemTitle)
goto error; goto error;
//system title patch //system title patch
/*
if (systemTitle) if (systemTitle)
{ {
iprintf("System Title Patch..."); iprintf("System Title Patch...");
@ -567,8 +555,10 @@ bool install(char* fpath, bool systemTitle)
fixHeader = true; fixHeader = true;
} }
*/
//check that there's space on nand //check that there's space on nand
/*
if (!_checkDsiSpace(installSize, (h->tid_high != 0x00030004))) if (!_checkDsiSpace(installSize, (h->tid_high != 0x00030004)))
{ {
if (sdnandMode && choicePrint("Install as system title?")) if (sdnandMode && choicePrint("Install as system title?"))
@ -581,6 +571,7 @@ bool install(char* fpath, bool systemTitle)
goto error; goto error;
} }
} }
*/
//check for saves //check for saves
char pubPath[PATH_MAX]; char pubPath[PATH_MAX];
@ -682,20 +673,29 @@ bool install(char* fpath, bool systemTitle)
//create 000000##.app //create 000000##.app
{ {
iprintf("Creating 000000%02x.app...", appVersion); // We must get the app name from the TMD (0x1E4-1E8).
// NTM/TMFH did it weirdly before by using a single byte at 0x1E7 called "appVersion"?
// Not sure how that even worked at all. The home menu deleted the incorrectly named apps
// and TwlNmenu showed them as being broken.
//
// This new code should always create valid titles.
FILE *tmd = fopen(tmdPath, "rb");
unsigned char appName[4];
fseek(tmd, 484, SEEK_SET);
fread(appName, 1, 4, tmd);
fclose(tmd);
iprintf("Creating %02x%02x%02x%02x.app...", appName[0], appName[1], appName[2], appName[3]);
swiWaitForVBlank(); swiWaitForVBlank();
char appPath[80]; char appPath[80];
sprintf(appPath, "%s/000000%02x.app", contentPath, appVersion); sprintf(appPath, "%s/%02x%02x%02x%02x.app", contentPath, appName[0], appName[1], appName[2], appName[3]);
//copy nds file to app //copy nds file to app
{ {
int result = 0; int result = 0;
if (!romIsCia(fpath))
result = copyFile(fpath, appPath); result = copyFile(fpath, appPath);
else
result = copyFilePart(fpath, 0x3900, fileSize, appPath);
if (result != 0) if (result != 0)
{ {
@ -867,5 +867,11 @@ complete:
if (!sdnandMode) if (!sdnandMode)
nandio_lock_writing(); nandio_lock_writing();
remove("sd:/_nds/TADDeliveryTool/tmp/temp.tmd");
remove("sd:/_nds/TADDeliveryTool/tmp/temp.tik");
remove("sd:/_nds/TADDeliveryTool/tmp/temp.srl.enc");
remove("sd:/_nds/TADDeliveryTool/tmp/temp.srl");
rmdir("sd:/_nds/TADDeliveryTool/tmp");
return result; return result;
} }

View File

@ -186,12 +186,7 @@ static void generateList(Menu* m)
} }
else else
{ {
if (strcasecmp(strrchr(ent->d_name, '.'), ".nds") == 0 || if (strcasecmp(strrchr(ent->d_name, '.'), ".tad") == 0)
strcasecmp(strrchr(ent->d_name, '.'), ".app") == 0 ||
strcasecmp(strrchr(ent->d_name, '.'), ".dsi") == 0 ||
strcasecmp(strrchr(ent->d_name, '.'), ".ids") == 0 ||
strcasecmp(strrchr(ent->d_name, '.'), ".srl") == 0 ||
strcasecmp(strrchr(ent->d_name, '.'), ".cia") == 0)
{ {
if (count < m->page * ITEMS_PER_PAGE) if (count < m->page * ITEMS_PER_PAGE)
count += 1; count += 1;
@ -237,7 +232,7 @@ static void printItem(Menu* m)
if (m->items[m->cursor].directory) if (m->items[m->cursor].directory)
clearScreen(&topScreen); clearScreen(&topScreen);
else else
printRomInfo(m->items[m->cursor].value); printTadInfo(m->items[m->cursor].value);
} }
static int subMenu() static int subMenu()

View File

@ -11,8 +11,6 @@ bool programEnd = false;
bool sdnandMode = true; bool sdnandMode = true;
bool unlaunchFound = false; bool unlaunchFound = false;
bool unlaunchPatches = false; bool unlaunchPatches = false;
bool devkpFound = false;
bool launcherDSiFound = false;
bool arm7Exiting = false; bool arm7Exiting = false;
bool charging = false; bool charging = false;
u8 batteryLevel = 0; u8 batteryLevel = 0;
@ -25,11 +23,11 @@ enum {
MAIN_MENU_MODE, MAIN_MENU_MODE,
MAIN_MENU_INSTALL, MAIN_MENU_INSTALL,
MAIN_MENU_TITLES, MAIN_MENU_TITLES,
MAIN_MENU_BACKUP, //MAIN_MENU_BACKUP,
MAIN_MENU_TEST, MAIN_MENU_TEST,
MAIN_MENU_FIX, MAIN_MENU_FIX,
MAIN_MENU_DATA_MANAGEMENT, //MAIN_MENU_DATA_MANAGEMENT,
MAIN_MENU_LANGUAGE_PATCHER, //MAIN_MENU_LANGUAGE_PATCHER,
MAIN_MENU_EXIT MAIN_MENU_EXIT
}; };
@ -57,32 +55,30 @@ static int _mainMenu(int cursor)
//top screen //top screen
clearScreen(&topScreen); clearScreen(&topScreen);
iprintf("\t\tNAND Title Manager\n"); iprintf("\t\tTAD Delivery Tool\n");
iprintf("\t\t\tmodified from\n"); iprintf("\t\t\tmodified from\n");
iprintf("\tTitle Manager for HiyaCFW\n"); iprintf("\tTitle Manager for HiyaCFW\n");
iprintf("\tand Nand Title Manager\n");
iprintf("\nversion %s\n", VERSION); iprintf("\nversion %s\n", VERSION);
iprintf("\n\n\x1B[41mWARNING:\x1B[47m This tool can write to\nyour internal NAND!\n\nThis always has a risk, albeit\nlow, of \x1B[41mbricking\x1B[47m your system\nand should be done with caution!\n"); iprintf("\n\n\x1B[41mWARNING:\x1B[47m This tool can write to\nyour internal NAND!\n\nThis always has a risk, albeit\nlow, of \x1B[41mbricking\x1B[47m your system\nand should be done with caution!\n");
iprintf("\n\t \x1B[46mhttps://dsi.cfw.guide\x1B[47m\n"); iprintf("\n\t \x1B[46mhttps://dsi.cfw.guide\x1B[47m\n");
iprintf("\n\n \x1B[46mgithub.com/Epicpkmn11/NTM/wiki\x1B[47m\n"); iprintf("\n\x1B[46mgithub.com/rvtr/TDT\x1B[47m\n");
iprintf("\x1b[22;0HJeff - 2018-2019"); iprintf("\x1b[21;0HJeff - 2018-2019");
iprintf("\x1b[23;0HPk11 - 2022-2023"); iprintf("\x1b[22;0HPk11 - 2022-2023");
iprintf("\x1b[23;0Hrmc - 2024-2024");
//menu //menu
Menu* m = newMenu(); Menu* m = newMenu();
setMenuHeader(m, "MAIN MENU"); setMenuHeader(m, "MAIN MENU");
char modeStr[32], datamanStr[32], launcherStr[32]; char modeStr[32];
sprintf(modeStr, "Mode: %s", sdnandMode ? "SDNAND" : "\x1B[41mSysNAND\x1B[47m"); sprintf(modeStr, "Mode: %s", sdnandMode ? "SDNAND" : "\x1B[41mSysNAND\x1B[47m");
sprintf(datamanStr, "\x1B[%02omEnable Data Management", devkpFound ? 037 : 047);
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, "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);
addMenuItem(m, "Fix FAT copy mismatch", NULL, 0); addMenuItem(m, "Fix FAT copy mismatch", NULL, 0);
addMenuItem(m, datamanStr, NULL, 0);
addMenuItem(m, launcherStr, NULL, 0);
addMenuItem(m, "\x1B[47mExit", NULL, 0); addMenuItem(m, "\x1B[47mExit", NULL, 0);
m->cursor = cursor; m->cursor = cursor;
@ -168,8 +164,10 @@ int main(int argc, char **argv)
char path[64]; char path[64];
sprintf(path, "nand:/title/00030017/%08lx/content/title.tmd", launcherTid); sprintf(path, "nand:/title/00030017/%08lx/content/title.tmd", launcherTid);
unsigned long long tmdSize = getFileSizePath(path); unsigned long long tmdSize = getFileSizePath(path);
if (tmdSize > 520) //if (tmdSize > 520)
// unlaunchFound = true;
unlaunchFound = true; unlaunchFound = true;
// unlaunch is always true just for testing.
//check if launcher patches are enabled //check if launcher patches are enabled
const static u32 tidValues[][2] = { const static u32 tidValues[][2] = {
@ -205,19 +203,13 @@ int main(int argc, char **argv)
} }
else if (!unlaunchPatches) else if (!unlaunchPatches)
{ {
messageBox("Unlaunch's Launcher Patches are\nnot enabled. You will need to\nprovide TMD files or reinstall.\n\n\x1B[46mhttps://dsi.cfw.guide/\x1B[47m"); messageBox("Unlaunch's Launcher Patches are\nnot enabled. You will need these\nto boot any TADs.\n\n\x1B[46mhttps://dsi.cfw.guide/\x1B[47m");
} }
} }
//check for dev.kp (Data Management visible)
devkpFound = (access("sd:/sys/dev.kp", F_OK) == 0);
//check for launcher.dsi (Language patcher)
launcherDSiFound = (access("nand:/launcher.dsi", F_OK) == 0);
messageBox("\x1B[41mWARNING:\x1B[47m This tool can write to\nyour internal NAND!\n\nThis always has a risk, albeit\nlow, of \x1B[41mbricking\x1B[47m your system\nand should be done with caution!\n\nIf you have not yet done so,\nyou should make a NAND backup."); messageBox("\x1B[41mWARNING:\x1B[47m This tool can write to\nyour internal NAND!\n\nThis always has a risk, albeit\nlow, of \x1B[41mbricking\x1B[47m your system\nand should be done with caution!\n\nIf you have not yet done so,\nyou should make a NAND backup.");
messageBox("If you are following a video\nguide, please stop.\n\nVideo guides for console moddingare often outdated or straight\nup incorrect to begin with.\n\nThe recommended guide for\nmodding your DSi is:\n\n\x1B[46mhttps://dsi.cfw.guide/\x1B[47m\n\nFor more information on using\nNTM, see the official wiki:\n\n\x1B[46mhttps://github.com/Epicpkmn11/\n\t\t\t\t\t\t\t\tNTM/wiki\x1B[47m"); messageBox("If you are following a video\nguide, please stop.\n\nVideo guides for console moddingare often outdated or straight\nup incorrect to begin with.\n\nThe recommended guide for\nmodding your DSi is:\n\n\x1B[46mhttps://dsi.cfw.guide/\x1B[47m\n\nFor more information on using\nTDT, see the official repo:\n\n\x1B[46mhttps://github.com/rvtr/TDT\x1B[47m");
//main menu //main menu
int cursor = 0; int cursor = 0;
@ -229,7 +221,6 @@ int main(int argc, char **argv)
{ {
case MAIN_MENU_MODE: case MAIN_MENU_MODE:
sdnandMode = !sdnandMode; sdnandMode = !sdnandMode;
devkpFound = (access(sdnandMode ? "sd:/sys/dev.kp" : "nand:/sys/dev.kp", F_OK) == 0);
break; break;
case MAIN_MENU_INSTALL: case MAIN_MENU_INSTALL:
@ -239,11 +230,11 @@ int main(int argc, char **argv)
case MAIN_MENU_TITLES: case MAIN_MENU_TITLES:
titleMenu(); titleMenu();
break; break;
/*
case MAIN_MENU_BACKUP: case MAIN_MENU_BACKUP:
backupMenu(); backupMenu();
break; break;
*/
case MAIN_MENU_TEST: case MAIN_MENU_TEST:
testMenu(); testMenu();
break; break;
@ -257,35 +248,6 @@ int main(int argc, char **argv)
} }
break; break;
case MAIN_MENU_DATA_MANAGEMENT:
if (!devkpFound && (choiceBox("Make Data Management visible\nin System Settings?") == YES) && (sdnandMode || nandio_unlock_writing()))
{
//ensure sys folder exists
if(access(sdnandMode ? "sd:/sys" : "nand:/sys", F_OK) != 0)
mkdir(sdnandMode ? "sd:/sys" : "nand:/sys", 0777);
//create empty file
FILE *file = fopen(sdnandMode ? "sd:/sys/dev.kp" : "nand:/sys/dev.kp", "wb");
fclose(file);
if(!sdnandMode)
nandio_lock_writing();
devkpFound = (access(sdnandMode ? "sd:/sys/dev.kp" : "nand:/sys/dev.kp", F_OK) == 0);
messageBox("Data Management is now visible\nin System Settings.\n");
}
break;
case MAIN_MENU_LANGUAGE_PATCHER:
if (launcherDSiFound && (choiceBox("Uninstall the language patched\nDSi Menu? (launcher.dsi)") == YES) && nandio_unlock_writing())
{
//delete launcher.dsi
remove("nand:/launcher.dsi");
nandio_lock_writing();
launcherDSiFound = (access("nand:/launcher.dsi", F_OK) == 0);
messageBox("The language patched DSi Menu\nhas been removed.\n");
}
break;
case MAIN_MENU_EXIT: case MAIN_MENU_EXIT:
programEnd = true; programEnd = true;
break; break;

View File

@ -1,6 +1,7 @@
#include "rom.h" #include "rom.h"
#include "main.h" #include "main.h"
#include "storage.h" #include "storage.h"
#include "tad.h"
#include <dirent.h> #include <dirent.h>
#include <nds.h> #include <nds.h>
#include <malloc.h> #include <malloc.h>
@ -19,11 +20,7 @@ tDSiHeader* getRomHeader(char const* fpath)
if (h) if (h)
{ {
if (romIsCia(fpath))
fseek(f, 0x3900, SEEK_SET);
else
fseek(f, 0, SEEK_SET); fseek(f, 0, SEEK_SET);
fread(h, sizeof(tDSiHeader), 1, f); fread(h, sizeof(tDSiHeader), 1, f);
} }
@ -50,11 +47,7 @@ tNDSBanner* getRomBanner(char const* fpath)
if (b) if (b)
{ {
if (romIsCia(fpath))
fseek(f, 0x3900, SEEK_SET);
else
fseek(f, 0, SEEK_SET); fseek(f, 0, SEEK_SET);
fseek(f, h->ndshdr.bannerOffset, SEEK_CUR); fseek(f, h->ndshdr.bannerOffset, SEEK_CUR);
fread(b, sizeof(tNDSBanner), 1, f); fread(b, sizeof(tNDSBanner), 1, f);
} }
@ -146,12 +139,6 @@ void printRomInfo(char const* fpath)
tDSiHeader* h = getRomHeader(fpath); tDSiHeader* h = getRomHeader(fpath);
tNDSBanner* b = getRomBanner(fpath); tNDSBanner* b = getRomBanner(fpath);
if (!isDsiHeader(h))
{
iprintf("Could not read dsi header.\n");
}
else
{
if (!b) if (!b)
{ {
iprintf("Could not read banner.\n"); iprintf("Could not read banner.\n");
@ -246,7 +233,6 @@ void printRomInfo(char const* fpath)
if (access(temp, F_OK) == 0) if (access(temp, F_OK) == 0)
printf("\t\x1B[%om%s\n\x1B[47m", (getFileSizePath(temp) == 0x4000) ? 047 : 041, strrchr(temp, '/') + 1); printf("\t\x1B[%om%s\n\x1B[47m", (getFileSizePath(temp) == 0x4000) ? 047 : 041, strrchr(temp, '/') + 1);
} }
}
free(b); free(b);
free(h); free(h);
@ -260,37 +246,11 @@ unsigned long long getRomSize(char const* fpath)
FILE* f = fopen(fpath, "rb"); FILE* f = fopen(fpath, "rb");
if (f) if (f)
{
//cia
if (romIsCia(fpath))
{
unsigned char bytes[4] = { 0 };
fseek(f, 0x38D0, SEEK_SET);
fread(bytes, 4, 1, f);
size = (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3];
}
else
{ {
fseek(f, 0, SEEK_END); fseek(f, 0, SEEK_END);
size = ftell(f); size = ftell(f);
} }
}
fclose(f); fclose(f);
return size; return size;
} }
bool romIsCia(char const* fpath)
{
if (!fpath) return false;
return (strstr(fpath, ".cia") != NULL || strstr(fpath, ".CIA") != NULL);
}
bool isDsiHeader(tDSiHeader* h)
{
if (!h) return false;
u16 crc16 = swiCRC16(0xFFFF, h, 0x15E);
return h->ndshdr.headerCRC16 == crc16;
}

View File

@ -17,7 +17,6 @@ void printRomInfo(char const* fpath);
unsigned long long getRomSize(char const* fpath); unsigned long long getRomSize(char const* fpath);
bool romIsCia(char const* fpath); bool romIsSrl(char const* fpath);
bool isDsiHeader(tDSiHeader* h);
#endif #endif

View File

@ -440,6 +440,7 @@ int getMenuSlotsFree()
const char* dirs[] = { const char* dirs[] = {
"00030004", "00030004",
"00030005", "00030005",
"0003000f",
"00030015", "00030015",
"00030017" "00030017"
}; };

372
arm9/src/tad.c Normal file
View File

@ -0,0 +1,372 @@
/*
A lot of this is heavily "inspired" by remaketad.pl in TwlIPL (/tools/bin/remaketad.pl)
That script was made to decrypt + unpack a dev TAD and and rebuild for SystemUpdaters.
https://github.com/rvtr/TwlIPL/blob/trunk/tools/bin/remaketad.pl
*/
#include "tad.h"
#include "storage.h"
#include "rom.h"
#include "main.h"
#include "nand/twltool/dsi.h"
#include <nds/ndstypes.h>
#include <malloc.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <dirent.h>
/*
The common keys for decrypting TADs.
DEV: Used in most TADs. Anything created with the standard maketad will be dev.
PROD: Used in some TADs for factory tools like PRE_IMPORT and IMPORT. Really uncommon. I only know of 24 prod TADs
to have ever been found, and 19 of those haven't ever been released (pleeeeeaaaaase release IMPORT soon).
All retail signed and can't be created with any leaked maketads.
DEBUGGER: Used in TwlSystemUpdater TADs. Created with maketad_updater.
If for whatever reason you want to make TADs, see here:
https://randommeaninglesscharacters.com/dsidev/man/maketad.html
*/
const unsigned char devKey[] = {
0xA1, 0x60, 0x4A, 0x6A, 0x71, 0x23, 0xB5, 0x29,
0xAE, 0x8B, 0xEC, 0x32, 0xC8, 0x16, 0xFC, 0xAA
};
const unsigned char prodKey[] = {
0xAF, 0x1B, 0xF5, 0x16, 0xA8, 0x07, 0xD2, 0x1A,
0xEA, 0x45, 0x98, 0x4F, 0x04, 0x74, 0x28, 0x61
};
const unsigned char debuggerKey[] = {
0xA2, 0xFD, 0xDD, 0xF2 ,0xE4, 0x23, 0x57, 0x4A,
0xE7, 0xED, 0x86, 0x57, 0xB5, 0xAB, 0x19, 0xD3
};
// Content IV be fine as a hardcoded string. Content IV is based off of the content index. (index # with zerobyte padding)
// All TADs I've seen only ever had a single content. It might be a good idea to add something down the line in case a
// weird TAD pops up, but until then this should do.
unsigned char content_iv[] = {
0x00, 0x00, 0x00, 0x00 ,0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
typedef struct {
uint32_t hdrSize;
uint16_t tadType;
uint16_t tadVersion;
uint32_t certSize;
uint32_t crlSize;
uint32_t ticketSize;
uint32_t tmdSize;
uint32_t srlSize;
uint32_t metaSize;
} Header;
typedef struct {
uint32_t hdrOffset;
uint32_t certOffset;
uint32_t crlOffset;
uint32_t ticketOffset;
uint32_t tmdOffset;
uint32_t srlOffset;
uint32_t metaOffset;
} Tad;
unsigned char srlCompany[2];
unsigned char srlTidLow[4];
unsigned char srlTidHigh[4];
unsigned char srlVerLow[1];
unsigned char srlVerHigh[1];
uint32_t swap_endian_u32(uint32_t x) {
return (x >> 24) | ((x >> 8) & 0xff00) | ((x << 8) & 0xff0000) | (x << 24);
}
uint16_t swap_endian_u16(uint16_t x) {
return (x >> 8) | (x << 8);
}
uint32_t round_up( const u32 v, const u32 align ) {
u32 r = ((v + align - 1) / align) * align;
return r;
}
void decrypt_cbc(const unsigned char* key, const unsigned char* iv, const unsigned char* encryptedData, size_t dataSize, size_t keySize, unsigned char* decryptedData) {
aes_context ctx;
aes_setkey_dec(&ctx, key, 128);
aes_crypt_cbc(&ctx, AES_DECRYPT, dataSize, iv, encryptedData, decryptedData);
}
int openTad(char const* src) {
if (!src) return 1;
FILE *file = fopen(src, "rb");
if (file == NULL) {
printf("ERROR: fopen()");
return 1;
}
// idk how to create folders recursively
mkdir("sd:/_nds", 0777);
mkdir("sd:/_nds/TADDeliveryTool", 0777);
mkdir("sd:/_nds/TADDeliveryTool/tmp", 0777);
/*
Please excuse my terrible copy paste coding. I do not know C and I'm translating from other languages
that I don't know (python, perl).
Anyways, the code below is determining the file offsets and sizes within the TAD.
This is done using the 32 byte header.
Example header from "KART_K04.tad"
00000020 49730000 00000E80 00000000
000002A4 00000208 000DFC00 00000000
Breaking it down...
Hex | Dec | Meaning
-----------+--------+------------
0x00000020 | 32 | Header size
0x4973 | Is | TAD type
0x0000 | 0 | TAD version
0x00000E80 | 3712 | Cert size
0x00000000 | 0 | Crl size
0x000002A4 | 676 | Ticket size
0x00000208 | 520 | TMD size
0x000DFC00 | 916480 | SRL size
0x00000000 | 0 | Meta size
Gee, looks awfully like a WAD header, doesn't it? Turns out TADs are just renamed WADs. Not even changed one bit.
There's literally a commit replacing every instance of WAD with TAD in TwlIPL...
https://github.com/rvtr/TwlIPL/commit/baca65d35d5d62d815c88e6374b895d5b0755277
*/
Header header;
fread(&header, sizeof(Header), 1, file);
iprintf("Parsing TAD header...\n");
Tad tad;
tad.hdrOffset = 0;
// All offsets in the TAD are aligned to 64 bytes.
tad.certOffset = round_up(swap_endian_u32(header.hdrSize), 64);
tad.crlOffset = round_up(tad.certOffset + swap_endian_u32(header.certSize), 64);
tad.ticketOffset = round_up(tad.crlOffset + swap_endian_u32(header.crlSize), 64);
tad.tmdOffset = round_up(tad.ticketOffset + swap_endian_u32(header.ticketSize), 64);
tad.srlOffset = round_up(tad.tmdOffset + swap_endian_u32(header.tmdSize), 64);
tad.metaOffset = round_up(tad.srlOffset + swap_endian_u32(header.srlSize), 64);
// TODO: Make sure offset calculation and alignment is correct by comparing that to total size
//iprintf(" hdrSize: %lu\n", swap_endian_u32(header.hdrSize));
//iprintf(" hdrOffset: %lu\n", tad.hdrOffset);
// Commenting this block out makes the TAD decrypt improperly. Truly a programming moment.
// 18803 = "Is". This is the standard TAD type.
if (swap_endian_u16(header.tadType) == 18803) {
//iprintf(" tadType: 'Is'\n");
} else {
iprintf(" tadType: UNKNOWN\nERROR: unexpected TAD type\n");
return 1;
}
//iprintf(" tadVersion: %u\n", swap_endian_u16(header.tadVersion));
//iprintf(" certSize: %lu\n", swap_endian_u32(header.certSize));
//iprintf(" certOffset: %lu\n", tad.certOffset);
//iprintf(" crlSize: %lu\n", swap_endian_u32(header.crlSize));
//iprintf(" crlOffset: %lu\n", tad.crlOffset);
//iprintf(" ticketSize: %lu\n", swap_endian_u32(header.ticketSize));
//iprintf(" ticketOffset: %lu\n", tad.ticketOffset);
//iprintf(" tmdSize: %lu\n", swap_endian_u32(header.tmdSize));
//iprintf(" tmdOffset: %lu\n", tad.tmdOffset);
//iprintf(" srlSize: %lu\n", swap_endian_u32(header.srlSize));
//iprintf(" srlOffset: %lu\n", tad.srlOffset);
//iprintf(" metaSize: %lu\n", swap_endian_u32(header.metaSize));
//iprintf(" metaOffset: %lu\n", tad.metaOffset);
fseek(file, tad.tmdOffset+396, SEEK_SET);
fread(srlTidHigh, 1, 4, file);
fread(srlTidLow, 1, 4, file);
fclose(file);
/*
Copy the contents of the TAD to the SD card.
For installing we only need the TMD, ticket, and SRL (obviously lol).
We can skip the cert since that already exists in NAND, and using the TAD's cert could introduce problems like
trying to sign files for dev on a prod console.
*/
iprintf("Copying output files...\n");
// Sorry for copy pasting, I'll make this a routine later
iprintf(" Copying TMD...\n");
copyFilePart(src, tad.tmdOffset, swap_endian_u32(header.tmdSize), "sd:/_nds/TADDeliveryTool/tmp/temp.tmd");
iprintf(" Copying ticket...\n");
copyFilePart(src, tad.ticketOffset, swap_endian_u32(header.ticketSize), "sd:/_nds/TADDeliveryTool/tmp/temp.tik");
iprintf(" Copying SRL...\n");
copyFilePart(src, tad.srlOffset, swap_endian_u32(header.srlSize), "sd:/_nds/TADDeliveryTool/tmp/temp.srl.enc");
/*
Get the title key + IV from the ticket.
*/
iprintf("Decrypting SRL...\n");
//iprintf(" Finding title key...\n");
FILE *ticket = fopen("sd:/_nds/TADDeliveryTool/tmp/temp.tik", "rb");
unsigned char title_key_enc[16];
fseek(ticket, 447, SEEK_SET);
fread(title_key_enc, 1, 16, ticket);
//iprintf(" Title key found!\n");
/* for (int i = 0; i < 16; i++) {iprintf("%02X", title_key_enc[i]);} */
iprintf("\n");
//iprintf(" Finding title key IV...\n");
unsigned char title_key_iv[16];
fseek(ticket, 476, SEEK_SET);
fread(title_key_iv, 1, 8, ticket);
memset(title_key_iv + 8, 0, 8);
//iprintf(" Title key IV found!\n");
/* for (int i = 0; i < 16; i++) {iprintf("%02X", title_key_iv[i]);} */
iprintf("\n");
fclose(ticket);
/*
This is SRL decryption (AES-CBC).
Common key + title key IV to decrypt title key, title key + content IV to decrypt content
We have to try each possible common key until we find one that works. I don't know a better way to do this
(nothing in the TAD would specify the key needed) so we'll try keys in the order of which ones are more common:
DEV --> DEBUGGER --> PROD
We check for only zerobytes at 0x15-1B to see if the SRL is decrypted properly. (should always be zerobytes)
https://problemkaputt.de/gbatek.htm#dscartridgeheader
https://gist.github.com/rvtr/f1069530129b7a57967e3fc4b30866b4#file-decrypt_tad-py-L84
*/
bool keyFail;
iprintf("Trying dev common key...\n");
keyFail = decryptTad(devKey, title_key_iv, title_key_enc, content_iv, swap_endian_u32(header.srlSize), srlTidLow);
if (keyFail == TRUE) {
remove("sd:/_nds/TADDeliveryTool/tmp/temp.srl");
iprintf("Key fail!\n\nTrying debugger common key...\n");
keyFail = decryptTad(debuggerKey, title_key_iv, title_key_enc, content_iv, swap_endian_u32(header.srlSize), srlTidLow);
}
if (keyFail == TRUE) {
remove("sd:/_nds/TADDeliveryTool/tmp/temp.srl");
iprintf("Key fail!\n\nTrying prod common key...\n");
keyFail = decryptTad(prodKey, title_key_iv, title_key_enc, content_iv, swap_endian_u32(header.srlSize), srlTidLow);
}
if (keyFail == TRUE) {
remove("sd:/_nds/TADDeliveryTool/tmp/temp.srl");
iprintf("All keys failed!\n");
return "ERROR";
}
return "sd:/_nds/TADDeliveryTool/tmp/temp.srl";
}
bool decryptTad(unsigned char* commonKey,
unsigned char* title_key_iv,
unsigned char* title_key_enc,
unsigned char* content_iv,
int srlSize,
unsigned char* srlTidLow) {
unsigned char title_key_dec[16];
unsigned char title_key_iv_bak[16];
unsigned char content_iv_bak[16];
unsigned char srl_buffer_enc[16];
unsigned char srl_buffer_dec[16];
// Backup IVs because PolarSSL will overwrite it
memcpy( title_key_iv_bak, title_key_iv, 16 );
memcpy( content_iv_bak, content_iv, 16 );
FILE *srlFile_enc = fopen("sd:/_nds/TADDeliveryTool/tmp/temp.srl.enc", "rb");
fseek(srlFile_enc, 0, SEEK_SET);
FILE *srlFile_dec = fopen("sd:/_nds/TADDeliveryTool/tmp/temp.srl", "wb");
fseek(srlFile_dec, 0, SEEK_SET);
iprintf(" Decrypting SRL in chunks..\n");
decrypt_cbc(commonKey, title_key_iv, title_key_enc, 16, 16, title_key_dec);
int i=0;
bool keyFail = FALSE;
while (i < srlSize && keyFail == FALSE) {
fread(srl_buffer_enc, 1, 16, srlFile_enc);
decrypt_cbc(title_key_dec, content_iv, srl_buffer_enc, 16, 16, srl_buffer_dec);
fwrite(srl_buffer_dec, 1, 16, srlFile_dec);
printProgressBar( ((float)i / (float)srlSize) );
if (i == 560) {
if (srl_buffer_dec[3] != srlTidLow[0] ||
srl_buffer_dec[2] != srlTidLow[1] ||
srl_buffer_dec[1] != srlTidLow[2] ||
srl_buffer_dec[0] != srlTidLow[3] ) {
keyFail = TRUE;
}
}
i=i+16;
}
fclose(srlFile_dec);
fclose(srlFile_enc);
// Restore IVs
memcpy( title_key_iv, title_key_iv_bak, 16 );
memcpy( content_iv, content_iv_bak, 16 );
return keyFail;
}
void printTadInfo(char const* fpath)
{
clearScreen(&topScreen);
if (!fpath) return;
FILE *file = fopen(fpath, "rb");
Header header;
fread(&header, sizeof(Header), 1, file);
Tad tad;
tad.hdrOffset = 0;
// All offsets in the TAD are aligned to 64 bytes.
tad.certOffset = round_up(swap_endian_u32(header.hdrSize), 64);
tad.crlOffset = round_up(tad.certOffset + swap_endian_u32(header.certSize), 64);
tad.ticketOffset = round_up(tad.crlOffset + swap_endian_u32(header.crlSize), 64);
tad.tmdOffset = round_up(tad.ticketOffset + swap_endian_u32(header.ticketSize), 64);
tad.srlOffset = round_up(tad.tmdOffset + swap_endian_u32(header.tmdSize), 64);
tad.metaOffset = round_up(tad.srlOffset + swap_endian_u32(header.srlSize), 64);
// Get info from TMD.
fseek(file, tad.tmdOffset+396, SEEK_SET);
fread(srlTidHigh, 1, 4, file);
fread(srlTidLow, 1, 4, file);
fseek(file, tad.tmdOffset+408, SEEK_SET);
fread(srlCompany, 1, 2, file);
fseek(file, tad.tmdOffset+476, SEEK_SET);
fread(srlVerHigh, 1, 1, file);
fread(srlVerLow, 1, 1, file);
// I am so sorry for this mess.
iprintf("\nSize:\n ");
fseek(file, 0, SEEK_END);
unsigned long long romSize = ftell(file);
iprintf("\x1B[42m"); //green
printBytes(romSize);
iprintf("\x1B[47m"); //white
iprintf(" (\x1B[42m%ld blocks\x1B[47m)\n", ((swap_endian_u32(header.srlSize) / BYTES_PER_BLOCK) * BYTES_PER_BLOCK + BYTES_PER_BLOCK) / BYTES_PER_BLOCK);
iprintf("Game Code:\n ");
iprintf("\x1B[42m"); //green
for (int i = 0; i < 4; i++) {printf("%c", srlTidLow[i]);}
iprintf("\x1B[47m"); //white
iprintf("\nGame Version:\n \x1B[42m%d.%d\x1B[47m (NUS: \x1B[42mv%d\x1B[47m)\n", (int)srlVerHigh[0] * 256, (int)srlVerLow[0], ((int)srlVerHigh[0] * 256) + (int)srlVerLow[0]);
iprintf("Company Code:\n \x1B[42m%c%c\x1B[47m(\x1B[42m%02x%02x\x1B[47m)\n", srlCompany[0], srlCompany[1], srlCompany[0], srlCompany[1]);
// Print program type based on TID high?
iprintf("Title ID: \n ");
iprintf("\x1B[42m"); //green
for (int i = 0; i < 4; i++) {printf("%02x", srlTidHigh[i]);}
iprintf(" ");
for (int i = 0; i < 4; i++) {printf("%02x", srlTidLow[i]);}
iprintf("\x1B[47m"); //white
//print full file path
iprintf("\n\n%s\n", fpath);
fclose(file);
}

15
arm9/src/tad.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef TAD_H
#define TAD_H
#include <nds/ndstypes.h>
#include <nds/memory.h>
int openTad(char const* src);
bool decryptTad(unsigned char* commonKey,
unsigned char* title_key_iv,
unsigned char* title_key_enc,
unsigned char* content_iv,
int srlSize,
unsigned char* srlTidLow);
#endif

View File

@ -92,6 +92,7 @@ static void generateList(Menu* m)
const char* dirs[] = { const char* dirs[] = {
"00030004", "00030004",
"00030005", "00030005",
//"0003000f",
"00030015", "00030015",
"00030017" "00030017"
}; };
@ -100,17 +101,12 @@ static void generateList(Menu* m)
{ // 00030004 { // 00030004
NULL //nothing blacklisted NULL //nothing blacklisted
}, },
{ // 00030005 { // 0003000f
"484e44", // DS Download Play "484e43", // WiFi Firmware
"484e45", // PictoChat
"484e49", // Nintendo DSi Camera
"484e4a", // Nintendo Zone
"484e4b", // Nintendo DSi Sound
NULL NULL
}, },
{ // 00030015 { // 00030015
"484e42", // System Settings "484e42", // System Settings
"484e46", // Nintendo DSi Shop
NULL NULL
}, },
{ // 00030017 { // 00030017
@ -159,8 +155,7 @@ static void generateList(Menu* m)
blacklisted = true; blacklisted = true;
// also blacklist specific all-region titles // also blacklist specific all-region titles
if ((strcmp("484e4441", ent->d_name) == 0) || // Download Play if ((strcmp("484e4341", ent->d_name) == 0) || // WiFi Firmware
(strcmp("484e4541", ent->d_name) == 0) || // PictoChat
(strcmp("34544e41", ent->d_name) == 0)) // TwlNmenu (strcmp("34544e41", ent->d_name) == 0)) // TwlNmenu
blacklisted = true; blacklisted = true;
} }

BIN
icon.bmp

Binary file not shown.

Before

Width:  |  Height:  |  Size: 586 B

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
icon.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB