mirror of
https://github.com/Atmosphere-NX/hac2l.git
synced 2025-06-20 18:52:39 +02:00
hac2l: print gamecard headers
This commit is contained in:
parent
f4bfc614de
commit
74c9f10eab
@ -25,55 +25,56 @@ namespace ams::hactool {
|
||||
constexpr size_t RsaKeySize = crypto::Rsa2048PssSha256Verifier::ModulusSize;
|
||||
|
||||
struct KeySet {
|
||||
u8 secure_boot_key[AesKeySize]; /* Secure boot key for use in key derivation. NOTE: CONSOLE UNIQUE. */
|
||||
u8 tsec_key[AesKeySize]; /* TSEC key for use in key derivation. NOTE: CONSOLE UNIQUE. */
|
||||
u8 device_key[AesKeySize]; /* Device key used to derive some FS keys. NOTE: CONSOLE UNIQUE. */
|
||||
u8 keyblob_keys[pkg1::KeyGeneration_Max][AesKeySize]; /* Actual keys used to decrypt keyblobs. NOTE: CONSOLE UNIQUE.*/
|
||||
u8 keyblob_mac_keys[pkg1::KeyGeneration_Max][AesKeySize]; /* Keys used to validate keyblobs. NOTE: CONSOLE UNIQUE. */
|
||||
u8 encrypted_keyblobs[pkg1::KeyGeneration_Max][0xB0]; /* Actual encrypted keyblobs (EKS). NOTE: CONSOLE UNIQUE. */
|
||||
u8 mariko_aes_class_keys[0xC][AesKeySize]; /* AES Class Keys set by mariko bootrom. */
|
||||
u8 mariko_kek[AesKeySize]; /* Key Encryption Key for mariko. */
|
||||
u8 mariko_bek[AesKeySize]; /* Boot Encryption Key for mariko. */
|
||||
u8 keyblobs[pkg1::KeyGeneration_Max][0x90]; /* Actual decrypted keyblobs (EKS). */
|
||||
u8 keyblob_key_sources[pkg1::KeyGeneration_Max][AesKeySize]; /* Seeds for keyblob keys. */
|
||||
u8 keyblob_mac_key_source[AesKeySize]; /* Seed for keyblob MAC key derivation. */
|
||||
u8 tsec_root_kek[AesKeySize]; /* Used to generate TSEC root keys. */
|
||||
u8 package1_mac_kek[AesKeySize]; /* Used to generate Package1 MAC keys. */
|
||||
u8 package1_kek[AesKeySize]; /* Used to generate Package1 keys. */
|
||||
u8 tsec_auth_signatures[pkg1::KeyGeneration_Max][AesKeySize]; /* Auth signatures, seeds for tsec root key/package1 mac kek/package1 key on 6.2.0+. */
|
||||
u8 tsec_root_keys[pkg1::KeyGeneration_Max][AesKeySize]; /* Key for master kek decryption, from TSEC firmware on 6.2.0+. */
|
||||
u8 master_kek_sources[pkg1::KeyGeneration_Max][AesKeySize]; /* Seeds for firmware master keks. */
|
||||
u8 mariko_master_kek_sources[pkg1::KeyGeneration_Max][AesKeySize]; /* Seeds for firmware master keks (Mariko). */
|
||||
u8 master_keks[pkg1::KeyGeneration_Max][AesKeySize]; /* Firmware master keks, stored in keyblob prior to 6.2.0. */
|
||||
u8 master_key_source[AesKeySize]; /* Seed for master key derivation. */
|
||||
u8 master_keys[pkg1::KeyGeneration_Max][AesKeySize]; /* Firmware master keys. */
|
||||
u8 package1_mac_keys[pkg1::KeyGeneration_Max][AesKeySize]; /* Package1 MAC keys. */
|
||||
u8 package1_keys[pkg1::KeyGeneration_Max][AesKeySize]; /* Package1 keys. */
|
||||
u8 package2_keys[pkg1::KeyGeneration_Max][AesKeySize]; /* Package2 keys. */
|
||||
u8 package2_key_source[AesKeySize]; /* Seed for Package2 key. */
|
||||
u8 per_console_key_source[AesKeySize]; /* Seed for Device key. */
|
||||
u8 aes_kek_generation_source[AesKeySize]; /* Seed for GenerateAesKek, usecase + generation 0. */
|
||||
u8 aes_key_generation_source[AesKeySize]; /* Seed for GenerateAesKey. */
|
||||
u8 key_area_key_application_source[AesKeySize]; /* Seed for kaek 0. */
|
||||
u8 key_area_key_ocean_source[AesKeySize]; /* Seed for kaek 1. */
|
||||
u8 key_area_key_system_source[AesKeySize]; /* Seed for kaek 2. */
|
||||
u8 titlekek_source[AesKeySize]; /* Seed for titlekeks. */
|
||||
u8 header_kek_source[AesKeySize]; /* Seed for header kek. */
|
||||
u8 sd_card_kek_source[AesKeySize]; /* Seed for SD card kek. */
|
||||
u8 sd_card_nca_key_source[0x20]; /* Seed for SD card encryption keys. */
|
||||
u8 sd_card_save_key_source[0x20]; /* Seed for SD card encryption keys. */
|
||||
u8 save_mac_kek_source[AesKeySize]; /* Seed for save kek. */
|
||||
u8 save_mac_key_source[AesKeySize]; /* Seed for save key. */
|
||||
u8 header_key_source[pkg1::KeyGeneration_Max]; /* Seed for NCA header key. */
|
||||
u8 header_key[pkg1::KeyGeneration_Max]; /* NCA header key. */
|
||||
u8 titlekeks[pkg1::KeyGeneration_Max][AesKeySize]; /* Title key encryption keys. */
|
||||
u8 key_area_keys[pkg1::KeyGeneration_Max][3][AesKeySize]; /* Key area encryption keys. */
|
||||
u8 xci_header_key[AesKeySize]; /* Key for XCI partially encrypted header. */
|
||||
u8 save_mac_key[AesKeySize]; /* Key used to sign savedata. */
|
||||
u8 secure_boot_key[AesKeySize]; /* Secure boot key for use in key derivation. NOTE: CONSOLE UNIQUE. */
|
||||
u8 tsec_key[AesKeySize]; /* TSEC key for use in key derivation. NOTE: CONSOLE UNIQUE. */
|
||||
u8 device_key[AesKeySize]; /* Device key used to derive some FS keys. NOTE: CONSOLE UNIQUE. */
|
||||
u8 keyblob_keys[pkg1::KeyGeneration_Max][AesKeySize]; /* Actual keys used to decrypt keyblobs. NOTE: CONSOLE UNIQUE.*/
|
||||
u8 keyblob_mac_keys[pkg1::KeyGeneration_Max][AesKeySize]; /* Keys used to validate keyblobs. NOTE: CONSOLE UNIQUE. */
|
||||
u8 encrypted_keyblobs[pkg1::KeyGeneration_Max][0xB0]; /* Actual encrypted keyblobs (EKS). NOTE: CONSOLE UNIQUE. */
|
||||
u8 mariko_aes_class_keys[0xC][AesKeySize]; /* AES Class Keys set by mariko bootrom. */
|
||||
u8 mariko_kek[AesKeySize]; /* Key Encryption Key for mariko. */
|
||||
u8 mariko_bek[AesKeySize]; /* Boot Encryption Key for mariko. */
|
||||
u8 keyblobs[pkg1::KeyGeneration_Max][0x90]; /* Actual decrypted keyblobs (EKS). */
|
||||
u8 keyblob_key_sources[pkg1::KeyGeneration_Max][AesKeySize]; /* Seeds for keyblob keys. */
|
||||
u8 keyblob_mac_key_source[AesKeySize]; /* Seed for keyblob MAC key derivation. */
|
||||
u8 tsec_root_kek[AesKeySize]; /* Used to generate TSEC root keys. */
|
||||
u8 package1_mac_kek[AesKeySize]; /* Used to generate Package1 MAC keys. */
|
||||
u8 package1_kek[AesKeySize]; /* Used to generate Package1 keys. */
|
||||
u8 tsec_auth_signatures[pkg1::KeyGeneration_Max][AesKeySize]; /* Auth signatures, seeds for tsec root key/package1 mac kek/package1 key on 6.2.0+. */
|
||||
u8 tsec_root_keys[pkg1::KeyGeneration_Max][AesKeySize]; /* Key for master kek decryption, from TSEC firmware on 6.2.0+. */
|
||||
u8 master_kek_sources[pkg1::KeyGeneration_Max][AesKeySize]; /* Seeds for firmware master keks. */
|
||||
u8 mariko_master_kek_sources[pkg1::KeyGeneration_Max][AesKeySize]; /* Seeds for firmware master keks (Mariko). */
|
||||
u8 master_keks[pkg1::KeyGeneration_Max][AesKeySize]; /* Firmware master keks, stored in keyblob prior to 6.2.0. */
|
||||
u8 master_key_source[AesKeySize]; /* Seed for master key derivation. */
|
||||
u8 master_keys[pkg1::KeyGeneration_Max][AesKeySize]; /* Firmware master keys. */
|
||||
u8 package1_mac_keys[pkg1::KeyGeneration_Max][AesKeySize]; /* Package1 MAC keys. */
|
||||
u8 package1_keys[pkg1::KeyGeneration_Max][AesKeySize]; /* Package1 keys. */
|
||||
u8 package2_keys[pkg1::KeyGeneration_Max][AesKeySize]; /* Package2 keys. */
|
||||
u8 package2_key_source[AesKeySize]; /* Seed for Package2 key. */
|
||||
u8 per_console_key_source[AesKeySize]; /* Seed for Device key. */
|
||||
u8 aes_kek_generation_source[AesKeySize]; /* Seed for GenerateAesKek, usecase + generation 0. */
|
||||
u8 aes_key_generation_source[AesKeySize]; /* Seed for GenerateAesKey. */
|
||||
u8 key_area_key_application_source[AesKeySize]; /* Seed for kaek 0. */
|
||||
u8 key_area_key_ocean_source[AesKeySize]; /* Seed for kaek 1. */
|
||||
u8 key_area_key_system_source[AesKeySize]; /* Seed for kaek 2. */
|
||||
u8 titlekek_source[AesKeySize]; /* Seed for titlekeks. */
|
||||
u8 header_kek_source[AesKeySize]; /* Seed for header kek. */
|
||||
u8 sd_card_kek_source[AesKeySize]; /* Seed for SD card kek. */
|
||||
u8 sd_card_nca_key_source[0x20]; /* Seed for SD card encryption keys. */
|
||||
u8 sd_card_save_key_source[0x20]; /* Seed for SD card encryption keys. */
|
||||
u8 save_mac_kek_source[AesKeySize]; /* Seed for save kek. */
|
||||
u8 save_mac_key_source[AesKeySize]; /* Seed for save key. */
|
||||
u8 header_key_source[pkg1::KeyGeneration_Max]; /* Seed for NCA header key. */
|
||||
u8 header_key[pkg1::KeyGeneration_Max]; /* NCA header key. */
|
||||
u8 titlekeks[pkg1::KeyGeneration_Max][AesKeySize]; /* Title key encryption keys. */
|
||||
u8 key_area_keys[pkg1::KeyGeneration_Max][3][AesKeySize]; /* Key area encryption keys. */
|
||||
u8 xci_header_key[AesKeySize]; /* Key for XCI partially encrypted header. */
|
||||
u8 xci_t1_titlekey_keks[gc::impl::GcCrypto::GcTitleKeyKekIndexMax][AesKeySize]; /* Kek used to decrypt XCI T1 title keys. */
|
||||
u8 save_mac_key[AesKeySize]; /* Key used to sign savedata. */
|
||||
u8 sd_card_keys[2][pkg1::KeyGeneration_Max];
|
||||
u8 nca_hdr_fixed_key_moduli[2][RsaKeySize]; /* NCA header fixed key RSA pubk. */
|
||||
u8 acid_fixed_key_moduli[2][RsaKeySize]; /* ACID fixed key RSA pubk. */
|
||||
u8 package2_fixed_key_modulus[RsaKeySize]; /* Package2 Header RSA pubk. */
|
||||
u8 nca_hdr_fixed_key_moduli[2][RsaKeySize]; /* NCA header fixed key RSA pubk. */
|
||||
u8 acid_fixed_key_moduli[2][RsaKeySize]; /* ACID fixed key RSA pubk. */
|
||||
u8 package2_fixed_key_modulus[RsaKeySize]; /* Package2 Header RSA pubk. */
|
||||
};
|
||||
|
||||
constinit KeySet g_keyset{};
|
||||
@ -334,6 +335,10 @@ namespace ams::hactool {
|
||||
}
|
||||
}
|
||||
|
||||
for (int gen = 0; gen < static_cast<int>(gc::impl::GcCrypto::GcTitleKeyKekIndexMax); ++gen) {
|
||||
TEST_KEY_WITH_GEN(xci_t1_titlekey_kek, gen);
|
||||
}
|
||||
|
||||
if (!matched_key) {
|
||||
fprintf(stderr, "[Warning]: Failed to match key \"%s\", (value \"%s\")\n", key, value);
|
||||
}
|
||||
@ -505,6 +510,9 @@ namespace ams::hactool {
|
||||
if (const auto res = gc::impl::EmbeddedDataHolder::SetLibraryEmbeddedKeys(m_options.dev); R_FAILED(res)) {
|
||||
fprintf(stderr, "[Warning]: Failed to preset internal keys for gamecard library (2%03d-%04d). Is master_key_04 correct?\n", res.GetModule(), res.GetDescription());
|
||||
}
|
||||
for (size_t i = 0; i < gc::impl::GcCrypto::GcTitleKeyKekIndexMax; ++i) {
|
||||
gc::impl::EmbeddedDataHolder::SetLibraryTitleKeyKek(i, g_keyset.xci_t1_titlekey_keks[i], sizeof(g_keyset.xci_t1_titlekey_keks[i]));
|
||||
}
|
||||
|
||||
/* Load titlekeys. */
|
||||
if (m_options.titlekey_path != nullptr) {
|
||||
|
@ -24,6 +24,8 @@ namespace ams::hactool {
|
||||
|
||||
constexpr size_t CardInitialDataRegionSize = 0x1000;
|
||||
|
||||
constexpr size_t CardPageSize = 0x200;
|
||||
|
||||
struct XciBodyHeader {
|
||||
gc::impl::CardHeaderWithSignature card_header;
|
||||
gc::impl::CardHeaderWithSignature card_header_for_sign2;
|
||||
@ -48,6 +50,7 @@ namespace ams::hactool {
|
||||
}
|
||||
|
||||
/* Default to treating the xci as though it has no key area. */
|
||||
fprintf(stderr, "[Warning]: Game card is missing key area/initial data header. Re-dump?\n");
|
||||
*out_key_area = nullptr;
|
||||
*out_body = std::make_shared<fs::SubStorage>(storage, 0, storage_size);
|
||||
R_SUCCEED();
|
||||
@ -128,7 +131,7 @@ namespace ams::hactool {
|
||||
R_ABORT_UNLESS(gc::impl::GcCrypto::DecryptCardHeader(std::addressof(ctx->card_data.decrypted_header.data), sizeof(ctx->card_data.decrypted_header.data)));
|
||||
|
||||
/* Set up the headers for ca10 sign2. */
|
||||
if (ctx->card_data.header.data.flags & fs::GameCardAttribute_HasHeaderSign2Flag) {
|
||||
if (ctx->card_data.header.data.flags & fs::GameCardAttribute_HasCa10CertificateFlag) {
|
||||
ctx->card_data.ca10_certificate = body_header.ca10_cert;
|
||||
ctx->card_data.header_for_hash = body_header.card_header_for_sign2;
|
||||
ctx->card_data.decrypted_header_for_hash = ctx->card_data.header_for_hash;
|
||||
@ -140,13 +143,13 @@ namespace ams::hactool {
|
||||
}
|
||||
|
||||
/* Read the T1 cert. */
|
||||
R_ABORT_UNLESS(ctx->body_storage->Read(0x7000, std::addressof(ctx->card_data.t1_certificate), sizeof(ctx->card_data.t1_certificate)));
|
||||
R_ABORT_UNLESS(ctx->body_storage->Read(CardPageSize * 0x38, std::addressof(ctx->card_data.t1_certificate), sizeof(ctx->card_data.t1_certificate)));
|
||||
|
||||
/* Parse the root partition. */
|
||||
{
|
||||
/* Create the root partition storage. */
|
||||
using AlignmentMatchingStorageForGameCard = fssystem::AlignmentMatchingStorageInBulkRead<1>;
|
||||
auto aligned_storage = std::make_shared<AlignmentMatchingStorageForGameCard>(ctx->body_storage, 0x200);
|
||||
auto aligned_storage = std::make_shared<AlignmentMatchingStorageForGameCard>(ctx->body_storage, CardPageSize);
|
||||
|
||||
/* Get the size of the body. */
|
||||
s64 body_size;
|
||||
@ -222,21 +225,91 @@ namespace ams::hactool {
|
||||
void Processor::PrintAsXci(ProcessAsXciContext &ctx) {
|
||||
auto _ = this->PrintHeader("XCI");
|
||||
|
||||
/* TODO: Print correct data instead of the secure partition's contents. */
|
||||
if (ctx.secure_partition.fs != nullptr) {
|
||||
PrintDirectory(ctx.secure_partition.fs, "secure:", "/");
|
||||
/* Print the initial data. */
|
||||
if (ctx.key_area_storage != nullptr) {
|
||||
auto _ = this->PrintHeader("Initial Data");
|
||||
|
||||
if (m_options.verify) {
|
||||
this->PrintBytesWithVerify("Package Id", std::memcmp(ctx.card_data.initial_data.payload.package_id, ctx.card_data.decrypted_header.data.package_id, sizeof(ctx.card_data.initial_data.payload.package_id)) == 0, ctx.card_data.initial_data.payload.package_id, sizeof(ctx.card_data.initial_data.payload.package_id));
|
||||
} else {
|
||||
this->PrintBytes("Package Id", ctx.card_data.initial_data.payload.package_id, sizeof(ctx.card_data.initial_data.payload.package_id));
|
||||
}
|
||||
|
||||
this->PrintBytes("Encrypted Title Key", ctx.card_data.initial_data.payload.auth_data, sizeof(ctx.card_data.initial_data.payload.auth_data));
|
||||
|
||||
const auto kek_idx = ctx.card_data.decrypted_header.data.key_index.Get<gc::impl::CardHeaderKeyIndex::TitleKeyDecIndex>();
|
||||
u8 key[sizeof(ctx.card_data.initial_data.payload.auth_data)];
|
||||
if (R_SUCCEEDED(gc::impl::GcCrypto::DecryptCardInitialData(key, sizeof(key), std::addressof(ctx.card_data.initial_data), sizeof(ctx.card_data.initial_data), kek_idx))) {
|
||||
this->PrintBytes("Decrypted Title Key", key, sizeof(key));
|
||||
} else {
|
||||
printf("%08x\n", gc::impl::GcCrypto::DecryptCardInitialData(key, sizeof(key), std::addressof(ctx.card_data.initial_data), sizeof(ctx.card_data.initial_data), kek_idx).GetValue());
|
||||
}
|
||||
} else {
|
||||
this->PrintString("Initial Data", "Missing/Not Dumped");
|
||||
}
|
||||
|
||||
/* TODO: Non-debug prints. */
|
||||
if (ctx.key_area_storage != nullptr) {
|
||||
this->PrintBytes("Initial Data", std::addressof(ctx.card_data.initial_data), sizeof(ctx.card_data.initial_data));
|
||||
}
|
||||
this->PrintBytes("Encrypted Header", std::addressof(ctx.card_data.header), sizeof(ctx.card_data.header));
|
||||
this->PrintBytes("Decrypted Header", std::addressof(ctx.card_data.decrypted_header), sizeof(ctx.card_data.decrypted_header));
|
||||
this->PrintBytes("Encrypted Header For Hash", std::addressof(ctx.card_data.header_for_hash), sizeof(ctx.card_data.header_for_hash));
|
||||
this->PrintBytes("Decrypted Header For Hash", std::addressof(ctx.card_data.decrypted_header_for_hash), sizeof(ctx.card_data.decrypted_header_for_hash));
|
||||
this->PrintBytes("T1 Card Cert", std::addressof(ctx.card_data.t1_certificate), sizeof(ctx.card_data.t1_certificate));
|
||||
this->PrintBytes("CA10 Cert", std::addressof(ctx.card_data.ca10_certificate), sizeof(ctx.card_data.ca10_certificate));
|
||||
/* Declare helper for printing a card header. */
|
||||
auto PrintCardHeader = [&](const char *header_name, const gc::impl::CardHeaderWithSignature &header, const void *modulus) {
|
||||
auto _ = this->PrintHeader(header_name);
|
||||
|
||||
/* Print the magic. */
|
||||
this->PrintMagic(header.data.magic);
|
||||
|
||||
/* Print the signature. */
|
||||
if (m_options.verify) {
|
||||
const bool signature_valid = R_SUCCEEDED(gc::impl::GcCrypto::VerifyCardHeader(std::addressof(header), sizeof(header), modulus, crypto::Rsa2048Pkcs1Sha256Verifier::ModulusSize));
|
||||
this->PrintBytesWithVerify("Signature", signature_valid, header.signature, sizeof(header.signature));
|
||||
} else {
|
||||
this->PrintBytes("Signature", header.signature, sizeof(header.signature));
|
||||
}
|
||||
|
||||
this->PrintBytes("Package Id", header.data.package_id, sizeof(header.data.package_id));
|
||||
|
||||
this->PrintString("Memory Capacity", fs::impl::IdString().ToString(static_cast<gc::impl::MemoryCapacity>(header.data.rom_size)));
|
||||
this->PrintHex12("Rom Area Start", static_cast<u64>(header.data.rom_area_start_page) * CardPageSize);
|
||||
this->PrintHex12("Backup Area Start", static_cast<u64>(header.data.backup_area_start_page) * CardPageSize);
|
||||
this->PrintHex12("Valid Data End", static_cast<u64>(header.data.valid_data_end_page) * CardPageSize);
|
||||
this->PrintHex12("Limit Area", static_cast<u64>(header.data.lim_area_page) * CardPageSize);
|
||||
this->PrintString("Kek Index", fs::impl::IdString().ToString(header.data.key_index.Get<gc::impl::CardHeaderKeyIndex::KekIndex>()));
|
||||
this->PrintInteger("Title Key Dec Index", header.data.key_index.Get<gc::impl::CardHeaderKeyIndex::TitleKeyDecIndex>());
|
||||
{
|
||||
auto _ = this->PrintHeader("Flags");
|
||||
this->PrintBool("Auto Boot", header.data.flags & fs::GameCardAttribute_AutoBootFlag);
|
||||
this->PrintBool("History Erase", header.data.flags & fs::GameCardAttribute_HistoryEraseFlag);
|
||||
this->PrintBool("Repair Tool", header.data.flags & fs::GameCardAttribute_RepairToolFlag);
|
||||
this->PrintBool("Different Region Cup to Terra Device", header.data.flags & fs::GameCardAttribute_DifferentRegionCupToTerraDeviceFlag);
|
||||
this->PrintBool("Different Region Cup to Global Device", header.data.flags & fs::GameCardAttribute_DifferentRegionCupToGlobalDeviceFlag);
|
||||
this->PrintBool("Has Ca10 Certificate", header.data.flags & fs::GameCardAttribute_HasCa10CertificateFlag);
|
||||
}
|
||||
this->PrintString("Sel Sec", fs::impl::IdString().ToString(static_cast<gc::impl::SelSec>(header.data.sel_sec)));
|
||||
this->PrintInteger("Sel T1 Key", header.data.sel_t1_key);
|
||||
this->PrintInteger("Sel Key", header.data.sel_key);
|
||||
this->PrintBytes("Initial Data Hash", header.data.initial_data_hash, sizeof(header.data.initial_data_hash));
|
||||
this->PrintBytes("Partition Header Hash", header.data.partition_fs_header_hash, sizeof(header.data.partition_fs_header_hash));
|
||||
this->PrintBytes("Encrypted Data Iv", header.data.iv, sizeof(header.data.iv));
|
||||
{
|
||||
auto _ = this->PrintHeader("Card Info");
|
||||
|
||||
auto &enc_data = header.data.encrypted_data;
|
||||
|
||||
this->PrintString("Card Fw Version", fs::impl::IdString().ToString(static_cast<gc::impl::FwVersion>(enc_data.fw_version[0])));
|
||||
this->PrintString("Clock Rate", fs::impl::IdString().ToString(static_cast<gc::impl::AccessControl1ClockRate>(enc_data.acc_ctrl_1)));
|
||||
this->PrintInteger("Wait1 Time Read", enc_data.wait_1_time_read);
|
||||
this->PrintInteger("Wait2 Time Read", enc_data.wait_2_time_read);
|
||||
this->PrintInteger("Wait1 Time Write", enc_data.wait_1_time_write);
|
||||
this->PrintInteger("Wait2 Time Write", enc_data.wait_2_time_write);
|
||||
this->PrintHex8("Fw Mode", enc_data.fw_mode);
|
||||
this->PrintString("Compatibility Type", fs::impl::IdString().ToString(static_cast<fs::GameCardCompatibilityType>(enc_data.compatibility_type)));
|
||||
this->PrintFormat("Cup Version", "%" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32 " (%" PRIu32")", (enc_data.cup_version >> 26) & 0x3F, (enc_data.cup_version >> 20) & 0x3F, (enc_data.cup_version >> 16) & 0x3F, (enc_data.cup_version >> 0) & 0xFFFF, enc_data.cup_version);
|
||||
this->PrintId64("Cup Id", enc_data.cup_id);
|
||||
this->PrintBytes("Upp Hash", enc_data.upp_hash, sizeof(enc_data.upp_hash));
|
||||
}
|
||||
};
|
||||
|
||||
/* Print the main card header. */
|
||||
PrintCardHeader("Main Header", ctx.card_data.decrypted_header, nullptr);
|
||||
|
||||
/* TODO: Print partitions. */
|
||||
|
||||
AMS_UNUSED(ctx);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user