From 46f8b8fa85f2d8ae2421c2d67cf794db01420bf3 Mon Sep 17 00:00:00 2001 From: Jacobwasbeast Date: Wed, 4 Dec 2024 08:34:58 -0600 Subject: [PATCH] Some small fixes The data now loads but SMBU says it can't be loaded The date time is for some reason in the future idk why still working on it --- .../Nfc/AmiiboDecryption/AmiiboBinReader.cs | 114 ++++++++++++------ .../Nfc/AmiiboDecryption/AmiiboDecrypter.cs | 30 ----- .../HOS/Services/Nfc/Nfp/VirtualAmiibo.cs | 18 ++- 3 files changed, 90 insertions(+), 72 deletions(-) diff --git a/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboBinReader.cs b/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboBinReader.cs index 8e32db885..8ba3fcf3f 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboBinReader.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboBinReader.cs @@ -3,9 +3,11 @@ using Ryujinx.HLE.HOS.Services.Nfc.Nfp; using Ryujinx.HLE.HOS.Services.Nfc.Nfp.NfpManager; using Ryujinx.HLE.HOS.Tamper; using System; +using System.CodeDom; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.Intrinsics.Arm; using System.Text; using System.Text.Json; @@ -64,17 +66,24 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Bin byte[] writeDate = new byte[2]; byte[] writeCounter = new byte[2]; byte formData = 0; - byte[] applicationAreas = new byte[212]; + byte[] applicationAreas = new byte[216]; + byte[] appid = new byte[2]; + byte[] SettingsBytes = new byte[2]; + //// apply to decrypt bytes self.data[304:308] = self._calculate_crc32(self.data[308:520]).to_bytes(4, "little") + //byte[] crc32Bytes = new byte[212]; + //Array.Copy(decryptedFileBytes, 308, crc32Bytes, 0, 212); + //byte[] toApply = BitConverter.GetBytes(CalculateCRC32(crc32Bytes)); + //Array.Reverse(crc32Bytes); + //Array.Copy(toApply, 0, decryptedFileBytes, 304, 4); // Reading specific pages and parsing bytes - for (int page = 0; page < 128; page++) // NTAG215 has 128 pages + for (int page = 0; page < 134; page++) // NTAG215 has 128 pages { int pageStartIdx = page * 4; // Each page is 4 bytes byte[] pageData = new byte[4]; bool isEncrypted = IsPageEncrypted(page); byte[] sourceBytes = isEncrypted ? decryptedFileBytes : fileBytes; Array.Copy(sourceBytes, pageStartIdx, pageData, 0, 4); - // Special handling for specific pages switch (page) { @@ -86,6 +95,10 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Bin byte internalValue = pageData[1]; Console.WriteLine($"Page 2: BCC1 + Internal Value 0x{internalValue:X2} (Expected 0x48)."); break; + case 5: + // byte 0 amd 1 are settings + Array.Copy(pageData, 0, SettingsBytes, 0, 2); + break; case 6: // Bytes 0 and 1 are init date, bytes 2 and 3 are write date @@ -126,22 +139,28 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Bin case 66: // Bytes 0 and 1 are write counter Array.Copy(pageData, 0, writeCounter, 0, 2); + // bytes 2 and 3 are appid + Array.Copy(pageData, 2, appid, 0, 2); break; // Pages 76 to 127 are application areas - case >= 76 and <= 127: + case >= 76 and <= 129: int appAreaOffset = (page - 76) * 4; Array.Copy(pageData, 0, applicationAreas, appAreaOffset, 4); break; } + } + // Debugging - string titleIdStr = BitConverter.ToString(titleId).Replace("-", ""); + uint titleIdStr = BitConverter.ToUInt32(titleId, 0); string usedCharacterStr = BitConverter.ToString(usedCharacter).Replace("-", ""); string variationStr = BitConverter.ToString(variation).Replace("-", ""); string amiiboIDStr = BitConverter.ToString(amiiboID).Replace("-", ""); string formDataStr = formData.ToString("X2"); string setIDStr = BitConverter.ToString(setID).Replace("-", ""); + uint settingsStr = BitConverter.ToUInt16(SettingsBytes, 0); + string nickName = Encoding.BigEndianUnicode.GetString(nickNameBytes).TrimEnd('\0'); string head = usedCharacterStr + variationStr; string tail = amiiboIDStr + setIDStr + "02"; @@ -161,6 +180,8 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Bin Console.WriteLine($"Nickname: {nickName}"); Console.WriteLine($"Init Date: {initDateStr}"); Console.WriteLine($"Write Date: {writeDateStr}"); + Console.WriteLine($"Settings: {settingsStr}"); + Console.WriteLine("Length of Application Areas: " + applicationAreas.Length); VirtualAmiiboFile virtualAmiiboFile = new VirtualAmiiboFile { @@ -168,9 +189,10 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Bin TagUuid = uid, AmiiboId = finalID }; - - DateTime initDateTime = DateTimeFromBytes(initDate); - DateTime writeDateTime = DateTimeFromBytes(writeDate); + ushort initDateValue = BitConverter.ToUInt16(initDate, 0); + ushort writeDateValue = BitConverter.ToUInt16(writeDate, 0); + DateTime initDateTime = DateTimeFromTag(initDateValue); + DateTime writeDateTime = DateTimeFromTag(writeDateValue); Console.WriteLine($"Parsed Init Date: {initDateTime}"); Console.WriteLine($"Parsed Write Date: {writeDateTime}"); @@ -178,18 +200,44 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Bin virtualAmiiboFile.FirstWriteDate = initDateTime; virtualAmiiboFile.LastWriteDate = writeDateTime; virtualAmiiboFile.WriteCounter = BitConverter.ToUInt16(writeCounter, 0); - - // Parse application areas - //List applicationAreasList = ParseAmiiboData(applicationAreas); - List applicationAreasList = new List(); - virtualAmiiboFile.ApplicationAreas = applicationAreasList; - - // Save the virtual Amiibo file VirtualAmiibo.SaveAmiiboFile(virtualAmiiboFile); - + VirtualAmiibo.applicationBytes = applicationAreas; return virtualAmiiboFile; } + public static uint CalculateCRC32(byte[] input) + { + // Setup CRC 32 table + uint p0 = 0xEDB88320u | 0x80000000u; + uint[] u0 = new uint[0x100]; + + for (uint i = 1; i < 0x100; i++) + { + uint t0 = i; + for (int j = 0; j < 8; j++) + { + if ((t0 & 1) != 0) + { + t0 = (t0 >> 1) ^ p0; + } + else + { + t0 >>= 1; + } + } + u0[i] = t0; + } + + // Calculate CRC32 from table + uint t = 0x0; + foreach (byte k in input) + { + t = (t >> 8) ^ u0[(k ^ t) & 0xFF]; + } + + return t ^ 0xFFFFFFFFu; + } + private static string GetKeyRetailBinPath() { return Path.Combine(AppDataManager.KeysDirPath, "key_retail.bin"); @@ -197,37 +245,25 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Bin public static bool IsPageEncrypted(int page) { - return (page >= 6 && page <= 9) || (page >= 43 && page <= 84); + // 0-4 are not encrypted, 5-12 is encrypted, 13-39 is not encrypted, + // 40-129 is encrypted, and 130-134 is not encrypted. + + return (page >= 5 && page <= 12) || (page >= 40 && page <= 129); } - public static DateTime DateTimeFromBytes(byte[] date) + public static DateTime DateTimeFromTag(ushort value) { - if (date == null || date.Length != 2) - { - Console.WriteLine("Invalid date bytes."); - return DateTime.MinValue; - } - - ushort value = BitConverter.ToUInt16(date, 0); - - int day = value & 0x1F; - int month = (value >> 5) & 0x0F; - int year = (value >> 9) & 0x7F; - try { - return new DateTime(2000 + year, month, day); + var day = value & 0x1F; + var month = (value >> 5) & 0x0F; + var year = (value >> 9) & 0x7F; + return new DateTime(1970 + year, month, day); } - catch (ArgumentOutOfRangeException) + catch { - Console.WriteLine("Invalid date values extracted."); - return DateTime.MinValue; + return DateTime.Now; } } - - public static List ParseAmiiboData(byte[] decryptedData) - { - return JsonSerializer.Deserialize>(decryptedData); - } } } diff --git a/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboDecrypter.cs b/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboDecrypter.cs index b2b309828..ffaef6558 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboDecrypter.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboDecrypter.cs @@ -79,35 +79,5 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Bin break; // Stop if no overflow } } - - public DateTime ParseDate(byte[] data, int offset) - { - ushort year = BitConverter.ToUInt16(data, offset); - byte month = data[offset + 2]; - byte day = data[offset + 3]; - byte hour = data[offset + 4]; - byte minute = data[offset + 5]; - byte second = data[offset + 6]; - - return new DateTime(year, month, day, hour, minute, second); - } - - public List ParseApplicationAreas(byte[] data, int startOffset, int areaSize) - { - var areas = new List(); - for (int i = 0; i < 8; i++) // Assuming 8 areas - { - int offset = startOffset + (i * areaSize); - string applicationId = BitConverter.ToString(data[offset..(offset + 4)]).Replace("-", ""); - byte[] areaData = data[(offset + 4)..(offset + areaSize)]; - areas.Add(new VirtualAmiiboApplicationArea - { - ApplicationAreaId = uint.Parse(applicationId), - ApplicationArea = areaData - }); - } - - return areas; - } } } diff --git a/src/Ryujinx.HLE/HOS/Services/Nfc/Nfp/VirtualAmiibo.cs b/src/Ryujinx.HLE/HOS/Services/Nfc/Nfp/VirtualAmiibo.cs index 579c9157e..0d72757a7 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nfc/Nfp/VirtualAmiibo.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nfc/Nfp/VirtualAmiibo.cs @@ -13,10 +13,9 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp { static class VirtualAmiibo { - private static uint _openedApplicationAreaId; - + public static uint _openedApplicationAreaId; + public static byte[] applicationBytes = new byte[0]; private static readonly AmiiboJsonSerializerContext _serializerContext = AmiiboJsonSerializerContext.Default; - public static byte[] GenerateUuid(string amiiboId, bool useRandomUuid) { if (useRandomUuid) @@ -103,6 +102,11 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp public static bool OpenApplicationArea(string amiiboId, uint applicationAreaId) { VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId); + if (applicationBytes.Length > 0) + { + _openedApplicationAreaId = applicationAreaId; + return true; + } if (virtualAmiiboFile.ApplicationAreas.Exists(item => item.ApplicationAreaId == applicationAreaId)) { @@ -116,6 +120,12 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp public static byte[] GetApplicationArea(string amiiboId) { + if (applicationBytes.Length > 0) + { + byte[] bytes = applicationBytes; + applicationBytes = new byte[0]; + return bytes; + } VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId); foreach (VirtualAmiiboApplicationArea applicationArea in virtualAmiiboFile.ApplicationAreas) @@ -209,5 +219,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp string filePath = Path.Join(AppDataManager.BaseDirPath, "system", "amiibo", $"{virtualAmiiboFile.AmiiboId}.json"); JsonHelper.SerializeToFile(filePath, virtualAmiiboFile, _serializerContext.VirtualAmiiboFile); } + + public static bool SaveFileExists(VirtualAmiiboFile virtualAmiiboFile) => File.Exists(Path.Join(AppDataManager.BaseDirPath, "system", "amiibo", $"{virtualAmiiboFile.AmiiboId}.json")); } }