From e476985f689706b3b84c0761a38b4bfd40df7a10 Mon Sep 17 00:00:00 2001 From: Lillian Skinner Date: Fri, 22 Nov 2024 03:53:42 -0500 Subject: [PATCH] HWInfo recovery by offsets --- arm9/src/main.c | 1 + arm9/src/nand/filesystem.c | 1 + arm9/src/nand/hwinfo.c | 226 +++++++++++++++++++++++++++++++++++++ arm9/src/nand/hwinfo.h | 79 +++++++++++++ arm9/src/nand/nandio.c | 6 +- arm9/src/nand/nandio.h | 2 + arm9/src/nand/sysfile.c | 124 ++------------------ arm9/src/nand/sysfile.h | 11 +- 8 files changed, 330 insertions(+), 120 deletions(-) create mode 100644 arm9/src/nand/hwinfo.c create mode 100644 arm9/src/nand/hwinfo.h diff --git a/arm9/src/main.c b/arm9/src/main.c index cc0cb44..2248389 100644 --- a/arm9/src/main.c +++ b/arm9/src/main.c @@ -193,6 +193,7 @@ int main(int argc, char **argv) mountMain(); mountNitroFS(); agingMode = false; + mkdir("sd:/TwlNandTool", 0777); // swiWaitForVBlank(); diff --git a/arm9/src/nand/filesystem.c b/arm9/src/nand/filesystem.c index 4502919..30b16a8 100644 --- a/arm9/src/nand/filesystem.c +++ b/arm9/src/nand/filesystem.c @@ -185,6 +185,7 @@ bool readMbr(void) { iprintf("\n>> MBR (Master Boot Record) "); iprintf("\n--------------------------------"); + memset(sector_buf, 0, 512); if(nand_ReadSectors(0, 1, sector_buf) == false) { iprintf("\nCouldn't read NAND!\n"); success = false; diff --git a/arm9/src/nand/hwinfo.c b/arm9/src/nand/hwinfo.c new file mode 100644 index 0000000..b5b16b2 --- /dev/null +++ b/arm9/src/nand/hwinfo.c @@ -0,0 +1,226 @@ +#include +#include +#include +#include +#include +#include +#include "f_xy.h" +#include "twltool/dsi.h" +#include "nandio.h" +#include "sector0.h" +#include "crypto.h" +#include "hwinfo.h" +#include "../message.h" +#include "../main.h" +#include "../video.h" +#include "../storage.h" + +static size_t i; + +hwsFormat hwsData = {0}; + +bool clearHWInfoStruct() { + // Dummy values are JPN. This seems to be the usual default. + for (int i = 0; i < 0x80; i++) { + hwsData.HWS_SIG[i] = 0xFF; + } + hwsData.HWS_HEADER = 0x01000000; + hwsData.HWS_SIZE = 0x1C000000; + hwsData.HWS_LANG = 0x01000000; + hwsData.HWS_PAD = 0x00000000; + hwsData.HWS_REGION = 0x00; + strcpy(hwsData.HWS_SERIAL, "AAAMP1234567"); // You're a real one if you understand this serial. + hwsData.HWS_TID = 0x50414E48; + return true; +} + +bool loadHWInfoStruct() { + return true; +} + +bool recoverHWInfo(bool simple) { + success = true; + bool hwinfofound = false; + clearScreen(cSUB); + + iprintf("\n>> Recover HWInfo Secure "); + iprintf("\n--------------------------------"); + + if (false){//nandMounted == true) { + + printf("\nChecking mounted TWL_MAIN..."); + if (false){//fileExists("nand:/sys/HWINFO_S.dat")) { + printf("\nFound HWInfo."); + if (copyFile("nand:/sys/HWINFO_S.dat", "sd:/HWINFO_S_BACKUP.dat") != 0) { + success = false; + printf("\nCouldn't copy HWInfo!"); + } else { + printf("\nCopied okay."); + // Read the file to file_buf + // Some verification here + // Dump the thing to the struct + hwinfofound = true; + } + } else { + printf("\nCouldn't find HWInfo!"); + } + } + + if (simple == false) { + agingMode = true; + if (recoverHWInfoOffset(HWS_OFFSET_OTHER)) { + hwinfofound = true; + } else if (recoverHWInfoOffset(HWS_OFFSET_BOX)) { + hwinfofound = true; + } else if (recoverHWInfoOffset(HWS_OFFSET_HANDHELD)) { + hwinfofound = true; + } + agingMode = false; + } + + clearScreen(cSUB); + iprintf("\n>> Recover HWInfo Secure "); + iprintf("\n--------------------------------"); + + if (hwinfofound == true) { + iprintf("\nEverything was ok!"); + } else { + iprintf("\nFailed to find HWInfo!"); + } + exitFunction(); + return success; +} + +/* + + Let's design recoverHWInfoOffset() around edge cases- meet the TWL-CPU-X4 (prototype). + The HWInfo is made up of one "real" HWInfo at the start, then a repeating secondary HWInfo to pad out to 16kb. + + 40E34ABB 0E81922C 0B2B24E5 CD4864D4 \ + 637F0199 D385B1AA A893F65E EDADE869 | + DA66D05D 5B31A897 E4AAF339 83FDD161 | "Real" HWInfo signature + 128804B7 B7BA3C06 CD5304ED 9642181C | + A57B3B8B 695E1B37 6F7F220B 019C3932 | + 8D45C9AE 99550547 71E77ECD 0C442E98 | + E2ECB154 BB4D7305 AF75D324 7231B36A | + A53677B1 EB4D0102 C8F31A43 EED93758 / + 01000000 1C000000 01000000 00000000 <-- Region and language info + 00414141 50503241 47303538 31000000 <-- Serial number + 4A414E48 <-- Launcher TID + + 785E7A35 9A9B3C08 B9AAE1D5 02D5CD71 <-- No idea what this entire block is! + E7CFDC89 607EC36A 7A680E45 D0B30B50 + BBD36599 99731FE3 91F61DDB 8788C2C1 + 50B19D58 ... and so on for 0x36C bytes. + + 64E1D65C 2649BBAA EDF4808A 3B5830A0 \ + 2E0C2E9A 481A0487 E9DC32DB A49BDA8C | + 901B5647 2E3473CB 7317122A 2F7ECCE3 | "Real" HWInfo signature + C880187C 0EA2C230 DFFED67A D6AC7C54 | + 98676C25 4B1726FF 3EAA6EE4 39A718CA | + EA2ECF98 9B41BA5F 3E32A49F 8262DE7E | + 201585B4 E4D27B32 B4D501EE 2B098032 / + 01000000 1C000000 01000000 00000000 <-- Region and language info + 002E2E02 2E2E022E 2E022E59 02595902 <-- Serial number (completely broken in copies) + 4A414E48 <-- Launcher TID + + 785E7A35 9A9B3C08 B9AAE1D5 02D5CD71 <-- This weird block appears again! + E7CFDC89 607EC36A 7A680E45 D0B30B50 + BBD36599 99731FE3 91F61DDB 8788C2C1 + 50B19D58 ... and so on for 0x36C bytes. + + I have no idea what testing this DSi went through. I can't say if this is unique to the X4 or not. + + Anyways, the "weird block" is repeated between every HWInfo chunk. We can check for... + - The common part of the launcher TID (0x414E48) + - The first 13 bytes of the "weird block" data following the TID + + Then to quickly verify this is a HWInfo, check if the "weird block" is repeated 0x36C + size of HWInfo later. + This will work on retail as well since the "weird block" here is 0xFF padding until 16kb, so it will always repeat. + + Never let down the prototype enjoyers, even if this makes the process way more annoying! + + Oh also here's another edge case! + The factory HWInfo Secure created by PRE_IMPORT will be entirely 0xFF. + It will only exist in units that did not leave the factory. This is less common, but there are hundreds of those DSis out there. + If you find 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF then do not proceed to recoverHWInfoDeep(). + +*/ +bool recoverHWInfoOffset(int address) { + success = false; + clearScreen(cSUB); + iprintf("\n>> Recover HWInfo Secure Offset "); + iprintf("\n--------------------------------"); + + memset(sector_buf, 0, 512); + good_nandio_read(address + 0x91, 32, file_buf, true); + // 0x414E48 + printf("\n "); + for (i = 0; i < 32; i++) { + printf("%02X", file_buf[i]); + if ((i + 1) % 2 == 0) { + printf(" "); + } + if ((i - 31) % 8 == 0 && i != 32) { + printf("\n "); + } + } + if (file_buf[16] == 0x41 && file_buf[17] == 0x4E && file_buf[18] == 0x48) { + success = true; + printf("\n\nLauncher TID found!"); + good_nandio_read(address + 0x400 + 0x91, 32, file_buf2, true); + for (int i = 19; i < 32; i++) { + if (file_buf[i] != file_buf2[i]) { + success = false; + break; + } + } + if (success == true) { + iprintf("\nSecondary data matches!\nClearing buffer..."); + memset(sector_buf, 0, 0xA4); + iprintf("\nLoading HWInfo..."); + good_nandio_read(address, 0xA4, file_buf, true); + memcpy(&hwsData, file_buf, 0xA4); + success = saveHWInfoSDMC(); + + clearScreen(cSUB); + iprintf("\n>> Recover HWInfo Secure Offset "); + iprintf("\n--------------------------------"); + if (success == true) { + iprintf("\nRecovery was ok!"); + } else { + iprintf("\nFailed to back up HWInfo!"); + } + } + // // Verify + // fopen fwrite fclose + } + exitFunction(); + return success; +} + +bool saveHWInfoSDMC(void) { + success = true; + clearScreen(cSUB); + + iprintf("\n>> Save HWInfo Secure to SDMC "); + iprintf("\n--------------------------------"); + + // I need to do region checking (world/korea/china) + printf("\nRemoving old HWInfo..."); + remove(HWS_PATH_SD); + printf("\nWriting HWInfo..."); + + FILE *file = fopen(HWS_PATH_SD, "wb"); + if(file) { + fwrite(sector_buf, 1, 0xA4, file); + fclose(file); + iprintf("\nFile written."); + } else { + success = false; + iprintf("\nFile failed to open!"); + } + + exitFunction(); + return success; +} \ No newline at end of file diff --git a/arm9/src/nand/hwinfo.h b/arm9/src/nand/hwinfo.h new file mode 100644 index 0000000..f9b1699 --- /dev/null +++ b/arm9/src/nand/hwinfo.h @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include +#include +#include "f_xy.h" +#include "twltool/dsi.h" +#include "nandio.h" +#include "sector0.h" +#include "crypto.h" +#include "../message.h" +#include "../main.h" +#include "../video.h" + +// Language code +// Differences in display text between Europe and North America are determined by combining region and language code +typedef enum TWL_LANG +{ + LANG_JAPANESE = 0, // Japanese + LANG_ENGLISH = 1, // English + LANG_FRENCH = 2, // French + LANG_GERMAN = 3, // German + LANG_ITALIAN = 4, // Italian + LANG_SPANISH = 5, // Spanish + LANG_SIMP_CHINESE = 6, // Simplified Chinese + LANG_KOREAN = 7, // Korean + LANG_CODE_MAX +} TWL_LANG; + +#define LANG_BITMAP_JAPAN ( ( 0x0001 << LANG_JAPANESE ) ) +#define LANG_BITMAP_AMERICA ( ( 0x0001 << LANG_ENGLISH ) | \ + ( 0x0001 << LANG_FRENCH ) | \ + ( 0x0001 << LANG_SPANISH ) ) +#define LANG_BITMAP_EUROPE ( ( 0x0001 << LANG_ENGLISH ) | \ + ( 0x0001 << LANG_FRENCH ) | \ + ( 0x0001 << LANG_GERMAN ) | \ + ( 0x0001 << LANG_ITALIAN ) | \ + ( 0x0001 << LANG_SPANISH ) ) +#define LANG_BITMAP_AUSTRALIA ( ( 0x0001 << LANG_ENGLISH ) ) +#define LANG_BITMAP_CHINA ( ( 0x0001 << LANG_SIMP_CHINESE ) ) +#define LANG_BITMAP_KOREA ( ( 0x0001 << LANG_KOREAN ) ) + +#define HWINFO_FILE_LENGTH ( 16 * 1024 ) +#define HWN_PATH "nand:/sys/HWINFO_N.dat" +#define HWS_PATH "nand:/sys/HWINFO_S.dat" +#define HWS_PATH_SD "sd:/TwlNandTool/HWINFO_S.dat" + +#define HWS_OFFSET_BOX 0x784000 +#define HWS_OFFSET_HANDHELD 0x790000 +#define HWS_OFFSET_OTHER 0x794000 + +#define HWN_VERSION 1 // HW information format version (start no.:1) +#define HWS_VERSION 1 // HW information format version (start no.:1) + +// I think these are for HWInfo Normal? This is from the TwlSDK Secure7 private package +//#define HWS_MOVABLE_UNIQUE_ID_LEN 16 // Unique ID Transferable between bodies +//#define HWS_MOVABLE_UNIQUE_ID_MASK 0x9865f16bd375414c // Unique ID shall be XOR of this value with serial no. + +typedef struct { + u32 HWS_SIG[0x80]; + u32 HWS_HEADER; // Always 0x01000000 + u32 HWS_SIZE; // Always 0x1C000000 + u32 HWS_LANG; + u32 HWS_PAD; + u8 HWS_REGION; + char HWS_SERIAL[15]; // Last 3 bytes are zerofilled. + // USA serials are 11, and others are 12. + // Kinda neat, seems like this padding was in case they needed more serials? + u32 HWS_TID; +} hwsFormat; + +extern hwsFormat hwsData; + +bool clearHWInfoStruct(); +bool loadHWInfoStruct(); +bool recoverHWInfo(bool simple); +bool recoverHWInfoOffset(int address); +bool saveHWInfoSDMC(void); \ No newline at end of file diff --git a/arm9/src/nand/nandio.c b/arm9/src/nand/nandio.c index 580dfa7..9fcfa7e 100644 --- a/arm9/src/nand/nandio.c +++ b/arm9/src/nand/nandio.c @@ -52,10 +52,12 @@ static u32 fat_sig_fix_offset = 0; static u32 sector_buf32[SECTOR_SIZE/sizeof(u32)]; u8 *sector_buf = (u8*)sector_buf32; -static u32 sector_buf232[SECTOR_SIZE/sizeof(u32)]; -u8 *sector_buf2 = (u8*)sector_buf232; +static u32 sector_buf322[SECTOR_SIZE/sizeof(u32)]; +u8 *sector_buf2 = (u8*)sector_buf322; static u32 file_buf32[BUFFER_SIZE/sizeof(u32)]; u8 *file_buf = (u8*)file_buf32; +static u32 file_buf322[BUFFER_SIZE/sizeof(u32)]; +u8 *file_buf2 = (u8*)file_buf322; void nandio_set_fat_sig_fix(u32 offset) { diff --git a/arm9/src/nand/nandio.h b/arm9/src/nand/nandio.h index 884f3b0..1687e68 100644 --- a/arm9/src/nand/nandio.h +++ b/arm9/src/nand/nandio.h @@ -46,6 +46,7 @@ typedef struct { extern u8 *sector_buf; extern u8 *file_buf; +extern u8 *file_buf2; extern bool is3DS; extern nandData nandInfo; @@ -57,6 +58,7 @@ extern u8 consoleIDfixed[8]; extern bool good_nandio_write(int inputAddress, int inputLength, u8 *buffer, bool crypt); extern bool good_nandio_write_file(int inputAddress, int inputLength, FILE *fp, bool crypt); +extern bool good_nandio_read(int inputAddress, int inputLength, u8 *buffer, bool crypt); extern bool nandio_startup(); extern bool nandio_shutdown(); diff --git a/arm9/src/nand/sysfile.c b/arm9/src/nand/sysfile.c index 5a4794d..cad2722 100644 --- a/arm9/src/nand/sysfile.c +++ b/arm9/src/nand/sysfile.c @@ -9,6 +9,7 @@ #include "nandio.h" #include "nandfirm.h" #include "sysfile.h" +#include "hwinfo.h" #include "sector0.h" #include "crypto.h" #include "../message.h" @@ -16,7 +17,7 @@ #include "../video.h" #include "../storage.h" -static size_t i; +//static size_t i; enum { SYSFILEMENU_RECOVER, @@ -29,71 +30,6 @@ enum { SYSFILEMENU_INIT_FONT }; -/* - - I just need to plan things out: - - verifyHWInfo - - Just test input HWInfo buffer - - recoverHWInfoShallow - - Check for easy to find file (in mounted TWL_MAIN, then by common HWInfo offsets) - - recoverHWInfoDeep - - Scrap the entire TWL_MAIN byte by byte to find HWInfo (last resort) - - resignHWInfo - - Let's design this around edge cases- meet the TWL-CPU-X4 (prototype). - The HWInfo is made up of one "real" HWInfo at the start, then a repeating secondary HWInfo to pad out to 16kb. - - 40E34ABB 0E81922C 0B2B24E5 CD4864D4 \ - 637F0199 D385B1AA A893F65E EDADE869 | - DA66D05D 5B31A897 E4AAF339 83FDD161 | "Real" HWInfo signature - 128804B7 B7BA3C06 CD5304ED 9642181C | - A57B3B8B 695E1B37 6F7F220B 019C3932 | - 8D45C9AE 99550547 71E77ECD 0C442E98 | - E2ECB154 BB4D7305 AF75D324 7231B36A | - A53677B1 EB4D0102 C8F31A43 EED93758 / - 01000000 1C000000 01000000 00000000 <-- Region and language info - 00414141 50503241 47303538 31000000 <-- Serial number - 4A414E48 <-- Launcher TID - - 785E7A35 9A9B3C08 B9AAE1D5 02D5CD71 <-- No idea what this entire block is! - E7CFDC89 607EC36A 7A680E45 D0B30B50 - BBD36599 99731FE3 91F61DDB 8788C2C1 - 50B19D58 ... and so on for 0x36C bytes. - - 64E1D65C 2649BBAA EDF4808A 3B5830A0 \ - 2E0C2E9A 481A0487 E9DC32DB A49BDA8C | - 901B5647 2E3473CB 7317122A 2F7ECCE3 | "Real" HWInfo signature - C880187C 0EA2C230 DFFED67A D6AC7C54 | - 98676C25 4B1726FF 3EAA6EE4 39A718CA | - EA2ECF98 9B41BA5F 3E32A49F 8262DE7E | - 201585B4 E4D27B32 B4D501EE 2B098032 / - 01000000 1C000000 01000000 00000000 <-- Region and language info - 002E2E02 2E2E022E 2E022E59 02595902 <-- Serial number (completely broken) - 4A414E48 <-- Launcher TID - - 785E7A35 9A9B3C08 B9AAE1D5 02D5CD71 <-- This weird block appears again! - E7CFDC89 607EC36A 7A680E45 D0B30B50 - BBD36599 99731FE3 91F61DDB 8788C2C1 - 50B19D58 ... and so on for 0x36C bytes. - - I have no idea what testing this DSi went through. I can't say if this is unique to the X4 or not. - - Anyways, the "weird block" is repeated between every HWInfo chunk. We can check for... - - 0x414E48: the common part of the launcher TID - - 0x785E7A35 9A9B3C08 B9AAE1D5 02D5CD71: the "weird block" data after the TID - - Then to verify this is a HWInfo, check if the "weird block" is repeated 0x36C + size of HWInfo later. - This will work on retail as well since the "weird block" here is 0xFF padding until 16kb, so it will always repeat. - - Never let down the prototype enjoyers, even if this makes the process way more annoying! - - Oh also here's another edge case! - The factory HWInfo Secure created by PRE_IMPORT will be entirely 0xFF. - It will only exist in uninitialized units (did not leave the factory). - If you find 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF then do not proceed to recoverHWInfoDeep. - -*/ - static int _sysfileMenu(int cursor) { @@ -150,6 +86,7 @@ int sysfileMain(void) { case SYSFILEMENU_RECOVER: + recoverHWInfo(false); break; case SYSFILEMENU_RECOVER2: @@ -228,9 +165,9 @@ bool makeCertChain(void) { printf("\nRemoving old cert.sys..."); char nitro_path[100]; snprintf(nitro_path, 100, "nitro:/import/%s/cert.sys", consoleSignName); - remove("nand:/sys/cert.sys"); + remove(CERT_PATH); printf("\nWriting cert.sys..."); - if (copyFile(nitro_path, "nand:/sys/cert.sys") != 0) { + if (copyFile(nitro_path, CERT_PATH) != 0) { success = false; } else { printf("\nDone!"); @@ -257,9 +194,9 @@ bool makeFontTable(void) { printf("\nRemoving old TWLFontTable..."); char nitro_path[100]; snprintf(nitro_path, 100, "nitro:/import/common/TWLFontTable.dat"); - remove("nand:/sys/TWLFontTable.dat"); + remove(FONT_PATH); printf("\nWriting TWLFontTable (world)..."); - if (copyFile(nitro_path, "nand:/sys/TWLFontTable.dat") != 0) { + if (copyFile(nitro_path, FONT_PATH) != 0) { success = false; } else { printf("\nDone!"); @@ -271,49 +208,4 @@ bool makeFontTable(void) { exitFunction(); return success; -} - -/* -bool recoverHWInfo(void) { - success = true; - bool hwinfofound = false; - clearScreen(cSUB); - - iprintf("\n>> Recover HWInfo Secure "); - iprintf("\n--------------------------------"); - - if (nandMounted == true) { - - printf("\nChecking mounted TWL_MAIN..."); - if (fileExists("nand:/sys/HWINFO_S.dat")) { - printf("\nFound HWInfo."); - if (copyFile("nand:/sys/HWINFO_S.dat", "sd:/HWINFO_S_BACKUP.dat") != 0) { - success = false; - printf("\nCouldn't copy HWInfo!"); - } else { - printf("\nCopied okay."); - // Some verification here - hwinfofound = true; - } - } else { - printf("\nCouldn't find HWInfo!"); - } - } else { - iprintf("\nChecking common offsets..."); - - -nandioread(offset + tidOffset, 16) -if (first 3 bytes == ANH) - nandioread(offset + tidOffset + 0x3CB, 16) - if (nandioread == nandioread) - // Verify - fopen fwrite fclose - - - - } - - exitFunction(); - return success; -} -*/ \ No newline at end of file +} \ No newline at end of file diff --git a/arm9/src/nand/sysfile.h b/arm9/src/nand/sysfile.h index ab3b45c..c702bd6 100644 --- a/arm9/src/nand/sysfile.h +++ b/arm9/src/nand/sysfile.h @@ -13,12 +13,19 @@ #include "../main.h" #include "../video.h" +#define CERT_PATH "nand:/sys/cert.sys" +#define DEVKP_PATH "nand:/sys/dev.kp" +#define HWID_PATH "nand:/sys/HWID.sgn" +#define FONT_PATH "nand:/sys/TWLFontTable.dat" +#define FLOG_PATH "nand:/sys/log/product.log" +#define CFG0_PATH "nand:/shared1/TWLCFG0.dat" +#define CFG1_PATH "nand:/shared1/TWLCFG1.dat" +#define WRAP_PATH "nand:/shared2/launcher/wrap.bin" + void wait(int ticks); int sysfileMain(); -bool recoverHWInfo(); -bool recoverHWInfoDeep(); bool makeSystemFolders(); bool makeCertChain(); bool makeFontTable(); \ No newline at end of file