diff options
| -rw-r--r-- | src/core/hle/service/mii/mii_manager.cpp | 35 | ||||
| -rw-r--r-- | src/core/hle/service/mii/mii_manager.h | 7 | ||||
| -rw-r--r-- | src/core/hle/service/mii/types.h | 60 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/amiibo_crypto.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp_device.cpp | 89 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp_device.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp_types.h | 10 | 
7 files changed, 157 insertions, 52 deletions
| diff --git a/src/core/hle/service/mii/mii_manager.cpp b/src/core/hle/service/mii/mii_manager.cpp index 3a2fe938f..c920650f5 100644 --- a/src/core/hle/service/mii/mii_manager.cpp +++ b/src/core/hle/service/mii/mii_manager.cpp @@ -510,7 +510,7 @@ CharInfo MiiManager::ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const {      return mii;  } -Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const { +Ver3StoreData MiiManager::BuildFromStoreData(const CharInfo& mii) const {      Service::Mii::MiiManager manager;      Ver3StoreData mii_v3{}; @@ -534,16 +534,13 @@ Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const {      mii_v3.region_information.character_set.Assign(mii.font_region);      mii_v3.appearance_bits1.face_shape.Assign(mii.faceline_type); -    mii_v3.appearance_bits1.skin_color.Assign(mii.faceline_color);      mii_v3.appearance_bits2.wrinkles.Assign(mii.faceline_wrinkle);      mii_v3.appearance_bits2.makeup.Assign(mii.faceline_make);      mii_v3.hair_style = mii.hair_type; -    mii_v3.appearance_bits3.hair_color.Assign(mii.hair_color);      mii_v3.appearance_bits3.flip_hair.Assign(mii.hair_flip);      mii_v3.appearance_bits4.eye_type.Assign(mii.eye_type); -    mii_v3.appearance_bits4.eye_color.Assign(mii.eye_color);      mii_v3.appearance_bits4.eye_scale.Assign(mii.eye_scale);      mii_v3.appearance_bits4.eye_vertical_stretch.Assign(mii.eye_aspect);      mii_v3.appearance_bits4.eye_rotation.Assign(mii.eye_rotate); @@ -551,7 +548,6 @@ Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const {      mii_v3.appearance_bits4.eye_y_position.Assign(mii.eye_y);      mii_v3.appearance_bits5.eyebrow_style.Assign(mii.eyebrow_type); -    mii_v3.appearance_bits5.eyebrow_color.Assign(mii.eyebrow_color);      mii_v3.appearance_bits5.eyebrow_scale.Assign(mii.eyebrow_scale);      mii_v3.appearance_bits5.eyebrow_yscale.Assign(mii.eyebrow_aspect);      mii_v3.appearance_bits5.eyebrow_rotation.Assign(mii.eyebrow_rotate); @@ -563,7 +559,6 @@ Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const {      mii_v3.appearance_bits6.nose_y_position.Assign(mii.nose_y);      mii_v3.appearance_bits7.mouth_type.Assign(mii.mouth_type); -    mii_v3.appearance_bits7.mouth_color.Assign(mii.mouth_color);      mii_v3.appearance_bits7.mouth_scale.Assign(mii.mouth_scale);      mii_v3.appearance_bits7.mouth_horizontal_stretch.Assign(mii.mouth_aspect);      mii_v3.appearance_bits8.mouth_y_position.Assign(mii.mouth_y); @@ -573,10 +568,7 @@ Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const {      mii_v3.appearance_bits9.mustache_y_position.Assign(mii.mustache_y);      mii_v3.appearance_bits9.bear_type.Assign(mii.beard_type); -    mii_v3.appearance_bits9.facial_hair_color.Assign(mii.beard_color); -    mii_v3.appearance_bits10.glasses_type.Assign(mii.glasses_type); -    mii_v3.appearance_bits10.glasses_color.Assign(mii.glasses_color);      mii_v3.appearance_bits10.glasses_scale.Assign(mii.glasses_scale);      mii_v3.appearance_bits10.glasses_y_position.Assign(mii.glasses_y); @@ -585,11 +577,36 @@ Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const {      mii_v3.appearance_bits11.mole_x_position.Assign(mii.mole_x);      mii_v3.appearance_bits11.mole_y_position.Assign(mii.mole_y); +    // These types are converted to V3 from a table +    mii_v3.appearance_bits1.skin_color.Assign(Ver3FacelineColorTable[mii.faceline_color]); +    mii_v3.appearance_bits3.hair_color.Assign(Ver3HairColorTable[mii.hair_color]); +    mii_v3.appearance_bits4.eye_color.Assign(Ver3EyeColorTable[mii.eye_color]); +    mii_v3.appearance_bits5.eyebrow_color.Assign(Ver3HairColorTable[mii.eyebrow_color]); +    mii_v3.appearance_bits7.mouth_color.Assign(Ver3MouthlineColorTable[mii.mouth_color]); +    mii_v3.appearance_bits9.facial_hair_color.Assign(Ver3HairColorTable[mii.beard_color]); +    mii_v3.appearance_bits10.glasses_color.Assign(Ver3GlassColorTable[mii.glasses_color]); +    mii_v3.appearance_bits10.glasses_type.Assign(Ver3GlassTypeTable[mii.glasses_type]); + +    mii_v3.crc = GenerateCrc16(&mii_v3, sizeof(Ver3StoreData) - sizeof(u16)); +      // TODO: Validate mii_v3 data      return mii_v3;  } +NfpStoreDataExtension MiiManager::SetFromStoreData(const CharInfo& mii) const { +    return { +        .faceline_color = static_cast<u8>(mii.faceline_color & 0xf), +        .hair_color = static_cast<u8>(mii.hair_color & 0x7f), +        .eye_color = static_cast<u8>(mii.eyebrow_color & 0x7f), +        .eyebrow_color = static_cast<u8>(mii.eyebrow_color & 0x7f), +        .mouth_color = static_cast<u8>(mii.mouth_color & 0x7f), +        .beard_color = static_cast<u8>(mii.beard_color & 0x7f), +        .glass_color = static_cast<u8>(mii.glasses_color & 0x7f), +        .glass_type = static_cast<u8>(mii.glasses_type & 0x1f), +    }; +} +  bool MiiManager::ValidateV3Info(const Ver3StoreData& mii_v3) const {      bool is_valid = mii_v3.version == 0 || mii_v3.version == 3; diff --git a/src/core/hle/service/mii/mii_manager.h b/src/core/hle/service/mii/mii_manager.h index 83ad3d343..5525fcd1c 100644 --- a/src/core/hle/service/mii/mii_manager.h +++ b/src/core/hle/service/mii/mii_manager.h @@ -23,11 +23,16 @@ public:      CharInfo BuildRandom(Age age, Gender gender, Race race);      CharInfo BuildDefault(std::size_t index);      CharInfo ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const; -    Ver3StoreData ConvertCharInfoToV3(const CharInfo& mii) const;      bool ValidateV3Info(const Ver3StoreData& mii_v3) const;      ResultVal<std::vector<MiiInfoElement>> GetDefault(SourceFlag source_flag);      Result GetIndex(const CharInfo& info, u32& index); +    // This is nn::mii::detail::Ver::StoreDataRaw::BuildFromStoreData +    Ver3StoreData BuildFromStoreData(const CharInfo& mii) const; + +    // This is nn::mii::detail::NfpStoreDataExtentionRaw::SetFromStoreData +    NfpStoreDataExtension SetFromStoreData(const CharInfo& mii) const; +  private:      const Common::UUID user_id{};      u64 update_counter{}; diff --git a/src/core/hle/service/mii/types.h b/src/core/hle/service/mii/types.h index 9e3247397..c48d08d79 100644 --- a/src/core/hle/service/mii/types.h +++ b/src/core/hle/service/mii/types.h @@ -365,10 +365,68 @@ struct Ver3StoreData {      } appearance_bits11;      std::array<u16_le, 0xA> author_name; -    INSERT_PADDING_BYTES(0x4); +    INSERT_PADDING_BYTES(0x2); +    u16_be crc;  };  static_assert(sizeof(Ver3StoreData) == 0x60, "Ver3StoreData is an invalid size"); +struct NfpStoreDataExtension { +    u8 faceline_color; +    u8 hair_color; +    u8 eye_color; +    u8 eyebrow_color; +    u8 mouth_color; +    u8 beard_color; +    u8 glass_color; +    u8 glass_type; +}; +static_assert(sizeof(NfpStoreDataExtension) == 0x8, "NfpStoreDataExtension is an invalid size"); + +constexpr std::array<u8, 0x10> Ver3FacelineColorTable{ +    0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x0, 0x1, 0x5, 0x5, +}; + +constexpr std::array<u8, 100> Ver3HairColorTable{ +    0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x0, 0x4, 0x3, 0x5, 0x4, 0x4, 0x6, 0x2, 0x0, +    0x6, 0x4, 0x3, 0x2, 0x2, 0x7, 0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, +    0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x0, 0x0, 0x4, +    0x4, 0x4, 0x4, 0x4, 0x4, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x5, 0x5, 0x5, +    0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x5, 0x7, 0x5, 0x7, 0x7, 0x7, 0x7, 0x7, 0x6, 0x7, +    0x7, 0x7, 0x7, 0x7, 0x3, 0x7, 0x7, 0x7, 0x7, 0x7, 0x0, 0x4, 0x4, 0x4, 0x4, +}; + +constexpr std::array<u8, 100> Ver3EyeColorTable{ +    0x0, 0x2, 0x2, 0x2, 0x1, 0x3, 0x2, 0x3, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x2, 0x2, 0x4, +    0x2, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, +    0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x1, 0x0, 0x4, 0x4, +    0x4, 0x4, 0x4, 0x4, 0x4, 0x0, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, +    0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x2, 0x2, +    0x3, 0x3, 0x3, 0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, +}; + +constexpr std::array<u8, 100> Ver3MouthlineColorTable{ +    0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x3, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x1, 0x4, +    0x4, 0x4, 0x0, 0x1, 0x2, 0x3, 0x4, 0x4, 0x2, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x1, 0x4, +    0x4, 0x2, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x3, 0x3, 0x3, 0x4, 0x4, 0x4, +    0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x4, 0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x4, +    0x4, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, +    0x3, 0x3, 0x3, 0x3, 0x4, 0x0, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, 0x3, 0x3, +}; + +constexpr std::array<u8, 100> Ver3GlassColorTable{ +    0x0, 0x1, 0x1, 0x1, 0x5, 0x1, 0x1, 0x4, 0x0, 0x5, 0x1, 0x1, 0x3, 0x5, 0x1, 0x2, 0x3, +    0x4, 0x5, 0x4, 0x2, 0x2, 0x4, 0x4, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, +    0x2, 0x2, 0x2, 0x2, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, +    0x3, 0x3, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x0, 0x5, 0x5, +    0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x1, 0x4, +    0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, +}; + +constexpr std::array<u8, 20> Ver3GlassTypeTable{ +    0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x1, +    0x2, 0x1, 0x3, 0x7, 0x7, 0x6, 0x7, 0x8, 0x7, 0x7, +}; +  struct MiiStoreData {      using Name = std::array<char16_t, 10>; diff --git a/src/core/hle/service/nfp/amiibo_crypto.cpp b/src/core/hle/service/nfp/amiibo_crypto.cpp index ad73edbda..bba862fb2 100644 --- a/src/core/hle/service/nfp/amiibo_crypto.cpp +++ b/src/core/hle/service/nfp/amiibo_crypto.cpp @@ -88,8 +88,9 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) {      encoded_data.application_area_id = nfc_data.user_memory.application_area_id;      encoded_data.application_id_byte = nfc_data.user_memory.application_id_byte;      encoded_data.unknown = nfc_data.user_memory.unknown; +    encoded_data.mii_extension = nfc_data.user_memory.mii_extension;      encoded_data.unknown2 = nfc_data.user_memory.unknown2; -    encoded_data.application_area_crc = nfc_data.user_memory.application_area_crc; +    encoded_data.register_info_crc = nfc_data.user_memory.register_info_crc;      encoded_data.application_area = nfc_data.user_memory.application_area;      encoded_data.hmac_tag = nfc_data.user_memory.hmac_tag;      encoded_data.lock_bytes = nfc_data.uuid.lock_bytes; @@ -122,8 +123,9 @@ EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) {      nfc_data.user_memory.application_area_id = encoded_data.application_area_id;      nfc_data.user_memory.application_id_byte = encoded_data.application_id_byte;      nfc_data.user_memory.unknown = encoded_data.unknown; +    nfc_data.user_memory.mii_extension = encoded_data.mii_extension;      nfc_data.user_memory.unknown2 = encoded_data.unknown2; -    nfc_data.user_memory.application_area_crc = encoded_data.application_area_crc; +    nfc_data.user_memory.register_info_crc = encoded_data.register_info_crc;      nfc_data.user_memory.application_area = encoded_data.application_area;      nfc_data.user_memory.hmac_tag = encoded_data.hmac_tag;      nfc_data.user_memory.model_info = encoded_data.model_info; diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfp/nfp_device.cpp index ddff90d6a..268337d2e 100644 --- a/src/core/hle/service/nfp/nfp_device.cpp +++ b/src/core/hle/service/nfp/nfp_device.cpp @@ -3,6 +3,17 @@  #include <array> +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4701) // Potentially uninitialized local variable 'result' used +#endif + +#include <boost/crc.hpp> + +#ifdef _MSC_VER +#pragma warning(pop) +#endif +  #include "common/input.h"  #include "common/logging/log.h"  #include "common/string_util.h" @@ -448,7 +459,7 @@ Result NfpDevice::DeleteRegisterInfo() {      rng.GenerateRandomBytes(&tag_data.unknown, sizeof(u8));      rng.GenerateRandomBytes(&tag_data.unknown2[0], sizeof(u32));      rng.GenerateRandomBytes(&tag_data.unknown2[1], sizeof(u32)); -    rng.GenerateRandomBytes(&tag_data.application_area_crc, sizeof(u32)); +    rng.GenerateRandomBytes(&tag_data.register_info_crc, sizeof(u32));      rng.GenerateRandomBytes(&tag_data.settings.init_date, sizeof(u32));      tag_data.settings.settings.font_region.Assign(0);      tag_data.settings.settings.amiibo_initialized.Assign(0); @@ -471,6 +482,7 @@ Result NfpDevice::SetRegisterInfoPrivate(const AmiiboName& amiibo_name) {      }      Service::Mii::MiiManager manager; +    const auto mii = manager.BuildDefault(0);      auto& settings = tag_data.settings;      if (tag_data.settings.settings.amiibo_initialized == 0) { @@ -479,16 +491,15 @@ Result NfpDevice::SetRegisterInfoPrivate(const AmiiboName& amiibo_name) {      }      SetAmiiboName(settings, amiibo_name); -    tag_data.owner_mii = manager.ConvertCharInfoToV3(manager.BuildDefault(0)); +    tag_data.owner_mii = manager.BuildFromStoreData(mii); +    tag_data.mii_extension = manager.SetFromStoreData(mii);      tag_data.unknown = 0; -    tag_data.unknown2[6] = 0; +    tag_data.unknown2 = {};      settings.country_code_id = 0;      settings.settings.font_region.Assign(0);      settings.settings.amiibo_initialized.Assign(1); -    // TODO: this is a mix of tag.file input -    std::array<u8, 0x7e> unknown_input{}; -    tag_data.application_area_crc = CalculateCrc(unknown_input); +    UpdateRegisterInfoCrc();      return Flush();  } @@ -685,6 +696,11 @@ Result NfpDevice::RecreateApplicationArea(u32 access_id, std::span<const u8> dat          return WrongDeviceState;      } +    if (is_app_area_open) { +        LOG_ERROR(Service_NFP, "Application area is open"); +        return WrongDeviceState; +    } +      if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {          LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);          return WrongDeviceState; @@ -715,10 +731,9 @@ Result NfpDevice::RecreateApplicationArea(u32 access_id, std::span<const u8> dat      tag_data.settings.settings.appdata_initialized.Assign(1);      tag_data.application_area_id = access_id;      tag_data.unknown = {}; +    tag_data.unknown2 = {}; -    // TODO: this is a mix of tag_data input -    std::array<u8, 0x7e> unknown_input{}; -    tag_data.application_area_crc = CalculateCrc(unknown_input); +    UpdateRegisterInfoCrc();      return Flush();  } @@ -752,6 +767,10 @@ Result NfpDevice::DeleteApplicationArea() {      rng.GenerateRandomBytes(&tag_data.application_id_byte, sizeof(u8));      tag_data.settings.settings.appdata_initialized.Assign(0);      tag_data.unknown = {}; +    tag_data.unknown2 = {}; +    is_app_area_open = false; + +    UpdateRegisterInfoCrc();      return Flush();  } @@ -835,32 +854,34 @@ void NfpDevice::UpdateSettingsCrc() {      // TODO: this reads data from a global, find what it is      std::array<u8, 8> unknown_input{}; -    settings.crc = CalculateCrc(unknown_input); -} - -u32 NfpDevice::CalculateCrc(std::span<const u8> data) { -    constexpr u32 magic = 0xedb88320; -    u32 crc = 0xffffffff; - -    if (data.size() == 0) { -        return 0; -    } - -    for (u8 input : data) { -        u32 temp = (crc ^ input) >> 1; -        if (((crc ^ input) & 1) != 0) { -            temp = temp ^ magic; -        } - -        for (std::size_t step = 0; step < 7; ++step) { -            crc = temp >> 1; -            if ((temp & 1) != 0) { -                crc = temp >> 1 ^ magic; -            } -        } -    } +    boost::crc_32_type crc; +    crc.process_bytes(&unknown_input, sizeof(unknown_input)); +    settings.crc = crc.checksum(); +} + +void NfpDevice::UpdateRegisterInfoCrc() { +#pragma pack(push, 1) +    struct CrcData { +        Mii::Ver3StoreData mii; +        u8 application_id_byte; +        u8 unknown; +        Mii::NfpStoreDataExtension mii_extension; +        std::array<u32, 0x5> unknown2; +    }; +    static_assert(sizeof(CrcData) == 0x7e, "CrcData is an invalid size"); +#pragma pack(pop) + +    const CrcData crc_data{ +        .mii = tag_data.owner_mii, +        .application_id_byte = tag_data.application_id_byte, +        .unknown = tag_data.unknown, +        .mii_extension = tag_data.mii_extension, +        .unknown2 = tag_data.unknown2, +    }; -    return ~crc; +    boost::crc_32_type crc; +    crc.process_bytes(&crc_data, sizeof(CrcData)); +    tag_data.register_info_crc = crc.checksum();  }  } // namespace Service::NFP diff --git a/src/core/hle/service/nfp/nfp_device.h b/src/core/hle/service/nfp/nfp_device.h index 06386401d..8813df998 100644 --- a/src/core/hle/service/nfp/nfp_device.h +++ b/src/core/hle/service/nfp/nfp_device.h @@ -80,7 +80,7 @@ private:      AmiiboDate GetAmiiboDate(s64 posix_time) const;      u64 RemoveVersionByte(u64 application_id) const;      void UpdateSettingsCrc(); -    u32 CalculateCrc(std::span<const u8>); +    void UpdateRegisterInfoCrc();      bool is_controller_set{};      int callback_key; diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h index 142343d6e..b3599a513 100644 --- a/src/core/hle/service/nfp/nfp_types.h +++ b/src/core/hle/service/nfp/nfp_types.h @@ -259,8 +259,9 @@ struct EncryptedAmiiboFile {      u32_be application_area_id;            // Encrypted Game id      u8 application_id_byte;      u8 unknown; -    std::array<u32, 0x7> unknown2; -    u32_be application_area_crc; +    Service::Mii::NfpStoreDataExtension mii_extension; +    std::array<u32, 0x5> unknown2; +    u32_be register_info_crc;      ApplicationArea application_area; // Encrypted Game data  };  static_assert(sizeof(EncryptedAmiiboFile) == 0x1F8, "AmiiboFile is an invalid size"); @@ -280,8 +281,9 @@ struct NTAG215File {      u32_be application_area_id;      u8 application_id_byte;      u8 unknown; -    std::array<u32, 0x7> unknown2; -    u32_be application_area_crc; +    Service::Mii::NfpStoreDataExtension mii_extension; +    std::array<u32, 0x5> unknown2; +    u32_be register_info_crc;      ApplicationArea application_area; // Encrypted Game data      HashData hmac_tag;                // Hash      UniqueSerialNumber uid;           // Unique serial number | 
