From beef7844833e9c73470dc5595618d1c96a34cf32 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Sun, 23 Jun 2024 09:17:00 +0200 Subject: [PATCH] Embrace nullables --- ByteOperations.cs | 2 +- FfuProtocol.cs | 11 ++ GPT.cs | 73 +------ ProgressUpdater.cs | 66 +++++++ Reader/Data/SignedImage.cs | 2 +- UnifiedFlashingPlatformTransport.ReadParam.cs | 90 ++++----- UnifiedFlashingPlatformTransport.WPI.cs | 187 +++++------------- UnifiedFlashingPlatformTransport.cs | 18 +- 8 files changed, 185 insertions(+), 264 deletions(-) create mode 100644 FfuProtocol.cs create mode 100644 ProgressUpdater.cs diff --git a/ByteOperations.cs b/ByteOperations.cs index 11752e4..55fa91f 100644 --- a/ByteOperations.cs +++ b/ByteOperations.cs @@ -255,7 +255,7 @@ namespace UnifiedFlashingPlatform return System.Collections.StructuralComparisons.StructuralEqualityComparer.Equals(Array1, Array2); } - internal static uint? FindPattern(byte[] SourceBuffer, uint SourceOffset, uint? SourceSize, byte[] Pattern, byte[] Mask, byte[] OutPattern) + internal static uint? FindPattern(byte[] SourceBuffer, uint SourceOffset, uint? SourceSize, byte[] Pattern, byte[]? Mask, byte[]? OutPattern) { // The mask is optional. // In the mask 0x00 means the value must match, and 0xFF means that this position is a wildcard. diff --git a/FfuProtocol.cs b/FfuProtocol.cs new file mode 100644 index 0000000..3511181 --- /dev/null +++ b/FfuProtocol.cs @@ -0,0 +1,11 @@ +namespace UnifiedFlashingPlatform +{ + internal enum FfuProtocol + { + ProtocolSyncV1 = 1, + ProtocolAsyncV1 = 2, + ProtocolSyncV2 = 4, + ProtocolAsyncV2 = 8, + ProtocolAsyncV3 = 16 + } +} diff --git a/GPT.cs b/GPT.cs index 18464b0..b85adde 100644 --- a/GPT.cs +++ b/GPT.cs @@ -30,7 +30,7 @@ namespace UnifiedFlashingPlatform [XmlType("Partitions")] public class GPT { - private byte[] GPTBuffer; + private byte[]? GPTBuffer; private readonly uint HeaderOffset; private readonly uint HeaderSize; private uint TableOffset; @@ -98,76 +98,11 @@ namespace UnifiedFlashingPlatform HasChanged = false; } - internal Partition GetPartition(string Name) + internal Partition? GetPartition(string Name) { return Partitions.Find(p => string.Equals(p.Name, Name, StringComparison.CurrentCultureIgnoreCase)); } - // Magic! - // SecureBoot hack for Bootloader Spec A starts here - internal byte[] InsertHack() - { - Partition HackPartition = Partitions.Find(p => p.Name == "HACK"); - Partition SBL1 = Partitions.Find(p => p.Name == "SBL1"); - Partition SBL2 = Partitions.Find(p => p.Name == "SBL2"); - - if ((SBL1 == null) || (SBL2 == null)) - { - throw new WPinternalsException("Bad GPT", "Can't patch GPT for the Secure Boot hack for Spec A devices. The provided GPT does not include a SBL1 and/or SBL2 partition."); - } - - if (HackPartition == null) - { - HackPartition = new Partition - { - Name = "HACK", - Attributes = SBL2.Attributes, - FirstSector = SBL1.LastSector, - LastSector = SBL1.LastSector, - - PartitionTypeGuid = SBL2.PartitionTypeGuid, - PartitionGuid = SBL2.PartitionGuid - }; - - Partitions.Add(HackPartition); - - SBL1.LastSector--; - - SBL2.PartitionTypeGuid = new Guid(new byte[] { 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74 }); - SBL2.PartitionGuid = new Guid(new byte[] { 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74 }); - } - - HasChanged = true; - - return Rebuild(); - } - - internal byte[] RemoveHack() - { - Partition HackPartition = Partitions.Find(p => p.Name == "HACK"); - Partition SBL1 = Partitions.Find(p => p.Name == "SBL1"); - Partition SBL2 = Partitions.Find(p => p.Name == "SBL2"); - - if ((SBL1 == null) || (SBL2 == null)) - { - throw new WPinternalsException("Bad GPT", "Can't un-patch GPT for the Secure Boot hack for Spec A devices. The provided GPT does not include a SBL1 and/or SBL2 partition."); - } - - if (HackPartition != null) - { - SBL2.PartitionTypeGuid = HackPartition.PartitionTypeGuid; - SBL2.PartitionGuid = HackPartition.PartitionGuid; - - _ = Partitions.Remove(HackPartition); - - SBL1.LastSector++; - } - - HasChanged = true; - - return Rebuild(); - } - internal byte[] Rebuild() { if (GPTBuffer == null) @@ -373,7 +308,7 @@ namespace UnifiedFlashingPlatform // Existing partitions, which are overwritten by the new partitions will be removed from the existing GPT. // Existing partition with the same name in the existing GPT is reused (guids and attribs remain, if not specified). ulong LowestSector = 0; - Partition DPP = GetPartition("DPP"); + Partition? DPP = GetPartition("DPP"); if (DPP != null) { LowestSector = DPP.LastSector + 1; @@ -613,7 +548,7 @@ namespace UnifiedFlashingPlatform private ulong _FirstSector; private ulong _LastSector; - public string Name; // 0x48 + public string? Name; // 0x48 public Guid PartitionTypeGuid; // 0x10 public Guid PartitionGuid; // 0x10 [XmlIgnore] diff --git a/ProgressUpdater.cs b/ProgressUpdater.cs new file mode 100644 index 0000000..9aeea35 --- /dev/null +++ b/ProgressUpdater.cs @@ -0,0 +1,66 @@ +using System; +using System.Diagnostics; + +namespace UnifiedFlashingPlatform +{ + public class ProgressUpdater + { + private readonly DateTime InitTime; + private DateTime LastUpdateTime; + private readonly ulong MaxValue; + private readonly Action ProgressUpdateCallback; + public int ProgressPercentage; + + public ProgressUpdater(ulong MaxValue, Action ProgressUpdateCallback) + { + InitTime = DateTime.Now; + LastUpdateTime = DateTime.Now; + this.MaxValue = MaxValue; + this.ProgressUpdateCallback = ProgressUpdateCallback; + SetProgress(0); + } + + private ulong _Progress; + public ulong Progress + { + get + { + return _Progress; + } + } + + public void SetProgress(ulong NewValue) + { + if (_Progress != NewValue) + { + int PreviousProgressPercentage = (int)((double)_Progress / MaxValue * 100); + ProgressPercentage = (int)((double)NewValue / MaxValue * 100); + + _Progress = NewValue; + + if (((DateTime.Now - LastUpdateTime) > TimeSpan.FromSeconds(0.5)) || (ProgressPercentage == 100)) + { +#if DEBUG + Debug.WriteLine("Init time: " + InitTime.ToShortTimeString() + " / Now: " + DateTime.Now.ToString() + " / NewValue: " + NewValue.ToString() + " / MaxValue: " + MaxValue.ToString() + " ->> Percentage: " + ProgressPercentage.ToString() + " / Remaining: " + TimeSpan.FromTicks((long)((DateTime.Now - InitTime).Ticks / ((double)NewValue / MaxValue) * (1 - ((double)NewValue / MaxValue)))).ToString()); +#endif + + if (((DateTime.Now - InitTime) < TimeSpan.FromSeconds(30)) && (ProgressPercentage < 15)) + { + ProgressUpdateCallback(ProgressPercentage, null); + } + else + { + ProgressUpdateCallback(ProgressPercentage, TimeSpan.FromTicks((long)((DateTime.Now - InitTime).Ticks / ((double)NewValue / MaxValue) * (1 - ((double)NewValue / MaxValue))))); + } + + LastUpdateTime = DateTime.Now; + } + } + } + + public void IncreaseProgress(ulong Progress) + { + SetProgress(_Progress + Progress); + } + } +} diff --git a/Reader/Data/SignedImage.cs b/Reader/Data/SignedImage.cs index 940d893..cec933d 100644 --- a/Reader/Data/SignedImage.cs +++ b/Reader/Data/SignedImage.cs @@ -23,7 +23,7 @@ namespace Img2Ffu.Reader.Data public ulong TotalChunkCount => Image.GetImageBlockCount(); public readonly List BlockHashes = []; - public X509Certificate Certificate; + public X509Certificate? Certificate; private readonly Stream Stream; diff --git a/UnifiedFlashingPlatformTransport.ReadParam.cs b/UnifiedFlashingPlatformTransport.ReadParam.cs index 2398aa2..6a54846 100644 --- a/UnifiedFlashingPlatformTransport.ReadParam.cs +++ b/UnifiedFlashingPlatformTransport.ReadParam.cs @@ -6,7 +6,7 @@ namespace UnifiedFlashingPlatform { public partial class UnifiedFlashingPlatformTransport { - public byte[] ReadParam(string Param) + public byte[]? ReadParam(string Param) { byte[] Request = new byte[0x0B]; string Header = ReadParamSignature; // NOKXFR @@ -14,7 +14,7 @@ namespace UnifiedFlashingPlatform Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length); Buffer.BlockCopy(Encoding.ASCII.GetBytes(Param), 0, Request, 7, Param.Length); - byte[] Response = ExecuteRawMethod(Request); + byte[]? Response = ExecuteRawMethod(Request); if ((Response == null) || (Response.Length < 0x10)) { return null; @@ -25,21 +25,21 @@ namespace UnifiedFlashingPlatform return Result; } - public string ReadStringParam(string Param) + public string? ReadStringParam(string Param) { - byte[] Bytes = ReadParam(Param); + byte[]? Bytes = ReadParam(Param); return Bytes == null ? null : Encoding.ASCII.GetString(Bytes).Trim('\0'); } public AppType ReadAppType() { - byte[] Bytes = ReadParam("APPT"); + byte[]? Bytes = ReadParam("APPT"); return Bytes == null ? AppType.Min : Bytes[0] == 1 ? AppType.UEFI : AppType.Min; } public ResetProtectionInfo? ReadResetProtection() { - byte[] Bytes = ReadParam("ATRP"); + byte[]? Bytes = ReadParam("ATRP"); return Bytes == null ? null : new ResetProtectionInfo() @@ -52,24 +52,24 @@ namespace UnifiedFlashingPlatform public bool? ReadBitlocker() { - byte[] Bytes = ReadParam("BITL"); + byte[]? Bytes = ReadParam("BITL"); return Bytes == null ? null : Bytes[0] == 1; } - public string ReadBuildInfo() + public string? ReadBuildInfo() { return ReadStringParam("BNFO"); } public ushort? ReadCurrentBootOption() { - byte[] Bytes = ReadParam("CUFO"); + byte[]? Bytes = ReadParam("CUFO"); return Bytes == null || Bytes.Length != 2 ? null : BitConverter.ToUInt16(Bytes.Reverse().ToArray()); } public bool? ReadDeviceAsyncSupport() { - byte[] Bytes = ReadParam("DAS\0"); + byte[]? Bytes = ReadParam("DAS\0"); return Bytes == null || Bytes.Length != 2 ? null : BitConverter.ToUInt16(Bytes.Reverse().ToArray()) == 1; } @@ -93,7 +93,7 @@ namespace UnifiedFlashingPlatform Buffer.BlockCopy(PartitionNameBuffer, 0, Request, 15, PartitionNameBuffer.Length); Buffer.BlockCopy(DirectoryNameBuffer, 0, Request, 87, DirectoryNameBuffer.Length); - byte[] Response = ExecuteRawMethod(Request); + byte[]? Response = ExecuteRawMethod(Request); if ((Response == null) || (Response.Length < 0x10)) { return null; @@ -105,7 +105,7 @@ namespace UnifiedFlashingPlatform return BitConverter.ToUInt64(Result.Reverse().ToArray()); } - public string ReadDevicePlatformID() + public string? ReadDevicePlatformID() { return ReadStringParam("DPI\0"); } @@ -114,14 +114,14 @@ namespace UnifiedFlashingPlatform // Reads the device properties from the UEFI Variable "MSRuntimeDeviceProperties" // in the g_guidMSRuntimeDeviceProperties namespace and returns it as a string. // - public string ReadDeviceProperties() + public string? ReadDeviceProperties() { return ReadStringParam("DPR\0"); } public DeviceTargetingInfo? ReadDeviceTargetInfo() { - byte[] Bytes = ReadParam("DTI\0"); + byte[]? Bytes = ReadParam("DTI\0"); if (Bytes == null) { return null; @@ -173,19 +173,19 @@ namespace UnifiedFlashingPlatform // public uint? ReadDataVerifySpeed() { - byte[] Bytes = ReadParam("DTSP"); + byte[]? Bytes = ReadParam("DTSP"); return Bytes == null || Bytes.Length != 4 ? null : BitConverter.ToUInt32(Bytes.Reverse().ToArray()); } public Guid? ReadDeviceID() { - byte[] Bytes = ReadParam("DUI\0"); + byte[]? Bytes = ReadParam("DUI\0"); return Bytes == null || Bytes.Length != 16 ? null : new Guid(Bytes); } public uint? ReadEmmcTestResult() { - byte[] Bytes = ReadParam("EMMT"); + byte[]? Bytes = ReadParam("EMMT"); return Bytes == null || Bytes.Length != 4 ? null : BitConverter.ToUInt32(Bytes.Reverse().ToArray()); } @@ -194,7 +194,7 @@ namespace UnifiedFlashingPlatform // public uint? ReadEmmcSize() { - byte[] Bytes = ReadParam("EMS\0"); + byte[]? Bytes = ReadParam("EMS\0"); return Bytes == null || Bytes.Length != 4 ? null : BitConverter.ToUInt32(Bytes.Reverse().ToArray()); } @@ -203,13 +203,13 @@ namespace UnifiedFlashingPlatform // public uint? ReadEmmcWriteSpeed() { - byte[] Bytes = ReadParam("EMWS"); + byte[]? Bytes = ReadParam("EMWS"); return Bytes == null || Bytes.Length != 4 ? null : BitConverter.ToUInt32(Bytes.Reverse().ToArray()); } public FlashAppInfo? ReadFlashAppInfo() { - byte[] Bytes = ReadParam("FAI\0"); + byte[]? Bytes = ReadParam("FAI\0"); return Bytes == null || Bytes.Length != 6 || Bytes[0] != 2 ? null : new FlashAppInfo() @@ -225,14 +225,14 @@ namespace UnifiedFlashingPlatform // Reads the device properties from the UEFI Variable "FfuConfigurationOptions" // in the g_guidLumiaGuid namespace and returns it as a string. // - public string ReadFlashOptions() + public string? ReadFlashOptions() { return ReadStringParam("FO\0\0"); } public uint? ReadFlashingStatus() { - byte[] Bytes = ReadParam("FS\0\0"); + byte[]? Bytes = ReadParam("FS\0\0"); return Bytes == null || Bytes.Length != 4 ? null : BitConverter.ToUInt32(Bytes.Reverse().ToArray()); } @@ -256,7 +256,7 @@ namespace UnifiedFlashingPlatform Buffer.BlockCopy(PartitionNameBuffer, 0, Request, 15, PartitionNameBuffer.Length); Buffer.BlockCopy(FileNameBuffer, 0, Request, 87, FileNameBuffer.Length); - byte[] Response = ExecuteRawMethod(Request); + byte[]? Response = ExecuteRawMethod(Request); if ((Response == null) || (Response.Length < 0x10)) { return null; @@ -270,7 +270,7 @@ namespace UnifiedFlashingPlatform public bool? ReadSecureBootStatus() { - byte[] Bytes = ReadParam("GSBS"); + byte[]? Bytes = ReadParam("GSBS"); return Bytes == null ? null : Bytes[0] == 1; } @@ -290,7 +290,7 @@ namespace UnifiedFlashingPlatform Buffer.BlockCopy(BitConverter.GetBytes((Name.Length + 1) * 2).Reverse().ToArray(), 0, Request, 35, 4); Buffer.BlockCopy(VariableNameBuffer, 0, Request, 39, VariableNameBuffer.Length); - byte[] Response = ExecuteRawMethod(Request); + byte[]? Response = ExecuteRawMethod(Request); if ((Response == null) || (Response.Length < 0x10)) { return null; @@ -323,7 +323,7 @@ namespace UnifiedFlashingPlatform Buffer.BlockCopy(BitConverter.GetBytes((Name.Length + 1) * 2).Reverse().ToArray(), 0, Request, 35, 4); Buffer.BlockCopy(VariableNameBuffer, 0, Request, 39, VariableNameBuffer.Length); - byte[] Response = ExecuteRawMethod(Request); + byte[]? Response = ExecuteRawMethod(Request); if ((Response == null) || (Response.Length < 0x10)) { return null; @@ -339,7 +339,7 @@ namespace UnifiedFlashingPlatform // public ulong? ReadLargestMemoryRegion() { - byte[] Bytes = ReadParam("LGMR"); + byte[]? Bytes = ReadParam("LGMR"); return Bytes == null || Bytes.Length != 8 ? null : BitConverter.ToUInt64(Bytes.Reverse().ToArray()); } @@ -354,7 +354,7 @@ namespace UnifiedFlashingPlatform Request[15] = (byte)LogType; - byte[] Response = ExecuteRawMethod(Request); + byte[]? Response = ExecuteRawMethod(Request); if ((Response == null) || (Response.Length < 0x10)) { return 0; @@ -369,7 +369,7 @@ namespace UnifiedFlashingPlatform // // Reads the MAC Address in the following format: "%02x-%02x-%02x-%02x-%02x-%02x" // - public string ReadMacAddress() + public string? ReadMacAddress() { return ReadStringParam("MAC\0"); } @@ -385,7 +385,7 @@ namespace UnifiedFlashingPlatform Request[15] = (byte)Mode; - byte[] Response = ExecuteRawMethod(Request); + byte[]? Response = ExecuteRawMethod(Request); if ((Response == null) || (Response.Length < 0x10)) { return null; @@ -396,7 +396,7 @@ namespace UnifiedFlashingPlatform return Result == null || Result.Length != 4 ? null : BitConverter.ToUInt32(Result.Reverse().ToArray()); } - public string ReadProcessorManufacturer() + public string? ReadProcessorManufacturer() { return ReadStringParam("pm\0\0"); } @@ -406,17 +406,17 @@ namespace UnifiedFlashingPlatform // public uint? ReadSDCardSize() { - byte[] Bytes = ReadParam("SDS\0"); + byte[]? Bytes = ReadParam("SDS\0"); return Bytes == null || Bytes.Length != 4 ? null : BitConverter.ToUInt32(Bytes.Reverse().ToArray()); } - public string ReadSupportedFFUProtocolInfo() + public string? ReadSupportedFFUProtocolInfo() { // TODO return ReadStringParam("SFPI"); } - public string ReadSMBIOSData() + public string? ReadSMBIOSData() { // TODO return ReadStringParam("SMBD"); @@ -424,7 +424,7 @@ namespace UnifiedFlashingPlatform public Guid? ReadSerialNumber() { - byte[] Bytes = ReadParam("SN\0\0"); + byte[]? Bytes = ReadParam("SN\0\0"); return Bytes == null || Bytes.Length != 16 ? null : new Guid(Bytes); } @@ -433,17 +433,17 @@ namespace UnifiedFlashingPlatform // public ulong? ReadSizeOfSystemMemory() { - byte[] Bytes = ReadParam("SOSM"); + byte[]? Bytes = ReadParam("SOSM"); return Bytes == null || Bytes.Length != 8 ? null : BitConverter.ToUInt64(Bytes.Reverse().ToArray()); } - public string ReadSecurityStatus() + public string? ReadSecurityStatus() { // TODO return ReadStringParam("SS\0\0"); } - public string ReadTelemetryLogSize() + public string? ReadTelemetryLogSize() { // TODO return ReadStringParam("TELS"); @@ -451,19 +451,19 @@ namespace UnifiedFlashingPlatform public uint? ReadTransferSize() { - byte[] Bytes = ReadParam("TS\0\0"); + byte[]? Bytes = ReadParam("TS\0\0"); return Bytes == null || Bytes.Length != 4 ? null : BitConverter.ToUInt32(Bytes.Reverse().ToArray()); } // // Reads the UEFI Boot Flag variable content and returns it as a string. // - public string ReadUEFIBootFlag() + public string? ReadUEFIBootFlag() { return ReadStringParam("UBF\0"); } - public string ReadUEFIBootOptions() + public string? ReadUEFIBootOptions() { // TODO return ReadStringParam("UEBO"); @@ -473,12 +473,12 @@ namespace UnifiedFlashingPlatform // Reads the device properties from the UEFI Variable "UnlockID" // in the g_guidOfflineDUIdEfiNamespace namespace and returns it as a string. // - public string ReadUnlockID() + public string? ReadUnlockID() { return ReadStringParam("UKID"); } - public string ReadUnlockTokenFiles() + public string? ReadUnlockTokenFiles() { // TODO return ReadStringParam("UKTF"); @@ -486,7 +486,7 @@ namespace UnifiedFlashingPlatform public USBSpeed? ReadUSBSpeed() { - byte[] Bytes = ReadParam("USBS"); + byte[]? Bytes = ReadParam("USBS"); return Bytes == null || Bytes.Length != 2 ? null : new USBSpeed() @@ -498,7 +498,7 @@ namespace UnifiedFlashingPlatform public uint? ReadWriteBufferSize() { - byte[] Bytes = ReadParam("WBS\0"); + byte[]? Bytes = ReadParam("WBS\0"); return Bytes == null || Bytes.Length != 4 ? null : BitConverter.ToUInt32(Bytes.Reverse().ToArray()); } } diff --git a/UnifiedFlashingPlatformTransport.WPI.cs b/UnifiedFlashingPlatformTransport.WPI.cs index 6040316..e21c0b1 100644 --- a/UnifiedFlashingPlatformTransport.WPI.cs +++ b/UnifiedFlashingPlatformTransport.WPI.cs @@ -8,15 +8,6 @@ using System.Text; namespace UnifiedFlashingPlatform { - internal enum FfuProtocol - { - ProtocolSyncV1 = 1, - ProtocolAsyncV1 = 2, - ProtocolSyncV2 = 4, - ProtocolAsyncV2 = 8, - ProtocolAsyncV3 = 16 - } - public partial class UnifiedFlashingPlatformTransport { private readonly PhoneInfo Info = new(); @@ -45,11 +36,7 @@ namespace UnifiedFlashingPlatform { byte[] Request = new byte[4]; ByteOperations.WriteAsciiString(Request, 0, HelloSignature); - byte[] Response = ExecuteRawMethod(Request); - if (Response == null) - { - throw new BadConnectionException(); - } + byte[] Response = ExecuteRawMethod(Request) ?? throw new BadConnectionException(); if (ByteOperations.ReadAsciiString(Response, 0, 4) != HelloSignature) { @@ -94,7 +81,7 @@ namespace UnifiedFlashingPlatform System.Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length); - byte[] Buffer = ExecuteRawMethod(Request); + byte[]? Buffer = ExecuteRawMethod(Request); if ((Buffer == null) || (Buffer.Length < 0x4408)) { throw new InvalidOperationException("Unable to read GPT!"); @@ -103,7 +90,7 @@ namespace UnifiedFlashingPlatform ushort Error = (ushort)((Buffer[6] << 8) + Buffer[7]); if (Error > 0) { - throw new NotSupportedException("ReadGPT: Error 0x" + Error.ToString("X4")); + throw new NotSupportedException($"ReadGPT: Error 0x{Error:X4}"); } // Length: 0x4400 for 512 (0x200) Sector Size (from sector 0 to sector 34) @@ -114,7 +101,7 @@ namespace UnifiedFlashingPlatform ? 512 : Buffer.Length == 0x6008 ? (uint)4096 - : throw new NotSupportedException("ReadGPT: Unsupported output size! 0x" + ReturnedGPTBufferLength.ToString("X4")); + : throw new NotSupportedException($"ReadGPT: Unsupported output size! 0x{ReturnedGPTBufferLength:X4}"); byte[] GPTBuffer = new byte[ReturnedGPTBufferLength - SectorSize]; System.Buffer.BlockCopy(Buffer, 8 + (int)SectorSize, GPTBuffer, 0, (int)ReturnedGPTBufferLength - (int)SectorSize); @@ -134,7 +121,7 @@ namespace UnifiedFlashingPlatform return new GPT(GPTBuffer, SectorSize); // NOKT message header and MBR are ignored } - private void ThrowFlashError(int ErrorCode) + private static void ThrowFlashError(int ErrorCode) { string SubMessage = ErrorCode switch { @@ -177,8 +164,11 @@ namespace UnifiedFlashingPlatform 0x0002 => "Flash read failed", _ => "Unknown error", }; - WPinternalsException Ex = new("Flash failed!"); - Ex.SubMessage = "Error 0x" + ErrorCode.ToString("X4") + ": " + SubMessage; + + WPinternalsException Ex = new("Flash failed!") + { + SubMessage = $"Error 0x{ErrorCode:X4}: {SubMessage}" + }; throw Ex; } @@ -187,10 +177,10 @@ namespace UnifiedFlashingPlatform { byte[] Request = new byte[FfuHeader.Length + 0x20]; - const string Header = "NOKXFS"; - Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length); + string Header = SecureFlashSignature; + Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length); Buffer.BlockCopy(BigEndian.GetBytes(0x0001, 2), 0, Request, 0x06, 2); // Protocol version = 0x0001 - Request[0x08] = 0; // Progress = 0% + Request[0x08] = (byte)Progress; // Progress = 0% (0 - 100) Request[0x0B] = 1; // Subblock count = 1 Buffer.BlockCopy(BigEndian.GetBytes(0x0000000B, 4), 0, Request, 0x0C, 4); // Subblock type for header = 0x0B Buffer.BlockCopy(BigEndian.GetBytes(FfuHeader.Length + 0x0C, 4), 0, Request, 0x10, 4); // Subblock length = length of header + 0x0C @@ -200,11 +190,7 @@ namespace UnifiedFlashingPlatform Buffer.BlockCopy(FfuHeader, 0, Request, 0x20, FfuHeader.Length); - byte[] Response = ExecuteRawMethod(Request); - if (Response == null) - { - throw new BadConnectionException(); - } + byte[] Response = ExecuteRawMethod(Request) ?? throw new BadConnectionException(); int ResultCode = (Response[6] << 8) + Response[7]; if (ResultCode != 0) @@ -217,10 +203,10 @@ namespace UnifiedFlashingPlatform { byte[] Request = new byte[FfuHeader.Length + 0x3C]; - const string Header = "NOKXFS"; - Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length); + string Header = SecureFlashSignature; + Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length); Buffer.BlockCopy(BigEndian.GetBytes(0x0002, 2), 0, Request, 0x06, 2); // Protocol version = 0x0002 - Request[0x08] = 0; // Progress = 0% + Request[0x08] = (byte)Progress; // Progress = 0% (0 - 100) Request[0x0B] = 1; // Subblock count = 1 Buffer.BlockCopy(BigEndian.GetBytes(0x00000021, 4), 0, Request, 0x0C, 4); // Subblock type for header v2 = 0x21 @@ -236,11 +222,7 @@ namespace UnifiedFlashingPlatform Buffer.BlockCopy(FfuHeader, 0, Request, 0x3C, FfuHeader.Length); - byte[] Response = ExecuteRawMethod(Request); - if (Response == null) - { - throw new BadConnectionException(); - } + byte[] Response = ExecuteRawMethod(Request) ?? throw new BadConnectionException(); if (Response.Length == 4) { @@ -258,8 +240,8 @@ namespace UnifiedFlashingPlatform { byte[] Request = new byte[FfuChunk.Length + 0x1C]; - const string Header = "NOKXFS"; - Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length); + string Header = SecureFlashSignature; + Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length); Buffer.BlockCopy(BigEndian.GetBytes((int)FfuProtocol.ProtocolSyncV1, 2), 0, Request, 0x06, 2); // Protocol version = 0x0001 Request[0x08] = (byte)Progress; // Progress = 0% (0 - 100) Request[0x0B] = 1; // Subblock count = 1 @@ -272,11 +254,7 @@ namespace UnifiedFlashingPlatform Buffer.BlockCopy(FfuChunk, 0, Request, 0x1C, FfuChunk.Length); - byte[] Response = ExecuteRawMethod(Request); - if (Response == null) - { - throw new BadConnectionException(); - } + byte[] Response = ExecuteRawMethod(Request) ?? throw new BadConnectionException(); int ResultCode = (Response[6] << 8) + Response[7]; if (ResultCode != 0) @@ -289,8 +267,8 @@ namespace UnifiedFlashingPlatform { byte[] Request = new byte[FfuChunk.Length + 0x20]; - const string Header = "NOKXFS"; - Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length); + string Header = SecureFlashSignature; + Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length); Buffer.BlockCopy(BigEndian.GetBytes((int)FfuProtocol.ProtocolSyncV2, 2), 0, Request, 0x06, 2); // Protocol Request[0x08] = (byte)Progress; // Progress = 0% (0 - 100) Request[0x0B] = 1; // Subblock count = 1 @@ -303,11 +281,7 @@ namespace UnifiedFlashingPlatform Buffer.BlockCopy(FfuChunk, 0, Request, 0x20, FfuChunk.Length); - byte[] Response = ExecuteRawMethod(Request); - if (Response == null) - { - throw new BadConnectionException(); - } + byte[] Response = ExecuteRawMethod(Request) ?? throw new BadConnectionException(); int ResultCode = (Response[6] << 8) + Response[7]; if (ResultCode != 0) @@ -320,8 +294,8 @@ namespace UnifiedFlashingPlatform { byte[] Request = new byte[FfuChunk.Length + 0x20]; - const string Header = "NOKXFS"; - Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length); + string Header = SecureFlashSignature; + Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length); Buffer.BlockCopy(BigEndian.GetBytes((int)FfuProtocol.ProtocolAsyncV3, 2), 0, Request, 0x06, 2); // Protocol Request[0x08] = (byte)Progress; // Progress = 0% (0 - 100) Request[0x0B] = 1; // Subblock count = 1 @@ -336,11 +310,7 @@ namespace UnifiedFlashingPlatform Buffer.BlockCopy(FfuChunk, 0, Request, 0x40, FfuChunk.Length); - byte[] Response = ExecuteRawMethod(Request); - if (Response == null) - { - throw new BadConnectionException(); - } + byte[] Response = ExecuteRawMethod(Request) ?? throw new BadConnectionException(); int ResultCode = (Response[6] << 8) + Response[7]; if (ResultCode != 0) @@ -349,67 +319,6 @@ namespace UnifiedFlashingPlatform } } - public class ProgressUpdater - { - private readonly DateTime InitTime; - private DateTime LastUpdateTime; - private readonly ulong MaxValue; - private readonly Action ProgressUpdateCallback; - public int ProgressPercentage; - - public ProgressUpdater(ulong MaxValue, Action ProgressUpdateCallback) - { - InitTime = DateTime.Now; - LastUpdateTime = DateTime.Now; - this.MaxValue = MaxValue; - this.ProgressUpdateCallback = ProgressUpdateCallback; - SetProgress(0); - } - - private ulong _Progress; - public ulong Progress - { - get - { - return _Progress; - } - } - - public void SetProgress(ulong NewValue) - { - if (_Progress != NewValue) - { - int PreviousProgressPercentage = (int)((double)_Progress / MaxValue * 100); - ProgressPercentage = (int)((double)NewValue / MaxValue * 100); - - _Progress = NewValue; - - if (((DateTime.Now - LastUpdateTime) > TimeSpan.FromSeconds(0.5)) || (ProgressPercentage == 100)) - { -#if DEBUG - Debug.WriteLine("Init time: " + InitTime.ToShortTimeString() + " / Now: " + DateTime.Now.ToString() + " / NewValue: " + NewValue.ToString() + " / MaxValue: " + MaxValue.ToString() + " ->> Percentage: " + ProgressPercentage.ToString() + " / Remaining: " + TimeSpan.FromTicks((long)((DateTime.Now - InitTime).Ticks / ((double)NewValue / MaxValue) * (1 - ((double)NewValue / MaxValue)))).ToString()); -#endif - - if (((DateTime.Now - InitTime) < TimeSpan.FromSeconds(30)) && (ProgressPercentage < 15)) - { - ProgressUpdateCallback(ProgressPercentage, null); - } - else - { - ProgressUpdateCallback(ProgressPercentage, TimeSpan.FromTicks((long)((DateTime.Now - InitTime).Ticks / ((double)NewValue / MaxValue) * (1 - ((double)NewValue / MaxValue))))); - } - - LastUpdateTime = DateTime.Now; - } - } - } - - public void IncreaseProgress(ulong Progress) - { - SetProgress(_Progress + Progress); - } - } - public void FlashFFU(string FFUPath, bool ResetAfterwards = true, byte Options = 0) { using FileStream FfuFile = new(FFUPath, FileMode.Open, FileAccess.Read); @@ -421,9 +330,9 @@ namespace UnifiedFlashingPlatform FlashFFU(FfuFile, null, ResetAfterwards, Options); } - public void FlashFFU(FileStream FfuFile, ProgressUpdater UpdaterPerChunk, bool ResetAfterwards = true, byte Options = 0) + public void FlashFFU(FileStream FfuFile, ProgressUpdater? UpdaterPerChunk, bool ResetAfterwards = true, byte Options = 0) { - ProgressUpdater Progress = UpdaterPerChunk; + ProgressUpdater? Progress = UpdaterPerChunk; PhoneInfo Info = ReadPhoneInfo(); if ((Info.SecureFfuSupportedProtocolMask & ((ushort)FfuProtocol.ProtocolSyncV1 | (ushort)FfuProtocol.ProtocolSyncV2)) == 0) @@ -526,8 +435,8 @@ namespace UnifiedFlashingPlatform if (Result.State == PhoneInfoState.Empty) { byte[] Request = new byte[4]; - ByteOperations.WriteAsciiString(Request, 0, "NOKV"); - byte[] Response = ExecuteRawMethod(Request); + ByteOperations.WriteAsciiString(Request, 0, InfoQuerySignature); + byte[]? Response = ExecuteRawMethod(Request); if ((Response != null) && (ByteOperations.ReadAsciiString(Response, 0, 4) != "NOKU")) { Result.App = (FlashAppType)Response[5]; @@ -569,7 +478,7 @@ namespace UnifiedFlashingPlatform } break; case 0x05: - Result.PlatformID = ByteOperations.ReadAsciiString(Response, (uint)SubblockPayloadOffset, SubblockLength).Trim(new char[] { ' ', '\0' }); + Result.PlatformID = ByteOperations.ReadAsciiString(Response, (uint)SubblockPayloadOffset, SubblockLength).Trim([' ', '\0']); break; case 0x0D: Result.AsyncSupport = Response[SubblockPayloadOffset + 1] == 1; @@ -600,7 +509,7 @@ namespace UnifiedFlashingPlatform ushort FlashType = BigEndian.ToUInt16(Response, SubblockPayloadOffset + 8); ushort FlashTypeIndex = BigEndian.ToUInt16(Response, SubblockPayloadOffset + 10); uint Unknown = BigEndian.ToUInt32(Response, SubblockPayloadOffset + 12); - string DevicePath = ByteOperations.ReadUnicodeString(Response, (uint)SubblockPayloadOffset + 16, (uint)SubblockLength - 16).Trim(new char[] { ' ', '\0' }); + string DevicePath = ByteOperations.ReadUnicodeString(Response, (uint)SubblockPayloadOffset + 16, (uint)SubblockLength - 16).Trim([' ', '\0']); Result.BootDevices.Add((SectorCount, SectorSize, FlashType, FlashTypeIndex, Unknown, DevicePath)); break; case 0x23: @@ -683,7 +592,7 @@ namespace UnifiedFlashingPlatform public uint SdCardSizeInSectors; public uint WriteBufferSize; public uint EmmcSizeInSectors; - public string PlatformID; + public string? PlatformID; public ushort SecureFfuSupportedProtocolMask; public bool AsyncSupport; @@ -695,16 +604,16 @@ namespace UnifiedFlashingPlatform public bool UefiSecureBootEnabled; public bool SecondaryHardwareKeyPresent; - public string Manufacturer; - public string Family; - public string ProductName; - public string ProductVersion; - public string SKUNumber; - public string BaseboardManufacturer; - public string BaseboardProduct; + public string? Manufacturer; + public string? Family; + public string? ProductName; + public string? ProductVersion; + public string? SKUNumber; + public string? BaseboardManufacturer; + public string? BaseboardProduct; public ulong LargestMemoryRegion; public AppType AppType; - public List<(uint SectorCount, uint SectorSize, ushort FlashType, ushort FlashIndex, uint Unknown, string DevicePath)> BootDevices = new(); + public List<(uint SectorCount, uint SectorSize, ushort FlashType, ushort FlashIndex, uint Unknown, string DevicePath)> BootDevices = []; public bool IsBootloaderSecure; @@ -713,18 +622,18 @@ namespace UnifiedFlashingPlatform switch (App) { case FlashAppType.FlashApp: - Debug.WriteLine("Flash app: " + FlashAppVersionMajor + "." + FlashAppVersionMinor); - Debug.WriteLine("Flash protocol: " + FlashAppProtocolVersionMajor + "." + FlashAppProtocolVersionMinor); + Debug.WriteLine($"Flash app: {FlashAppVersionMajor}.{FlashAppVersionMinor}"); + Debug.WriteLine($"Flash protocol: {FlashAppProtocolVersionMajor}.{FlashAppProtocolVersionMinor}"); break; } - Debug.WriteLine("SecureBoot: " + ((!PlatformSecureBootEnabled || !UefiSecureBootEnabled) ? "Disabled" : "Enabled") + " (Platform Secure Boot: " + (PlatformSecureBootEnabled ? "Enabled" : "Disabled") + ", UEFI Secure Boot: " + (UefiSecureBootEnabled ? "Enabled" : "Disabled") + ")"); + Debug.WriteLine($"SecureBoot: {((!PlatformSecureBootEnabled || !UefiSecureBootEnabled) ? "Disabled" : "Enabled")} (Platform Secure Boot: {(PlatformSecureBootEnabled ? "Enabled" : "Disabled")}, UEFI Secure Boot: {(UefiSecureBootEnabled ? "Enabled" : "Disabled")})"); - Debug.WriteLine("Flash app security: " + (!IsBootloaderSecure ? "Disabled" : "Enabled")); + Debug.WriteLine($"Flash app security: {(!IsBootloaderSecure ? "Disabled" : "Enabled")}"); - Debug.WriteLine("Flash app security: " + (!IsBootloaderSecure ? "Disabled" : "Enabled") + " (FFU security: " + (SecureFfuEnabled ? "Enabled" : "Disabled") + ", RDC: " + (RdcPresent ? "Present" : "Not found") + ", Authenticated: " + (Authenticated ? "True" : "False") + ")"); + Debug.WriteLine($"Flash app security: {(!IsBootloaderSecure ? "Disabled" : "Enabled")} (FFU security: {(SecureFfuEnabled ? "Enabled" : "Disabled")}, RDC: {(RdcPresent ? "Present" : "Not found")}, Authenticated: {(Authenticated ? "True" : "False")})"); - Debug.WriteLine("JTAG: " + (JtagDisabled ? "Disabled" : "Enabled")); + Debug.WriteLine($"JTAG: {(JtagDisabled ? "Disabled" : "Enabled")}"); } } diff --git a/UnifiedFlashingPlatformTransport.cs b/UnifiedFlashingPlatformTransport.cs index f2b57b1..a5e7448 100644 --- a/UnifiedFlashingPlatformTransport.cs +++ b/UnifiedFlashingPlatformTransport.cs @@ -31,9 +31,9 @@ namespace UnifiedFlashingPlatform public partial class UnifiedFlashingPlatformTransport : IDisposable { private bool Disposed = false; - private readonly USBDevice? USBDevice = null; - private readonly USBPipe? InputPipe = null; - private readonly USBPipe? OutputPipe = null; + private readonly USBDevice USBDevice; + private readonly USBPipe InputPipe; + private readonly USBPipe OutputPipe; private readonly object UsbLock = new(); public UnifiedFlashingPlatformTransport(string DevicePath) @@ -59,12 +59,12 @@ namespace UnifiedFlashingPlatform } } - public byte[] ExecuteRawMethod(byte[] RawMethod) + public byte[]? ExecuteRawMethod(byte[] RawMethod) { return ExecuteRawMethod(RawMethod, RawMethod.Length); } - public byte[] ExecuteRawMethod(byte[] RawMethod, int Length) + public byte[]? ExecuteRawMethod(byte[] RawMethod, int Length) { byte[] Buffer = new byte[0xF000]; // Should be at least 0x4408 for receiving the GPT packet. byte[]? Result = null; @@ -172,7 +172,7 @@ namespace UnifiedFlashingPlatform _ = ExecuteRawMethod(Request); } - public byte[] Echo(byte[] DataPayload) + public byte[]? Echo(byte[] DataPayload) { byte[] Request = new byte[10 + DataPayload.Length]; string Header = EchoSignature; // NOKXCE @@ -181,7 +181,7 @@ namespace UnifiedFlashingPlatform Buffer.BlockCopy(BitConverter.GetBytes(DataPayload.Length).Reverse().ToArray(), 0, Request, 6, 4); Buffer.BlockCopy(DataPayload, 0, Request, 10, DataPayload.Length); - byte[] Response = ExecuteRawMethod(Request); + byte[]? Response = ExecuteRawMethod(Request); if ((Response == null) || (Response.Length < 6 + DataPayload.Length)) { return null; @@ -209,7 +209,7 @@ namespace UnifiedFlashingPlatform } // WIP! - public string ReadLog() + public string? ReadLog() { PhoneInfo Info = ReadPhoneInfo(); @@ -238,7 +238,7 @@ namespace UnifiedFlashingPlatform Buffer.BlockCopy(BitConverter.GetBytes(BufferSizeInt).Reverse().ToArray(), 0, Request, 7, 4); Buffer.BlockCopy(BitConverter.GetBytes(i).Reverse().ToArray(), 0, Request, 11, 8); - byte[] Response = ExecuteRawMethod(Request); + byte[]? Response = ExecuteRawMethod(Request); if ((Response == null) || (Response.Length < 0xC)) { return null;