diff --git a/arm9/source/game/ncch.c b/arm9/source/game/ncch.c index 9348a4c..ff8054a 100644 --- a/arm9/source/game/ncch.c +++ b/arm9/source/game/ncch.c @@ -1,10 +1,7 @@ #include "ncch.h" -#include "support.h" -#include "disadiff.h" #include "keydb.h" #include "aes.h" #include "sha.h" -#include "ff.h" #define EXEFS_KEYID(name) (((strncmp(name, "banner", 8) == 0) || (strncmp(name, "icon", 8) == 0)) ? 0 : 1) @@ -51,100 +48,6 @@ u32 GetNcchCtr(u8* ctr, NcchHeader* ncch, u8 section) { return 0; } -u32 GetNcchSeed(u8* seed, NcchHeader* ncch) { - static u8 lseed[16+8] __attribute__((aligned(4))) = { 0 }; // seed plus title ID for easy validation - u64 titleId = ncch->programId; - u32 hash_seed = ncch->hash_seed; - u32 sha256sum[8]; - - memcpy(lseed+16, &(ncch->programId), 8); - sha_quick(sha256sum, lseed, 16 + 8, SHA256_MODE); - if (hash_seed == sha256sum[0]) { - memcpy(seed, lseed, 16); - return 0; - } - - // setup a large enough buffer - u8* buffer = (u8*) malloc(max(STD_BUFFER_SIZE, SEEDSAVE_AREA_SIZE)); - if (!buffer) return 1; - - // try to grab the seed from NAND database - const char* nand_drv[] = {"1:", "4:"}; // SysNAND and EmuNAND - for (u32 i = 0; i < countof(nand_drv); i++) { - UINT btr = 0; - FIL file; - char path[128]; - - // grab the key Y from movable.sed - u8 movable_keyy[16]; - snprintf(path, 128, "%s/private/movable.sed", nand_drv[i]); - if (f_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) - continue; - f_lseek(&file, 0x110); - f_read(&file, movable_keyy, 0x10, &btr); - f_close(&file); - - // build the seed save path - sha_quick(sha256sum, movable_keyy, 0x10, SHA256_MODE); - snprintf(path, 128, "%s/data/%08lX%08lX%08lX%08lX/sysdata/0001000F/00000000", - nand_drv[i], sha256sum[0], sha256sum[1], sha256sum[2], sha256sum[3]); - - // check seedsave for seed - u8* seeddb = buffer; - if (ReadDisaDiffIvfcLvl4(path, NULL, SEEDSAVE_AREA_OFFSET, SEEDSAVE_AREA_SIZE, seeddb) != SEEDSAVE_AREA_SIZE) - continue; - - // search for the seed - for (u32 s = 0; s < SEEDSAVE_MAX_ENTRIES; s++) { - if (titleId != getle64(seeddb + (s*8))) continue; - memcpy(lseed, seeddb + (SEEDSAVE_MAX_ENTRIES*8) + (s*16), 16); - sha_quick(sha256sum, lseed, 16 + 8, SHA256_MODE); - if (hash_seed == sha256sum[0]) { - memcpy(seed, lseed, 16); - free(buffer); - return 0; // found! - } - } - } - - // not found -> try seeddb.bin - SeedInfo* seeddb = (SeedInfo*) (void*) buffer; - size_t len = LoadSupportFile(SEEDDB_NAME, seeddb, STD_BUFFER_SIZE); - if (len && (seeddb->n_entries <= (len - 16) / 32)) { // check filesize / seeddb size - for (u32 s = 0; s < seeddb->n_entries; s++) { - if (titleId != seeddb->entries[s].titleId) - continue; - memcpy(lseed, seeddb->entries[s].seed, 16); - sha_quick(sha256sum, lseed, 16 + 8, SHA256_MODE); - if (hash_seed == sha256sum[0]) { - memcpy(seed, lseed, 16); - free(buffer); - return 0; // found! - } - } - } - - // out of options -> failed! - free(buffer); - return 1; -} - -u32 AddSeedToDb(SeedInfo* seed_info, SeedInfoEntry* seed_entry) { - if (!seed_entry) { // no seed entry -> reset database - memset(seed_info, 0, 16); - return 0; - } - // check if entry already in DB - u32 n_entries = seed_info->n_entries; - SeedInfoEntry* seed = seed_info->entries; - for (u32 i = 0; i < n_entries; i++, seed++) - if (seed->titleId == seed_entry->titleId) return 0; - // actually a new seed entry - memcpy(seed, seed_entry, sizeof(SeedInfoEntry)); - seed_info->n_entries++; - return 0; -} - u32 SetNcchKey(NcchHeader* ncch, u16 crypto, u32 keyid) { u8 flags3 = (crypto >> 8) & 0xFF; u8 flags7 = crypto & 0xFF; @@ -177,7 +80,7 @@ u32 SetNcchKey(NcchHeader* ncch, u16 crypto, u32 keyid) { if ((memcmp(lsignature, ncch->signature, 16) != 0) || (ltitleId != ncch->programId)) { u8 keydata[16+16] __attribute__((aligned(4))); memcpy(keydata, ncch->signature, 16); - if (GetNcchSeed(keydata + 16, ncch) != 0) + if (FindSeed(keydata + 16, ncch->programId, ncch->hash_seed) != 0) return 1; sha_quick(seedkeyY, keydata, 32, SHA256_MODE); memcpy(lsignature, ncch->signature, 16); @@ -357,3 +260,12 @@ u32 SetNcchSdFlag(void* data) { // data must be at least 0x600 byte and start wi return 0; } + +u32 SetupSystemForNcch(NcchHeader* ncch, bool to_emunand) { + u16 crypto = NCCH_GET_CRYPTO(ncch); + if ((crypto & 0x20) && // seed crypto + (SetupSeedSystemCrypto(ncch->programId, ncch->hash_seed, to_emunand) != 0) && + (SetupSeedPrePurchase(ncch->programId, to_emunand) != 0)) + return 1; + return 0; +} diff --git a/arm9/source/game/ncch.h b/arm9/source/game/ncch.h index 78dbbb3..5780a13 100644 --- a/arm9/source/game/ncch.h +++ b/arm9/source/game/ncch.h @@ -2,6 +2,7 @@ #include "common.h" #include "exefs.h" +#include "seedsave.h" #define NCCH_MEDIA_UNIT 0x200 @@ -17,13 +18,6 @@ #define NCCH_STDCRYPTO 0x0000 #define NCCH_GET_CRYPTO(ncch) (!NCCH_ENCRYPTED(ncch) ? NCCH_NOCRYPTO : (((ncch)->flags[3] << 8) | ((ncch)->flags[7]&(0x01|0x20)))) -#define SEEDDB_NAME "seeddb.bin" -#define SEEDDB_SIZE(sdb) (16 + ((sdb)->n_entries * sizeof(SeedInfoEntry))) - -#define SEEDSAVE_MAX_ENTRIES 2000 -#define SEEDSAVE_AREA_OFFSET 0x4000 -#define SEEDSAVE_AREA_SIZE (SEEDSAVE_MAX_ENTRIES * (8+16)) - // wrapper defines #define DecryptNcch(data, offset, size, ncch, exefs) CryptNcch(data, offset, size, ncch, exefs, NCCH_NOCRYPTO) #define EncryptNcch(data, offset, size, ncch, exefs, crypto) CryptNcch(data, offset, size, ncch, exefs, crypto) @@ -89,23 +83,10 @@ typedef struct { u8 hash_romfs[0x20]; } __attribute__((packed, aligned(16))) NcchHeader; -typedef struct { - u64 titleId; - u8 seed[16]; - u8 reserved[8]; -} PACKED_STRUCT SeedInfoEntry; - -typedef struct { - u32 n_entries; - u8 padding[12]; - SeedInfoEntry entries[256]; // this number is only a placeholder -} PACKED_STRUCT SeedInfo; - u32 ValidateNcchHeader(NcchHeader* header); u32 SetNcchKey(NcchHeader* ncch, u16 crypto, u32 keyid); u32 SetupNcchCrypto(NcchHeader* ncch, u16 crypt_to); u32 CryptNcch(void* data, u32 offset, u32 size, NcchHeader* ncch, ExeFsHeader* exefs, u16 crypto); u32 CryptNcchSequential(void* data, u32 offset, u32 size, u16 crypto); u32 SetNcchSdFlag(void* data); - -u32 AddSeedToDb(SeedInfo* seed_info, SeedInfoEntry* seed_entry); +u32 SetupSystemForNcch(NcchHeader* ncch, bool to_emunand); diff --git a/arm9/source/game/seedsave.c b/arm9/source/game/seedsave.c new file mode 100644 index 0000000..0c82655 --- /dev/null +++ b/arm9/source/game/seedsave.c @@ -0,0 +1,240 @@ +#include "seedsave.h" +#include "support.h" +#include "nandcmac.h" +#include "sha.h" +#include "ff.h" + +#define TITLETAG_MAX_ENTRIES 2000 // same as SEEDSAVE_MAX_ENTRIES +#define TITLETAG_AREA_OFFSET 0x10000 // thanks @luigoalma + +// this structure is 0x80 bytes, thanks @luigoalma +typedef struct { + char magic[4]; // "PREP" for prepurchase install. NIM excepts "PREP" to do seed downloads on the background. + // playable date parameters + // 2000-01-01 is a safe bet for a stub entry + s32 year; + u8 month; + u8 day; + u16 country_code; // enum list of values, this will affect seed downloading, just requires at least one valid enum value. 1 == Japan, it's enough. + // everything after this point can be 0 padded + u32 seed_status; // 0 == not tried, 1 == last attempt failed, 2 == seed downloaded successfully + s32 seed_result; // result related to last download attempt + s32 seed_support_error_code; // support code derived from the result code + // after this point, all is unused or padding. NIM wont use or access this at all. + // It's memset to 0 by NIM + u8 unknown[0x68]; +} PACKED_STRUCT TitleTagEntry; + +typedef struct { + u32 unknown0; + u32 n_entries; + u8 unknown1[0x1000 - 0x8]; + u64 titleId[TITLETAG_MAX_ENTRIES]; + TitleTagEntry tag[TITLETAG_MAX_ENTRIES]; +} PACKED_STRUCT TitleTag; + +u32 GetSeedPath(char* path, const char* drv) { + u8 movable_keyy[16] = { 0 }; + u32 sha256sum[8]; + UINT btr = 0; + FIL file; + + // grab the key Y from movable.sed + // wrong result if movable.sed does not have it + snprintf(path, 128, "%2.2s/private/movable.sed", drv); + if (f_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) + return 1; + f_lseek(&file, 0x110); + f_read(&file, movable_keyy, 0x10, &btr); + f_close(&file); + if (btr != 0x10) + return 1; + + // build the seed save path + sha_quick(sha256sum, movable_keyy, 0x10, SHA256_MODE); + snprintf(path, 128, "%2.2s/data/%08lX%08lX%08lX%08lX/sysdata/0001000F/00000000", + drv, sha256sum[0], sha256sum[1], sha256sum[2], sha256sum[3]); + + return 0; +} + +u32 FindSeed(u8* seed, u64 titleId, u32 hash_seed) { + static u8 lseed[16+8] __attribute__((aligned(4))) = { 0 }; // seed plus title ID for easy validation + u32 sha256sum[8]; + + memcpy(lseed+16, &titleId, 8); + sha_quick(sha256sum, lseed, 16 + 8, SHA256_MODE); + if (hash_seed == sha256sum[0]) { + memcpy(seed, lseed, 16); + return 0; + } + + // setup a large enough buffer + u8* buffer = (u8*) malloc(max(STD_BUFFER_SIZE, sizeof(SeedDb))); + if (!buffer) return 1; + + // try to grab the seed from NAND database + const char* nand_drv[] = {"1:", "4:"}; // SysNAND and EmuNAND + for (u32 i = 0; i < countof(nand_drv); i++) { + char path[128]; + SeedDb* seeddb = (SeedDb*) (void*) buffer; + + // read SEEDDB from file + if (GetSeedPath(path, nand_drv[i]) != 0) continue; + if ((ReadDisaDiffIvfcLvl4(path, NULL, SEEDSAVE_AREA_OFFSET, sizeof(SeedDb), seeddb) != sizeof(SeedDb)) || + (seeddb->n_entries > SEEDSAVE_MAX_ENTRIES)) + continue; + + // search for the seed + for (u32 s = 0; s < seeddb->n_entries; s++) { + if (titleId != seeddb->titleId[s]) continue; + memcpy(lseed, &(seeddb->seed[s]), sizeof(Seed)); + sha_quick(sha256sum, lseed, 16 + 8, SHA256_MODE); + if (hash_seed == sha256sum[0]) { + memcpy(seed, lseed, 16); + free(buffer); + return 0; // found! + } + } + } + + // not found -> try seeddb.bin + SeedInfo* seeddb = (SeedInfo*) (void*) buffer; + size_t len = LoadSupportFile(SEEDINFO_NAME, seeddb, STD_BUFFER_SIZE); + if (len && (seeddb->n_entries <= (len - 16) / 32)) { // check filesize / seeddb size + for (u32 s = 0; s < seeddb->n_entries; s++) { + if (titleId != seeddb->entries[s].titleId) + continue; + memcpy(lseed, &(seeddb->entries[s].seed), sizeof(Seed)); + sha_quick(sha256sum, lseed, 16 + 8, SHA256_MODE); + if (hash_seed == sha256sum[0]) { + memcpy(seed, lseed, 16); + free(buffer); + return 0; // found! + } + } + } + + // out of options -> failed! + free(buffer); + return 1; +} + +u32 AddSeedToDb(SeedInfo* seed_info, SeedInfoEntry* seed_entry) { + if (!seed_entry) { // no seed entry -> reset database + memset(seed_info, 0, 16); + return 0; + } + // check if entry already in DB + u32 n_entries = seed_info->n_entries; + SeedInfoEntry* seed = seed_info->entries; + for (u32 i = 0; i < n_entries; i++, seed++) + if (seed->titleId == seed_entry->titleId) return 0; + // actually a new seed entry + memcpy(seed, seed_entry, sizeof(SeedInfoEntry)); + seed_info->n_entries++; + return 0; +} + +u32 InstallSeedDbToSystem(SeedInfo* seed_info, bool to_emunand) { + char path[128]; + SeedDb* seeddb = (SeedDb*) malloc(sizeof(SeedDb)); + if (!seeddb) return 1; + + // read the current SEEDDB database + if ((GetSeedPath(path, to_emunand ? "4:" : "1:") != 0) || + (ReadDisaDiffIvfcLvl4(path, NULL, SEEDSAVE_AREA_OFFSET, sizeof(SeedDb), seeddb) != sizeof(SeedDb)) || + (seeddb->n_entries >= SEEDSAVE_MAX_ENTRIES)) { + free (seeddb); + return 1; + } + + // find free slots, insert seeds from SeedInfo + for (u32 slot = 0, s = 0; s < seed_info->n_entries; s++) { + SeedInfoEntry* entry = &(seed_info->entries[s]); + for (slot = 0; slot < seeddb->n_entries; slot++) + if (seeddb->titleId[slot] == entry->titleId) break; + if (slot >= SEEDSAVE_MAX_ENTRIES) break; + if (slot >= seeddb->n_entries) seeddb->n_entries = slot + 1; + seeddb->titleId[slot] = entry->titleId; + memcpy(&(seeddb->seed[slot]), &(entry->seed), sizeof(Seed)); + } + + // write back to system (warning: no write protection checks here) + u32 size = WriteDisaDiffIvfcLvl4(path, NULL, SEEDSAVE_AREA_OFFSET, sizeof(SeedDb), seeddb); + FixFileCmac(path, false); + + free (seeddb); + return (size == sizeof(SeedDb)) ? 0 : 1; +} + +u32 SetupSeedPrePurchase(u64 titleId, bool to_emunand) { + // here, we ask the system to install the seed for us + TitleTag* titletag = (TitleTag*) malloc(sizeof(TitleTag)); + if (!titletag) return 1; + + char path[128]; + if ((GetSeedPath(path, to_emunand ? "4:" : "1:") != 0) || + (ReadDisaDiffIvfcLvl4(path, NULL, TITLETAG_AREA_OFFSET, sizeof(TitleTag), titletag) != sizeof(TitleTag)) || + (titletag->n_entries >= TITLETAG_MAX_ENTRIES)) { + free (titletag); + return 1; + } + + // pointers for TITLETAG title IDs and seeds + // find a free slot, insert titletag + u32 slot = 0; + for (; slot < titletag->n_entries; slot++) + if (titletag->titleId[slot] == titleId) break; + if (slot >= titletag->n_entries) + titletag->n_entries = slot + 1; + + TitleTagEntry* ttag = &(titletag->tag[slot]); + titletag->titleId[slot] = titleId; + memset(ttag, 0, sizeof(TitleTagEntry)); + memcpy(ttag->magic, "PREP", 4); + ttag->year = 2000; + ttag->month = 1; + ttag->day = 1; + ttag->country_code = 1; + + // write back to system (warning: no write protection checks here) + u32 size = WriteDisaDiffIvfcLvl4(path, NULL, TITLETAG_AREA_OFFSET, sizeof(TitleTag), titletag); + FixFileCmac(path, false); + + free(titletag); + return (size == sizeof(TitleTag)) ? 0 : 1; +} + +u32 SetupSeedSystemCrypto(u64 titleId, u32 hash_seed, bool to_emunand) { + // attempt to find the seed inside the seeddb.bin support file + SeedInfo* seeddb = (SeedInfo*) malloc(STD_BUFFER_SIZE); + if (!seeddb) return 1; + + size_t len = LoadSupportFile(SEEDINFO_NAME, seeddb, STD_BUFFER_SIZE); + if (len && (seeddb->n_entries <= (len - 16) / 32)) { // check filesize / seeddb size + for (u32 s = 0; s < seeddb->n_entries; s++) { + if (titleId != seeddb->entries[s].titleId) + continue; + // found a candidate, hash and verify it + u8 lseed[16+8] __attribute__((aligned(4))) = { 0 }; // seed plus title ID for easy validation + u32 sha256sum[8]; + memcpy(lseed+16, &titleId, 8); + memcpy(lseed, &(seeddb->entries[s].seed), sizeof(Seed)); + sha_quick(sha256sum, lseed, 16 + 8, SHA256_MODE); + u32 res = 0; // assuming the installed seed to be correct + if (hash_seed == sha256sum[0]) { + // found, install it + seeddb->n_entries = 1; + seeddb->entries[0].titleId = titleId; + memcpy(&(seeddb->entries[0].seed), lseed, sizeof(Seed)); + res = InstallSeedDbToSystem(seeddb, to_emunand); + } + free(seeddb); + return res; + } + } + + free(seeddb); + return 1; +} diff --git a/arm9/source/game/seedsave.h b/arm9/source/game/seedsave.h new file mode 100644 index 0000000..5f79f23 --- /dev/null +++ b/arm9/source/game/seedsave.h @@ -0,0 +1,41 @@ +#pragma once + +#include "common.h" +#include "disadiff.h" + +#define SEEDINFO_NAME "seeddb.bin" +#define SEEDINFO_SIZE(sdb) (16 + ((sdb)->n_entries * sizeof(SeedInfoEntry))) + +#define SEEDSAVE_MAX_ENTRIES 2000 +#define SEEDSAVE_AREA_OFFSET 0x3000 + +typedef struct { + u8 byte[16]; +} PACKED_STRUCT Seed; + +typedef struct { + u64 titleId; + Seed seed; + u8 reserved[8]; +} PACKED_STRUCT SeedInfoEntry; + +typedef struct { + u32 n_entries; + u8 padding[12]; + SeedInfoEntry entries[SEEDSAVE_MAX_ENTRIES]; // this number is only a placeholder +} PACKED_STRUCT SeedInfo; + +typedef struct { + u32 unknown0; + u32 n_entries; + u8 unknown1[0x1000 - 0x8]; + u64 titleId[SEEDSAVE_MAX_ENTRIES]; + Seed seed[SEEDSAVE_MAX_ENTRIES]; +} PACKED_STRUCT SeedDb; + +u32 GetSeedPath(char* path, const char* drv); +u32 FindSeed(u8* seed, u64 titleId, u32 hash_seed); +u32 AddSeedToDb(SeedInfo* seed_info, SeedInfoEntry* seed_entry); +u32 InstallSeedDbToSystem(SeedInfo* seed_info, bool to_emunand); +u32 SetupSeedPrePurchase(u64 titleId, bool to_emunand); +u32 SetupSeedSystemCrypto(u64 titleId, u32 hash_seed, bool to_emunand); diff --git a/arm9/source/godmode.c b/arm9/source/godmode.c index 62f0b7d..545910f 100644 --- a/arm9/source/godmode.c +++ b/arm9/source/godmode.c @@ -2112,7 +2112,7 @@ u32 HomeMoreMenu(char* current_path) { bool seed_sys = false; bool seed_emu = false; if (BuildSeedInfo(NULL, false) == 0) { - ShowString("Building " SEEDDB_NAME "..."); + ShowString("Building " SEEDINFO_NAME "..."); seed_sys = (BuildSeedInfo("1:", false) == 0); seed_emu = (BuildSeedInfo("4:", false) == 0); if (!seed_sys || BuildSeedInfo(NULL, true) != 0) @@ -2121,7 +2121,7 @@ u32 HomeMoreMenu(char* current_path) { ShowPrompt(false, "Built in " OUTPUT_PATH ":\n \n%18.18-s %s\n%18.18-s %s\n%18.18-s %s", TIKDB_NAME_ENC, tik_enc_sys ? tik_enc_emu ? "OK (Sys&Emu)" : "OK (Sys)" : "Failed", TIKDB_NAME_DEC, tik_dec_sys ? tik_dec_emu ? "OK (Sys&Emu)" : "OK (Sys)" : "Failed", - SEEDDB_NAME, seed_sys ? seed_emu ? "OK (Sys&Emu)" : "OK (Sys)" : "Failed"); + SEEDINFO_NAME, seed_sys ? seed_emu ? "OK (Sys&Emu)" : "OK (Sys)" : "Failed"); GetDirContents(current_dir, current_path); return 0; } diff --git a/arm9/source/utils/gameutil.c b/arm9/source/utils/gameutil.c index a728b31..eebd857 100644 --- a/arm9/source/utils/gameutil.c +++ b/arm9/source/utils/gameutil.c @@ -1589,6 +1589,7 @@ u32 InstallCiaSystemData(CiaStub* cia, const char* drv) { bool sdtie = ((*drv == 'A') || (*drv == 'B')); bool syscmd = (((*drv == '1') || (*drv == '4')) || (((*drv == '2') || (*drv == '5')) && (title_id[3] != 0x04))); + bool to_emunand = ((*drv == 'B') || (*drv == '4') || (*drv == '5')); char path_titledb[32]; char path_ticketdb[32]; @@ -1662,6 +1663,10 @@ u32 InstallCiaSystemData(CiaStub* cia, const char* drv) { (CreateSaveData(drv, tid64, "banner.sav", sizeof(TwlIconData), false) != 0)) return 1; + // install seed to system (if available) + if (ncch && (SetupSystemForNcch(ncch, to_emunand) != 0)) + return 1; + // write ticket and title databases // ensure remounting the old mount path char path_store[256] = { 0 }; @@ -3081,7 +3086,7 @@ u32 BuildTitleKeyInfo(const char* path, bool dec, bool dump) { u32 BuildSeedInfo(const char* path, bool dump) { static SeedInfo* seed_info = NULL; - const char* path_out = OUTPUT_PATH "/" SEEDDB_NAME; + const char* path_out = OUTPUT_PATH "/" SEEDINFO_NAME; const char* path_in = path; u32 inputtype = 0; // 0 -> none, 1 -> seeddb.bin, 2 -> seed system save @@ -3106,16 +3111,7 @@ u32 BuildSeedInfo(const char* path, bool dump) { char path_str[128]; if (path_in && (strnlen(path_in, 16) == 2)) { // when only a drive is given... - // grab the key Y from movable.sed - u8 movable_keyy[16] __attribute__((aligned(4))); - snprintf(path_str, 128, "%s/private/movable.sed", path_in); - if (fvx_qread(path_str, movable_keyy, 0x110, 0x10, NULL) != FR_OK) - return 1; - // build the seed save path - u32 sha256sum[8]; - sha_quick(sha256sum, movable_keyy, 0x10, SHA256_MODE); - snprintf(path_str, 128, "%s/data/%08lX%08lX%08lX%08lX/sysdata/0001000F/00000000", - path_in, sha256sum[0], sha256sum[1], sha256sum[2], sha256sum[3]); + if (GetSeedPath(path_str, path_in) != 0) return 1; path_in = path_str; inputtype = 2; } @@ -3126,7 +3122,7 @@ u32 BuildSeedInfo(const char* path, bool dump) { UINT br; if ((fvx_qread(path_in, seed_info_merge, 0, STD_BUFFER_SIZE, &br) != FR_OK) || - (SEEDDB_SIZE(seed_info_merge) != br)) { + (SEEDINFO_SIZE(seed_info_merge) != br)) { free(seed_info_merge); return 1; } @@ -3135,27 +3131,27 @@ u32 BuildSeedInfo(const char* path, bool dump) { u32 n_entries = seed_info_merge->n_entries; SeedInfoEntry* seed = seed_info_merge->entries; for (u32 i = 0; i < n_entries; i++, seed++) { - if (SEEDDB_SIZE(seed_info) + 32 > STD_BUFFER_SIZE) break; // no error message + if (SEEDINFO_SIZE(seed_info) + 32 > STD_BUFFER_SIZE) break; // no error message AddSeedToDb(seed_info, seed); // ignore result } free(seed_info_merge); } else if (inputtype == 2) { // seed system save input - u8* seedsave = (u8*) malloc(SEEDSAVE_AREA_SIZE); + SeedDb* seedsave = (SeedDb*) malloc(sizeof(SeedDb)); if (!seedsave) return 1; - if (ReadDisaDiffIvfcLvl4(path_in, NULL, SEEDSAVE_AREA_OFFSET, SEEDSAVE_AREA_SIZE, seedsave) != SEEDSAVE_AREA_SIZE) { + if ((ReadDisaDiffIvfcLvl4(path_in, NULL, SEEDSAVE_AREA_OFFSET, sizeof(SeedDb), seedsave) != sizeof(SeedDb)) || + (seedsave->n_entries >= SEEDSAVE_MAX_ENTRIES)) { free(seedsave); return 1; } SeedInfoEntry seed = { 0 }; - for (u32 s = 0; s < SEEDSAVE_MAX_ENTRIES; s++) { - seed.titleId = getle64(seedsave + (s*8)); - memcpy(seed.seed, seedsave + (SEEDSAVE_MAX_ENTRIES*8) + (s*16), 16); - if (((seed.titleId >> 32) != 0x00040000) || - (!getle64(seed.seed) && !getle64(seed.seed + 8))) continue; - if (SEEDDB_SIZE(seed_info) + 32 > STD_BUFFER_SIZE) break; // no error message + for (u32 s = 0; s < seedsave->n_entries; s++) { + seed.titleId = seedsave->titleId[s]; + memcpy(&(seed.seed), &(seedsave->seed[s]), sizeof(Seed)); + if ((seed.titleId >> 32) != 0x00040000) continue; + if (SEEDINFO_SIZE(seed_info) + 32 > STD_BUFFER_SIZE) break; // no error message AddSeedToDb(seed_info, &seed); // ignore result } @@ -3163,7 +3159,7 @@ u32 BuildSeedInfo(const char* path, bool dump) { } if (dump) { - u32 dump_size = SEEDDB_SIZE(seed_info); + u32 dump_size = SEEDINFO_SIZE(seed_info); u32 ret = 0; if (dump_size > 16) { diff --git a/arm9/source/utils/scripting.c b/arm9/source/utils/scripting.c index 6817ea0..3293156 100644 --- a/arm9/source/utils/scripting.c +++ b/arm9/source/utils/scripting.c @@ -1363,8 +1363,8 @@ bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) { (BuildTitleKeyInfo(NULL, tik_dec, true) == 0)) ret = true; } - } else if (strncasecmp(argv[0], SEEDDB_NAME, _ARG_MAX_LEN) == 0) { - if (flags & _FLG('w')) fvx_unlink(OUTPUT_PATH "/" SEEDDB_NAME); + } else if (strncasecmp(argv[0], SEEDINFO_NAME, _ARG_MAX_LEN) == 0) { + if (flags & _FLG('w')) fvx_unlink(OUTPUT_PATH "/" SEEDINFO_NAME); if (BuildSeedInfo(NULL, false) == 0) { ShowString("Building to " OUTPUT_PATH ":\n%s ...", argv[0]); if (((BuildSeedInfo("1:", false) == 0) ||