diff options
| author | Narr the Reg <juangerman-13@hotmail.com> | 2022-02-08 14:09:30 -0600 | 
|---|---|---|
| committer | Narr the Reg <juangerman-13@hotmail.com> | 2022-02-08 14:09:30 -0600 | 
| commit | 29f9a454eb2597eb50db68c31cb655c51de72dae (patch) | |
| tree | 7a6972808c9f0d9d007f9ac17a5a068dd5771565 /src/core | |
| parent | 41b65d38fa57dcfefa9e944ef90c66bb5aa5d254 (diff) | |
nfp: Validate amiibo files
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/hle/service/nfp/nfp.cpp | 115 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp.h | 71 | 
2 files changed, 145 insertions, 41 deletions
| diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index 7f1fb3a71..1e91aa340 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -108,7 +108,7 @@ void IUser::StartDetection(Kernel::HLERequestContext& ctx) {      // TODO(german77): Loop through all interfaces      if (device_handle == nfp_interface.GetHandle()) { -        const auto result = nfp_interface.StartDetection(); +        const auto result = nfp_interface.StartDetection(nfp_protocol);          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(result);          return; @@ -209,7 +209,6 @@ void IUser::GetApplicationArea(Kernel::HLERequestContext& ctx) {      if (device_handle == nfp_interface.GetHandle()) {          std::vector<u8> data{};          const auto result = nfp_interface.GetApplicationArea(data); -          ctx.WriteBuffer(data);          IPC::ResponseBuilder rb{ctx, 3};          rb.Push(result); @@ -232,7 +231,6 @@ void IUser::SetApplicationArea(Kernel::HLERequestContext& ctx) {      // TODO(german77): Loop through all interfaces      if (device_handle == nfp_interface.GetHandle()) {          const auto result = nfp_interface.SetApplicationArea(data); -          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(result);          return; @@ -255,7 +253,6 @@ void IUser::CreateApplicationArea(Kernel::HLERequestContext& ctx) {      // TODO(german77): Loop through all interfaces      if (device_handle == nfp_interface.GetHandle()) {          const auto result = nfp_interface.CreateApplicationArea(access_id, data); -          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(result);          return; @@ -390,7 +387,7 @@ void IUser::AttachDeactivateEvent(Kernel::HLERequestContext& ctx) {  }  void IUser::GetState(Kernel::HLERequestContext& ctx) { -    LOG_INFO(Service_NFC, "called"); +    LOG_DEBUG(Service_NFC, "called");      IPC::ResponseBuilder rb{ctx, 3, 0};      rb.Push(ResultSuccess); @@ -400,7 +397,7 @@ void IUser::GetState(Kernel::HLERequestContext& ctx) {  void IUser::GetDeviceState(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx};      const auto device_handle{rp.Pop<u64>()}; -    LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); +    LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);      // TODO(german77): Loop through all interfaces      if (device_handle == nfp_interface.GetHandle()) { @@ -419,7 +416,7 @@ void IUser::GetDeviceState(Kernel::HLERequestContext& ctx) {  void IUser::GetNpadId(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx};      const auto device_handle{rp.Pop<u64>()}; -    LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); +    LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);      // TODO(german77): Loop through all interfaces      if (device_handle == nfp_interface.GetHandle()) { @@ -438,7 +435,7 @@ void IUser::GetNpadId(Kernel::HLERequestContext& ctx) {  void IUser::GetApplicationAreaSize(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx};      const auto device_handle{rp.Pop<u64>()}; -    LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); +    LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);      // TODO(german77): Loop through all interfaces      if (device_handle == nfp_interface.GetHandle()) { @@ -493,6 +490,11 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {      LOG_INFO(Service_NFP, "New Amiibo detected");      std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); + +    if (!IsAmiiboValid()) { +        return false; +    } +      device_state = DeviceState::TagFound;      activate_event->GetWritableEvent().Signal();      return true; @@ -501,13 +503,54 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {  void Module::Interface::CloseAmiibo() {      LOG_INFO(Service_NFP, "Remove amiibo");      device_state = DeviceState::TagRemoved; -    write_counter = 0;      is_application_area_initialized = false;      application_area_id = 0;      application_area_data.clear();      deactivate_event->GetWritableEvent().Signal();  } +bool Module::Interface::IsAmiiboValid() const { +    LOG_INFO(Service_NFP, "uuid_lock=0x{0:x}", amiibo.uuid_lock); +    LOG_INFO(Service_NFP, "compability_container=0x{0:x}", amiibo.compability_container); +    LOG_INFO(Service_NFP, "crypto_init=0x{0:x}", amiibo.crypto_init); +    LOG_INFO(Service_NFP, "write_count={}", amiibo.write_count); + +    LOG_INFO(Service_NFP, "character_id=0x{0:x}", amiibo.model_info.character_id); +    LOG_INFO(Service_NFP, "character_variant={}", amiibo.model_info.character_variant); +    LOG_INFO(Service_NFP, "amiibo_type={}", amiibo.model_info.amiibo_type); +    LOG_INFO(Service_NFP, "model_number=0x{0:x}", amiibo.model_info.model_number); +    LOG_INFO(Service_NFP, "series={}", amiibo.model_info.series); +    LOG_INFO(Service_NFP, "fixed_value=0x{0:x}", amiibo.model_info.fixed); + +    LOG_INFO(Service_NFP, "tag_dynamic_lock=0x{0:x}", amiibo.tag_dynamic_lock); +    LOG_INFO(Service_NFP, "tag_CFG0=0x{0:x}", amiibo.tag_CFG0); +    LOG_INFO(Service_NFP, "tag_CFG1=0x{0:x}", amiibo.tag_CFG1); + +    // Check against all know constants on an amiibo binary +    if (amiibo.uuid_lock != 0xE00F) { +        return false; +    } +    if (amiibo.compability_container != 0xEEFF10F1UL) { +        return false; +    } +    if ((amiibo.crypto_init & 0xFF) != 0xA5) { +        return false; +    } +    if (amiibo.model_info.fixed != 0x02) { +        return false; +    } +    if ((amiibo.tag_dynamic_lock & 0xFFFFFF) != 0x0F0001) { +        return false; +    } +    if (amiibo.tag_CFG0 != 0x04000000UL) { +        return false; +    } +    if (amiibo.tag_CFG1 != 0x5F) { +        return false; +    } +    return true; +} +  Kernel::KReadableEvent& Module::Interface::GetActivateEvent() const {      return activate_event->GetReadableEvent();  } @@ -522,13 +565,12 @@ void Module::Interface::Initialize() {  void Module::Interface::Finalize() {      device_state = DeviceState::Unaviable; -    write_counter = 0;      is_application_area_initialized = false;      application_area_id = 0;      application_area_data.clear();  } -ResultCode Module::Interface::StartDetection() { +ResultCode Module::Interface::StartDetection(s32 protocol_) {      auto npad_device = system.HIDCore().GetEmulatedController(npad_id);      // TODO(german77): Add callback for when nfc data is available @@ -536,6 +578,7 @@ ResultCode Module::Interface::StartDetection() {      if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) {          npad_device->SetPollingMode(Common::Input::PollingMode::NFC);          device_state = DeviceState::SearchingForTag; +        protocol = protocol_;          return ResultSuccess;      } @@ -589,8 +632,8 @@ ResultCode Module::Interface::GetTagInfo(TagInfo& tag_info) const {          tag_info = {              .uuid = amiibo.uuid,              .uuid_length = static_cast<u8>(amiibo.uuid.size()), -            .protocol = 0xFFFFFFFF, // TODO(ogniK): Figure out actual values -            .tag_type = 0xFFFFFFFF, +            .protocol = protocol, +            .tag_type = static_cast<u32>(amiibo.model_info.amiibo_type),          };          return ResultSuccess;      } @@ -610,7 +653,7 @@ ResultCode Module::Interface::GetCommonInfo(CommonInfo& common_info) const {          .last_write_year = 2022,          .last_write_month = 2,          .last_write_day = 7, -        .write_counter = write_counter, +        .write_counter = amiibo.write_count,          .version = 1,          .application_area_size = ApplicationAreaSize,      }; @@ -652,11 +695,11 @@ ResultCode Module::Interface::OpenApplicationArea(u32 access_id) {          LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);          return ErrCodes::WrongDeviceState;      } -    // if (AmiiboApplicationDataExist(access_id)) { -    //    application_area_data = LoadAmiiboApplicationData(access_id); -    //    application_area_id = access_id; -    //    is_application_area_initialized = true; -    // } +    if (AmiiboApplicationDataExist(access_id)) { +        application_area_data = LoadAmiiboApplicationData(access_id); +        application_area_id = access_id; +        is_application_area_initialized = true; +    }      if (!is_application_area_initialized) {          LOG_ERROR(Service_NFP, "Application area is not initialized");          return ErrCodes::ApplicationAreaIsNotInitialized; @@ -689,8 +732,7 @@ ResultCode Module::Interface::SetApplicationArea(const std::vector<u8>& data) {          return ErrCodes::ApplicationAreaIsNotInitialized;      }      application_area_data = data; -    write_counter++; -    // SaveAmiiboApplicationData(application_area_id,application_area_data); +    SaveAmiiboApplicationData(application_area_id, application_area_data);      return ResultSuccess;  } @@ -699,21 +741,32 @@ ResultCode Module::Interface::CreateApplicationArea(u32 access_id, const std::ve          LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);          return ErrCodes::WrongDeviceState;      } -    // if (AmiiboApplicationDataExist(access_id)) { -    //    LOG_ERROR(Service_NFP, "Application area already exist"); -    //    return ErrCodes::ApplicationAreaExist; -    // } -    // if (LoadAmiiboApplicationData(access_id,data)) { -    //    is_application_area_initialized = true; -    //    application_area_id = access_id; -    // } +    if (AmiiboApplicationDataExist(access_id)) { +        LOG_ERROR(Service_NFP, "Application area already exist"); +        return ErrCodes::ApplicationAreaExist; +    }      application_area_data = data;      application_area_id = access_id; -    write_counter = 0; -    // SaveAmiiboApplicationData(application_area_id,application_area_data); +    SaveAmiiboApplicationData(application_area_id, application_area_data);      return ResultSuccess;  } +bool Module::Interface::AmiiboApplicationDataExist(u32 access_id) const { +    // TODO(german77): Check if file exist +    return false; +} + +const std::vector<u8> Module::Interface::LoadAmiiboApplicationData(u32 access_id) const { +    // TODO(german77): Read file +    std::vector<u8> data(ApplicationAreaSize); +    return data; +} + +void Module::Interface::SaveAmiiboApplicationData(u32 access_id, +                                                  const std::vector<u8>& data) const { +    // TODO(german77): Save file +} +  u64 Module::Interface::GetHandle() const {      // Generate a handle based of the npad id      return static_cast<u64>(npad_id); diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h index 4642ed634..633539dcc 100644 --- a/src/core/hle/service/nfp/nfp.h +++ b/src/core/hle/service/nfp/nfp.h @@ -53,11 +53,43 @@ enum class MountTarget : u32 {      All,  }; +enum class AmiiboType : u8 { +    Figure, +    Card, +    Yarn, +}; + +enum class AmiiboSeries : u8 { +    SuperSmashBros, +    SuperMario, +    ChibiRobo, +    YoshiWoollyWorld, +    Splatoon, +    AnimalCrossing, +    EightBitMario, +    Skylanders, +    Unknown8, +    TheLegendOfZelda, +    ShovelKnight, +    Unknown11, +    Kiby, +    Pokemon, +    MarioSportsSuperstars, +    MonsterHunter, +    BoxBoy, +    Pikmin, +    FireEmblem, +    Metroid, +    Others, +    MegaMan, +    Diablo +}; +  struct TagInfo {      std::array<u8, 10> uuid;      u8 uuid_length;      INSERT_PADDING_BYTES(0x15); -    u32 protocol; +    s32 protocol;      u32 tag_type;      INSERT_PADDING_BYTES(0x30);  }; @@ -77,10 +109,13 @@ static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size");  struct ModelInfo {      u16 character_id;      u8 character_variant; -    u8 figure_type; +    AmiiboType amiibo_type;      u16 model_number; -    u8 series; -    INSERT_PADDING_BYTES(0x39); +    AmiiboSeries series; +    u8 fixed;                   // Must be 02 +    INSERT_PADDING_BYTES(0x4);  // Unknown +    INSERT_PADDING_BYTES(0x20); // Probably a SHA256-(HMAC?) hash +    INSERT_PADDING_BYTES(0x14); // SHA256-HMAC  };  static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size"); @@ -105,11 +140,21 @@ public:          struct AmiiboFile {              std::array<u8, 10> uuid; -            INSERT_PADDING_BYTES(0x4); // Compability container -            INSERT_PADDING_BYTES(0x46); -            ModelInfo model_info; +            u16 uuid_lock;               // Must be 0F E0 +            u32 compability_container;   // Must be F1 10 FF EE +            u16 crypto_init;             // Must be A5 XX +            u16 write_count;             // Number of times the amiibo has been written? +            INSERT_PADDING_BYTES(0x20);  // System crypts +            INSERT_PADDING_BYTES(0x20);  // SHA256-(HMAC?) hash +            ModelInfo model_info;        // This struct is bigger than documentation +            INSERT_PADDING_BYTES(0xC);   // SHA256-HMAC +            INSERT_PADDING_BYTES(0x114); // section 1 encrypted buffer +            INSERT_PADDING_BYTES(0x54);  // section 2 encrypted buffer +            u32 tag_dynamic_lock;        // Must be 01 00 0F XX +            u32 tag_CFG0;                // Must be 00 00 00 04 +            u32 tag_CFG1;                // Must be 50 00 00 00          }; -        static_assert(sizeof(AmiiboFile) == 0x94, "AmiiboFile is an invalid size"); +        static_assert(sizeof(AmiiboFile) == 0x214, "AmiiboFile is an invalid size");          void CreateUserInterface(Kernel::HLERequestContext& ctx);          bool LoadAmiibo(const std::vector<u8>& buffer); @@ -118,7 +163,7 @@ public:          void Initialize();          void Finalize(); -        ResultCode StartDetection(); +        ResultCode StartDetection(s32 protocol_);          ResultCode StopDetection();          ResultCode Mount();          ResultCode Unmount(); @@ -144,6 +189,12 @@ public:          std::shared_ptr<Module> module;      private: +        /// Validates that the amiibo file is not corrupted +        bool IsAmiiboValid() const; +        bool AmiiboApplicationDataExist(u32 access_id) const; +        const std::vector<u8> LoadAmiiboApplicationData(u32 access_id) const; +        void SaveAmiiboApplicationData(u32 access_id, const std::vector<u8>& data) const; +          const Core::HID::NpadIdType npad_id;          DeviceState device_state{DeviceState::Unaviable}; @@ -151,7 +202,7 @@ public:          Kernel::KEvent* activate_event;          Kernel::KEvent* deactivate_event;          AmiiboFile amiibo{}; -        u16 write_counter{}; +        s32 protocol;          bool is_application_area_initialized{};          u32 application_area_id;          std::vector<u8> application_area_data; | 
