mirror of
https://github.com/rvtr/TDT.git
synced 2025-10-31 13:51:07 -04:00
Fix mismatched TMD app name and installed app name
This commit is contained in:
parent
6786ee2cea
commit
4e84d280f6
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@ -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
|
||||||
|
|||||||
@ -388,9 +388,9 @@ bool install(char* tadPath, bool systemTitle)
|
|||||||
result = decryptTad(fpath);
|
result = decryptTad(fpath);
|
||||||
//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
|
||||||
@ -403,19 +403,6 @@ bool install(char* tadPath, bool systemTitle)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
//patch dev titles to system titles on SysNAND.
|
|
||||||
//
|
|
||||||
//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.
|
||||||
{
|
{
|
||||||
@ -453,28 +440,17 @@ bool install(char* tadPath, 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
|
||||||
))
|
))
|
||||||
{
|
{
|
||||||
@ -498,6 +474,9 @@ bool install(char* tadPath, 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);
|
||||||
@ -685,11 +664,23 @@ bool install(char* tadPath, 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
|
||||||
{
|
{
|
||||||
|
|||||||
@ -23,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
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -62,10 +62,10 @@ static int _mainMenu(int cursor)
|
|||||||
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/rvtr/TDT\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[24;0Hrmc - 2024-2024");
|
iprintf("\x1b[23;0Hrmc - 2024-2024");
|
||||||
|
|
||||||
//menu
|
//menu
|
||||||
Menu* m = newMenu();
|
Menu* m = newMenu();
|
||||||
|
|||||||
204
arm9/src/tad.c
204
arm9/src/tad.c
@ -31,19 +31,24 @@
|
|||||||
If for whatever reason you want to make TADs, see here:
|
If for whatever reason you want to make TADs, see here:
|
||||||
https://randommeaninglesscharacters.com/dsidev/man/maketad.html
|
https://randommeaninglesscharacters.com/dsidev/man/maketad.html
|
||||||
*/
|
*/
|
||||||
const unsigned char devKey[] = {
|
const unsigned char commonKey[3][16] = {
|
||||||
0xA1, 0x60, 0x4A, 0x6A, 0x71, 0x23, 0xB5, 0x29,
|
// DEV
|
||||||
0xAE, 0x8B, 0xEC, 0x32, 0xC8, 0x16, 0xFC, 0xAA
|
{0xA1, 0x60, 0x4A, 0x6A, 0x71, 0x23, 0xB5, 0x29,
|
||||||
|
0xAE, 0x8B, 0xEC, 0x32, 0xC8, 0x16, 0xFC, 0xAA},
|
||||||
|
// PROD
|
||||||
|
{0xAF, 0x1B, 0xF5, 0x16, 0xA8, 0x07, 0xD2, 0x1A,
|
||||||
|
0xEA, 0x45, 0x98, 0x4F, 0x04, 0x74, 0x28, 0x61},
|
||||||
|
// DEBUGGER
|
||||||
|
{0xA2, 0xFD, 0xDD, 0xF2 ,0xE4, 0x23, 0x57, 0x4A,
|
||||||
|
0xE7, 0xED, 0x86, 0x57, 0xB5, 0xAB, 0x19, 0xD3}
|
||||||
};
|
};
|
||||||
const unsigned char prodKey[] = {
|
// Content IV be fine as a hardcoded string. Content IV is based off of the content index. (index # with zerobyte padding)
|
||||||
0xAF, 0x1B, 0xF5, 0x16, 0xA8, 0x07, 0xD2, 0x1A,
|
// 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
|
||||||
0xEA, 0x45, 0x98, 0x4F, 0x04, 0x74, 0x28, 0x61
|
// 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
|
||||||
};
|
};
|
||||||
const unsigned char debuggerKey[] = {
|
|
||||||
0xA2, 0xFD, 0xDD, 0xF2 ,0xE4, 0x23, 0x57, 0x4A,
|
|
||||||
0xE7, 0xED, 0x86, 0x57, 0xB5, 0xAB, 0x19, 0xD3
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t hdrSize;
|
uint32_t hdrSize;
|
||||||
uint16_t tadType;
|
uint16_t tadType;
|
||||||
@ -96,6 +101,9 @@ int decryptTad(char const* src)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// idk how to create folders recursively
|
||||||
|
mkdir("sd:/_nds", 0777);
|
||||||
|
mkdir("sd:/_nds/tadtests", 0777);
|
||||||
mkdir("sd:/_nds/tadtests/tmp", 0777);
|
mkdir("sd:/_nds/tadtests/tmp", 0777);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -131,7 +139,8 @@ int decryptTad(char const* src)
|
|||||||
|
|
||||||
Header header;
|
Header header;
|
||||||
fread(&header, sizeof(Header), 1, file);
|
fread(&header, sizeof(Header), 1, file);
|
||||||
iprintf("Parsing TAD header:\n");
|
fclose(file);
|
||||||
|
iprintf("Parsing TAD header...\n");
|
||||||
Tad tad;
|
Tad tad;
|
||||||
tad.hdrOffset = 0;
|
tad.hdrOffset = 0;
|
||||||
// All offsets in the TAD are aligned to 64 bytes.
|
// All offsets in the TAD are aligned to 64 bytes.
|
||||||
@ -142,28 +151,21 @@ int decryptTad(char const* src)
|
|||||||
tad.srlOffset = round_up(tad.tmdOffset + swap_endian_u32(header.tmdSize), 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);
|
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
|
// 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(" hdrSize: %lu\n", swap_endian_u32(header.hdrSize));
|
||||||
iprintf(" hdrOffset: %lu\n", tad.hdrOffset);
|
//iprintf(" hdrOffset: %lu\n", tad.hdrOffset);
|
||||||
// 18803 = "Is". This is the standard TAD type.
|
//iprintf(" tadVersion: %u\n", swap_endian_u16(header.tadVersion));
|
||||||
if (swap_endian_u16(header.tadType) == 18803) {
|
//iprintf(" certSize: %lu\n", swap_endian_u32(header.certSize));
|
||||||
iprintf(" tadType: 'Is'\n");
|
//iprintf(" certOffset: %lu\n", tad.certOffset);
|
||||||
} else {
|
//iprintf(" crlSize: %lu\n", swap_endian_u32(header.crlSize));
|
||||||
iprintf(" tadType: UNKNOWN\nERROR: unexpected TAD type\n");
|
//iprintf(" crlOffset: %lu\n", tad.crlOffset);
|
||||||
return 1;
|
//iprintf(" ticketSize: %lu\n", swap_endian_u32(header.ticketSize));
|
||||||
}
|
//iprintf(" ticketOffset: %lu\n", tad.ticketOffset);
|
||||||
iprintf(" tadVersion: %u\n", swap_endian_u16(header.tadVersion));
|
//iprintf(" tmdSize: %lu\n", swap_endian_u32(header.tmdSize));
|
||||||
iprintf(" certSize: %lu\n", swap_endian_u32(header.certSize));
|
//iprintf(" tmdOffset: %lu\n", tad.tmdOffset);
|
||||||
iprintf(" certOffset: %lu\n", tad.certOffset);
|
//iprintf(" srlSize: %lu\n", swap_endian_u32(header.srlSize));
|
||||||
iprintf(" crlSize: %lu\n", swap_endian_u32(header.crlSize));
|
//iprintf(" srlOffset: %lu\n", tad.srlOffset);
|
||||||
iprintf(" crlOffset: %lu\n", tad.crlOffset);
|
//iprintf(" metaSize: %lu\n", swap_endian_u32(header.metaSize));
|
||||||
iprintf(" ticketSize: %lu\n", swap_endian_u32(header.ticketSize));
|
//iprintf(" metaOffset: %lu\n", tad.metaOffset);
|
||||||
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);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copy the contents of the TAD to the SD card.
|
Copy the contents of the TAD to the SD card.
|
||||||
@ -174,57 +176,36 @@ int decryptTad(char const* src)
|
|||||||
trying to sign files for dev on a prod console.
|
trying to sign files for dev on a prod console.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
iprintf("\n--------------------------------\nCopying output files:\n");
|
iprintf("Copying output files...\n");
|
||||||
// Sorry for copy pasting, I'll make this a routine later
|
// Sorry for copy pasting, I'll make this a routine later
|
||||||
iprintf(" Copying TMD...\n");
|
//iprintf(" Copying TMD...\n");
|
||||||
FILE *tmdFile = fopen("sd:/_nds/tadtests/tmp/temp.tmd", "wb");
|
copyFilePart(src, tad.tmdOffset, swap_endian_u32(header.tmdSize), "sd:/_nds/tadtests/tmp/temp.tmd");
|
||||||
fseek(file, tad.tmdOffset, SEEK_SET);
|
|
||||||
for (int i = 0; i < swap_endian_u32(header.tmdSize); i++) {
|
|
||||||
char ch = fgetc(file);
|
|
||||||
fputc(ch, tmdFile);
|
|
||||||
}
|
|
||||||
fclose(tmdFile);
|
|
||||||
|
|
||||||
iprintf(" Copying ticket...\n");
|
//iprintf(" Copying ticket...\n");
|
||||||
FILE *ticketFile = fopen("sd:/_nds/tadtests/tmp/temp.tik", "wb");
|
copyFilePart(src, tad.ticketOffset, swap_endian_u32(header.ticketSize), "sd:/_nds/tadtests/tmp/temp.tik");
|
||||||
fseek(file, tad.ticketOffset, SEEK_SET);
|
|
||||||
for (int i = 0; i < swap_endian_u32(header.ticketSize); i++) {
|
|
||||||
char ch = fgetc(file);
|
|
||||||
fputc(ch, ticketFile);
|
|
||||||
}
|
|
||||||
fclose(ticketFile);
|
|
||||||
|
|
||||||
iprintf(" Copying SRL...\n");
|
//iprintf(" Copying SRL...\n");
|
||||||
FILE *srlFile = fopen("sd:/_nds/tadtests/tmp/temp.srl.enc", "wb");
|
copyFilePart(src, tad.srlOffset, swap_endian_u32(header.srlSize), "sd:/_nds/tadtests/tmp/temp.srl.enc");
|
||||||
fseek(file, tad.srlOffset, SEEK_SET);
|
|
||||||
for (int i = 0; i < swap_endian_u32(header.srlSize); i++) {
|
|
||||||
char ch = fgetc(file);
|
|
||||||
fputc(ch, srlFile);
|
|
||||||
}
|
|
||||||
fclose(srlFile);
|
|
||||||
fclose(file);
|
|
||||||
|
|
||||||
iprintf("\n--------------------------------\n");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Get the title key + IV from the ticket.
|
Get the title key + IV from the ticket.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
iprintf("Decrypting SRL:\n\n");
|
iprintf("Decrypting SRL...\n");
|
||||||
iprintf(" Finding title key...\n");
|
//iprintf(" Finding title key...\n");
|
||||||
FILE *ticket = fopen("sd:/_nds/tadtests/tmp/temp.tik", "rb");
|
FILE *ticket = fopen("sd:/_nds/tadtests/tmp/temp.tik", "rb");
|
||||||
unsigned char title_key_enc[16];
|
unsigned char title_key_enc[16];
|
||||||
fseek(ticket, 447, SEEK_SET);
|
fseek(ticket, 447, SEEK_SET);
|
||||||
fread(title_key_enc, 1, 16, ticket);
|
fread(title_key_enc, 1, 16, ticket);
|
||||||
iprintf(" Title key found!\n");
|
//iprintf(" Title key found!\n");
|
||||||
/* for (int i = 0; i < 16; i++) {iprintf("%02X", title_key_enc[i]);} */
|
/* for (int i = 0; i < 16; i++) {iprintf("%02X", title_key_enc[i]);} */
|
||||||
iprintf("\n");
|
iprintf("\n");
|
||||||
iprintf(" Finding title key IV...\n");
|
//iprintf(" Finding title key IV...\n");
|
||||||
unsigned char title_key_iv[16];
|
unsigned char title_key_iv[16];
|
||||||
fseek(ticket, 476, SEEK_SET);
|
fseek(ticket, 476, SEEK_SET);
|
||||||
fread(title_key_iv, 1, 8, ticket);
|
fread(title_key_iv, 1, 8, ticket);
|
||||||
memset(title_key_iv + 8, 0, 8);
|
memset(title_key_iv + 8, 0, 8);
|
||||||
iprintf(" Title key IV found!\n");
|
//iprintf(" Title key IV found!\n");
|
||||||
/* for (int i = 0; i < 16; i++) {iprintf("%02X", title_key_iv[i]);} */
|
/* for (int i = 0; i < 16; i++) {iprintf("%02X", title_key_iv[i]);} */
|
||||||
iprintf("\n");
|
iprintf("\n");
|
||||||
fclose(ticket);
|
fclose(ticket);
|
||||||
@ -244,42 +225,31 @@ int decryptTad(char const* src)
|
|||||||
https://problemkaputt.de/gbatek.htm#dscartridgeheader
|
https://problemkaputt.de/gbatek.htm#dscartridgeheader
|
||||||
https://gist.github.com/rvtr/f1069530129b7a57967e3fc4b30866b4#file-decrypt_tad-py-L84
|
https://gist.github.com/rvtr/f1069530129b7a57967e3fc4b30866b4#file-decrypt_tad-py-L84
|
||||||
*/
|
*/
|
||||||
|
//iprintf(" Decrypting title key...\n");
|
||||||
iprintf(" Decrypting title key...\n");
|
|
||||||
unsigned char title_key_dec[16];
|
unsigned char title_key_dec[16];
|
||||||
decrypt_cbc(devKey, title_key_iv, title_key_enc, sizeof(title_key_enc), sizeof(devKey), title_key_dec);
|
decrypt_cbc(commonKey[0], title_key_iv, title_key_enc, sizeof(title_key_enc), 16, title_key_dec);
|
||||||
printf(" Title key decrypted!\n");
|
//printf(" Title key decrypted!\n");
|
||||||
/* for (int i = 0; i < 16; i++) {printf("%02X", title_key_dec[i]);} */
|
/* for (int i = 0; i < 16; i++) {printf("%02X", title_key_dec[i]);} */
|
||||||
|
|
||||||
iprintf("\n Decrypting SRL chunks...\n");
|
|
||||||
unsigned char srl_buffer_enc[16];
|
unsigned char srl_buffer_enc[16];
|
||||||
unsigned char srl_buffer_dec[16];
|
unsigned char srl_buffer_dec[16];
|
||||||
// Should be fine as a hardcoded string. Content IV is based off of the content index. (index # with zerobyte padding)
|
|
||||||
// All TADs I've only ever 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
|
|
||||||
};
|
|
||||||
FILE *srlFile_enc = fopen("sd:/_nds/tadtests/tmp/temp.srl.enc", "rb");
|
FILE *srlFile_enc = fopen("sd:/_nds/tadtests/tmp/temp.srl.enc", "rb");
|
||||||
fseek(srlFile_enc, 0, SEEK_SET);
|
fseek(srlFile_enc, 0, SEEK_SET);
|
||||||
FILE *srlFile_dec = fopen("sd:/_nds/tadtests/tmp/temp.srl", "wb");
|
FILE *srlFile_dec = fopen("sd:/_nds/tadtests/tmp/temp.srl", "wb");
|
||||||
fseek(srlFile_dec, 0, SEEK_SET);
|
fseek(srlFile_dec, 0, SEEK_SET);
|
||||||
|
|
||||||
|
//iprintf("\n Decrypting SRL chunks...\n");
|
||||||
for (int i = 0; i < swap_endian_u32(header.srlSize);) {
|
for (int i = 0; i < swap_endian_u32(header.srlSize);) {
|
||||||
fread(srl_buffer_enc, 1, 16, srlFile_enc);
|
fread(srl_buffer_enc, 1, 16, srlFile_enc);
|
||||||
/* ===== silly debug ===== */
|
|
||||||
iprintf("%ld - %d / %ld\n", ftell(file), i, swap_endian_u32(header.srlSize));
|
|
||||||
/* ===== end of debug ===== */
|
|
||||||
|
|
||||||
decrypt_cbc(title_key_dec, content_iv, srl_buffer_enc, 16, 16, srl_buffer_dec);
|
decrypt_cbc(title_key_dec, content_iv, srl_buffer_enc, 16, 16, srl_buffer_dec);
|
||||||
fwrite(srl_buffer_dec, 1, 16, srlFile_dec);
|
fwrite(srl_buffer_dec, 1, 16, srlFile_dec);
|
||||||
|
printProgressBar( ((float)i / (float)swap_endian_u32(header.srlSize)) );
|
||||||
i=i+16;
|
i=i+16;
|
||||||
}
|
}
|
||||||
fclose(srlFile_enc);
|
fclose(srlFile_enc);
|
||||||
fclose(srlFile_dec);
|
fclose(srlFile_dec);
|
||||||
iprintf("\nReady to install!");
|
|
||||||
return "sd:/_nds/tadtests/tmp/temp.srl";
|
return "sd:/_nds/tadtests/tmp/temp.srl";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void printTadInfo(char const* fpath)
|
void printTadInfo(char const* fpath)
|
||||||
@ -288,16 +258,15 @@ void printTadInfo(char const* fpath)
|
|||||||
if (!fpath) return;
|
if (!fpath) return;
|
||||||
|
|
||||||
|
|
||||||
uint32_t srlCompany;
|
unsigned char srlCompany[2];
|
||||||
uint32_t srlTidLow;
|
unsigned char srlTidLow[4];
|
||||||
uint32_t srlTidHigh;
|
unsigned char srlTidHigh[4];
|
||||||
unsigned char srlVerLow = 0x00;
|
unsigned char srlVerLow[1];
|
||||||
unsigned char srlVerHigh = 0x00;
|
unsigned char srlVerHigh[1];
|
||||||
|
|
||||||
FILE *file = fopen(fpath, "rb");
|
FILE *file = fopen(fpath, "rb");
|
||||||
Header header;
|
Header header;
|
||||||
fread(&header, sizeof(Header), 1, file);
|
fread(&header, sizeof(Header), 1, file);
|
||||||
iprintf("Parsing TAD header:\n");
|
|
||||||
Tad tad;
|
Tad tad;
|
||||||
tad.hdrOffset = 0;
|
tad.hdrOffset = 0;
|
||||||
// All offsets in the TAD are aligned to 64 bytes.
|
// All offsets in the TAD are aligned to 64 bytes.
|
||||||
@ -308,45 +277,42 @@ void printTadInfo(char const* fpath)
|
|||||||
tad.srlOffset = round_up(tad.tmdOffset + swap_endian_u32(header.tmdSize), 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);
|
tad.metaOffset = round_up(tad.srlOffset + swap_endian_u32(header.srlSize), 64);
|
||||||
// Get info from TMD.
|
// Get info from TMD.
|
||||||
fseek(file, swap_endian_u32(tad.tmdOffset)+396, SEEK_SET);
|
fseek(file, tad.tmdOffset+396, SEEK_SET);
|
||||||
fread(srlTidHigh, 1, 4, file);
|
fread(srlTidHigh, 1, 4, file);
|
||||||
fread(srlTidLow, 1, 4, file);
|
fread(srlTidLow, 1, 4, file);
|
||||||
fseek(file, swap_endian_u32(tad.tmdOffset)+408, SEEK_SET);
|
fseek(file, tad.tmdOffset+408, SEEK_SET);
|
||||||
fread(srlCompany, 1, 4, file);
|
fread(srlCompany, 1, 2, file);
|
||||||
fseek(file, swap_endian_u32(tad.tmdOffset)+476, SEEK_SET);
|
fseek(file, tad.tmdOffset+476, SEEK_SET);
|
||||||
fread(srlVerHigh, 1, 1, file);
|
fread(srlVerHigh, 1, 1, file);
|
||||||
fread(srlVerLow, 1, 1, file);
|
fread(srlVerLow, 1, 1, file);
|
||||||
|
|
||||||
iprintf(" tadVersion: %u\n", swap_endian_u16(header.tadVersion));
|
// I am so sorry for this mess.
|
||||||
iprintf(" certSize: %lu\n", swap_endian_u32(header.certSize));
|
iprintf("\nSize:\n ");
|
||||||
iprintf(" certOffset: %lu\n", tad.certOffset);
|
fseek(file, 0, SEEK_END);
|
||||||
iprintf(" crlSize: %lu\n", swap_endian_u32(header.crlSize));
|
unsigned long long romSize = ftell(file);
|
||||||
iprintf(" crlOffset: %lu\n", tad.crlOffset);
|
iprintf("\x1B[42m"); //green
|
||||||
iprintf(" ticketSize: %lu\n", swap_endian_u32(header.ticketSize));
|
printBytes(romSize);
|
||||||
iprintf(" ticketOffset: %lu\n", tad.ticketOffset);
|
iprintf("\x1B[47m"); //white
|
||||||
iprintf(" tmdSize: %lu\n", swap_endian_u32(header.tmdSize));
|
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(" 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);
|
|
||||||
|
|
||||||
//proper title
|
iprintf("Game Code:\n ");
|
||||||
// TODO! Might not be possible though :((
|
iprintf("\x1B[42m"); //green
|
||||||
|
for (int i = 0; i < 4; i++) {printf("%c", srlTidLow[i]);}
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
|
|
||||||
//size in blocks, rounded up
|
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("Size: (%ld blocks)\n", ((swap_endian_u32(header.srlSize) / BYTES_PER_BLOCK) * BYTES_PER_BLOCK + BYTES_PER_BLOCK) / BYTES_PER_BLOCK);
|
|
||||||
|
|
||||||
iprintf("Game Code: %c\n", (char)srlTidLow);
|
|
||||||
|
|
||||||
iprintf("Game Version: %u.%u (NUS: v%u)\n", srlVerHigh * 256, srlVerLow, (srlVerHigh * 256) + srlVerLow);
|
|
||||||
|
|
||||||
iprintf("Company Code: %c (%lu)\n", (char)srlCompany, srlCompany);
|
|
||||||
|
|
||||||
|
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?
|
// Print program type based on TID high?
|
||||||
iprintf("Title ID: %08lx %08lx", srlTidHigh, srlTidLow);
|
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
|
//print full file path
|
||||||
iprintf("\n%s\n", fpath);
|
iprintf("\n\n%s\n", fpath);
|
||||||
|
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user