1
0
Fork 0
mirror of https://github.com/DarkMatterCore/nxdumptool.git synced 2024-11-22 18:26:39 +00:00

Standardize complete gamecard image (#150)

Makes it possible to retrieve the raw gamecard UID in one go, without having to manually parse the gamecard specific data block.
This commit is contained in:
Johnson 2023-12-05 19:21:45 +01:00 committed by GitHub
parent 8c4e432035
commit af275a558e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 78 additions and 32 deletions

View file

@ -188,6 +188,7 @@ static bool saveGameCardCertificate(void *userdata);
static bool saveGameCardInitialData(void *userdata); static bool saveGameCardInitialData(void *userdata);
static bool saveGameCardSpecificData(void *userdata); static bool saveGameCardSpecificData(void *userdata);
static bool saveGameCardIdSet(void *userdata); static bool saveGameCardIdSet(void *userdata);
static bool saveGameCardUid(void *userdata);
static bool saveGameCardHfsPartition(void *userdata); static bool saveGameCardHfsPartition(void *userdata);
static bool saveGameCardRawHfsPartition(HashFileSystemContext *hfs_ctx); static bool saveGameCardRawHfsPartition(HashFileSystemContext *hfs_ctx);
static bool saveGameCardExtractedHfsPartition(HashFileSystemContext *hfs_ctx); static bool saveGameCardExtractedHfsPartition(HashFileSystemContext *hfs_ctx);
@ -445,16 +446,9 @@ static MenuElement *g_gameCardMenuElements[] = {
.userdata = NULL .userdata = NULL
}, },
&(MenuElement){ &(MenuElement){
.str = "dump gamecard header", .str = "dump gamecard initial data",
.child_menu = NULL, .child_menu = NULL,
.task_func = &saveGameCardHeader, .task_func = &saveGameCardInitialData,
.element_options = NULL,
.userdata = NULL
},
&(MenuElement){
.str = "dump gamecard cardinfo",
.child_menu = NULL,
.task_func = &saveGameCardCardInfo,
.element_options = NULL, .element_options = NULL,
.userdata = NULL .userdata = NULL
}, },
@ -465,20 +459,6 @@ static MenuElement *g_gameCardMenuElements[] = {
.element_options = NULL, .element_options = NULL,
.userdata = NULL .userdata = NULL
}, },
&(MenuElement){
.str = "dump gamecard initial data",
.child_menu = NULL,
.task_func = &saveGameCardInitialData,
.element_options = NULL,
.userdata = NULL
},
&(MenuElement){
.str = "dump gamecard specific data",
.child_menu = NULL,
.task_func = &saveGameCardSpecificData,
.element_options = NULL,
.userdata = NULL
},
&(MenuElement){ &(MenuElement){
.str = "dump gamecard id set", .str = "dump gamecard id set",
.child_menu = NULL, .child_menu = NULL,
@ -487,7 +467,35 @@ static MenuElement *g_gameCardMenuElements[] = {
.userdata = NULL .userdata = NULL
}, },
&(MenuElement){ &(MenuElement){
.str = "dump hfs partitions", .str = "dump gamecard uid",
.child_menu = NULL,
.task_func = &saveGameCardUid,
.element_options = NULL,
.userdata = NULL
},
&(MenuElement){
.str = "dump gamecard header (optional)",
.child_menu = NULL,
.task_func = &saveGameCardHeader,
.element_options = NULL,
.userdata = NULL
},
&(MenuElement){
.str = "dump gamecard cardinfo (optional)",
.child_menu = NULL,
.task_func = &saveGameCardCardInfo,
.element_options = NULL,
.userdata = NULL
},
&(MenuElement){
.str = "dump gamecard specific data (optional)",
.child_menu = NULL,
.task_func = &saveGameCardSpecificData,
.element_options = NULL,
.userdata = NULL
},
&(MenuElement){
.str = "dump hfs partitions (optional)",
.child_menu = &(Menu){ .child_menu = &(Menu){
.id = MenuId_HFS, .id = MenuId_HFS,
.parent = NULL, .parent = NULL,
@ -500,7 +508,7 @@ static MenuElement *g_gameCardMenuElements[] = {
.userdata = NULL .userdata = NULL
}, },
&(MenuElement){ &(MenuElement){
.str = "dump console lafw blob", .str = "dump console lafw blob (optional)",
.child_menu = NULL, .child_menu = NULL,
.task_func = &saveConsoleLafwBlob, .task_func = &saveConsoleLafwBlob,
.element_options = NULL, .element_options = NULL,
@ -1046,6 +1054,10 @@ int main(int argc, char *argv[])
consolePrint("______________________________\n\n"); consolePrint("______________________________\n\n");
} }
} }
} else
if (cur_menu->id == MenuId_GameCard) {
consolePrint("For a full gamecard image: dump XCI, initial data, certificate, id set and uid.\n");
consolePrint("______________________________\n\n");
} }
for(u32 i = cur_menu->scroll; i < element_count; i++) for(u32 i = cur_menu->scroll; i < element_count; i++)
@ -2597,6 +2609,11 @@ end:
return success; return success;
} }
/* This will save the Gamecard Specific Data. Its format is specific and internal to the current LAFW firmware version and session of the GCBRG ASIC. */
/* Depending on which Switch system version the gamecard was dumped from, this data can change. */
/* Even re-inserting the gamecard will change parts of this data. */
/* For this reason the gamecard specific data is mostly uninteresting for gamecard preservation. */
/* Instead, take a look at saveGameCardIdSet and saveGameCardUid which is a more standardised format of the Gamecard ID data. */
static bool saveGameCardSpecificData(void *userdata) static bool saveGameCardSpecificData(void *userdata)
{ {
(void)userdata; (void)userdata;
@ -2657,6 +2674,39 @@ end:
return success; return success;
} }
static bool saveGameCardUid(void *userdata)
{
(void)userdata;
GameCardSecurityInformation gc_security_information = {0};
bool success = false;
u32 crc = 0;
char *filename = NULL;
if (!gamecardGetSecurityInformation(&gc_security_information))
{
consolePrint("failed to get gamecard security information\n");
goto end;
}
crc = crc32Calculate(gc_security_information.specific_data.card_uid, sizeof(gc_security_information.specific_data.card_uid));
snprintf(path, MAX_ELEMENTS(path), " (Card UID) (%08X).bin", crc);
filename = generateOutputGameCardFileName("Gamecard", path, true);
if (!filename) goto end;
if (!saveFileData(filename, gc_security_information.specific_data.card_uid, sizeof(gc_security_information.specific_data.card_uid))) goto end;
consolePrint("successfully saved gamecard uid as \"%s\"\n", filename);
success = true;
end:
if (filename) free(filename);
return success;
}
static bool saveGameCardHfsPartition(void *userdata) static bool saveGameCardHfsPartition(void *userdata)
{ {
u32 hfs_partition_type = (userdata ? *((u32*)userdata) : HashFileSystemPartitionType_None); u32 hfs_partition_type = (userdata ? *((u32*)userdata) : HashFileSystemPartitionType_None);

View file

@ -108,9 +108,9 @@ NXDT_ASSERT(FsCardId3, 0x4);
/// Returned by fsDeviceOperatorGetGameCardIdSet. /// Returned by fsDeviceOperatorGetGameCardIdSet.
typedef struct { typedef struct {
FsCardId1 id1; FsCardId1 id1; ///< Specifies maker code, memory capacity, and memory type
FsCardId2 id2; FsCardId2 id2; ///< Specifies card security number and card type
FsCardId3 id3; FsCardId3 id3; ///< Always zero (so far)
} FsGameCardIdSet; } FsGameCardIdSet;
NXDT_ASSERT(FsGameCardIdSet, 0xC); NXDT_ASSERT(FsGameCardIdSet, 0xC);

View file

@ -961,10 +961,6 @@ static bool gamecardReadSecurityInformation(GameCardSecurityInformation *out)
/* Jackpot. */ /* Jackpot. */
memcpy(out, g_fsProgramMemory.data + offset + sizeof(GameCardInitialData) - sizeof(GameCardSecurityInformation), sizeof(GameCardSecurityInformation)); memcpy(out, g_fsProgramMemory.data + offset + sizeof(GameCardInitialData) - sizeof(GameCardSecurityInformation), sizeof(GameCardSecurityInformation));
/* Clear out the current ASIC session hash. */
/* It's not actually part of the gamecard data, and this changes every time a gamecard (re)insertion takes place. */
memset(out->specific_data.asic_session_hash, 0xFF, sizeof(out->specific_data.asic_session_hash));
found = true; found = true;
break; break;
} }