Project Maintenance

This commit is contained in:
Gustave Monce
2021-08-09 20:21:09 +02:00
parent 9865ef7f79
commit 847ce0506d
411 changed files with 5922 additions and 54941 deletions
+30 -5
View File
@@ -44,12 +44,16 @@ namespace WPinternals
internal static void WriteAsciiString(byte[] ByteArray, UInt32 Offset, string Text, UInt32? MaxBufferLength = null)
{
if (MaxBufferLength != null)
{
Array.Clear(ByteArray, (int)Offset, (int)MaxBufferLength);
}
byte[] TextBytes = System.Text.ASCIIEncoding.ASCII.GetBytes(Text);
int WriteLength = TextBytes.Length;
if (WriteLength > MaxBufferLength)
{
WriteLength = (int)MaxBufferLength;
}
Buffer.BlockCopy(TextBytes, 0, ByteArray, (int)Offset, WriteLength);
}
@@ -57,12 +61,16 @@ namespace WPinternals
internal static void WriteUnicodeString(byte[] ByteArray, UInt32 Offset, string Text, UInt32? MaxBufferLength = null)
{
if (MaxBufferLength != null)
{
Array.Clear(ByteArray, (int)Offset, (int)MaxBufferLength);
}
byte[] TextBytes = System.Text.UnicodeEncoding.Unicode.GetBytes(Text);
int WriteLength = TextBytes.Length;
if (WriteLength > MaxBufferLength)
{
WriteLength = (int)MaxBufferLength;
}
Buffer.BlockCopy(TextBytes, 0, ByteArray, (int)Offset, WriteLength);
}
@@ -152,9 +160,13 @@ namespace WPinternals
internal static UInt32 Align(UInt32 Base, UInt32 Offset, UInt32 Alignment)
{
if (((Offset - Base) % Alignment) == 0)
{
return Offset;
}
else
{
return ((((Offset - Base) / Alignment) + 1) * Alignment) + Base;
}
}
internal static UInt32? FindPatternInFile(string FileName, byte[] Pattern, byte[] Mask, out byte[] OutPattern)
@@ -164,7 +176,7 @@ namespace WPinternals
UInt32? Result = null;
FileStream Stream = new FileStream(FileName, FileMode.Open, FileAccess.Read);
FileStream Stream = new(FileName, FileMode.Open, FileAccess.Read);
byte[] Buffer = new byte[0x10000 + Pattern.Length - 1];
UInt32 BufferReadPosition = 0; // Position in buffer where file-chunk is being read.
@@ -200,11 +212,13 @@ namespace WPinternals
for (i = 0; i < Pattern.Length; i++)
{
if (Buffer[SearchPositionBuffer + i] != Pattern[i])
{
if ((Mask == null) || (Mask[i] == 0))
{
Match = false;
break;
}
}
}
if (Match)
@@ -227,17 +241,17 @@ namespace WPinternals
internal static UInt32? FindAscii(byte[] SourceBuffer, string Pattern)
{
return FindPattern(SourceBuffer, System.Text.ASCIIEncoding.ASCII.GetBytes((string)Pattern), null, null);
return FindPattern(SourceBuffer, System.Text.ASCIIEncoding.ASCII.GetBytes(Pattern), null, null);
}
internal static UInt32? FindUnicode(byte[] SourceBuffer, string Pattern)
{
return FindPattern(SourceBuffer, System.Text.UnicodeEncoding.Unicode.GetBytes((string)Pattern), null, null);
return FindPattern(SourceBuffer, System.Text.UnicodeEncoding.Unicode.GetBytes(Pattern), null, null);
}
internal static UInt32? FindUint(byte[] SourceBuffer, UInt32 Pattern)
{
return FindPattern(SourceBuffer, BitConverter.GetBytes((UInt32)Pattern), null, null);
return FindPattern(SourceBuffer, BitConverter.GetBytes(Pattern), null, null);
}
internal static UInt32? FindPattern(byte[] SourceBuffer, byte[] Pattern, byte[] Mask, byte[] OutPattern)
@@ -267,11 +281,13 @@ namespace WPinternals
for (i = 0; i < Pattern.Length; i++)
{
if (SourceBuffer[SearchPosition + i] != Pattern[i])
{
if ((Mask == null) || (Mask[i] == 0))
{
Match = false;
break;
}
}
}
if (Match)
@@ -279,7 +295,10 @@ namespace WPinternals
Result = SearchPosition;
if (OutPattern != null)
{
System.Buffer.BlockCopy(SourceBuffer, (int)SearchPosition, OutPattern, 0, Pattern.Length);
}
break;
}
@@ -294,7 +313,9 @@ namespace WPinternals
byte Checksum = 0;
for (UInt32 i = Offset; i < (Offset + Size); i++)
{
Checksum += Buffer[i];
}
return (byte)(0x100 - Checksum);
}
@@ -304,12 +325,14 @@ namespace WPinternals
UInt16 Checksum = 0;
for (UInt32 i = Offset; i < (Offset + Size - 1); i += 2)
{
Checksum += BitConverter.ToUInt16(Buffer, (int)i);
}
return (UInt16)(0x10000 - Checksum);
}
private static UInt32[] CRC32Table = new UInt32[] {
private static readonly UInt32[] CRC32Table = new UInt32[] {
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
@@ -358,7 +381,9 @@ namespace WPinternals
internal static UInt32 CRC32(byte[] Input, UInt32 Offset, UInt32 Length)
{
if ((Input == null) || ((Offset + Length) > Input.Length))
{
throw new ArgumentException();
}
unchecked
{
+55 -11
View File
@@ -31,7 +31,7 @@ namespace WPinternals
internal byte[] SecurityHeader;
internal byte[] ImageHeader;
internal byte[] StoreHeader;
private int?[] ChunkIndexes;
private readonly int?[] ChunkIndexes;
private FileStream FFUFile = null;
private int FileOpenCount = 0;
@@ -55,7 +55,10 @@ namespace WPinternals
byte[] ShortSecurityHeader = new byte[0x20];
FFUFile.Read(ShortSecurityHeader, 0, 0x20);
if (ByteOperations.ReadAsciiString(ShortSecurityHeader, 0x04, 0x0C) != "SignedImage ")
{
throw new BadImageFormatException();
}
ChunkSize = ByteOperations.ReadInt32(ShortSecurityHeader, 0x10) * 1024;
UInt32 SecurityHeaderSize = ByteOperations.ReadUInt32(ShortSecurityHeader, 0x00);
UInt32 CatalogSize = ByteOperations.ReadUInt32(ShortSecurityHeader, 0x18);
@@ -68,7 +71,10 @@ namespace WPinternals
byte[] ShortImageHeader = new byte[0x1C];
FFUFile.Read(ShortImageHeader, 0, 0x1C);
if (ByteOperations.ReadAsciiString(ShortImageHeader, 0x04, 0x0C) != "ImageFlash ")
{
throw new BadImageFormatException();
}
UInt32 ImageHeaderSize = ByteOperations.ReadUInt32(ShortImageHeader, 0x00);
UInt32 ManifestSize = ByteOperations.ReadUInt32(ShortImageHeader, 0x10);
ImageHeader = new byte[RoundUpToChunks(ImageHeaderSize + ManifestSize)];
@@ -107,7 +113,9 @@ namespace WPinternals
if (DiskAccessMethod == 0) // 0 = From begin, 2 = From end. We ignore chunks at end of disk. These contain secondairy GPT.
{
if ((ChunkIndex + ChunkCount - 1) > HighestChunkIndex)
{
HighestChunkIndex = ChunkIndex + ChunkCount - 1;
}
}
}
WriteDescriptorEntryOffset += 8 + (LocationCount * 0x08);
@@ -148,7 +156,9 @@ namespace WPinternals
TotalSize = HeaderSize + PayloadSize;
if (TotalSize != (UInt64)FFUFile.Length)
{
throw new WPinternalsException("Bad FFU file", "Bad FFU file: " + Path + "." + Environment.NewLine + "Expected size: " + TotalSize.ToString() + ". Actual size: " + FFUFile.Length + ".");
}
}
catch (WPinternalsException)
{
@@ -168,7 +178,7 @@ namespace WPinternals
{
bool Result = false;
FileStream FFUFile = new FileStream(FileName, FileMode.Open, FileAccess.Read);
FileStream FFUFile = new(FileName, FileMode.Open, FileAccess.Read);
byte[] Signature = new byte[0x10];
FFUFile.Read(Signature, 0, 0x10);
@@ -207,24 +217,34 @@ namespace WPinternals
if (FFUFile != null)
{
if (FFUFile.Position != Position)
{
FFUFile.Seek(Position, SeekOrigin.Begin);
}
}
}
internal UInt32 RoundUpToChunks(UInt32 Size)
{
if ((Size % ChunkSize) > 0)
{
return (UInt32)(((Size / ChunkSize) + 1) * ChunkSize);
}
else
{
return Size;
}
}
internal UInt32 RoundDownToChunks(UInt32 Size)
{
if ((Size % ChunkSize) > 0)
{
return (UInt32)((Size / ChunkSize) * ChunkSize);
}
else
{
return Size;
}
}
internal byte[] GetSectors(int StartSector, int SectorCount)
@@ -248,10 +268,14 @@ namespace WPinternals
int LastSector = (ChunkSize / 0x200) - 1;
if (j == FirstChunk)
{
FirstSector = GetSectorNumberInChunkFromSectorIndex(StartSector);
}
if (j == LastChunk)
{
LastSector = GetSectorNumberInChunkFromSectorIndex(StartSector + SectorCount - 1);
}
int Offset = FirstSector * 0x200;
int Size = (LastSector - FirstSector + 1) * 0x200;
@@ -268,9 +292,12 @@ namespace WPinternals
internal byte[] GetPartition(string Name)
{
Partition Target = GPT.Partitions.Where(p => (string.Compare(p.Name, Name, true) == 0)).FirstOrDefault();
Partition Target = GPT.Partitions.Find(p => (string.Compare(p.Name, Name, true) == 0));
if (Target == null)
{
throw new ArgumentOutOfRangeException();
}
return GetSectors((int)Target.FirstSector, (int)(Target.LastSector - Target.FirstSector + 1));
}
@@ -291,22 +318,26 @@ namespace WPinternals
private void WritePartition(string Name, string FilePath, Action<int, TimeSpan?> ProgressUpdateCallback, ProgressUpdater UpdaterPerSector, bool Compress = false)
{
Partition Target = GPT.Partitions.Where(p => (string.Compare(p.Name, Name, true) == 0)).FirstOrDefault();
Partition Target = GPT.Partitions.Find(p => (string.Compare(p.Name, Name, true) == 0));
if (Target == null)
{
throw new ArgumentOutOfRangeException();
}
int FirstChunk = GetChunkIndexFromSectorIndex((int)Target.FirstSector);
int LastChunk = GetChunkIndexFromSectorIndex((int)Target.LastSector);
ProgressUpdater Updater = UpdaterPerSector;
if ((Updater == null) && (ProgressUpdateCallback != null))
{
Updater = new ProgressUpdater(Target.LastSector - Target.FirstSector + 1, ProgressUpdateCallback);
}
byte[] Buffer = new byte[ChunkSize];
OpenFile();
FileStream OutputFile = new FileStream(FilePath, FileMode.Create, FileAccess.Write);
FileStream OutputFile = new(FilePath, FileMode.Create, FileAccess.Write);
Stream OutStream = OutputFile;
// We use gzip compression
@@ -333,18 +364,21 @@ namespace WPinternals
int LastSector = (ChunkSize / 0x200) - 1;
if (j == FirstChunk)
{
FirstSector = GetSectorNumberInChunkFromSectorIndex((int)Target.FirstSector);
}
if (j == LastChunk)
{
LastSector = GetSectorNumberInChunkFromSectorIndex((int)Target.LastSector);
}
int Offset = FirstSector * 0x200;
int Size = (LastSector - FirstSector + 1) * 0x200;
OutStream.Write(Buffer, Offset, Size);
if (Updater != null)
Updater.IncreaseProgress((UInt64)(ChunkSize / 0x200));
Updater?.IncreaseProgress((UInt64)(ChunkSize / 0x200));
}
OutStream.Close();
@@ -356,7 +390,9 @@ namespace WPinternals
{
long BaseOffset = (long)SecurityHeader.Length + ImageHeader.Length + StoreHeader.Length;
if (ChunkIndexes[ChunkIndex] == null)
{
return new byte[ChunkSize];
}
else
{
OpenFile();
@@ -372,7 +408,9 @@ namespace WPinternals
{
long BaseOffset = SecurityHeader.Length + ImageHeader.Length + StoreHeader.Length;
if (ChunkIndexes[ChunkIndex] == null)
{
Array.Clear(Chunk, 0, ChunkSize);
}
else
{
OpenFile();
@@ -398,9 +436,12 @@ namespace WPinternals
{
Partition Target = GPT.GetPartition(PartitionName);
if (Target == null)
{
throw new InvalidOperationException("Partitionname is not found!");
}
int ChunkIndex = GetChunkIndexFromSectorIndex((int)Target.FirstSector);
return (ChunkIndexes[ChunkIndex] != null);
return ChunkIndexes[ChunkIndex] != null;
}
private int GetChunkIndexFromSectorIndex(ulong p)
@@ -423,7 +464,10 @@ namespace WPinternals
uint Length = (uint)ByteOperations.FindPattern(Data, Start, 0x100, new byte[] { 0x00 }, null, null) - Start;
uint? Offset0D = ByteOperations.FindPattern(Data, Start, 0x100, new byte[] { 0x0D }, null, null);
if ((Offset0D != null) && (Offset0D < (Start + Length)))
{
Length = (uint)Offset0D - Start;
}
Result = ByteOperations.ReadAsciiString(Data, Start, Length);
}
}
@@ -434,10 +478,10 @@ namespace WPinternals
internal string GetOSVersion()
{
byte[] efiesp = GetPartition("EFIESP");
MemoryStream s = new MemoryStream(efiesp);
DiscUtils.Fat.FatFileSystem fs = new DiscUtils.Fat.FatFileSystem(s);
MemoryStream s = new(efiesp);
DiscUtils.Fat.FatFileSystem fs = new(s);
Stream mss = fs.OpenFile(@"Windows\System32\Boot\mobilestartup.efi", FileMode.Open, FileAccess.Read);
MemoryStream msms = new MemoryStream();
MemoryStream msms = new();
mss.CopyTo(msms);
byte[] mobilestartup = msms.ToArray();
Version OSVersion = PE.GetProductVersion(mobilestartup);
+119 -47
View File
@@ -31,18 +31,18 @@ namespace WPinternals
public class GPT
{
private byte[] GPTBuffer;
private UInt32 HeaderOffset;
private UInt32 HeaderSize;
private readonly UInt32 HeaderOffset;
private readonly UInt32 HeaderSize;
private UInt32 TableOffset;
private UInt32 TableSize;
private UInt32 PartitionEntrySize;
private UInt32 MaxPartitions;
private readonly UInt32 PartitionEntrySize;
private readonly UInt32 MaxPartitions;
internal UInt64 FirstUsableSector;
internal UInt64 LastUsableSector;
internal bool HasChanged = false;
[XmlElement("Partition")]
public List<Partition> Partitions = new List<Partition>();
public List<Partition> Partitions = new();
public GPT() // Only for serialization
{
@@ -53,7 +53,10 @@ namespace WPinternals
this.GPTBuffer = GPTBuffer;
UInt32? TempHeaderOffset = ByteOperations.FindAscii(GPTBuffer, "EFI PART");
if (TempHeaderOffset == null)
{
throw new WPinternalsException("Bad GPT", "The GPT read isn't valid. Couldn't find the text \"EFI PART\".");
}
HeaderOffset = (UInt32)TempHeaderOffset;
HeaderSize = ByteOperations.ReadUInt32(GPTBuffer, HeaderOffset + 0x0C);
TableOffset = HeaderOffset + 0x200;
@@ -63,7 +66,9 @@ namespace WPinternals
PartitionEntrySize = ByteOperations.ReadUInt32(GPTBuffer, HeaderOffset + 0x54);
TableSize = MaxPartitions * PartitionEntrySize;
if ((TableOffset + TableSize) > GPTBuffer.Length)
{
throw new WPinternalsException("Bad GPT", "The GPT read isn't valid. The sizes defined in the GPT header exceed the provided GPT size.");
}
UInt32 PartitionOffset = TableOffset;
@@ -71,8 +76,11 @@ namespace WPinternals
{
string Name = ByteOperations.ReadUnicodeString(GPTBuffer, PartitionOffset + 0x38, 0x48).TrimEnd(new char[] { (char)0, ' ' });
if (Name.Length == 0)
{
break;
Partition CurrentPartition = new Partition();
}
Partition CurrentPartition = new();
CurrentPartition.Name = Name;
CurrentPartition.FirstSector = ByteOperations.ReadUInt64(GPTBuffer, PartitionOffset + 0x20);
CurrentPartition.LastSector = ByteOperations.ReadUInt64(GPTBuffer, PartitionOffset + 0x28);
@@ -88,30 +96,34 @@ namespace WPinternals
internal Partition GetPartition(string Name)
{
return Partitions.Where(p => (string.Compare(p.Name, Name, true) == 0)).FirstOrDefault();
return Partitions.Find(p => (string.Compare(p.Name, Name, true) == 0));
}
// Magic!
// SecureBoot hack for Bootloader Spec A starts here
internal byte[] InsertHack()
{
Partition HackPartition = Partitions.Where(p => (p.Name == "HACK")).FirstOrDefault();
Partition SBL1 = Partitions.Where(p => (p.Name == "SBL1")).FirstOrDefault();
Partition SBL2 = Partitions.Where(p => (p.Name == "SBL2")).FirstOrDefault();
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();
HackPartition.Name = "HACK";
HackPartition.Attributes = SBL2.Attributes;
HackPartition.FirstSector = SBL1.LastSector;
HackPartition.LastSector = SBL1.LastSector;
HackPartition = new Partition
{
Name = "HACK",
Attributes = SBL2.Attributes,
FirstSector = SBL1.LastSector,
LastSector = SBL1.LastSector,
HackPartition.PartitionTypeGuid = SBL2.PartitionTypeGuid;
HackPartition.PartitionGuid = SBL2.PartitionGuid;
PartitionTypeGuid = SBL2.PartitionTypeGuid,
PartitionGuid = SBL2.PartitionGuid
};
Partitions.Add(HackPartition);
@@ -128,12 +140,14 @@ namespace WPinternals
internal byte[] RemoveHack()
{
Partition HackPartition = Partitions.Where(p => (p.Name == "HACK")).FirstOrDefault();
Partition SBL1 = Partitions.Where(p => (p.Name == "SBL1")).FirstOrDefault();
Partition SBL2 = Partitions.Where(p => (p.Name == "SBL2")).FirstOrDefault();
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)
{
@@ -159,7 +173,9 @@ namespace WPinternals
GPTBuffer = new byte[TableSize];
}
else
{
Array.Clear(GPTBuffer, (int)TableOffset, (int)TableSize);
}
UInt32 PartitionOffset = TableOffset;
foreach (Partition CurrentPartition in Partitions)
@@ -188,21 +204,21 @@ namespace WPinternals
internal void MergePartitionsFromStream(Stream Partitions, bool RoundToChunks)
{
using (TextReader tr = new StreamReader(Partitions))
{
MergePartitions(tr.ReadToEnd(), RoundToChunks);
}
using TextReader tr = new StreamReader(Partitions);
MergePartitions(tr.ReadToEnd(), RoundToChunks);
}
internal void MergePartitions(string Xml, bool RoundToChunks, ZipArchive Archive = null)
{
GPT GptToMerge;
if (Xml == null)
{
GptToMerge = new GPT();
}
else
{
XmlSerializer x = new XmlSerializer(typeof(GPT), "");
MemoryStream s = new MemoryStream(System.Text.Encoding.ASCII.GetBytes(Xml));
XmlSerializer x = new(typeof(GPT), "");
MemoryStream s = new(System.Text.Encoding.ASCII.GetBytes(Xml));
GptToMerge = (GPT)x.Deserialize(s);
s.Dispose();
}
@@ -211,7 +227,7 @@ namespace WPinternals
{
foreach (Partition NewPartition in GptToMerge.Partitions)
{
ZipArchiveEntry Entry = Archive.Entries.Where(e => ((string.Compare(e.Name, NewPartition.Name, true) == 0) || (e.Name.StartsWith(NewPartition.Name + ".", true, System.Globalization.CultureInfo.GetCultureInfo("en-US"))))).FirstOrDefault();
ZipArchiveEntry Entry = Archive.Entries.FirstOrDefault(e => ((string.Compare(e.Name, NewPartition.Name, true) == 0) || (e.Name.StartsWith(NewPartition.Name + ".", true, System.Globalization.CultureInfo.GetCultureInfo("en-US")))));
if (Entry == null)
{
// There is a partition entry in the xml, but this partition is not present in the archive.
@@ -234,9 +250,14 @@ namespace WPinternals
// If the location of the new partition is specified, it must be the same as the current partition.
if ((NewPartition.FirstSector != 0) && (NewPartition.FirstSector != OldPartition.FirstSector))
{
throw new WPinternalsException("Incorrect location for partition \"" + NewPartition.Name + "\". A partition defined in the xml file got its boundaries updated, but as the partition isn't provided in the archive, it is not possible to relocate it.");
}
if ((NewPartition.LastSector != 0) && (NewPartition.LastSector != OldPartition.LastSector))
{
throw new WPinternalsException("Incorrect length for partition \"" + NewPartition.Name + "\". A partition defined in the xml file got its boundaries updated, but as the partition isn't provided in the archive, it is not possible to relocate it.");
}
NewPartition.FirstSector = OldPartition.FirstSector;
NewPartition.LastSector = OldPartition.LastSector;
@@ -248,7 +269,7 @@ namespace WPinternals
// If the length is specified in the xml, it must match the file in the archive.
ulong StreamLengthInSectors = (ulong)Entry.Length / 0x200;
using (DecompressedStream DecompressedStream = new DecompressedStream(Entry.Open()))
using (DecompressedStream DecompressedStream = new(Entry.Open()))
{
try
{
@@ -264,7 +285,9 @@ namespace WPinternals
else
{
if (NewPartition.SizeInSectors != StreamLengthInSectors)
{
throw new WPinternalsException("Inconsistent length specified for partition \"" + NewPartition.Name + "\". The provided partition in the archive does not match the length specified in the xml file.");
}
}
}
}
@@ -293,9 +316,14 @@ namespace WPinternals
// If the location of the new partition is specified, it must be the same as the current partition.
if ((NewPartition.FirstSector != 0) && (NewPartition.FirstSector != OldPartition.FirstSector))
{
throw new WPinternalsException("Incorrect location for partition \"" + NewPartition.Name + "\". A partition defined in the xml file got its boundaries updated, but as the partition isn't provided in the archive, it is not possible to relocate it.");
}
if ((NewPartition.LastSector != 0) && (NewPartition.LastSector != OldPartition.LastSector))
{
throw new WPinternalsException("Incorrect length for partition \"" + NewPartition.Name + "\". A partition defined in the xml file got its boundaries updated, but as the partition isn't provided in the archive, it is not possible to relocate it.");
}
NewPartition.FirstSector = OldPartition.FirstSector;
NewPartition.LastSector = OldPartition.LastSector;
@@ -303,7 +331,7 @@ namespace WPinternals
}
}
List<Partition> DynamicPartitions = new List<Partition>();
List<Partition> DynamicPartitions = new();
if (Archive != null)
{
// Partitions which are present in the archive, and which have no start-sector in the new GPT data (dynamic relocation),
@@ -314,7 +342,7 @@ namespace WPinternals
Partition OldPartition = SortedPartitions.ElementAt(i);
// Present in archive?
ZipArchiveEntry Entry = Archive.Entries.Where(e => ((string.Compare(e.Name, OldPartition.Name, true) == 0) || (e.Name.StartsWith(OldPartition.Name + ".", true, System.Globalization.CultureInfo.GetCultureInfo("en-US"))))).FirstOrDefault();
ZipArchiveEntry Entry = Archive.Entries.FirstOrDefault(e => ((string.Compare(e.Name, OldPartition.Name, true) == 0) || (e.Name.StartsWith(OldPartition.Name + ".", true, System.Globalization.CultureInfo.GetCultureInfo("en-US")))));
if (Entry != null)
{
// Not present in new GPT or present in GPT without FirstSector?
@@ -325,10 +353,14 @@ namespace WPinternals
this.Partitions.Remove(OldPartition);
}
else
{
break;
}
}
else
{
break;
}
}
}
@@ -339,22 +371,31 @@ namespace WPinternals
UInt64 LowestSector = 0;
Partition DPP = this.GetPartition("DPP");
if (DPP != null)
{
LowestSector = DPP.LastSector + 1;
}
foreach (Partition NewPartition in GptToMerge.Partitions)
{
// If the new partition is a dynamic partition, then skip it here. It will be added later.
if (DynamicPartitions.Select(p => p.Name).Any(n => string.Compare(n, NewPartition.Name, true) == 0))
{
continue;
}
// Sanity check
if (NewPartition.FirstSector < LowestSector)
{
throw new WPinternalsException("Bad sector alignment for partition: " + NewPartition.Name + ". The partition is located before DPP.");
}
Partition CurrentPartition = this.GetPartition(NewPartition.Name);
if (CurrentPartition == null)
{
CurrentPartition = new Partition();
CurrentPartition.Name = NewPartition.Name;
CurrentPartition = new Partition
{
Name = NewPartition.Name
};
this.Partitions.Add(CurrentPartition);
HasChanged = true;
}
@@ -376,18 +417,34 @@ namespace WPinternals
}
if ((NewPartition.PartitionGuid != Guid.Empty) || (NewPartition.PartitionGuid != CurrentPartition.PartitionGuid))
{
HasChanged = true;
}
if (NewPartition.PartitionGuid != Guid.Empty)
{
CurrentPartition.PartitionGuid = NewPartition.PartitionGuid;
}
if (CurrentPartition.PartitionGuid != Guid.Empty)
{
CurrentPartition.PartitionGuid = Guid.NewGuid();
}
if ((NewPartition.PartitionTypeGuid != Guid.Empty) || (NewPartition.PartitionTypeGuid != CurrentPartition.PartitionTypeGuid))
{
HasChanged = true;
}
if (NewPartition.PartitionTypeGuid != Guid.Empty)
{
CurrentPartition.PartitionTypeGuid = NewPartition.PartitionTypeGuid;
}
if (CurrentPartition.PartitionTypeGuid != Guid.Empty)
{
CurrentPartition.PartitionTypeGuid = Guid.NewGuid();
}
for (int i = this.Partitions.Count - 1; i >= 0; i--)
{
@@ -408,10 +465,10 @@ namespace WPinternals
// Check if the sizes of the partitions in the archive do not exceed the size of the partition, as listed in the GPT.
foreach (Partition OldPartition in this.Partitions)
{
ZipArchiveEntry Entry = Archive.Entries.Where(e => ((string.Compare(e.Name, OldPartition.Name, true) == 0) || (e.Name.StartsWith(OldPartition.Name + ".", true, System.Globalization.CultureInfo.GetCultureInfo("en-US"))))).FirstOrDefault();
ZipArchiveEntry Entry = Archive.Entries.FirstOrDefault(e => ((string.Compare(e.Name, OldPartition.Name, true) == 0) || (e.Name.StartsWith(OldPartition.Name + ".", true, System.Globalization.CultureInfo.GetCultureInfo("en-US")))));
if (Entry != null)
{
DecompressedStream DecompressedStream = new DecompressedStream(Entry.Open());
DecompressedStream DecompressedStream = new(Entry.Open());
ulong StreamLengthInSectors = (ulong)Entry.Length / 0x200;
try
{
@@ -423,7 +480,10 @@ namespace WPinternals
UInt64 MaxPartitionSizeInSectors = OldPartition.SizeInSectors;
Partition NextPartition = this.Partitions.Where(p => p.FirstSector > OldPartition.FirstSector).OrderBy(p => p.FirstSector).FirstOrDefault();
if (NextPartition != null)
{
MaxPartitionSizeInSectors = NextPartition.FirstSector - OldPartition.FirstSector;
}
if (StreamLengthInSectors > MaxPartitionSizeInSectors)
{
throw new WPinternalsException("Incorrect length for partition \"" + OldPartition.Name + "\". The provided partition in the archive does not match the length specified in the xml file.");
@@ -446,8 +506,9 @@ namespace WPinternals
// Always start a new partition on a new chunk (0x100 sector boundary), to be more flexible during custom flash
if (RoundToChunks && (((double)FirstFreeSector % 0x100) != 0))
{
FirstFreeSector = (UInt64)(Math.Ceiling((double)FirstFreeSector / 0x100) * 0x100);
}
}
foreach (Partition NewPartition in DynamicPartitions)
{
@@ -456,8 +517,8 @@ namespace WPinternals
NewPartition.FirstSector = FirstFreeSector;
HasChanged = true;
}
ZipArchiveEntry Entry = Archive.Entries.Where(e => ((string.Compare(e.Name, NewPartition.Name, true) == 0) || (e.Name.StartsWith(NewPartition.Name + ".", true, System.Globalization.CultureInfo.GetCultureInfo("en-US"))))).FirstOrDefault();
DecompressedStream DecompressedStream = new DecompressedStream(Entry.Open());
ZipArchiveEntry Entry = Archive.Entries.FirstOrDefault(e => ((string.Compare(e.Name, NewPartition.Name, true) == 0) || (e.Name.StartsWith(NewPartition.Name + ".", true, System.Globalization.CultureInfo.GetCultureInfo("en-US")))));
DecompressedStream DecompressedStream = new(Entry.Open());
ulong StreamLengthInSectors = (ulong)Entry.Length / 0x200;
try
{
@@ -475,7 +536,9 @@ namespace WPinternals
// Always start a new partition on a new chunk (0x100 sector boundary), to be more flexible during custom flash
if (RoundToChunks && (((double)FirstFreeSector % 0x100) != 0))
{
FirstFreeSector = (UInt64)(Math.Ceiling((double)FirstFreeSector / 0x100) * 0x100);
}
}
}
@@ -486,31 +549,31 @@ namespace WPinternals
{
string DirPath = System.IO.Path.GetDirectoryName(Path);
if (!Directory.Exists(DirPath))
{
Directory.CreateDirectory(DirPath);
}
XmlSerializer x = new XmlSerializer(typeof(GPT), "");
XmlSerializer x = new(typeof(GPT), "");
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
XmlSerializerNamespaces ns = new();
ns.Add("", "");
System.IO.StreamWriter FileWriter = new System.IO.StreamWriter(Path);
StreamWriter FileWriter = new(Path);
x.Serialize(FileWriter, this, ns);
FileWriter.Close();
}
internal static GPT ReadPartitions(string Path)
{
XmlSerializer x = new XmlSerializer(typeof(GPT), "");
using (FileStream s = new FileStream(Path, FileMode.Open))
{
return (GPT)x.Deserialize(s);
}
XmlSerializer x = new(typeof(GPT), "");
using FileStream s = new(Path, FileMode.Open);
return (GPT)x.Deserialize(s);
}
internal void RestoreBackupPartitions()
{
// This is necessary, because the partitions and backup-partitions can exchange.
// This may cause the startsector to be higher than the maximum allowed sector for flashing with a Lumia V1 programmer (hardcoded in programmer)
List<string> RevisePartitions = new List<string>(new string[] { "SBL1", "SBL2", "SBL3", "UEFI", "TZ", "RPM", "WINSECAPP" });
List<string> RevisePartitions = new(new string[] { "SBL1", "SBL2", "SBL3", "UEFI", "TZ", "RPM", "WINSECAPP" });
foreach (string RevisePartitionName in RevisePartitions)
{
Partition RevisePartition = GetPartition(RevisePartitionName);
@@ -528,9 +591,10 @@ namespace WPinternals
}
if (RevisePartition.LastSector >= 0xF400)
{
throw new WPinternalsException("Unsupported partition layout!", "The last sector of one of the BACKUP partitions defined in GPT exceeds the maximum threshold expected in order to restore BACKUP partitions to the device.");
}
}
}
}
@@ -552,15 +616,21 @@ namespace WPinternals
get
{
if (_SizeInSectors != 0)
{
return _SizeInSectors;
}
else
{
return LastSector - FirstSector + 1;
}
}
set
{
_SizeInSectors = value;
if (FirstSector != 0)
{
LastSector = FirstSector + _SizeInSectors - 1;
}
}
}
@@ -575,7 +645,9 @@ namespace WPinternals
{
_FirstSector = value;
if (_SizeInSectors != 0)
{
_LastSector = FirstSector + _SizeInSectors - 1;
}
}
}
+48 -31
View File
@@ -40,13 +40,13 @@ namespace WPinternals
UInt64 OutputSize = ByteOperations.ReadUInt64(Input, Offset + 5);
SevenZip.Compression.LZMA.Decoder Coder = new SevenZip.Compression.LZMA.Decoder();
SevenZip.Compression.LZMA.Decoder Coder = new();
Coder.SetDecoderProperties(Properties);
MemoryStream InStream = new MemoryStream(Input, (int)Offset + 0x0D, (int)InputSize - 0x0D);
MemoryStream InStream = new(Input, (int)Offset + 0x0D, (int)InputSize - 0x0D);
byte[] Output = new byte[OutputSize];
MemoryStream OutStream = new MemoryStream(Output, true);
MemoryStream OutStream = new(Output, true);
Coder.Code(InStream, OutStream, (Int64)InputSize - 0x0D, (Int64)OutputSize, null);
@@ -59,10 +59,10 @@ namespace WPinternals
internal static byte[] Compress(byte[] Input, UInt32 Offset, UInt32 InputSize)
{
SevenZip.Compression.LZMA.Encoder Coder = new SevenZip.Compression.LZMA.Encoder();
SevenZip.Compression.LZMA.Encoder Coder = new();
MemoryStream InStream = new MemoryStream(Input, (int)Offset, (int)InputSize);
MemoryStream OutStream = new MemoryStream();
MemoryStream InStream = new(Input, (int)Offset, (int)InputSize);
MemoryStream OutStream = new();
// Write the encoder properties
Coder.WriteCoderProperties(OutStream);
@@ -71,7 +71,7 @@ namespace WPinternals
OutStream.Write(BitConverter.GetBytes(InStream.Length), 0, 8);
// Encode the file
Coder.Code(InStream, OutStream, (Int64)InputSize, -1, null);
Coder.Code(InStream, OutStream, InputSize, -1, null);
byte[] Output = new byte[OutStream.Length];
Buffer.BlockCopy(OutStream.GetBuffer(), 0, Output, 0, (int)OutStream.Length);
@@ -86,14 +86,14 @@ namespace WPinternals
public class LZMACompressionStream : Stream
{
private SevenZip.Compression.LZMA.Encoder Encoder = null;
private SevenZip.Compression.LZMA.Decoder Decoder = null;
private PumpStream BufferStream;
private Stream stream;
private bool LeaveOpen;
private Thread WorkThread;
private CancellationTokenSource source;
private CancellationToken token;
private readonly SevenZip.Compression.LZMA.Encoder Encoder = null;
private readonly SevenZip.Compression.LZMA.Decoder Decoder = null;
private readonly PumpStream BufferStream;
private readonly Stream stream;
private readonly bool LeaveOpen;
private readonly Thread WorkThread;
private readonly CancellationTokenSource source;
private readonly CancellationToken token;
public LZMACompressionStream(Stream stream, CompressionMode mode, bool LeaveOpen, int DictionarySize, int PosStateBits,
int LitContextBits, int LitPosBits, int Algorithm, int NumFastBytes, string MatchFinder, bool EndMarker)
@@ -108,10 +108,13 @@ namespace WPinternals
{
Encoder = new SevenZip.Compression.LZMA.Encoder();
if (DictionarySize != 0)
{
Encoder.SetCoderProperties(
new SevenZip.CoderPropID[8] {CoderPropID.DictionarySize, CoderPropID.PosStateBits, CoderPropID.LitContextBits,
new CoderPropID[8] {CoderPropID.DictionarySize, CoderPropID.PosStateBits, CoderPropID.LitContextBits,
CoderPropID.LitPosBits, CoderPropID.Algorithm, CoderPropID.NumFastBytes, CoderPropID.MatchFinder, CoderPropID.EndMarker},
new object[8] { DictionarySize, PosStateBits, LitContextBits, LitPosBits, Algorithm, NumFastBytes, MatchFinder, EndMarker });
}
Encoder.WriteCoderProperties(stream);
WorkThread = new Thread(new ThreadStart(Encode));
}
@@ -135,26 +138,31 @@ namespace WPinternals
private void Encode()
{
Encoder.Code(BufferStream, stream, -1, -1, null, token);
if (LeaveOpen == false)
if (!LeaveOpen)
{
stream.Close();
}
}
private void Decode()
{
Decoder.Code(stream, BufferStream, -1, -1, null, token);
BufferStream.Close();
if (LeaveOpen == false)
if (!LeaveOpen)
{
stream.Close();
}
}
public override void Close()
{
if (Encoder != null)
{
BufferStream.Close();
}
else if (WorkThread.IsAlive)
{
if (source != null)
source.Cancel();
source?.Cancel();
WorkThread.Join();
}
}
@@ -169,9 +177,9 @@ namespace WPinternals
BufferStream.Write(buffer, offset, count);
}
public override bool CanRead { get { return (Decoder != null); } }
public override bool CanRead { get { return Decoder != null; } }
public override bool CanSeek { get { return false; } }
public override bool CanWrite { get { return (Encoder != null); } }
public override bool CanWrite { get { return Encoder != null; } }
public override void Flush() { }
public override long Length { get { return 0; } }
public override long Position { get { return 0; } set { } }
@@ -181,9 +189,9 @@ namespace WPinternals
public class PumpStream : Stream
{
private Queue<byte[]> BufferQueue;
private readonly Queue<byte[]> BufferQueue;
private int BufferOffset;
private long MaxBufferSize;
private readonly long MaxBufferSize;
private long BufferSize;
private bool Closed;
private bool EOF;
@@ -214,7 +222,9 @@ namespace WPinternals
{
Closed = true;
lock (BufferQueue)
{
Monitor.Pulse(BufferQueue);
}
}
public override int Read(byte[] buffer, int offset, int count)
@@ -222,7 +232,7 @@ namespace WPinternals
int BytesRead = 0;
lock (BufferQueue)
{
while (BytesRead < count && EOF == false)
while (BytesRead < count && !EOF)
{
if (BufferQueue.Count > 0)
{
@@ -230,7 +240,7 @@ namespace WPinternals
if ((b.Length - BufferOffset) <= (count - BytesRead))
{
Array.Copy(b, BufferOffset, buffer, offset + BytesRead, (b.Length - BufferOffset));
Array.Copy(b, BufferOffset, buffer, offset + BytesRead, b.Length - BufferOffset);
BufferQueue.Dequeue();
BufferSize -= b.Length;
@@ -241,22 +251,25 @@ namespace WPinternals
}
else
{
Array.Copy(b, BufferOffset, buffer, offset + BytesRead, (count - BytesRead));
Array.Copy(b, BufferOffset, buffer, offset + BytesRead, count - BytesRead);
BufferOffset += (count - BytesRead);
BytesRead += (count - BytesRead);
}
}
else
{
if (Closed == false)
if (!Closed)
{
if (Monitor.Wait(BufferQueue, ReadTimeout) == false)
if (!Monitor.Wait(BufferQueue, ReadTimeout))
{
throw new IOException("Could not read from stream: Timeout expired waiting for data to be written.");
}
}
else
{
EOF = true;
}
}
}
}
@@ -269,8 +282,12 @@ namespace WPinternals
lock (BufferQueue)
{
while (BufferSize >= MaxBufferSize)
if (Monitor.Wait(BufferQueue, WriteTimeout) == false)
{
if (!Monitor.Wait(BufferQueue, WriteTimeout))
{
throw new IOException("Could not write to stream: Timeout expired waiting for data to be read.");
}
}
byte[] b = new byte[count];
Array.Copy(buffer, offset, b, 0, count);
+78 -51
View File
@@ -38,18 +38,25 @@ namespace WPinternals
{
internal static string SearchFFU(string ProductType, string ProductCode, string OperatorCode)
{
string FoundProductType;
return SearchFFU(ProductType, ProductCode, OperatorCode, out FoundProductType);
return SearchFFU(ProductType, ProductCode, OperatorCode, out string FoundProductType);
}
internal static string SearchFFU(string ProductType, string ProductCode, string OperatorCode, out string FoundProductType)
{
if (ProductType == "")
if (ProductType?.Length == 0)
{
ProductType = null;
if (ProductCode == "")
}
if (ProductCode?.Length == 0)
{
ProductCode = null;
if (OperatorCode == "")
}
if (OperatorCode?.Length == 0)
{
OperatorCode = null;
}
if (ProductCode != null)
{
@@ -61,12 +68,16 @@ namespace WPinternals
{
ProductType = ProductType.ToUpper();
if (ProductType.StartsWith("RM") && !ProductType.StartsWith("RM-"))
ProductType = "RM-" + ProductType.Substring(2);
{
ProductType = "RM-" + ProductType[2..];
}
}
if (OperatorCode != null)
{
OperatorCode = OperatorCode.ToUpper();
}
DiscoveryQueryParameters DiscoveryQueryParams = new DiscoveryQueryParameters
DiscoveryQueryParameters DiscoveryQueryParams = new()
{
manufacturerName = "Microsoft",
manufacturerProductLine = "Lumia",
@@ -76,20 +87,20 @@ namespace WPinternals
manufacturerHardwareVariant = ProductCode,
operatorName = OperatorCode
};
DiscoveryParameters DiscoveryParams = new DiscoveryParameters
DiscoveryParameters DiscoveryParams = new()
{
query = DiscoveryQueryParams
};
DataContractJsonSerializer Serializer1 = new DataContractJsonSerializer(typeof(DiscoveryParameters));
MemoryStream JsonStream1 = new MemoryStream();
DataContractJsonSerializer Serializer1 = new(typeof(DiscoveryParameters));
MemoryStream JsonStream1 = new();
Serializer1.WriteObject(JsonStream1, DiscoveryParams);
JsonStream1.Seek(0L, SeekOrigin.Begin);
string JsonContent = new StreamReader(JsonStream1).ReadToEnd();
Uri RequestUri = new Uri("https://api.swrepository.com/rest-api/discovery/1/package");
Uri RequestUri = new("https://api.swrepository.com/rest-api/discovery/1/package");
HttpClient HttpClient = new HttpClient();
HttpClient HttpClient = new();
HttpClient.DefaultRequestHeaders.UserAgent.TryParseAdd("SoftwareRepository");
HttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
@@ -106,33 +117,35 @@ namespace WPinternals
}
SoftwarePackage Package = null;
using (MemoryStream JsonStream2 = new MemoryStream(Encoding.UTF8.GetBytes(JsonResultString)))
using (MemoryStream JsonStream2 = new(Encoding.UTF8.GetBytes(JsonResultString)))
{
DataContractJsonSerializer Serializer2 = new DataContractJsonSerializer(typeof(SoftwarePackages));
DataContractJsonSerializer Serializer2 = new(typeof(SoftwarePackages));
SoftwarePackages SoftwarePackages = (SoftwarePackages)Serializer2.ReadObject(JsonStream2);
if (SoftwarePackages != null)
{
Package = SoftwarePackages.softwarePackages.FirstOrDefault<SoftwarePackage>();
Package = SoftwarePackages.softwarePackages.FirstOrDefault();
}
}
if (Package == null)
{
throw new WPinternalsException("FFU not found", "No FFU has been found in the remote software repository for the requested model.");
}
FoundProductType = Package.manufacturerHardwareModel[0];
SoftwareFile FileInfo = Package.files.Where(f => f.fileName.EndsWith(".ffu", StringComparison.OrdinalIgnoreCase)).First();
SoftwareFile FileInfo = Package.files.First(f => f.fileName.EndsWith(".ffu", StringComparison.OrdinalIgnoreCase));
Uri FileInfoUri = new Uri("https://api.swrepository.com/rest-api/discovery/fileurl/1/" + Package.id + "/" + FileInfo.fileName);
Uri FileInfoUri = new("https://api.swrepository.com/rest-api/discovery/fileurl/1/" + Package.id + "/" + FileInfo.fileName);
Task<string> GetFileInfoTask = HttpClient.GetStringAsync(FileInfoUri);
GetFileInfoTask.Wait();
string FileInfoString = GetFileInfoTask.Result;
string FfuUrl = "";
FileUrlResult FileUrl = null;
using (MemoryStream JsonStream3 = new MemoryStream(Encoding.UTF8.GetBytes(FileInfoString)))
using (MemoryStream JsonStream3 = new(Encoding.UTF8.GetBytes(FileInfoString)))
{
DataContractJsonSerializer Serializer3 = new DataContractJsonSerializer(typeof(FileUrlResult));
DataContractJsonSerializer Serializer3 = new(typeof(FileUrlResult));
FileUrl = (FileUrlResult)Serializer3.ReadObject(JsonStream3);
if (FileUrl != null)
{
@@ -147,17 +160,21 @@ namespace WPinternals
internal static string SearchENOSW(string ProductType, string PhoneFirmwareRevision)
{
if (ProductType == "")
if (ProductType?.Length == 0)
{
ProductType = null;
}
if (ProductType != null)
{
ProductType = ProductType.ToUpper();
if (ProductType.StartsWith("RM") && !ProductType.StartsWith("RM-"))
ProductType = "RM-" + ProductType.Substring(2);
{
ProductType = "RM-" + ProductType[2..];
}
}
DiscoveryQueryParameters DiscoveryQueryParams = new DiscoveryQueryParameters
DiscoveryQueryParameters DiscoveryQueryParams = new()
{
manufacturerName = "Microsoft",
manufacturerProductLine = "Lumia",
@@ -165,20 +182,20 @@ namespace WPinternals
packageClass = "Public",
manufacturerHardwareModel = ProductType
};
DiscoveryParameters DiscoveryParams = new DiscoveryParameters
DiscoveryParameters DiscoveryParams = new()
{
query = DiscoveryQueryParams
};
DataContractJsonSerializer Serializer1 = new DataContractJsonSerializer(typeof(DiscoveryParameters));
MemoryStream JsonStream1 = new MemoryStream();
DataContractJsonSerializer Serializer1 = new(typeof(DiscoveryParameters));
MemoryStream JsonStream1 = new();
Serializer1.WriteObject(JsonStream1, DiscoveryParams);
JsonStream1.Seek(0L, SeekOrigin.Begin);
string JsonContent = new StreamReader(JsonStream1).ReadToEnd();
Uri RequestUri = new Uri("https://api.swrepository.com/rest-api/discovery/1/package");
Uri RequestUri = new("https://api.swrepository.com/rest-api/discovery/1/package");
HttpClient HttpClient = new HttpClient();
HttpClient HttpClient = new();
HttpClient.DefaultRequestHeaders.UserAgent.TryParseAdd("SoftwareRepository");
HttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
@@ -195,33 +212,37 @@ namespace WPinternals
}
SoftwarePackage Package = null;
using (MemoryStream JsonStream2 = new MemoryStream(Encoding.UTF8.GetBytes(JsonResultString)))
using (MemoryStream JsonStream2 = new(Encoding.UTF8.GetBytes(JsonResultString)))
{
DataContractJsonSerializer Serializer2 = new DataContractJsonSerializer(typeof(SoftwarePackages));
DataContractJsonSerializer Serializer2 = new(typeof(SoftwarePackages));
SoftwarePackages SoftwarePackages = (SoftwarePackages)Serializer2.ReadObject(JsonStream2);
if (SoftwarePackages != null)
{
foreach (SoftwarePackage pkg in SoftwarePackages.softwarePackages)
Package = SoftwarePackages.softwarePackages.FirstOrDefault<SoftwarePackage>();
{
Package = SoftwarePackages.softwarePackages.FirstOrDefault();
}
}
}
if (Package == null)
{
throw new WPinternalsException("ENOSW package not found", "No ENOSW package has been found in the remote software repository for the requested model.");
}
SoftwareFile FileInfo = Package.files.Where(f => f.fileName.EndsWith(".secwim", StringComparison.OrdinalIgnoreCase)).First();
SoftwareFile FileInfo = Package.files.First(f => f.fileName.EndsWith(".secwim", StringComparison.OrdinalIgnoreCase));
SoftwareFile DPLF = Package.files.Where(f => f.fileName.EndsWith(".dpl", StringComparison.OrdinalIgnoreCase)).First();
Uri DPLUri = new Uri("https://api.swrepository.com/rest-api/discovery/fileurl/1/" + Package.id + "/" + DPLF.fileName);
SoftwareFile DPLF = Package.files.First(f => f.fileName.EndsWith(".dpl", StringComparison.OrdinalIgnoreCase));
Uri DPLUri = new("https://api.swrepository.com/rest-api/discovery/fileurl/1/" + Package.id + "/" + DPLF.fileName);
Task<string> GetDPLTask = HttpClient.GetStringAsync(DPLUri);
GetDPLTask.Wait();
string DPLString = GetDPLTask.Result;
string DPLUrl = "";
FileUrlResult FileUrlDPL = null;
using (MemoryStream JsonStream3 = new MemoryStream(Encoding.UTF8.GetBytes(DPLString)))
using (MemoryStream JsonStream3 = new(Encoding.UTF8.GetBytes(DPLString)))
{
DataContractJsonSerializer Serializer3 = new DataContractJsonSerializer(typeof(FileUrlResult));
DataContractJsonSerializer Serializer3 = new(typeof(FileUrlResult));
FileUrlDPL = (FileUrlResult)Serializer3.ReadObject(JsonStream3);
if (FileUrlDPL != null)
{
@@ -229,16 +250,18 @@ namespace WPinternals
}
}
if (DPLUrl == "")
if (DPLUrl?.Length == 0)
{
throw new WPinternalsException("DPL not found", "No DPL has been found in the remote software repository for the requested model.");
}
Task<string> GetDPLStrTask = HttpClient.GetStringAsync(DPLUrl);
GetDPLStrTask.Wait();
string DPLStrString = GetDPLStrTask.Result;
DPL.Package dpl;
XmlSerializer serializer = new XmlSerializer(typeof(DPL.Package));
using (StringReader reader = new StringReader(DPLStrString.Replace("ft:", "").Replace("dpl:", "").Replace("typedes:", "")))
XmlSerializer serializer = new(typeof(DPL.Package));
using (StringReader reader = new(DPLStrString.Replace("ft:", "").Replace("dpl:", "").Replace("typedes:", "")))
{
dpl = (DPL.Package)serializer.Deserialize(reader);
}
@@ -250,19 +273,21 @@ namespace WPinternals
DPL.Range range = file.Extensions.MmosWimFile.UseCaseCompatibilities.Compatibility.FirstOrDefault().Range;
if (IsFirmwareBetween(PhoneFirmwareRevision, range.From, range.To))
FileInfo = Package.files.Where(f => f.fileName.EndsWith(name, StringComparison.OrdinalIgnoreCase)).First();
{
FileInfo = Package.files.First(f => f.fileName.EndsWith(name, StringComparison.OrdinalIgnoreCase));
}
}
Uri FileInfoUri = new Uri("https://api.swrepository.com/rest-api/discovery/fileurl/1/" + Package.id + "/" + FileInfo.fileName);
Uri FileInfoUri = new("https://api.swrepository.com/rest-api/discovery/fileurl/1/" + Package.id + "/" + FileInfo.fileName);
Task<string> GetFileInfoTask = HttpClient.GetStringAsync(FileInfoUri);
GetFileInfoTask.Wait();
string FileInfoString = GetFileInfoTask.Result;
string ENOSWUrl = "";
FileUrlResult FileUrl = null;
using (MemoryStream JsonStream3 = new MemoryStream(Encoding.UTF8.GetBytes(FileInfoString)))
using (MemoryStream JsonStream3 = new(Encoding.UTF8.GetBytes(FileInfoString)))
{
DataContractJsonSerializer Serializer3 = new DataContractJsonSerializer(typeof(FileUrlResult));
DataContractJsonSerializer Serializer3 = new(typeof(FileUrlResult));
FileUrl = (FileUrlResult)Serializer3.ReadObject(JsonStream3);
if (FileUrl != null)
{
@@ -291,7 +316,9 @@ namespace WPinternals
{
ProductType = ProductType.ToUpper();
if (ProductType.StartsWith("RM") && !ProductType.StartsWith("RM-"))
ProductType = "RM-" + ProductType.Substring(2);
{
ProductType = "RM-" + ProductType[2..];
}
LogFile.Log("Getting Emergency files for: " + ProductType, LogType.FileAndConsole);
@@ -301,15 +328,15 @@ namespace WPinternals
ProductType = "RM-1113";
}
List<string> Result = new List<string>();
List<string> Result = new();
WebClient Client = new WebClient();
WebClient Client = new();
string Src;
string FileName;
string Config = null;
try
{
Config = Client.DownloadString(@"https://repairavoidance.blob.core.windows.net/packages/EmergencyFlash/" + ProductType + "/emergency_flash_config.xml");
Config = Client.DownloadString("https://repairavoidance.blob.core.windows.net/packages/EmergencyFlash/" + ProductType + "/emergency_flash_config.xml");
}
catch
{
@@ -318,7 +345,7 @@ namespace WPinternals
}
Client.Dispose();
XmlDocument Doc = new XmlDocument();
XmlDocument Doc = new();
Doc.LoadXml(Config);
// Hex
@@ -326,7 +353,7 @@ namespace WPinternals
if (Node != null)
{
FileName = Node.Attributes["image_path"].InnerText;
Src = @"https://repairavoidance.blob.core.windows.net/packages/EmergencyFlash/" + ProductType + "/" + FileName;
Src = "https://repairavoidance.blob.core.windows.net/packages/EmergencyFlash/" + ProductType + "/" + FileName;
LogFile.Log("Hex-file: " + Src);
Result.Add(Src);
}
@@ -336,7 +363,7 @@ namespace WPinternals
if (Node != null)
{
FileName = Node.Attributes["image_path"].InnerText;
Src = @"https://repairavoidance.blob.core.windows.net/packages/EmergencyFlash/" + ProductType + "/" + FileName;
Src = "https://repairavoidance.blob.core.windows.net/packages/EmergencyFlash/" + ProductType + "/" + FileName;
LogFile.Log("Mbn-file: " + Src);
Result.Add(Src);
}
@@ -345,7 +372,7 @@ namespace WPinternals
foreach (XmlNode SubNode in Doc.SelectNodes("//emergency_flash_config/first_boot_images/first_boot_image"))
{
FileName = SubNode.Attributes["image_path"].InnerText;
Src = @"https://repairavoidance.blob.core.windows.net/packages/EmergencyFlash/" + ProductType + "/" + FileName;
Src = "https://repairavoidance.blob.core.windows.net/packages/EmergencyFlash/" + ProductType + "/" + FileName;
LogFile.Log("Firehose-programmer-file: " + Src);
Result.Add(Src);
}
@@ -354,7 +381,7 @@ namespace WPinternals
foreach (XmlNode SubNode in Doc.SelectNodes("//emergency_flash_config/second_boot_firehose_single_image/firehose_image"))
{
FileName = SubNode.Attributes["image_path"].InnerText;
Src = @"https://repairavoidance.blob.core.windows.net/packages/EmergencyFlash/" + ProductType + "/" + FileName;
Src = "https://repairavoidance.blob.core.windows.net/packages/EmergencyFlash/" + ProductType + "/" + FileName;
LogFile.Log("Firehose-payload-file: " + Src);
Result.Add(Src);
}
+91 -46
View File
@@ -51,8 +51,8 @@ namespace WPinternals
{
foreach (ManagementObject drive in partition.GetRelated("Win32_DiskDrive"))
{
if ((drive["PNPDeviceID"].ToString().IndexOf("VEN_QUALCOMM&PROD_MMC_STORAGE") >= 0) ||
(drive["PNPDeviceID"].ToString().IndexOf("VEN_MSFT&PROD_PHONE_MMC_STOR") >= 0))
if ((drive["PNPDeviceID"].ToString().Contains("VEN_QUALCOMM&PROD_MMC_STORAGE", StringComparison.CurrentCulture)) ||
(drive["PNPDeviceID"].ToString().Contains("VEN_MSFT&PROD_PHONE_MMC_STOR", StringComparison.CurrentCulture)))
{
Label = (logical["VolumeName"] == null ? "" : logical["VolumeName"].ToString());
if ((Drive == null) || (string.Compare(Label, "MainOS", true) == 0)) // Always prefer the MainOS drive-mapping
@@ -62,11 +62,15 @@ namespace WPinternals
VolumeLabel = Label;
}
if (string.Compare(Label, "MainOS", true) == 0)
{
break;
}
}
}
if (string.Compare(Label, "MainOS", true) == 0)
{
break;
}
}
}
}
@@ -77,7 +81,7 @@ namespace WPinternals
{
try
{
QualcommSerial SerialDevice = new QualcommSerial(DevicePath);
QualcommSerial SerialDevice = new(DevicePath);
SerialDevice.Close();
SerialDevice.Dispose();
@@ -97,11 +101,13 @@ namespace WPinternals
internal void Reboot()
{
if (Serial == null)
{
return;
}
try
{
QualcommSerial SerialDevice = new QualcommSerial(Serial);
QualcommSerial SerialDevice = new(Serial);
SerialDevice.EncodeCommands = false;
@@ -120,7 +126,9 @@ namespace WPinternals
protected override void Dispose(bool disposing)
{
if (Disposed)
{
return;
}
if (disposing)
{
@@ -135,7 +143,9 @@ namespace WPinternals
OpenWithWriteAccess = false;
if (IsVolumeOpen())
{
throw new Exception("Volume already opened");
}
if (WriteAccess)
{
@@ -169,7 +179,9 @@ namespace WPinternals
}
if ((int)hVolume == -1)
{
throw new Exception(Marshal.GetLastWin32Error().ToString());
}
OpenWithWriteAccess = WriteAccess;
}
@@ -197,7 +209,9 @@ namespace WPinternals
internal void SetSectorPosition(UInt64 Sector)
{
if (!IsVolumeOpen())
{
throw new Exception("Volume is not opened");
}
int High = (int)(Sector >> (32 - 9));
NativeMethods.SetFilePointer(hVolume, (int)(Sector << 9), ref High, EMoveMethod.Begin);
@@ -206,38 +220,49 @@ namespace WPinternals
internal void WriteSector(byte[] buffer)
{
if (!IsVolumeOpen())
{
throw new Exception("Volume is not opened");
}
if (!OpenWithWriteAccess)
{
throw new Exception("Volume is not opened with Write Acces");
}
uint count = 0;
bool result = NativeMethods.WriteFile(hVolume, buffer, 512, out count, IntPtr.Zero);
bool result = NativeMethods.WriteFile(hVolume, buffer, 512, out uint count, IntPtr.Zero);
if (!result)
{
throw new Exception("Exception: 0x" + Marshal.GetLastWin32Error().ToString("X8"));
}
}
internal void ReadSector(byte[] buffer)
{
if (!IsVolumeOpen())
{
throw new Exception("Volume is not opened");
}
uint count = 1;
bool result = NativeMethods.ReadFile(hVolume, buffer, 512, out count, IntPtr.Zero);
bool result = NativeMethods.ReadFile(hVolume, buffer, 512, out uint count, IntPtr.Zero);
if (!result)
{
throw new Exception("Exception: 0x" + Marshal.GetLastWin32Error().ToString("X8"));
}
}
internal void ReadSectors(byte[] buffer, out uint ActualSectorsRead, uint SizeInSectors = uint.MaxValue)
{
if (!IsVolumeOpen())
{
throw new Exception("Volume is not opened");
}
uint count = 1;
bool Result = NativeMethods.ReadFile(hVolume, buffer, (SizeInSectors * 0x200) < buffer.Length ? (SizeInSectors * 0x200) : (uint)buffer.Length, out count, IntPtr.Zero);
bool Result = NativeMethods.ReadFile(hVolume, buffer, (SizeInSectors * 0x200) < buffer.Length ? (SizeInSectors * 0x200) : (uint)buffer.Length, out uint count, IntPtr.Zero);
ActualSectorsRead = count / 0x200;
if (!Result)
{
throw new Exception("Failed to read sectors. Exception: 0x" + Marshal.GetLastWin32Error().ToString("X8"));
}
}
internal byte[] ReadSectors(UInt64 StartSector, UInt64 SectorCount)
@@ -246,17 +271,22 @@ namespace WPinternals
bool VolumeWasOpen = IsVolumeOpen();
if (!VolumeWasOpen)
{
OpenVolume(false);
}
SetSectorPosition(StartSector);
uint SectorsRead;
ReadSectors(Result, out SectorsRead);
ReadSectors(Result, out uint SectorsRead);
if (!VolumeWasOpen)
{
CloseVolume();
}
if (Result == null)
{
throw new Exception("Failed to read from phone");
}
return Result;
}
@@ -295,28 +325,22 @@ namespace WPinternals
{
bool VolumeWasOpen = IsVolumeOpen();
if (!VolumeWasOpen)
{
OpenVolume(false);
}
SetSectorPosition(StartSector);
ProgressUpdater Progress = UpdaterPerSector;
if ((Progress == null) && (ProgressUpdateCallback != null))
Progress = new ProgressUpdater(SectorCount, ProgressUpdateCallback);
byte[] Buffer;
if (SectorCount >= 0x80)
Buffer = new byte[0x10000];
else
Buffer = new byte[SectorCount * 0x200];
Stream Stream;
if (Path == null)
Stream = OutputStream;
else
Stream = File.Open(Path, FileMode.Create);
using (BinaryWriter Writer = new BinaryWriter(Stream))
{
uint ActualSectorsRead;
Progress = new ProgressUpdater(SectorCount, ProgressUpdateCallback);
}
byte[] Buffer = SectorCount >= 0x80 ? (new byte[0x10000]) : (new byte[SectorCount * 0x200]);
Stream Stream = Path == null ? OutputStream : File.Open(Path, FileMode.Create);
using (BinaryWriter Writer = new(Stream))
{
for (UInt64 i = 0; i < SectorCount; i += 0x80)
{
// TODO: Reading sectors and writing to compressed stream should be on different threads.
@@ -326,16 +350,17 @@ namespace WPinternals
// BinaryWriter doesnt support async.
// Calling async directly on the EntryStream of a Ziparchive blocks.
ReadSectors(Buffer, out ActualSectorsRead, (SectorCount - i) >= 0x80 ? 0x80 : (uint)(SectorCount - i));
ReadSectors(Buffer, out uint ActualSectorsRead, (SectorCount - i) >= 0x80 ? 0x80 : (uint)(SectorCount - i));
Writer.Write(Buffer, 0, (int)ActualSectorsRead * 0x200);
if (Progress != null)
Progress.IncreaseProgress(ActualSectorsRead);
Progress?.IncreaseProgress(ActualSectorsRead);
}
Stream.Flush();
}
if (!VolumeWasOpen)
{
CloseVolume();
}
}
internal void BackupPartition(string PartitionName, string Path)
@@ -372,17 +397,21 @@ namespace WPinternals
{
bool VolumeWasOpen = IsVolumeOpen();
if (!VolumeWasOpen)
{
OpenVolume(false);
}
SetSectorPosition(1);
byte[] GPTBuffer = ReadSectors(1, 33);
GPT GPT = new GPT(GPTBuffer);
Partition Partition = GPT.Partitions.Where((p) => p.Name == PartitionName).First();
GPT GPT = new(GPTBuffer);
Partition Partition = GPT.Partitions.First((p) => p.Name == PartitionName);
DumpSectors(Partition.FirstSector, Partition.LastSector - Partition.FirstSector + 1, Path, OutputStream, ProgressUpdateCallback, UpdaterPerSector);
if (!VolumeWasOpen)
{
CloseVolume();
}
}
internal void WriteSectors(UInt64 StartSector, byte[] Buffer)
@@ -391,29 +420,37 @@ namespace WPinternals
bool VolumeWasOpen = IsVolumeOpen();
if (!VolumeWasOpen)
{
OpenVolume(true);
}
SetSectorPosition(StartSector);
uint count = 1;
Result = NativeMethods.WriteFile(hVolume, Buffer, (uint)Buffer.Length, out count, IntPtr.Zero);
Result = NativeMethods.WriteFile(hVolume, Buffer, (uint)Buffer.Length, out uint count, IntPtr.Zero);
if (!VolumeWasOpen)
{
CloseVolume();
}
if (!Result)
{
throw new Exception("Failed to write sectors.");
}
}
internal void WriteSectors(byte[] Buffer, uint Length = uint.MaxValue)
{
if (!IsVolumeOpen())
{
throw new Exception("Volume is not opened");
}
uint count = 1;
bool Result = NativeMethods.WriteFile(hVolume, Buffer, (Length < Buffer.Length ? Length : (uint)Buffer.Length), out count, IntPtr.Zero);
bool Result = NativeMethods.WriteFile(hVolume, Buffer, Length < Buffer.Length ? Length : (uint)Buffer.Length, out uint count, IntPtr.Zero);
if (!Result)
{
throw new Exception("Failed to write sectors. Exception: 0x" + Marshal.GetLastWin32Error().ToString("X8"));
}
}
internal void WriteSectors(UInt64 StartSector, string Path)
@@ -435,22 +472,23 @@ namespace WPinternals
{
bool VolumeWasOpen = IsVolumeOpen();
if (!VolumeWasOpen)
{
OpenVolume(true);
}
SetSectorPosition(StartSector);
byte[] Buffer;
using (BinaryReader Reader = new BinaryReader(File.Open(Path, FileMode.Open)))
using (BinaryReader Reader = new(File.Open(Path, FileMode.Open)))
{
ProgressUpdater Progress = UpdaterPerSector;
if ((Progress == null) && (ProgressUpdateCallback != null))
{
Progress = new ProgressUpdater((UInt64)(Reader.BaseStream.Length / 0x200), ProgressUpdateCallback);
}
if (Reader.BaseStream.Length >= 0x10000)
Buffer = new byte[0x10000];
else
Buffer = new byte[Reader.BaseStream.Length];
Buffer = Reader.BaseStream.Length >= 0x10000 ? (new byte[0x10000]) : (new byte[Reader.BaseStream.Length]);
int Count;
for (UInt64 i = 0; i < (UInt64)(Reader.BaseStream.Length / 0x200); i += 0x80)
@@ -459,13 +497,14 @@ namespace WPinternals
WriteSectors(Buffer, (uint)Count);
if (Progress != null)
Progress.IncreaseProgress((ulong)Count / 0x200);
Progress?.IncreaseProgress((ulong)Count / 0x200);
}
}
if (!VolumeWasOpen)
{
CloseVolume();
}
}
internal void RestorePartition(string Path, string PartitionName)
@@ -487,21 +526,27 @@ namespace WPinternals
{
bool VolumeWasOpen = IsVolumeOpen();
if (!VolumeWasOpen)
{
OpenVolume(true);
}
SetSectorPosition(1);
byte[] GPTBuffer = ReadSectors(1, 33);
GPT GPT = new GPT(GPTBuffer);
Partition Partition = GPT.Partitions.Where((p) => p.Name == PartitionName).First();
GPT GPT = new(GPTBuffer);
Partition Partition = GPT.Partitions.First((p) => p.Name == PartitionName);
ulong PartitionSize = (Partition.LastSector - Partition.FirstSector + 1) * 0x200;
ulong FileSize = (ulong)new FileInfo(Path).Length;
if (FileSize > PartitionSize)
{
throw new InvalidOperationException("Partition can not be restored, because its size is too big!");
}
WriteSectors(Partition.FirstSector, Path, ProgressUpdateCallback);
if (!VolumeWasOpen)
{
CloseVolume();
}
}
}
}
+239 -93
View File
@@ -46,7 +46,7 @@ namespace WPinternals
internal class NokiaFlashModel : NokiaPhoneModel
{
private UefiSecurityStatusResponse _SecurityStatus = null;
private PhoneInfo Info = new PhoneInfo();
private readonly PhoneInfo Info = new();
internal event InterfaceChangedHandler InterfaceChanged = delegate { };
@@ -61,7 +61,10 @@ namespace WPinternals
System.Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Param), 0, Request, 7, Param.Length);
byte[] Response = ExecuteRawMethod(Request);
if ((Response == null) || (Response.Length < 0x10)) return null;
if ((Response == null) || (Response.Length < 0x10))
{
return null;
}
byte[] Result = new byte[Response[0x10]];
System.Buffer.BlockCopy(Response, 0x11, Result, 0, Response[0x10]);
@@ -71,7 +74,11 @@ namespace WPinternals
public string ReadStringParam(string Param)
{
byte[] Bytes = ReadParam(Param);
if (Bytes == null) return null;
if (Bytes == null)
{
return null;
}
return System.Text.ASCIIEncoding.ASCII.GetString(Bytes).Trim(new char[] { '\0' });
}
@@ -99,7 +106,9 @@ namespace WPinternals
{
uint? flags = ReadSecurityFlags();
if (!flags.HasValue)
{
return null;
}
var finalconfig = (Fuse)flags.Value;
return finalconfig.HasFlag(fuse);
@@ -108,7 +117,10 @@ namespace WPinternals
public uint? ReadSecurityFlags()
{
byte[] Response = ReadParam("FCS");
if ((Response == null) || (Response.Length != 4)) return null;
if ((Response == null) || (Response.Length != 4))
{
return null;
}
// This value is in big endian
return (UInt32)((Response[0] << 24) | (Response[1] << 16) | (Response[2] << 8) | Response[3]);
@@ -117,7 +129,10 @@ namespace WPinternals
public uint? ReadCurrentChargeLevel()
{
byte[] Response = ReadParam("CS");
if ((Response == null) || (Response.Length != 8)) return null;
if ((Response == null) || (Response.Length != 8))
{
return null;
}
// This value is in big endian
return (UInt32)((Response[0] << 24) | (Response[1] << 16) | (Response[2] << 8) | Response[3]) + 1;
@@ -126,7 +141,10 @@ namespace WPinternals
public int? ReadCurrentChargeCurrent()
{
byte[] Response = ReadParam("CS");
if ((Response == null) || (Response.Length != 8)) return null;
if ((Response == null) || (Response.Length != 8))
{
return null;
}
// This value is in big endian and needs to be XOR'd with 0xFFFFFFFF
return (Int32)(((Response[4] << 24) | (Response[5] << 16) | (Response[6] << 8) | Response[7]) ^ 0xFFFFFFFF) + 1;
@@ -135,12 +153,17 @@ namespace WPinternals
public UefiSecurityStatusResponse ReadSecurityStatus()
{
if (_SecurityStatus != null)
{
return _SecurityStatus;
}
byte[] Response = ReadParam("SS");
if (Response == null) return null;
if (Response == null)
{
return null;
}
UefiSecurityStatusResponse Result = new UefiSecurityStatusResponse();
UefiSecurityStatusResponse Result = new();
Result.IsTestDevice = Response[0];
Result.PlatformSecureBootStatus = Convert.ToBoolean(Response[1]);
@@ -160,7 +183,10 @@ namespace WPinternals
{
UefiSecurityStatusResponse SecurityStatus = ReadSecurityStatus();
if (SecurityStatus != null)
return (SecurityStatus.AuthenticationStatus || SecurityStatus.RdcStatus || !SecurityStatus.SecureFfuEfuseStatus);
{
return SecurityStatus.AuthenticationStatus || SecurityStatus.RdcStatus || !SecurityStatus.SecureFfuEfuseStatus;
}
return null;
}
@@ -168,7 +194,7 @@ namespace WPinternals
{
byte[] AsskMask = new byte[0x10] { 1, 0, 16, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64 };
byte[] Request = new byte[0xAC];
string Header = "NOKXFT";
const string Header = "NOKXFT";
System.Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Request[7] = 1;
System.Buffer.BlockCopy(BigEndian.GetBytes(0x18, 4), 0, Request, 0x08, 4); // Subblocktype = 0x18
@@ -176,20 +202,23 @@ namespace WPinternals
System.Buffer.BlockCopy(BigEndian.GetBytes(0x00, 4), 0, Request, 0x10, 4); // AsicIndex = 0x00
System.Buffer.BlockCopy(AsskMask, 0, Request, 0x14, 0x10);
byte[] TerminalResponse = ExecuteRawMethod(Request);
if ((TerminalResponse != null) && (TerminalResponse.Length > 0x20) && (BigEndian.ToUInt32(TerminalResponse, 0x14) == (TerminalResponse.Length - 0x18)) && (BitConverter.ToUInt32(TerminalResponse, 0x1C) == (TerminalResponse.Length - 0x20)))
if ((TerminalResponse?.Length > 0x20) && (BigEndian.ToUInt32(TerminalResponse, 0x14) == (TerminalResponse.Length - 0x18)) && (BitConverter.ToUInt32(TerminalResponse, 0x1C) == (TerminalResponse.Length - 0x20)))
{
// Parse Terminal Response from offset 0x18
TerminalResponse ParsedResponse = Terminal.Parse(TerminalResponse, 0x18);
return ParsedResponse;
}
else return null;
else
{
return null;
}
}
public void SendFfuHeaderV1(byte[] FfuHeader, byte Options = 0)
{
byte[] Request = new byte[FfuHeader.Length + 0x20];
string Header = "NOKXFS";
const string Header = "NOKXFS";
System.Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
System.Buffer.BlockCopy(BigEndian.GetBytes(0x0001, 2), 0, Request, 0x06, 2); // Protocol version = 0x0001
Request[0x08] = 0; // Progress = 0%
@@ -204,17 +233,22 @@ namespace WPinternals
byte[] Response = ExecuteRawMethod(Request);
if (Response == null)
{
throw new BadConnectionException();
}
int ResultCode = (Response[6] << 8) + Response[7];
if (ResultCode != 0)
{
ThrowFlashError(ResultCode);
}
}
public void SendFfuHeaderV2(UInt32 TotalHeaderLength, UInt32 OffsetForThisPart, byte[] FfuHeader, byte Options = 0)
{
byte[] Request = new byte[FfuHeader.Length + 0x3C];
string Header = "NOKXFS";
const string Header = "NOKXFS";
System.Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
System.Buffer.BlockCopy(BigEndian.GetBytes((int)FfuProtocol.ProtocolSyncV2, 2), 0, Request, 0x06, 2); // Protocol version = 0x0001
Request[0x08] = 0; // Progress = 0%
@@ -235,19 +269,27 @@ namespace WPinternals
byte[] Response = ExecuteRawMethod(Request);
if (Response == null)
{
throw new BadConnectionException();
}
if (Response.Length == 4)
{
throw new WPinternalsException("Flash protocol v2 not supported", "The device reported that the Flash protocol v2 was not supported while sending the FFU header.");
}
int ResultCode = (Response[6] << 8) + Response[7];
if (ResultCode != 0)
{
ThrowFlashError(ResultCode);
}
}
public void SendFfuPayloadV1(byte[] FfuChunk, int Progress = 0, byte Options = 0)
{
byte[] Request = new byte[FfuChunk.Length + 0x1C];
string Header = "NOKXFS";
const string Header = "NOKXFS";
System.Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
System.Buffer.BlockCopy(BigEndian.GetBytes((int)FfuProtocol.ProtocolSyncV1, 2), 0, Request, 0x06, 2); // Protocol version = 0x0001
Request[0x08] = (byte)Progress; // Progress = 0% (0 - 100)
@@ -263,17 +305,22 @@ namespace WPinternals
byte[] Response = ExecuteRawMethod(Request);
if (Response == null)
{
throw new BadConnectionException();
}
int ResultCode = (Response[6] << 8) + Response[7];
if (ResultCode != 0)
{
ThrowFlashError(ResultCode);
}
}
public void SendFfuPayloadV2(byte[] FfuChunk, int Progress = 0, byte Options = 0)
{
byte[] Request = new byte[FfuChunk.Length + 0x20];
string Header = "NOKXFS";
const string Header = "NOKXFS";
System.Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
System.Buffer.BlockCopy(BigEndian.GetBytes((int)FfuProtocol.ProtocolSyncV2, 2), 0, Request, 0x06, 2); // Protocol
Request[0x08] = (byte)Progress; // Progress = 0% (0 - 100)
@@ -289,17 +336,22 @@ namespace WPinternals
byte[] Response = ExecuteRawMethod(Request);
if (Response == null)
{
throw new BadConnectionException();
}
int ResultCode = (Response[6] << 8) + Response[7];
if (ResultCode != 0)
{
ThrowFlashError(ResultCode);
}
}
public void SendFfuPayloadV3(byte[] FfuChunk, UInt32 WriteDescriptorIndex, UInt32 CRC, int Progress = 0, byte Options = 0)
{
byte[] Request = new byte[FfuChunk.Length + 0x20];
string Header = "NOKXFS";
const string Header = "NOKXFS";
System.Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
System.Buffer.BlockCopy(BigEndian.GetBytes((int)FfuProtocol.ProtocolAsyncV3, 2), 0, Request, 0x06, 2); // Protocol
Request[0x08] = (byte)Progress; // Progress = 0% (0 - 100)
@@ -317,10 +369,15 @@ namespace WPinternals
byte[] Response = ExecuteRawMethod(Request);
if (Response == null)
{
throw new BadConnectionException();
}
int ResultCode = (Response[6] << 8) + Response[7];
if (ResultCode != 0)
{
ThrowFlashError(ResultCode);
}
}
public void BackupPartitionToRam(string PartitionName)
@@ -329,7 +386,7 @@ namespace WPinternals
if (new string[] { "MODEM_FSG", "MODEM_FS1", "MODEM_FS2", "SSD", "DPP" }.Any(s => s == PartitionName))
{
byte[] Request = new byte[84];
string Header = "NOKXFB";
const string Header = "NOKXFB";
System.Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Request[0x07] = 1; // Subblock count = 1
Request[0x08] = 6; // Subblock ID = 6 = Create Partition Backup to RAM
@@ -344,16 +401,20 @@ namespace WPinternals
byte[] Response = ExecuteRawMethod(Request);
int ResultCode = (Response[6] << 8) + Response[7];
if (ResultCode != 0)
{
ThrowFlashError(ResultCode);
}
}
else
{
throw new WPinternalsException("Specified partition cannot be backupped to RAM", "Partition name: \"" + PartitionName + "\".");
}
}
public void LoadMmosBinary(UInt32 TotalLength, UInt32 Offset, bool SkipMmosSupportCheck, byte[] MmosPart)
{
byte[] Request = new byte[MmosPart.Length + 0x20];
string Header = "NOKXFL";
const string Header = "NOKXFL";
System.Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Request[0x07] = 1; // Subblock count = 1
System.Buffer.BlockCopy(BigEndian.GetBytes(0x0000001E, 4), 0, Request, 0x08, 4); // Subblock ID = Load MMOS Binary = 0x1E
@@ -361,14 +422,19 @@ namespace WPinternals
System.Buffer.BlockCopy(BigEndian.GetBytes(TotalLength, 4), 0, Request, 0x10, 4);
System.Buffer.BlockCopy(BigEndian.GetBytes(Offset, 4), 0, Request, 0x14, 4);
if (SkipMmosSupportCheck)
{
Request[0x18] = 1;
}
System.Buffer.BlockCopy(BigEndian.GetBytes(MmosPart.Length, 4), 0, Request, 0x1C, 4);
Buffer.BlockCopy(MmosPart, 0, Request, 0x20, MmosPart.Length);
byte[] Response = ExecuteRawMethod(Request);
int ResultCode = (Response[6] << 8) + Response[7];
if (ResultCode != 0)
{
ThrowFlashError(ResultCode);
}
}
internal void SwitchToMmosContext()
@@ -384,51 +450,48 @@ namespace WPinternals
private void ThrowFlashError(int ErrorCode)
{
string SubMessage;
switch (ErrorCode)
string SubMessage = ErrorCode switch
{
case 0x0008: SubMessage = "Unsupported protocol / Invalid options"; break;
case 0x000F: SubMessage = "Invalid sub block count"; break;
case 0x0010: SubMessage = "Invalid sub block length"; break;
case 0x0012: SubMessage = "Authentication required"; break;
case 0x000E: SubMessage = "Invalid sub block type"; break;
case 0x0013: SubMessage = "Failed async message"; break;
case 0x1000: SubMessage = "Invalid header type"; break;
case 0x1001: SubMessage = "FFU header contain unknown extra data"; break;
case 0x0001: SubMessage = "Couldn't allocate memory"; break;
case 0x1106: SubMessage = "Security header validation failed"; break;
case 0x1105: SubMessage = "Invalid hash table size"; break;
case 0x1104: SubMessage = "Invalid catalog size"; break;
case 0x1103: SubMessage = "Invalid chunk size"; break;
case 0x1102: SubMessage = "Unsupported algorithm"; break;
case 0x1101: SubMessage = "Invalid struct size"; break;
case 0x1100: SubMessage = "Invalid signature"; break;
case 0x1202: SubMessage = "Invalid struct size"; break;
case 0x1203: SubMessage = "Unsupported algorithm"; break;
case 0x1204: SubMessage = "Invalid chunk size"; break;
case 0x1005: SubMessage = "Data not aligned correctly"; break;
case 0x0009: SubMessage = "Locate protocol failed"; break;
case 0x1003: SubMessage = "Hash mismatch"; break;
case 0x1006: SubMessage = "Couldn't find hash from security header for index"; break;
case 0x1004: SubMessage = "Security header import missing / All FFU headers have not been imported"; break;
case 0x1304: SubMessage = "Invalid platform ID"; break;
case 0x1307: SubMessage = "Invalid write descriptor info"; break;
case 0x1306: SubMessage = "Invalid write descriptor info"; break;
case 0x1305: SubMessage = "Invalid block size"; break;
case 0x1303: SubMessage = "Unsupported FFU version"; break;
case 0x1302: SubMessage = "Unsupported struct version"; break;
case 0x1301: SubMessage = "Invalid update type"; break;
case 0x100B: SubMessage = "Too much payload data, all data has already been written"; break;
case 0x1008: SubMessage = "Internal error"; break;
case 0x1007: SubMessage = "Payload data does not contain all data"; break;
case 0x0004: SubMessage = "Flash write failed"; break;
case 0x000D: SubMessage = "Flash verify failed"; break;
case 0x0002: SubMessage = "Flash read failed"; break;
default: SubMessage = "Unknown error"; break;
}
WPinternalsException Ex = new WPinternalsException("Flash failed!");
0x0008 => "Unsupported protocol / Invalid options",
0x000F => "Invalid sub block count",
0x0010 => "Invalid sub block length",
0x0012 => "Authentication required",
0x000E => "Invalid sub block type",
0x0013 => "Failed async message",
0x1000 => "Invalid header type",
0x1001 => "FFU header contain unknown extra data",
0x0001 => "Couldn't allocate memory",
0x1106 => "Security header validation failed",
0x1105 => "Invalid hash table size",
0x1104 => "Invalid catalog size",
0x1103 => "Invalid chunk size",
0x1102 => "Unsupported algorithm",
0x1101 => "Invalid struct size",
0x1100 => "Invalid signature",
0x1202 => "Invalid struct size",
0x1203 => "Unsupported algorithm",
0x1204 => "Invalid chunk size",
0x1005 => "Data not aligned correctly",
0x0009 => "Locate protocol failed",
0x1003 => "Hash mismatch",
0x1006 => "Couldn't find hash from security header for index",
0x1004 => "Security header import missing / All FFU headers have not been imported",
0x1304 => "Invalid platform ID",
0x1307 => "Invalid write descriptor info",
0x1306 => "Invalid write descriptor info",
0x1305 => "Invalid block size",
0x1303 => "Unsupported FFU version",
0x1302 => "Unsupported struct version",
0x1301 => "Invalid update type",
0x100B => "Too much payload data, all data has already been written",
0x1008 => "Internal error",
0x1007 => "Payload data does not contain all data",
0x0004 => "Flash write failed",
0x000D => "Flash verify failed",
0x0002 => "Flash read failed",
_ => "Unknown error",
};
WPinternalsException Ex = new("Flash failed!");
Ex.SubMessage = "Error 0x" + ErrorCode.ToString("X4") + ": " + SubMessage;
throw Ex;
@@ -452,11 +515,13 @@ namespace WPinternals
PhoneInfo Info = ReadPhoneInfo();
if ((Info.SecureFfuSupportedProtocolMask & ((ushort)FfuProtocol.ProtocolSyncV1 | (ushort)FfuProtocol.ProtocolSyncV2)) == 0)
{
throw new WPinternalsException("Flash failed!", "Protocols not supported. The device reports that both Protocol Sync v1 and Protocol Sync v2 are not supported for FFU flashing. Is this an old device?");
}
UInt64 CombinedFFUHeaderSize = FFU.HeaderSize;
byte[] FfuHeader = new byte[CombinedFFUHeaderSize];
using (System.IO.FileStream FfuFile = new System.IO.FileStream(FFU.Path, System.IO.FileMode.Open, System.IO.FileAccess.Read))
using (FileStream FfuFile = new(FFU.Path, System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
FfuFile.Read(FfuHeader, 0, (int)CombinedFFUHeaderSize);
SendFfuHeaderV1(FfuHeader, Options);
@@ -477,8 +542,7 @@ namespace WPinternals
SendFfuPayloadV1(Payload, (int)((double)ChunkCount * 100 / FFU.TotalChunkCount), 0);
Position += (ulong)Payload.Length;
if (Progress != null)
Progress.IncreaseProgress(1);
Progress?.IncreaseProgress(1);
}
}
else
@@ -500,14 +564,15 @@ namespace WPinternals
SendFfuPayloadV2(Payload, (int)((double)ChunkCount * 100 / FFU.TotalChunkCount), 0);
Position += PayloadSize;
if (Progress != null)
Progress.IncreaseProgress((ulong)(PayloadSize / FFU.ChunkSize));
Progress?.IncreaseProgress((ulong)(PayloadSize / FFU.ChunkSize));
}
}
}
if (ResetAfterwards)
{
ResetPhone();
}
LogFile.EndAction("FlashFFU");
}
@@ -520,17 +585,19 @@ namespace WPinternals
PhoneInfo Info = ReadPhoneInfo();
if (!Info.MmosOverUsbSupported)
{
throw new WPinternalsException("Flash failed!", "Protocols not supported. The device reports that loading Microsoft Manufacturing Operating System over USB is not supported.");
}
FileInfo info = new FileInfo(MMOSPath);
FileInfo info = new(MMOSPath);
uint length = uint.Parse(info.Length.ToString());
int offset = 0;
int maximumbuffersize = 0x00240000;
const int maximumbuffersize = 0x00240000;
uint totalcounts = (uint)Math.Truncate((decimal)length / maximumbuffersize);
using (System.IO.FileStream MMOSFile = new System.IO.FileStream(MMOSPath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
using (FileStream MMOSFile = new(MMOSPath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
for (int i = 1; i <= (uint)Math.Truncate((decimal)length / maximumbuffersize); i++)
{
@@ -565,7 +632,7 @@ namespace WPinternals
byte[] Request = new byte[Data.Length + 0x40];
string Header = "NOKF";
const string Header = "NOKF";
System.Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Request[0x05] = 0; // Device type = 0
System.Buffer.BlockCopy(BigEndian.GetBytes(StartSector, 4), 0, Request, 0x0B, 4); // Start sector
@@ -582,7 +649,7 @@ namespace WPinternals
public void DisableRebootTimeOut()
{
byte[] Request = new byte[4];
string Header = "NOKD";
const string Header = "NOKD";
System.Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
ExecuteRawMethod(Request);
}
@@ -590,7 +657,7 @@ namespace WPinternals
public void Shutdown()
{
byte[] Request = new byte[4];
string Header = "NOKZ";
const string Header = "NOKZ";
System.Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
ExecuteRawMethod(Request);
}
@@ -598,9 +665,12 @@ namespace WPinternals
public FlashVersion GetFlashVersion()
{
byte[] Response = ReadParam("FAI");
if ((Response == null) || (Response.Length < 6)) return null;
if ((Response == null) || (Response.Length < 6))
{
return null;
}
FlashVersion Result = new FlashVersion();
FlashVersion Result = new();
Result.ProtocolMajor = Response[1];
Result.ProtocolMinor = Response[2];
@@ -622,7 +692,9 @@ namespace WPinternals
FlashAppType OriginalAppType = Info.App;
bool Switch = ((Info.App != FlashAppType.BootManager) && Info.IsBootloaderSecure);
if (Switch)
{
SwitchToBootManagerContext();
}
byte[] Request = new byte[0x04];
const string Header = "NOKT";
@@ -631,11 +703,15 @@ namespace WPinternals
byte[] Buffer = ExecuteRawMethod(Request);
if ((Buffer == null) || (Buffer.Length < 0x4408))
{
throw new InvalidOperationException("Unable to read GPT!");
}
UInt16 Error = (UInt16)((Buffer[6] << 8) + Buffer[7]);
if (Error > 0)
{
throw new NotSupportedException("ReadGPT: Error 0x" + Error.ToString("X4"));
}
byte[] GPTBuffer = new byte[Buffer.Length - 0x208];
System.Buffer.BlockCopy(Buffer, 0x208, GPTBuffer, 0, 0x4200);
@@ -643,9 +719,13 @@ namespace WPinternals
if (Switch)
{
if (OriginalAppType == FlashAppType.FlashApp)
{
SwitchToFlashAppContext();
}
else
{
SwitchToPhoneInfoAppContext();
}
}
return new GPT(GPTBuffer); // NOKT message header and MBR are ignored
@@ -654,14 +734,18 @@ namespace WPinternals
internal void WriteGPT(GPT NewGPT)
{
bool? unlocked = IsBootLoaderUnlocked();
if (unlocked.HasValue && !unlocked.Value)
if (unlocked == false)
{
throw new InvalidOperationException("Bootloader is not unlocked!");
}
byte[] Buffer = NewGPT.Rebuild();
UInt32? HeaderOffset = ByteOperations.FindAscii(Buffer, "EFI PART");
if (HeaderOffset != 0)
{
throw new BadImageFormatException();
}
FlashSectors(1, Buffer);
}
@@ -694,24 +778,25 @@ namespace WPinternals
private void FlashRawPartition(string Path, Stream Stream, string PartitionName, Action<int, TimeSpan?> ProgressUpdateCallback, ProgressUpdater UpdaterPerSector)
{
bool? unlocked = IsBootLoaderUnlocked();
if (unlocked.HasValue && !unlocked.Value)
if (unlocked == false)
{
throw new InvalidOperationException("Bootloader is not unlocked!");
}
GPT GPT = ReadGPT();
Partition Partition = GPT.Partitions.Where((p) => p.Name == PartitionName).First();
Partition Partition = GPT.Partitions.First((p) => p.Name == PartitionName);
ulong PartitionSize = (Partition.LastSector - Partition.FirstSector + 1) * 0x200;
Stream InputStream = null;
if (Path != null)
{
InputStream = new DecompressedStream(File.Open(Path, FileMode.Open));
}
else if (Stream != null)
{
if (Stream is DecompressedStream)
InputStream = Stream;
else
InputStream = new DecompressedStream(Stream);
InputStream = Stream is DecompressedStream ? Stream : new DecompressedStream(Stream);
}
if (InputStream != null)
@@ -726,11 +811,16 @@ namespace WPinternals
catch { }
if ((InputStreamLength != null) && ((UInt64)InputStream.Length > PartitionSize))
{
throw new InvalidOperationException("Partition can not be flashed, because its size is too big!");
}
ProgressUpdater Progress = UpdaterPerSector;
if ((Progress == null) && (ProgressUpdateCallback != null) && (InputStreamLength != null))
{
Progress = new ProgressUpdater((UInt64)(InputStreamLength / 0x200), ProgressUpdateCallback);
}
int ProgressPercentage = 0;
const int FlashBufferSize = 0x200000; // Flash 8 GB phone -> buffersize 0x200000 = 11:45 min, buffersize 0x20000 = 12:30 min
@@ -745,7 +835,9 @@ namespace WPinternals
if (BytesRead > 0)
{
if (BytesRead == FlashBufferSize)
{
FlashBufferFinalSize = FlashBuffer;
}
else
{
FlashBufferFinalSize = new byte[BytesRead];
@@ -773,10 +865,12 @@ namespace WPinternals
// Partition "Data" can always be erased.
// Other partitions can only be erased when a valid RDC certificate is present or full SX authentication was performed.
if (PartitionName.Length > 0x23)
{
throw new ArgumentException("PartitionName cannot exceed 0x23 chars!");
}
byte[] Request = new byte[0x50];
string Header = "NOKXFP";
const string Header = "NOKXFP";
System.Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Request[0x06] = 1; // Protocol version must be 1
Request[0x07] = 0; // Device type = 0
@@ -791,13 +885,14 @@ namespace WPinternals
internal FlashAppType GetFlashAppType()
{
byte[] Request;
Request = new byte[4];
byte[] Request = new byte[4];
ByteOperations.WriteAsciiString(Request, 0, "NOKV");
byte[] Response = ExecuteRawMethod(Request);
if ((Response == null) || (ByteOperations.ReadAsciiString(Response, 0, 4) == "NOKU"))
{
throw new NotSupportedException();
}
return (FlashAppType)Response[5];
}
@@ -811,8 +906,7 @@ namespace WPinternals
if (Result.State == PhoneInfoState.Empty)
{
byte[] Request;
Request = new byte[4];
byte[] Request = new byte[4];
ByteOperations.WriteAsciiString(Request, 0, "NOKV");
byte[] Response = ExecuteRawMethod(Request);
if ((Response != null) && (ByteOperations.ReadAsciiString(Response, 0, 4) != "NOKU"))
@@ -878,7 +972,7 @@ namespace WPinternals
Result.EmmcSizeInSectors = BigEndian.ToUInt32(Response, SubblockPayloadOffset);
break;
case 0x05:
Result.PlatformID = ByteOperations.ReadAsciiString(Response, (uint)SubblockPayloadOffset, (uint)SubblockLength).Trim(new char[] { ' ', '\0' });
Result.PlatformID = ByteOperations.ReadAsciiString(Response, (uint)SubblockPayloadOffset, SubblockLength).Trim(new char[] { ' ', '\0' });
break;
case 0x0D:
Result.AsyncSupport = (Response[SubblockPayloadOffset + 1] == 1);
@@ -908,7 +1002,7 @@ namespace WPinternals
Result.State = PhoneInfoState.Basic;
}
if ((ExtendedInfo) && (Result.State == PhoneInfoState.Basic))
if (ExtendedInfo && (Result.State == PhoneInfoState.Basic))
{
FlashAppType OriginalType = Result.App;
@@ -946,7 +1040,9 @@ namespace WPinternals
Result.IsBootloaderSecure = !(Info.Authenticated || Info.RdcPresent || !Info.SecureFfuEnabled);
if (!PhoneInfoLogged)
{
Result.Log(LogType.FileOnly);
}
return Result;
}
@@ -990,9 +1086,14 @@ namespace WPinternals
ByteOperations.WriteAsciiString(Request, 0, "NOKI");
byte[] Response = ExecuteRawMethod(Request);
if (Response == null)
{
throw new BadConnectionException();
}
if (ByteOperations.ReadAsciiString(Response, 0, 4) != "NOKI")
{
throw new WPinternalsException("Bad response from phone!", "The phone did not answer properly to the Hello message sent.");
}
}
internal UInt16 ReadSecureFfuSupportedProtocolMask()
@@ -1006,10 +1107,16 @@ namespace WPinternals
ByteOperations.WriteAsciiString(Request, 0, "NOKXCBP");
byte[] Response = ExecuteRawMethod(Request);
if (ByteOperations.ReadAsciiString(Response, 0, 4) == "NOKU")
{
throw new NotSupportedException();
}
UInt16 Error = (UInt16)((Response[6] << 8) + Response[7]);
if (Error > 0)
{
throw new NotSupportedException("SwitchToPhoneInfoAppContext: Error 0x" + Error.ToString("X4"));
}
DisableRebootTimeOut();
Info.App = FlashAppType.PhoneInfoApp;
InterfaceChanged(PhoneInterfaces.Lumia_Flash);
@@ -1027,7 +1134,9 @@ namespace WPinternals
byte[] Request;
if (Info.State == PhoneInfoState.Empty)
{
ReadPhoneInfo(ExtendedInfo: false);
}
if (Info.App == FlashAppType.BootManager)
{
@@ -1049,10 +1158,15 @@ namespace WPinternals
ByteOperations.WriteAsciiString(Request, 0, "NOKXCBF"); // This will stop charging the phone
byte[] Response = ExecuteRawMethod(Request);
if (ByteOperations.ReadAsciiString(Response, 0, 4) == "NOKU")
{
throw new NotSupportedException();
}
UInt16 Error = (UInt16)((Response[6] << 8) + Response[7]);
if (Error > 0)
{
throw new NotSupportedException("SwitchToFlashAppContext: Error 0x" + Error.ToString("X4"));
}
}
DisableRebootTimeOut();
@@ -1061,7 +1175,9 @@ namespace WPinternals
// If current Info class was retrieved while in BootMgr mode, then we need to invalidate this data, because it is incomplete.
if (Info.PlatformID == null)
{
Info.State = PhoneInfoState.Empty;
}
InterfaceChanged(PhoneInterfaces.Lumia_Flash);
}
@@ -1072,12 +1188,21 @@ namespace WPinternals
ByteOperations.WriteAsciiString(Request, 0, "NOKXCBB");
byte[] Response = ExecuteRawMethod(Request);
if (ByteOperations.ReadAsciiString(Response, 0, 4) == "NOKU")
{
throw new NotSupportedException();
}
UInt16 Error = (UInt16)((Response[6] << 8) + Response[7]);
if (Error > 0)
{
throw new NotSupportedException("SwitchToBootManagerContext: Error 0x" + Error.ToString("X4"));
}
if (DisableTimeOut)
{
DisableRebootTimeOut();
}
Info.App = FlashAppType.BootManager;
InterfaceChanged(PhoneInterfaces.Lumia_Bootloader);
}
@@ -1133,7 +1258,9 @@ namespace WPinternals
byte[] Response = ExecuteRawMethod(Request);
UInt32 Status = ByteOperations.ReadUInt32(Response, 6);
if (Status != 0)
{
ThrowFlashError((int)Status);
}
}
}
@@ -1202,15 +1329,29 @@ namespace WPinternals
if (State == PhoneInfoState.Extended)
{
if (this.Type != null)
{
LogFile.Log("Phone type: " + this.Type, Type);
}
if (ProductCode != null)
{
LogFile.Log("Product code: " + ProductCode, Type);
}
if (RKH != null)
{
LogFile.Log("Root key hash: " + Converter.ConvertHexToString(RKH, ""), Type);
if (Firmware != null && Firmware.Length > 0)
}
if (Firmware?.Length > 0)
{
LogFile.Log("Firmware version: " + Firmware, Type);
if (!(Type == LogType.ConsoleOnly) && (Imei != null))
}
if (Type != LogType.ConsoleOnly && (Imei != null))
{
LogFile.Log("IMEI: " + Imei, LogType.FileOnly);
}
}
switch (App)
@@ -1234,9 +1375,14 @@ namespace WPinternals
LogFile.Log("SecureBoot: " + ((!PlatformSecureBootEnabled || !UefiSecureBootEnabled) ? "Disabled" : "Enabled") + " (Platform Secure Boot: " + (PlatformSecureBootEnabled ? "Enabled" : "Disabled") + ", UEFI Secure Boot: " + (PlatformSecureBootEnabled ? "Enabled" : "Disabled") + ")", Type);
if ((Type == LogType.ConsoleOnly) || (Type == LogType.FileAndConsole))
{
LogFile.Log("Flash app security: " + (!IsBootloaderSecure ? "Disabled" : "Enabled"), LogType.ConsoleOnly);
}
if ((Type == LogType.FileOnly) || (Type == LogType.FileAndConsole))
{
LogFile.Log("Flash app security: " + (!IsBootloaderSecure ? "Disabled" : "Enabled") + " (FFU security: " + (SecureFfuEnabled ? "Enabled" : "Disabled") + ", RDC: " + (RdcPresent ? "Present" : "Not found") + ", Authenticated: " + (Authenticated ? "True" : "False") + ")", LogType.FileOnly);
}
LogFile.Log("JTAG: " + (JtagDisabled ? "Disabled" : "Enabled"), Type);
}
+84 -38
View File
@@ -29,9 +29,9 @@ namespace WPinternals
internal class NokiaPhoneModel : IDisposable
{
protected bool Disposed = false;
private USBDevice Device = null;
private readonly USBDevice Device = null;
private int MessageId = 0;
private object UsbLock = new object();
private readonly object UsbLock = new();
public NokiaPhoneModel(string DevicePath)
{
@@ -50,18 +50,22 @@ namespace WPinternals
lock (UsbLock)
{
string jsonrpc = "2.0";
const string jsonrpc = "2.0";
int id = MessageId++;
string method = JsonMethod;
Dictionary<string, object> @params = new Dictionary<string, object>();
Dictionary<string, object> @params = new();
if (Params != null)
{
foreach (KeyValuePair<string, object> Param in Params)
{
if (Param.Value is byte[])
@params.Add(Param.Key, ((byte[])Param.Value).Select(b => (int)b).ToArray()); // convert to int-array
if (Param.Value is byte[] v)
{
@params.Add(Param.Key, v.Select(b => (int)b).ToArray()); // convert to int-array
}
else
{
@params.Add(Param.Key, Param.Value);
}
}
}
@params.Add("MessageVersion", 0);
@@ -77,7 +81,11 @@ namespace WPinternals
try
{
JsonElement? ResultToken = ResultMessage.RootElement.GetProperty("result");
if ((ResultToken == null) || (ResultElement == null)) return null;
if ((ResultToken == null) || (ResultElement == null))
{
return null;
}
return ResultToken.Value.GetProperty(ResultElement);
}
catch
@@ -88,55 +96,83 @@ namespace WPinternals
public void ExecuteJsonMethod(string JsonMethod, Dictionary<string, object> Params)
{
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, Params, null);
_ = ExecuteJsonMethodAsJsonToken(JsonMethod, Params, null);
}
public string ExecuteJsonMethodAsString(string JsonMethod, Dictionary<string, object> Params, string ResultElement)
{
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, Params, ResultElement);
if (Token == null) return null;
if (Token == null)
{
return null;
}
return Token.Value.GetString();
}
public string ExecuteJsonMethodAsString(string JsonMethod, string ResultElement)
{
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, null, ResultElement);
if (Token == null) return null;
if (Token == null)
{
return null;
}
return Token.Value.GetString();
}
public int ExecuteJsonMethodAsInteger(string JsonMethod, Dictionary<string, object> Params, string ResultElement)
{
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, Params, ResultElement);
if (Token == null) return 0;
if (Token == null)
{
return 0;
}
return Token.Value.GetInt32();
}
public int ExecuteJsonMethodAsInteger(string JsonMethod, string ResultElement)
{
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, null, ResultElement);
if (Token == null) return 0;
if (Token == null)
{
return 0;
}
return Token.Value.GetInt32();
}
public byte[] ExecuteJsonMethodAsBytes(string JsonMethod, Dictionary<string, object> Params, string ResultElement)
{
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, Params, ResultElement);
if (Token == null) return null;
if (Token == null)
{
return null;
}
return Token.Value.EnumerateArray().Select(x => x.GetByte()).ToArray();
}
public byte[] ExecuteJsonMethodAsBytes(string JsonMethod, string ResultElement)
{
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, null, ResultElement);
if (Token == null) return null;
if (Token == null)
{
return null;
}
return Token.Value.EnumerateArray().Select(x => x.GetByte()).ToArray();
}
public bool? ExecuteJsonMethodAsBoolean(string JsonMethod, string ResultElement)
{
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, null, ResultElement);
if (Token == null) return null;
if (Token == null)
{
return null;
}
return Token.Value.GetBoolean();
}
@@ -144,28 +180,29 @@ namespace WPinternals
{
lock (UsbLock)
{
string jsonrpc = "2.0";
const string jsonrpc = "2.0";
int id = MessageId++;
string method = JsonMethod;
Dictionary<string, object> @params = new Dictionary<string, object>();
Dictionary<string, object> @params = new();
if (Params != null)
{
foreach (KeyValuePair<string, object> Param in Params)
{
if (Param.Value is byte[])
@params.Add(Param.Key, ((byte[])Param.Value).Select(b => (int)b).ToArray()); // convert to int-array
if (Param.Value is byte[] v)
{
@params.Add(Param.Key, v.Select(b => (int)b).ToArray()); // convert to int-array
}
else
{
@params.Add(Param.Key, Param.Value);
}
}
}
@params.Add("MessageVersion", 0);
string Request = JsonSerializer.Serialize(new { jsonrpc, id, method, @params });
byte[] OutBuffer = System.Text.Encoding.ASCII.GetBytes(Request);
Device.OutputPipe.BeginWrite(OutBuffer, 0, OutBuffer.Length, (AsyncResultWrite) =>
{
Device.OutputPipe.EndWrite(AsyncResultWrite);
}, null);
Device.OutputPipe.BeginWrite(OutBuffer, 0, OutBuffer.Length, (AsyncResultWrite) => Device.OutputPipe.EndWrite(AsyncResultWrite), null);
}
}
@@ -178,48 +215,48 @@ namespace WPinternals
public void ExecuteJsonMethodAsStringAsync(string JsonMethod, Dictionary<string, object> Params, string ResultElement, object State, JsonMethodCallbackString Callback)
{
ExecuteJsonMethodAsTokenAsync(JsonMethod, Params, ResultElement, State, (ReturnState, Token) => { Callback(ReturnState, Token.Value.GetRawText()); });
ExecuteJsonMethodAsTokenAsync(JsonMethod, Params, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetRawText()));
}
public void ExecuteJsonMethodAsStringAsync(string JsonMethod, string ResultElement, object State, JsonMethodCallbackString Callback)
{
ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, (ReturnState, Token) => { Callback(ReturnState, Token.Value.GetRawText()); });
ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetRawText()));
}
public delegate void JsonMethodCallbackBoolean(object State, bool Result);
public void ExecuteJsonMethodAsBooleanAsync(string JsonMethod, Dictionary<string, object> Params, string ResultElement, object State, JsonMethodCallbackBoolean Callback)
{
ExecuteJsonMethodAsTokenAsync(JsonMethod, Params, ResultElement, State, (ReturnState, Token) => { Callback(ReturnState, Token.Value.GetBoolean()); });
ExecuteJsonMethodAsTokenAsync(JsonMethod, Params, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetBoolean()));
}
public void ExecuteJsonMethodAsBooleanAsync(string JsonMethod, string ResultElement, object State, JsonMethodCallbackBoolean Callback)
{
ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, (ReturnState, Token) => { Callback(ReturnState, Token.Value.GetBoolean()); });
ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetBoolean()));
}
public delegate void JsonMethodCallbackBytes(object State, byte[] Result);
public void ExecuteJsonMethodAsBytesAsync(string JsonMethod, Dictionary<string, object> Params, string ResultElement, object State, JsonMethodCallbackBytes Callback)
{
ExecuteJsonMethodAsTokenAsync(JsonMethod, Params, ResultElement, State, (ReturnState, Token) => { Callback(ReturnState, Token.Value.EnumerateArray().Select(x => x.GetByte()).ToArray()); });
ExecuteJsonMethodAsTokenAsync(JsonMethod, Params, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.EnumerateArray().Select(x => x.GetByte()).ToArray()));
}
public void ExecuteJsonMethodAsBytesAsync(string JsonMethod, string ResultElement, object State, JsonMethodCallbackBytes Callback)
{
ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, (ReturnState, Token) => { Callback(ReturnState, Token.Value.EnumerateArray().Select(x => x.GetByte()).ToArray()); });
ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.EnumerateArray().Select(x => x.GetByte()).ToArray()));
}
public delegate void JsonMethodCallbackInteger(object State, int Result);
public void ExecuteJsonMethodAsIntegerAsync(string JsonMethod, Dictionary<string, object> Params, string ResultElement, object State, JsonMethodCallbackInteger Callback)
{
ExecuteJsonMethodAsTokenAsync(JsonMethod, Params, ResultElement, State, (ReturnState, Token) => { Callback(ReturnState, Token.Value.GetInt32()); });
ExecuteJsonMethodAsTokenAsync(JsonMethod, Params, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetInt32()));
}
public void ExecuteJsonMethodAsIntegerAsync(string JsonMethod, string ResultElement, object State, JsonMethodCallbackInteger Callback)
{
ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, (ReturnState, Token) => { Callback(ReturnState, Token.Value.GetInt32()); });
ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetInt32()));
}
public delegate void JsonMethodCallbackToken(object State, JsonElement? Result);
@@ -231,18 +268,22 @@ namespace WPinternals
lock (UsbLock)
{
string jsonrpc = "2.0";
const string jsonrpc = "2.0";
int id = MessageId++;
string method = JsonMethod;
Dictionary<string, object> @params = new Dictionary<string, object>();
Dictionary<string, object> @params = new();
if (Params != null)
{
foreach (KeyValuePair<string, object> Param in Params)
{
if (Param.Value is byte[])
@params.Add(Param.Key, ((byte[])Param.Value).Select(b => (int)b).ToArray()); // convert to int-array
if (Param.Value is byte[] v)
{
@params.Add(Param.Key, v.Select(b => (int)b).ToArray()); // convert to int-array
}
else
{
@params.Add(Param.Key, Param.Value);
}
}
}
@params.Add("MessageVersion", 0);
@@ -260,7 +301,11 @@ namespace WPinternals
JsonDocument ResultMessage = JsonDocument.Parse(System.Text.ASCIIEncoding.ASCII.GetString(Buffer, 0, Length));
JsonElement? ResultToken = ResultMessage.RootElement.GetProperty("result");
if ((ResultToken == null) || (ResultElement == null)) Callback(AsyncResultRead.AsyncState, null);
if ((ResultToken == null) || (ResultElement == null))
{
Callback(AsyncResultRead.AsyncState, null);
}
Callback(AsyncResultRead.AsyncState, ResultToken.Value.GetProperty(ResultElement));
}, AsyncResultWrite.AsyncState);
}, State);
@@ -349,12 +394,13 @@ namespace WPinternals
protected virtual void Dispose(bool disposing)
{
if (Disposed)
{
return;
}
if (disposing)
{
if (Device != null)
Device.Dispose();
Device?.Dispose();
}
// Clean unmanaged resources here.
+35 -27
View File
@@ -33,26 +33,26 @@ namespace WPinternals
{
internal class PatchEngine
{
internal List<PatchDefinition> PatchDefinitions = new List<PatchDefinition>();
internal readonly List<TargetRedirection> TargetRedirections = new List<TargetRedirection>();
internal List<PatchDefinition> PatchDefinitions = new();
internal readonly List<TargetRedirection> TargetRedirections = new();
internal PatchEngine() { }
internal PatchEngine(string PatchDefinitionsXmlString)
{
XmlSerializer x = new XmlSerializer(PatchDefinitions.GetType(), null, new Type[] { }, new XmlRootAttribute("PatchDefinitions"), "");
MemoryStream s = new MemoryStream(System.Text.Encoding.ASCII.GetBytes(PatchDefinitionsXmlString));
XmlSerializer x = new(PatchDefinitions.GetType(), null, Array.Empty<Type>(), new XmlRootAttribute("PatchDefinitions"), "");
MemoryStream s = new(System.Text.Encoding.ASCII.GetBytes(PatchDefinitionsXmlString));
PatchDefinitions = (List<PatchDefinition>)x.Deserialize(s);
}
internal void WriteDefinitions(string FilePath)
{
XmlSerializer x = new XmlSerializer(PatchDefinitions.GetType(), null, new Type[] { }, new XmlRootAttribute("PatchDefinitions"), "");
XmlSerializer x = new(PatchDefinitions.GetType(), null, Array.Empty<Type>(), new XmlRootAttribute("PatchDefinitions"), "");
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
XmlSerializerNamespaces ns = new();
ns.Add("", "");
System.IO.StreamWriter FileWriter = new System.IO.StreamWriter(FilePath);
StreamWriter FileWriter = new(FilePath);
XmlWriter XmlWriter = XmlWriter.Create(FileWriter, new XmlWriterSettings() { OmitXmlDeclaration = true, Indent = true, NewLineHandling = NewLineHandling.Entitize });
FileWriter.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
@@ -98,7 +98,6 @@ namespace WPinternals
}
}
private DiscUtils.DiscFileSystem _TargetImage = null;
internal DiscUtils.DiscFileSystem TargetImage
{
@@ -116,7 +115,7 @@ namespace WPinternals
internal bool Patch(string PatchDefinition)
{
bool Result = false;
List<FilePatcher> LoadedFiles = new List<FilePatcher>();
List<FilePatcher> LoadedFiles = new();
LogFile.Log("Attempt patch: " + PatchDefinition);
@@ -142,16 +141,18 @@ namespace WPinternals
}
}
if (TargetPath == null)
{
TargetPath = Path.Combine(this.TargetPath + "\\", CurrentTargetFile.Path);
}
// Lookup file
FilePatcher CurrentFile = LoadedFiles.SingleOrDefault(f => string.Compare(f.FilePath, TargetPath, true) == 0);
if (CurrentFile == null)
{
if ((TargetImage != null) && (!TargetPath.Contains(':')))
CurrentFile = new FilePatcher(TargetPath, TargetImage.OpenFile(TargetPath, FileMode.Open, FileAccess.ReadWrite));
else
CurrentFile = new FilePatcher(TargetPath);
CurrentFile = (TargetImage != null) && (!TargetPath.Contains(':'))
? new FilePatcher(TargetPath, TargetImage.OpenFile(TargetPath, FileMode.Open, FileAccess.ReadWrite))
: new FilePatcher(TargetPath);
LoadedFiles.Add(CurrentFile);
}
@@ -236,7 +237,7 @@ namespace WPinternals
internal void Restore(string PatchDefinition)
{
List<FilePatcher> LoadedFiles = new List<FilePatcher>();
List<FilePatcher> LoadedFiles = new();
try
{
@@ -260,7 +261,9 @@ namespace WPinternals
}
}
if (TargetPath == null)
{
TargetPath = Path.Combine(this.TargetPath, CurrentTargetFile.Path);
}
// Lookup file
FilePatcher CurrentFile = LoadedFiles.SingleOrDefault(f => string.Compare(f.FilePath, TargetPath, true) == 0);
@@ -286,7 +289,9 @@ namespace WPinternals
}
if (!Match)
{
break;
}
}
}
@@ -389,22 +394,22 @@ namespace WPinternals
internal FilePatcher(string FilePath)
{
this.FilePath = FilePath;
using (FileStream stream = File.OpenRead(FilePath))
{
SHA1Managed sha = new SHA1Managed();
Hash = sha.ComputeHash(stream);
}
using FileStream stream = File.OpenRead(FilePath);
SHA1Managed sha = new();
Hash = sha.ComputeHash(stream);
}
internal FilePatcher(string FilePath, Stream FileStream)
{
if (!FileStream.CanSeek || !FileStream.CanWrite)
{
throw new WPinternalsException("Incorrect filestream", "The provided file stream for patching does not support seeking and/or writing.");
}
this.FilePath = FilePath;
this.Stream = FileStream;
FileStream.Position = 0;
SHA1Managed sha = new SHA1Managed();
SHA1Managed sha = new();
Hash = sha.ComputeHash(FileStream);
FileStream.Position = 0;
}
@@ -413,7 +418,7 @@ namespace WPinternals
{
if (FilePath.Contains(':'))
{
FileInfo fileInfo = new FileInfo(FilePath);
FileInfo fileInfo = new(FilePath);
// Enable Take Ownership AND Restore ownership to original owner
// Take Ownership Privilge is not enough.
@@ -460,7 +465,7 @@ namespace WPinternals
if (FilePath.Contains(':'))
{
FileInfo fileInfo = new FileInfo(FilePath);
FileInfo fileInfo = new(FilePath);
// Restore original owner and access rules.
// The OriginalACL cannot be reused directly.
@@ -487,7 +492,7 @@ namespace WPinternals
[XmlAttribute]
public string Name;
public List<TargetVersion> TargetVersions = new List<TargetVersion>();
public List<TargetVersion> TargetVersions = new();
}
public class TargetVersion // Must be public to be serializable
@@ -495,7 +500,7 @@ namespace WPinternals
[XmlAttribute]
public string Description;
public List<TargetFile> TargetFiles = new List<TargetFile>();
public List<TargetFile> TargetFiles = new();
}
public class TargetFile // Must be public to be serializable
@@ -544,8 +549,8 @@ namespace WPinternals
}
}
public List<Patch> Patches = new List<Patch>();
public List<TargetFile> Obsolete = new List<TargetFile>();
public List<Patch> Patches = new();
public List<TargetFile> Obsolete = new();
}
public class Patch // Must be public to be serializable
@@ -563,7 +568,10 @@ namespace WPinternals
{
string NewValue = value;
if (NewValue.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
NewValue = NewValue.Substring(2);
{
NewValue = NewValue[2..];
}
Address = Convert.ToUInt32(NewValue, 16);
}
}
+34 -35
View File
@@ -34,10 +34,10 @@ namespace WPinternals
internal sealed class Privilege
{
#region Private static members
private static LocalDataStoreSlot tlsSlot = Thread.AllocateDataSlot();
private static HybridDictionary privileges = new HybridDictionary();
private static HybridDictionary luids = new HybridDictionary();
private static ReaderWriterLock privilegeLock = new ReaderWriterLock();
private static readonly LocalDataStoreSlot tlsSlot = Thread.AllocateDataSlot();
private static readonly HybridDictionary privileges = new();
private static readonly HybridDictionary luids = new();
private static readonly ReaderWriterLock privilegeLock = new();
#endregion
#region Private members
@@ -115,7 +115,7 @@ namespace WPinternals
{
privilegeLock.ReleaseReaderLock();
if (false == NativeMethods.LookupPrivilegeValue(null, privilege, ref luid))
if (!NativeMethods.LookupPrivilegeValue(null, privilege, ref luid))
{
int error = Marshal.GetLastWin32Error();
@@ -131,7 +131,7 @@ namespace WPinternals
{
throw new ArgumentException(
string.Format("{0} is not a valid privilege name", privilege),
"privilege");
nameof(privilege));
}
else
{
@@ -170,11 +170,10 @@ namespace WPinternals
{
private bool disposed = false;
private int referenceCount = 1;
private SafeTokenHandle threadHandle = new SafeTokenHandle(IntPtr.Zero);
private bool isImpersonating = false;
private SafeTokenHandle threadHandle = new(IntPtr.Zero);
private static SafeTokenHandle processHandle = new SafeTokenHandle(IntPtr.Zero);
private static readonly object syncRoot = new object();
private static SafeTokenHandle processHandle = new(IntPtr.Zero);
private static readonly object syncRoot = new();
#region Constructor and finalizer
public TlsContents()
@@ -189,7 +188,7 @@ namespace WPinternals
{
if (processHandle.IsInvalid)
{
if (false == NativeMethods.OpenProcessToken(
if (!NativeMethods.OpenProcessToken(
NativeMethods.GetCurrentProcess(),
TokenAccessLevels.Duplicate,
ref processHandle))
@@ -206,13 +205,13 @@ namespace WPinternals
// Open the thread token; if there is no thread token,
// copy the process token onto the thread
if (false == NativeMethods.OpenThreadToken(
if (!NativeMethods.OpenThreadToken(
NativeMethods.GetCurrentThread(),
TokenAccessLevels.Query | TokenAccessLevels.AdjustPrivileges,
true,
ref this.threadHandle))
{
if (success == true)
if (success)
{
error = Marshal.GetLastWin32Error();
@@ -221,11 +220,11 @@ namespace WPinternals
success = false;
}
if (success == true)
if (success)
{
error = 0;
if (false == NativeMethods.DuplicateTokenEx(
if (!NativeMethods.DuplicateTokenEx(
processHandle,
TokenAccessLevels.Impersonate | TokenAccessLevels.Query | TokenAccessLevels.AdjustPrivileges,
IntPtr.Zero,
@@ -238,9 +237,9 @@ namespace WPinternals
}
}
if (success == true)
if (success)
{
if (false == NativeMethods.SetThreadToken(
if (!NativeMethods.SetThreadToken(
IntPtr.Zero,
this.threadHandle))
{
@@ -249,11 +248,11 @@ namespace WPinternals
}
}
if (success == true)
if (success)
{
// This thread is now impersonating; it needs to be reverted to its original state
this.isImpersonating = true;
this.IsImpersonating = true;
}
}
else
@@ -307,7 +306,10 @@ namespace WPinternals
private void Dispose(bool disposing)
{
if (this.disposed) return;
if (this.disposed)
{
return;
}
if (this.threadHandle != null)
{
@@ -315,7 +317,7 @@ namespace WPinternals
this.threadHandle = null;
}
if (this.isImpersonating)
if (this.IsImpersonating)
{
NativeMethods.RevertToSelf();
}
@@ -354,10 +356,7 @@ namespace WPinternals
get { return this.threadHandle; }
}
public bool IsImpersonating
{
get { return this.isImpersonating; }
}
public bool IsImpersonating { get; } = false;
#endregion
}
#endregion
@@ -367,7 +366,7 @@ namespace WPinternals
{
if (privilegeName == null)
{
throw new ArgumentNullException("privilegeName");
throw new ArgumentNullException(nameof(privilegeName));
}
this.luid = LuidFromPrivilege(privilegeName);
@@ -422,15 +421,15 @@ namespace WPinternals
(this.tlsContents.ReferenceCountValue > 1 ||
!this.tlsContents.IsImpersonating))
{
NativeMethods.TOKEN_PRIVILEGE newState = new NativeMethods.TOKEN_PRIVILEGE();
NativeMethods.TOKEN_PRIVILEGE newState = new();
newState.PrivilegeCount = 1;
newState.Privilege.Luid = this.luid;
newState.Privilege.Attributes = (this.initialState ? NativeMethods.SE_PRIVILEGE_ENABLED : NativeMethods.SE_PRIVILEGE_DISABLED);
NativeMethods.TOKEN_PRIVILEGE previousState = new NativeMethods.TOKEN_PRIVILEGE();
NativeMethods.TOKEN_PRIVILEGE previousState = new();
uint previousSize = 0;
if (false == NativeMethods.AdjustTokenPrivileges(
if (!NativeMethods.AdjustTokenPrivileges(
this.tlsContents.ThreadHandle,
false,
ref newState,
@@ -475,10 +474,10 @@ namespace WPinternals
{
if (callback == null)
{
throw new ArgumentNullException("callback");
throw new ArgumentNullException(nameof(callback));
}
Privilege p = new Privilege(privilege);
Privilege p = new(privilege);
try
{
@@ -551,17 +550,17 @@ namespace WPinternals
this.tlsContents.IncrementReferenceCount();
}
NativeMethods.TOKEN_PRIVILEGE newState = new NativeMethods.TOKEN_PRIVILEGE();
NativeMethods.TOKEN_PRIVILEGE newState = new();
newState.PrivilegeCount = 1;
newState.Privilege.Luid = this.luid;
newState.Privilege.Attributes = enable ? NativeMethods.SE_PRIVILEGE_ENABLED : NativeMethods.SE_PRIVILEGE_DISABLED;
NativeMethods.TOKEN_PRIVILEGE previousState = new NativeMethods.TOKEN_PRIVILEGE();
NativeMethods.TOKEN_PRIVILEGE previousState = new();
uint previousSize = 0;
// Place the new privilege on the thread token and remember the previous state.
if (false == NativeMethods.AdjustTokenPrivileges(
if (!NativeMethods.AdjustTokenPrivileges(
this.tlsContents.ThreadHandle,
false,
ref newState,
@@ -633,7 +632,7 @@ namespace WPinternals
if (this.tlsContents != null)
{
if (0 == this.tlsContents.DecrementReferenceCount())
if (this.tlsContents.DecrementReferenceCount() == 0)
{
this.tlsContents = null;
Thread.SetData(tlsSlot, null);
+9 -15
View File
@@ -26,7 +26,7 @@ namespace WPinternals
{
internal class QualcommDownload
{
private QualcommSerial Serial;
private readonly QualcommSerial Serial;
public QualcommDownload(QualcommSerial Serial)
{
@@ -48,11 +48,7 @@ namespace WPinternals
public void SendToPhoneMemory(UInt32 Address, Stream Data, UInt32 Length = UInt32.MaxValue)
{
long Remaining;
if (Length > (Data.Length - Data.Position))
Remaining = Data.Length - Data.Position;
else
Remaining = Length;
long Remaining = Length > (Data.Length - Data.Position) ? Data.Length - Data.Position : Length;
UInt32 CurrentLength;
byte[] Buffer = new byte[0x107];
Buffer[0] = 0x0F;
@@ -62,10 +58,8 @@ namespace WPinternals
{
System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentAddress).Reverse().ToArray(), 0, Buffer, 1, 4); // Address is in Big Endian
if (Remaining >= 0x100)
CurrentLength = 0x100;
else
CurrentLength = (UInt32)Remaining;
CurrentLength = Remaining >= 0x100 ? 0x100 : (UInt32)Remaining;
CurrentLength = (UInt32)(Data.Read(Buffer, 7, (int)CurrentLength));
Serial.SendCommand(Buffer, new byte[] { 0x02 });
@@ -78,11 +72,12 @@ namespace WPinternals
{
long Remaining;
if (Offset > (Data.Length - 1))
{
throw new ArgumentException("Wrong offset");
if (Length > (Data.Length - Offset))
Remaining = Data.Length - Offset;
else
Remaining = Length;
}
Remaining = Length > (Data.Length - Offset) ? Data.Length - Offset : Length;
UInt32 CurrentLength;
UInt32 CurrentOffset = Offset;
byte[] Buffer = new byte[0x107];
@@ -90,7 +85,6 @@ namespace WPinternals
byte[] CurrentBytes;
while (Remaining > 0)
{
if (Remaining >= 0x100)
{
CurrentLength = 0x100;
+25 -23
View File
@@ -31,7 +31,7 @@ namespace WPinternals
internal class QualcommFlasher
{
private QualcommSerial Serial;
private readonly QualcommSerial Serial;
public QualcommFlasher(QualcommSerial Serial)
{
@@ -99,11 +99,9 @@ namespace WPinternals
public void Flash(UInt32 StartInBytes, Stream Data, Action<int, TimeSpan?> ProgressUpdateCallback, ProgressUpdater UpdaterPerSector, UInt32 LengthInBytes = UInt32.MaxValue)
{
long Remaining;
if ((LengthInBytes == UInt32.MaxValue) || (LengthInBytes > (Data.Length - Data.Position)))
Remaining = Data.Length - Data.Position;
else
Remaining = LengthInBytes;
long Remaining = (LengthInBytes == UInt32.MaxValue) || (LengthInBytes > (Data.Length - Data.Position))
? Data.Length - Data.Position
: LengthInBytes;
UInt32 CurrentLength;
byte[] Buffer = new byte[0x405];
byte[] ResponsePattern = new byte[5];
@@ -114,17 +112,16 @@ namespace WPinternals
ProgressUpdater Progress = UpdaterPerSector;
if ((Progress == null) && (ProgressUpdateCallback != null))
{
Progress = new ProgressUpdater(GetSectorCount((UInt64)Remaining), ProgressUpdateCallback);
}
while (Remaining > 0)
{
System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentPosition), 0, Buffer, 1, 4); // Start is in bytes and in Little Endian (on Samsung devices start is in sectors!)
System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentPosition), 0, ResponsePattern, 1, 4); // Start is in bytes and in Little Endian (on Samsung devices start is in sectors!)
if (Remaining >= 0x400)
CurrentLength = 0x400;
else
CurrentLength = (UInt32)Remaining;
CurrentLength = Remaining >= 0x400 ? 0x400 : (UInt32)Remaining;
CurrentLength = (uint)Data.Read(Buffer, 5, (int)CurrentLength);
@@ -134,15 +131,16 @@ namespace WPinternals
System.Buffer.BlockCopy(Buffer, 0, FinalCommand, 0, (int)CurrentLength + 5);
}
else
{
FinalCommand = Buffer;
}
Serial.SendCommand(FinalCommand, ResponsePattern);
CurrentPosition += CurrentLength;
Remaining -= CurrentLength;
if (Progress != null)
Progress.IncreaseProgress(GetSectorCount(CurrentLength));
Progress?.IncreaseProgress(GetSectorCount(CurrentLength));
}
}
@@ -165,11 +163,14 @@ namespace WPinternals
{
long RemainingBytes;
if (OffsetInBytes > (Data.Length - 1))
{
throw new ArgumentException("Wrong offset");
if ((LengthInBytes == UInt32.MaxValue) || (LengthInBytes > (Data.Length - OffsetInBytes)))
RemainingBytes = Data.Length - OffsetInBytes;
else
RemainingBytes = LengthInBytes;
}
RemainingBytes = (LengthInBytes == UInt32.MaxValue) || (LengthInBytes > (Data.Length - OffsetInBytes))
? Data.Length - OffsetInBytes
: LengthInBytes;
UInt32 CurrentLength;
UInt32 CurrentOffset = OffsetInBytes;
byte[] Buffer = new byte[0x405];
@@ -181,17 +182,17 @@ namespace WPinternals
ProgressUpdater Progress = UpdaterPerSector;
if ((Progress == null) && (ProgressUpdateCallback != null))
{
Progress = new ProgressUpdater(GetSectorCount((UInt64)RemainingBytes), ProgressUpdateCallback);
}
while (RemainingBytes > 0)
{
System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentPosition), 0, Buffer, 1, 4); // Start position is in bytes and in Little Endian (on Samsung phones the start position is in Sectors!!)
System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentPosition), 0, ResponsePattern, 1, 4); // Start position is in bytes and in Little Endian (on Samsung phones the start position is in Sectors!!)
if (RemainingBytes >= 0x400)
CurrentLength = 0x400;
else
CurrentLength = (UInt32)RemainingBytes;
CurrentLength = RemainingBytes >= 0x400 ? 0x400 : (UInt32)RemainingBytes;
System.Buffer.BlockCopy(Data, (int)CurrentOffset, Buffer, 5, (int)CurrentLength);
if (CurrentLength < 0x400)
@@ -200,7 +201,9 @@ namespace WPinternals
System.Buffer.BlockCopy(Buffer, 0, FinalCommand, 0, (int)CurrentLength + 5);
}
else
{
FinalCommand = Buffer;
}
Serial.SendCommand(FinalCommand, ResponsePattern);
@@ -208,14 +211,13 @@ namespace WPinternals
CurrentOffset += CurrentLength;
RemainingBytes -= CurrentLength;
if (Progress != null)
Progress.IncreaseProgress(GetSectorCount(CurrentLength));
Progress?.IncreaseProgress(GetSectorCount(CurrentLength));
}
}
public UInt64 GetSectorCount(UInt64 ByteCount)
{
return (ByteCount / 0x200) + ((ByteCount % 0x200) > 0 ? (UInt64)1 : (UInt64)0);
return (ByteCount / 0x200) + ((ByteCount % 0x200) > 0 ? 1 : (UInt64)0);
}
public void Reboot()
+11 -8
View File
@@ -29,7 +29,7 @@ namespace WPinternals
{
internal static List<QualcommPartition> GetPossibleLoadersForRootKeyHash(string Path, byte[] RootKeyHash)
{
List<QualcommPartition> Result = new List<QualcommPartition>();
List<QualcommPartition> Result = new();
try
{
@@ -38,7 +38,7 @@ namespace WPinternals
{
try
{
FileInfo Info = new FileInfo(FilePath);
FileInfo Info = new(FilePath);
if (Info.Length <= 0x80000)
{
QualcommPartition Loader;
@@ -48,10 +48,7 @@ namespace WPinternals
#endif
byte[] Binary = ParseAsHexFile(FilePath);
if (Binary == null)
Loader = new QualcommPartition(FilePath);
else
Loader = new QualcommPartition(Binary);
Loader = Binary == null ? new QualcommPartition(FilePath) : new QualcommPartition(Binary);
// Make sure the RootKeyHash is not blank
// If the RootKeyHash is blank, this is an engineering device, and it will accept any RKH
@@ -66,7 +63,7 @@ namespace WPinternals
}
else
{
if ((ByteOperations.FindUnicode(Loader.Binary, "QHSUSB_ARMPRG") != null)) // To detect that this is a loader, and not SBL1 or something. V1 loaders are QHSUSB_ARMPRG. V2 loaders are QHSUSB__BULK. Only V1 supported for now, because V2 only accepts signed payload.
if (ByteOperations.FindUnicode(Loader.Binary, "QHSUSB_ARMPRG") != null) // To detect that this is a loader, and not SBL1 or something. V1 loaders are QHSUSB_ARMPRG. V2 loaders are QHSUSB__BULK. Only V1 supported for now, because V2 only accepts signed payload.
{
Result.Add(Loader);
}
@@ -94,15 +91,21 @@ namespace WPinternals
foreach (string Line in Lines)
{
if (Line[0] != ':')
{
throw new BadImageFormatException();
}
byte[] LineBytes = Converter.ConvertStringToHex(Line.Substring(1));
byte[] LineBytes = Converter.ConvertStringToHex(Line[1..]);
if ((LineBytes[0] + 5) != LineBytes.Length)
{
throw new BadImageFormatException();
}
if (Buffer == null)
{
Buffer = new byte[0x40000];
}
if (LineBytes[3] == 0) // This is mem data
{
+8
View File
@@ -88,7 +88,9 @@ namespace WPinternals
HeaderOffset = ImageOffset + 8;
}
else
{
throw new WPinternalsException("Invalid programmer", "The type of elf image could not be determined from the provided programmer.");
}
}
else if (ByteOperations.FindPattern(Binary, Offset, (uint)LongHeaderPattern.Length, LongHeaderPattern, LongHeaderMask, null) == null)
{
@@ -104,11 +106,17 @@ namespace WPinternals
}
if (ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X00) != 0)
{
ImageOffset = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X00);
}
else if (HeaderType == QualcommPartitionHeaderType.Short)
{
ImageOffset += 0x28;
}
else
{
ImageOffset += 0x50;
}
ImageAddress = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X04);
ImageSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X08);
+45 -30
View File
@@ -35,7 +35,7 @@ namespace WPinternals
internal class QualcommSahara
{
private QualcommSerial Serial;
private readonly QualcommSerial Serial;
public QualcommSahara(QualcommSerial Serial)
{
@@ -58,8 +58,7 @@ namespace WPinternals
try
{
Step = 1;
byte[] Hello = null;
Hello = Serial.GetResponse(new byte[] { 0x01, 0x00, 0x00, 0x00 });
byte[] Hello = Serial.GetResponse(new byte[] { 0x01, 0x00, 0x00, 0x00 });
// Incoming Hello packet:
// 00000001 = Hello command id
@@ -91,34 +90,40 @@ namespace WPinternals
Serial.SendData(HelloResponse);
Step = 3;
using (System.IO.FileStream FileStream = new System.IO.FileStream(Path, System.IO.FileMode.Open, System.IO.FileAccess.Read))
using System.IO.FileStream FileStream = new(Path, System.IO.FileMode.Open, System.IO.FileAccess.Read);
while (true)
{
while (true)
Step = 4;
byte[] ReadDataRequest = Serial.GetResponse(null);
UInt32 ResponseID = ByteOperations.ReadUInt32(ReadDataRequest, 0);
if (ResponseID == 4)
{
Step = 4;
byte[] ReadDataRequest = Serial.GetResponse(null);
UInt32 ResponseID = ByteOperations.ReadUInt32(ReadDataRequest, 0);
if (ResponseID == 4)
break;
if (ResponseID != 3)
{
Step = 5;
throw new BadConnectionException();
}
Offset = ByteOperations.ReadUInt32(ReadDataRequest, 0x0C);
Length = ByteOperations.ReadUInt32(ReadDataRequest, 0x10);
if ((ImageBuffer == null) || (ImageBuffer.Length != Length))
ImageBuffer = new byte[Length];
if (FileStream.Position != Offset)
FileStream.Seek(Offset, System.IO.SeekOrigin.Begin);
Step = 6;
FileStream.Read(ImageBuffer, 0, (int)Length);
Step = 7;
Serial.SendData(ImageBuffer);
break;
}
if (ResponseID != 3)
{
Step = 5;
throw new BadConnectionException();
}
Offset = ByteOperations.ReadUInt32(ReadDataRequest, 0x0C);
Length = ByteOperations.ReadUInt32(ReadDataRequest, 0x10);
if ((ImageBuffer == null) || (ImageBuffer.Length != Length))
{
ImageBuffer = new byte[Length];
}
if (FileStream.Position != Offset)
{
FileStream.Seek(Offset, System.IO.SeekOrigin.Begin);
}
Step = 6;
FileStream.Read(ImageBuffer, 0, (int)Length);
Step = 7;
Serial.SendData(ImageBuffer);
}
}
catch (Exception Ex)
@@ -128,7 +133,9 @@ namespace WPinternals
}
if (Result)
{
LogFile.Log("Programmer loaded into phone memory", LogType.FileOnly);
}
return Result;
}
@@ -232,7 +239,7 @@ namespace WPinternals
{
Incoming = System.Text.Encoding.ASCII.GetString(Serial.GetResponse(null));
LogFile.Log("In: " + Incoming, LogType.FileOnly);
};
}
LogFile.Log("Incoming Hello-response received", LogType.FileOnly);
HandshakeCompleted = true;
@@ -242,9 +249,13 @@ namespace WPinternals
while (!HandshakeCompleted && (HelloSendCount < 6));
if (HandshakeCompleted)
{
LogFile.Log("Handshake completed with programmer in testmode", LogType.FileOnly);
}
else
{
LogFile.Log("Handshake with programmer failed", LogType.FileOnly);
}
return HandshakeCompleted;
}
@@ -253,16 +264,20 @@ namespace WPinternals
{
bool SendImageResult = await Task.Run(() => SendImage(ProgrammerPath));
if (!SendImageResult)
{
return false;
}
await Task.Run(() => StartProgrammer());
bool Connected = await Task.Run(() => ConnectToProgrammerInTestMode());
if (!Connected)
{
return false;
}
LogFile.Log("Rebooting phone", LogType.FileAndConsole);
string Command03 = "<?xml version=\"1.0\" ?><data><power value=\"reset\"/></data>";
const string Command03 = "<?xml version=\"1.0\" ?><data><power value=\"reset\"/></data>";
LogFile.Log("Out: " + Command03, LogType.FileOnly);
Serial.SendData(System.Text.Encoding.ASCII.GetBytes(Command03));
+64 -34
View File
@@ -27,9 +27,9 @@ namespace WPinternals
internal class QualcommSerial : IDisposable
{
private bool Disposed = false;
private SerialPort Port = null;
private USBDevice USBDevice = null;
private CRC16 CRC16;
private readonly SerialPort Port = null;
private readonly USBDevice USBDevice = null;
private readonly CRC16 CRC16;
public bool EncodeCommands = true;
public bool DecodeResponses = true;
@@ -44,9 +44,11 @@ namespace WPinternals
string PortName = (string)Microsoft.Win32.Registry.GetValue(@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\" + DevicePathElements[1] + @"\" + DevicePathElements[2] + @"\Device Parameters", "PortName", null);
if (PortName != null)
{
Port = new SerialPort(PortName, 115200);
Port.ReadTimeout = 1000;
Port.WriteTimeout = 1000;
Port = new SerialPort(PortName, 115200)
{
ReadTimeout = 1000,
WriteTimeout = 1000
};
Port.Open();
}
}
@@ -62,30 +64,22 @@ namespace WPinternals
public void SendData(byte[] Data)
{
byte[] FormattedData;
if (EncodeCommands)
FormattedData = FormatCommand(Data);
else
FormattedData = Data;
if (Port != null)
Port.Write(FormattedData, 0, FormattedData.Length);
byte[] FormattedData = EncodeCommands ? FormatCommand(Data) : Data;
Port?.Write(FormattedData, 0, FormattedData.Length);
if (USBDevice != null)
{
USBDevice.OutputPipe.Write(FormattedData);
}
}
public byte[] SendCommand(byte[] Command, byte[] ResponsePattern)
{
byte[] FormattedCommand;
if (EncodeCommands)
FormattedCommand = FormatCommand(Command);
else
FormattedCommand = Command;
if (Port != null)
Port.Write(FormattedCommand, 0, FormattedCommand.Length);
byte[] FormattedCommand = EncodeCommands ? FormatCommand(Command) : Command;
Port?.Write(FormattedCommand, 0, FormattedCommand.Length);
if (USBDevice != null)
{
USBDevice.OutputPipe.Write(FormattedCommand);
}
return GetResponse(ResponsePattern);
}
@@ -105,9 +99,14 @@ namespace WPinternals
int BytesRead = 0;
if (Port != null)
{
BytesRead = Port.Read(ResponseBuffer, Length, ResponseBuffer.Length - Length);
}
if (USBDevice != null)
{
BytesRead = USBDevice.InputPipe.Read(ResponseBuffer);
}
if (BytesRead == 0)
{
@@ -130,6 +129,7 @@ namespace WPinternals
if (ResponsePattern != null)
{
for (int i = 0; i < ResponsePattern.Length; i++)
{
if (DecodedResponse[i] != ResponsePattern[i])
{
byte[] LogResponse = new byte[DecodedResponse.Length < 0x10 ? DecodedResponse.Length : 0x10];
@@ -137,6 +137,7 @@ namespace WPinternals
LogFile.Log("Expected: " + Converter.ConvertHexToString(ResponsePattern, ""), LogType.FileOnly);
throw new BadMessageException();
}
}
}
return DecodedResponse;
@@ -149,10 +150,11 @@ namespace WPinternals
}
while (IsIncomplete);
if (Port != null)
Port.DiscardInBuffer();
Port?.DiscardInBuffer();
if (USBDevice != null)
{
USBDevice.InputPipe.Flush();
}
throw new BadConnectionException();
}
@@ -160,7 +162,9 @@ namespace WPinternals
private byte[] FormatCommand(byte[] Command)
{
if ((Command == null) || (Command.Length == 0))
{
throw new BadMessageException();
}
byte[] Decoded = new byte[(Command.Length * 2) + 4];
int Length = 0;
@@ -175,7 +179,9 @@ namespace WPinternals
Decoded[Length++] = (byte)(Command[i] ^ 0x20);
}
else
{
Decoded[Length++] = Command[i];
}
}
UInt16 Checksum = CRC16.CalculateChecksum(Command);
@@ -185,14 +191,20 @@ namespace WPinternals
Decoded[Length++] = (byte)((Checksum & 0xFF) ^ 0x20);
}
else
{
Decoded[Length++] = (byte)(Checksum & 0xFF);
}
if (((byte)(Checksum >> 8) == 0x7D) || ((byte)(Checksum >> 8) == 0x7E))
{
Decoded[Length++] = 0x7D;
Decoded[Length++] = (byte)((Checksum >> 8) ^ 0x20);
}
else
{
Decoded[Length++] = (byte)(Checksum >> 8);
}
Decoded[Length++] = 0x7E;
if (Length > 0)
@@ -202,13 +214,17 @@ namespace WPinternals
return Result;
}
else
{
return null;
}
}
private byte[] DecodeResponse(byte[] Response, UInt32 Length)
{
if ((Response == null) || (Response.Length == 0) || (Response[0] != 0x7E))
{
throw new BadMessageException();
}
UInt32 SourceLength = Length;
Length = 0;
@@ -219,24 +235,33 @@ namespace WPinternals
while (SourcePos < SourceLength)
{
if (Response[SourcePos] == 0x7E)
{
break;
if (Response[SourcePos] == 0x7D)
Message[Length++] = (byte)(Response[++SourcePos] ^ 0x20);
else
Message[Length++] = Response[SourcePos];
}
Message[Length++] = Response[SourcePos] == 0x7D ? (byte)(Response[++SourcePos] ^ 0x20) : Response[SourcePos];
SourcePos++;
}
if (SourcePos == SourceLength) throw new IncompleteMessageException();
if (SourcePos == SourceLength)
{
throw new IncompleteMessageException();
}
if (Length < 3) throw new BadMessageException();
if (Length < 3)
{
throw new BadMessageException();
}
byte[] TrimmedMessage = new byte[Length - 2];
Buffer.BlockCopy(Message, 0, TrimmedMessage, 0, (int)(Length - 2));
UInt16 Checksum = CRC16.CalculateChecksum(TrimmedMessage);
if (((byte)(Checksum & 0xFF) != Message[Length - 2]) || ((byte)(Checksum >> 8) != Message[Length - 1]))
{
throw new BadMessageException();
}
return TrimmedMessage;
}
@@ -254,14 +279,16 @@ namespace WPinternals
public void Close()
{
if (Port != null) Port.Close();
if (USBDevice != null) USBDevice.Dispose();
Port?.Close();
USBDevice?.Dispose();
}
protected virtual void Dispose(bool disposing)
{
if (Disposed)
{
return;
}
if (disposing)
{
@@ -277,7 +304,10 @@ namespace WPinternals
internal void SetTimeOut(int v)
{
if (USBDevice != null)
{
USBDevice.ControlPipeTimeout = v;
}
if (Port != null)
{
Port.ReadTimeout = v;
@@ -292,7 +322,7 @@ namespace WPinternals
public class CRC16
{
private UInt16[] ChecksumTable =
private readonly UInt16[] ChecksumTable =
new UInt16[] {
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
@@ -328,7 +358,7 @@ namespace WPinternals
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};
private UInt16 Seed, FinalXor;
private readonly UInt16 Seed, FinalXor;
public CRC16(UInt16 Polynomial, UInt16 Seed, UInt16 FinalXor)
{
+6
View File
@@ -35,7 +35,9 @@ namespace WPinternals
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
}, null, null);
if (Offset == null)
{
throw new BadImageFormatException();
}
UInt32 PartitionLoaderTableOffset = (UInt32)Offset;
@@ -49,7 +51,9 @@ namespace WPinternals
},
FoundPattern);
if (Offset == null)
{
throw new BadImageFormatException();
}
UInt32 SharedMemoryAddress = ByteOperations.ReadUInt32(FoundPattern, 0x0C);
UInt32 GlobalIsSecurityEnabledAddress = SharedMemoryAddress + 0x28;
@@ -65,7 +69,9 @@ namespace WPinternals
},
null);
if (Offset == null)
{
throw new BadImageFormatException();
}
UInt32 ReturnAddress = (UInt32)Offset - ImageOffset + ImageAddress;
+2
View File
@@ -44,7 +44,9 @@ namespace WPinternals
null);
if (PatchOffset == null)
{
throw new BadImageFormatException();
}
Buffer.BlockCopy(new byte[] { 0x00, 0x00, 0xA0, 0xE3 }, 0, Binary, (int)PatchOffset + 8, 4);
+5 -4
View File
@@ -41,7 +41,7 @@ namespace WPinternals
{
if (FFU.IsFFU(FileName))
{
FFU FFUFile = new FFU(FileName);
FFU FFUFile = new(FileName);
Binary = FFUFile.GetPartition("SBL3");
}
}
@@ -50,18 +50,17 @@ namespace WPinternals
// If not succeeded, then try to parse it as raw image
if (Binary == null)
{
byte[] SBL3Header;
byte[] SBL3Pattern = new byte[] { 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x8F, 0xFF, 0xFF, 0xFF, 0xFF };
byte[] SBL3Mask = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF };
UInt32? Offset = ByteOperations.FindPatternInFile(FileName, SBL3Pattern, SBL3Mask, out SBL3Header);
UInt32? Offset = ByteOperations.FindPatternInFile(FileName, SBL3Pattern, SBL3Mask, out byte[] SBL3Header);
if (Offset != null)
{
UInt32 Length = ByteOperations.ReadUInt32(SBL3Header, 0x10) + 0x28; // SBL3 Image Size + Header Size
Binary = new byte[Length];
FileStream Stream = new FileStream(FileName, FileMode.Open, FileAccess.Read);
FileStream Stream = new(FileName, FileMode.Open, FileAccess.Read);
Stream.Seek((long)Offset, SeekOrigin.Begin);
Stream.Read(Binary, 0, (int)Length);
Stream.Close();
@@ -77,7 +76,9 @@ namespace WPinternals
null, null);
if (PatchOffset == null)
{
throw new BadImageFormatException();
}
Buffer.BlockCopy(new byte[] { 0x00, 0x00, 0xA0, 0xE3 }, 0, Binary, (int)PatchOffset + 4, 4);
+79 -23
View File
@@ -39,22 +39,22 @@ namespace WPinternals
{
internal byte[] Binary;
private byte[] DecompressedImage;
internal List<EFI> EFIs = new List<EFI>();
private byte PaddingByteValue = 0xFF;
private UInt32 DecompressedVolumeSectionHeaderOffset;
private UInt32 DecompressedVolumeHeaderOffset;
private UInt32 VolumeSize;
private UInt16 VolumeHeaderSize;
private UInt32 FileHeaderOffset;
private UInt32 SectionHeaderOffset;
private UInt32 CompressedSubImageOffset;
internal List<EFI> EFIs = new();
private readonly byte PaddingByteValue = 0xFF;
private readonly UInt32 DecompressedVolumeSectionHeaderOffset;
private readonly UInt32 DecompressedVolumeHeaderOffset;
private readonly UInt32 VolumeSize;
private readonly UInt16 VolumeHeaderSize;
private readonly UInt32 FileHeaderOffset;
private readonly UInt32 SectionHeaderOffset;
private readonly UInt32 CompressedSubImageOffset;
private UInt32 CompressedSubImageSize;
// First 0x28 bytes are Qualcomm partition header
// Inside the attributes of the VolumeHeader, the Volume-alignment is set to 8 (on Windows Phone UEFI images)
// The Volume always starts right after the Qualcomm header at position 0x28.
// So the VolumeHeader-alignment is always complied.
private UInt32 VolumeHeaderOffset = 0x28;
private readonly UInt32 VolumeHeaderOffset = 0x28;
internal UEFI(byte[] UefiBinary)
{
@@ -62,13 +62,12 @@ namespace WPinternals
string VolumeHeaderMagic;
UInt32? Offset = ByteOperations.FindAscii(Binary, "_FVH");
if (Offset == null)
throw new BadImageFormatException();
else
VolumeHeaderOffset = (UInt32)Offset - 0x28;
VolumeHeaderOffset = Offset == null ? throw new BadImageFormatException() : (UInt32)Offset - 0x28;
if (!VerifyVolumeChecksum(Binary, VolumeHeaderOffset))
{
throw new BadImageFormatException();
}
VolumeSize = ByteOperations.ReadUInt32(Binary, VolumeHeaderOffset + 0x20); // TODO: This is actually a QWORD
VolumeHeaderSize = ByteOperations.ReadUInt16(Binary, VolumeHeaderOffset + 0x30);
@@ -83,7 +82,9 @@ namespace WPinternals
do
{
if (!VerifyFileChecksum(Binary, FileHeaderOffset))
{
throw new BadImageFormatException();
}
FileType = ByteOperations.ReadUInt8(Binary, FileHeaderOffset + 0x12);
FileSize = ByteOperations.ReadUInt24(Binary, FileHeaderOffset + 0x14);
@@ -105,7 +106,9 @@ namespace WPinternals
while (!VolumeFound && (FileHeaderOffset < (VolumeHeaderOffset + VolumeSize)));
if (!VolumeFound)
{
throw new BadImageFormatException();
}
// Look in file for section of type EFI_SECTION_GUID_DEFINED (0x02)
@@ -136,7 +139,9 @@ namespace WPinternals
while (!DecompressedVolumeFound && (SectionHeaderOffset < (FileHeaderOffset + FileSize)));
if (!DecompressedVolumeFound)
{
throw new BadImageFormatException();
}
// Decompress subvolume
CompressedSubImageOffset = SectionHeaderOffset + SectionHeaderSize;
@@ -170,17 +175,23 @@ namespace WPinternals
while (!DecompressedVolumeFound && (DecompressedVolumeSectionHeaderOffset < DecompressedImage.Length));
if (!DecompressedVolumeFound)
{
throw new BadImageFormatException();
}
DecompressedVolumeHeaderOffset = DecompressedVolumeSectionHeaderOffset + 4;
// PARSE COMPRESSED VOLUME
VolumeHeaderMagic = ByteOperations.ReadAsciiString(DecompressedImage, DecompressedVolumeHeaderOffset + 0x28, 0x04);
if (VolumeHeaderMagic != "_FVH")
{
throw new BadImageFormatException();
}
if (!VerifyVolumeChecksum(DecompressedImage, DecompressedVolumeHeaderOffset))
{
throw new BadImageFormatException();
}
Int32 DecompressedVolumeSize = ByteOperations.ReadInt32(DecompressedImage, DecompressedVolumeHeaderOffset + 0x20); // TODO: This is actually a QWORD
UInt16 DecompressedVolumeHeaderSize = ByteOperations.ReadUInt16(DecompressedImage, DecompressedVolumeHeaderOffset + 0x30);
@@ -191,7 +202,9 @@ namespace WPinternals
do
{
if ((DecompressedFileHeaderOffset + 0x18) >= (DecompressedVolumeHeaderOffset + DecompressedVolumeSize))
{
break;
}
bool ContentFound = false;
for (int i = 0; i < 0x18; i++)
@@ -203,19 +216,26 @@ namespace WPinternals
}
}
if (!ContentFound)
{
break;
}
FileSize = ByteOperations.ReadUInt24(DecompressedImage, DecompressedFileHeaderOffset + 0x14);
if ((DecompressedFileHeaderOffset + FileSize) >= (DecompressedVolumeHeaderOffset + DecompressedVolumeSize))
{
break;
}
if (!VerifyFileChecksum(DecompressedImage, DecompressedFileHeaderOffset))
{
throw new BadImageFormatException();
}
CurrentEFI = new EFI();
CurrentEFI.Type = ByteOperations.ReadUInt8(DecompressedImage, DecompressedFileHeaderOffset + 0x12);
CurrentEFI = new EFI
{
Type = ByteOperations.ReadUInt8(DecompressedImage, DecompressedFileHeaderOffset + 0x12)
};
byte[] FileGuidBytes = new byte[0x10];
System.Buffer.BlockCopy(DecompressedImage, (int)DecompressedFileHeaderOffset + 0x00, FileGuidBytes, 0, 0x10);
CurrentEFI.Guid = new Guid(FileGuidBytes);
@@ -266,9 +286,11 @@ namespace WPinternals
internal byte[] GetFile(string Name)
{
EFI File = EFIs.Where(f => (string.Compare(Name, f.Name, true) == 0) || (string.Compare(Name, f.Guid.ToString(), true) == 0)).FirstOrDefault();
EFI File = EFIs.Find(f => (string.Compare(Name, f.Name, true) == 0) || (string.Compare(Name, f.Guid.ToString(), true) == 0));
if (File == null)
{
return null;
}
byte[] Bytes = new byte[File.Size];
Buffer.BlockCopy(DecompressedImage, (int)File.BinaryOffset, Bytes, 0, (int)File.Size);
@@ -278,9 +300,11 @@ namespace WPinternals
internal byte[] GetFile(Guid Guid)
{
EFI File = EFIs.Where(f => (Guid == f.Guid)).FirstOrDefault();
EFI File = EFIs.Find(f => (Guid == f.Guid));
if (File == null)
{
return null;
}
byte[] Bytes = new byte[File.Size];
Buffer.BlockCopy(DecompressedImage, (int)File.BinaryOffset, Bytes, 0, (int)File.Size);
@@ -290,9 +314,11 @@ namespace WPinternals
internal void ReplaceFile(string Name, byte[] Binary)
{
EFI File = EFIs.Where(f => (string.Compare(Name, f.Name, true) == 0) || (string.Compare(Name, f.Guid.ToString(), true) == 0)).FirstOrDefault();
EFI File = EFIs.Find(f => (string.Compare(Name, f.Name, true) == 0) || (string.Compare(Name, f.Guid.ToString(), true) == 0));
if (File == null)
{
throw new ArgumentOutOfRangeException();
}
UInt32 OldBinarySize = File.Size;
UInt32 NewBinarySize = (UInt32)Binary.Length;
@@ -318,7 +344,9 @@ namespace WPinternals
// Insert section-padding
for (int i = 0; i < NewSectionPadding; i++)
{
NewImage[File.BinaryOffset + NewBinarySize + i] = PaddingByteValue;
}
// Copy file-tail
Buffer.BlockCopy(
@@ -330,7 +358,9 @@ namespace WPinternals
// Insert file-padding
for (int i = 0; i < NewFilePadding; i++)
{
NewImage[File.BinaryOffset + NewFileSize + i] = PaddingByteValue;
}
// Copy volume-tail
Buffer.BlockCopy(
@@ -371,7 +401,9 @@ namespace WPinternals
{
Buffer.BlockCopy(Binary, 0, DecompressedImage, (int)File.BinaryOffset, Binary.Length);
for (int i = 0; i < NewSectionPadding; i++)
{
DecompressedImage[File.BinaryOffset + Binary.Length + i] = PaddingByteValue;
}
}
// Calculate File-checksum
@@ -408,28 +440,38 @@ namespace WPinternals
// Filesize includes fileheader. But it does not include the padding-bytes. Not even the padding bytes of the last section.
UInt32 NewFileSize;
if ((CompressedSubImageOffset + CompressedSubImageSize + OldSectionPadding) >= (FileHeaderOffset + OldFileSize))
{
// Compressed image is the last section of this file
NewFileSize = CompressedSubImageOffset - FileHeaderOffset + (UInt32)NewCompressedImage.Length;
}
else
{
// Compressed image is NOT the last section of this file
NewFileSize = OldFileSize - CompressedSubImageSize - OldSectionPadding + (UInt32)NewCompressedImage.Length + NewSectionPadding;
}
// Add section padding
for (int i = 0; i < NewSectionPadding; i++)
{
NewBinary[CompressedSubImageOffset + NewCompressedImage.Length + i] = PaddingByteValue;
}
// If there are more bytes after the section padding of the compressed image, then copy the trailing sections
if (((Int32)FileHeaderOffset + OldFileSize - CompressedSubImageOffset - CompressedSubImageSize - OldSectionPadding) > 0)
{
Buffer.BlockCopy(Binary, (int)(CompressedSubImageOffset + CompressedSubImageSize + OldSectionPadding), NewBinary,
(int)(CompressedSubImageOffset + NewCompressedImage.Length + NewSectionPadding),
(int)(FileHeaderOffset + OldFileSize - CompressedSubImageOffset - CompressedSubImageSize - OldSectionPadding));
}
// Add file padding
// Filesize does not include last section padding or file padding
UInt32 OldFilePadding = ByteOperations.Align(0, OldFileSize, 8) - OldFileSize;
UInt32 NewFilePadding = ByteOperations.Align(0, NewFileSize, 8) - NewFileSize;
for (int i = 0; i < NewFilePadding; i++)
{
NewBinary[FileHeaderOffset + NewFileSize + i] = PaddingByteValue;
}
if (NewCompressedImage.Length > CompressedSubImageSize)
{
@@ -441,7 +483,9 @@ namespace WPinternals
Buffer.BlockCopy(Binary, (int)(FileHeaderOffset + OldFileSize + OldFilePadding), NewBinary, (int)(FileHeaderOffset + NewFileSize + NewFilePadding),
(int)(VolumeHeaderOffset + VolumeSize - FileHeaderOffset - OldFileSize - OldFilePadding));
for (int i = (int)(VolumeHeaderOffset + VolumeSize - OldFileSize - OldFilePadding + NewFileSize + NewFilePadding); i < VolumeHeaderOffset + VolumeSize; i++)
{
NewBinary[i] = PaddingByteValue;
}
}
CompressedSubImageSize = (UInt32)NewCompressedImage.Length;
@@ -475,12 +519,12 @@ namespace WPinternals
ByteOperations.WriteUInt16(Header, 0x32, 0); // Clear checksum
UInt16 CurrentChecksum = ByteOperations.ReadUInt16(Image, Offset + 0x32);
UInt16 NewChecksum = ByteOperations.CalculateChecksum16(Header, 0, VolumeHeaderSize);
return (CurrentChecksum == NewChecksum);
return CurrentChecksum == NewChecksum;
}
private void CalculateFileChecksum(byte[] Image, UInt32 Offset)
{
UInt16 FileHeaderSize = 0x18;
const UInt16 FileHeaderSize = 0x18;
UInt32 FileSize = ByteOperations.ReadUInt24(Image, Offset + 0x14);
ByteOperations.WriteUInt16(Image, Offset + 0x10, 0); // Clear checksum
@@ -505,7 +549,7 @@ namespace WPinternals
{
// This function only checks fixed checksum-values 0x55 and 0xAA.
UInt16 FileHeaderSize = 0x18;
const UInt16 FileHeaderSize = 0x18;
UInt32 FileSize = ByteOperations.ReadUInt24(Image, Offset + 0x14);
byte[] Header = new byte[FileHeaderSize - 1];
@@ -515,7 +559,9 @@ namespace WPinternals
byte CalculatedHeaderChecksum = ByteOperations.CalculateChecksum8(Header, 0, (UInt32)FileHeaderSize - 1);
if (CurrentHeaderChecksum != CalculatedHeaderChecksum)
{
return false;
}
byte FileAttribs = ByteOperations.ReadUInt8(Image, Offset + 0x13);
byte CurrentFileChecksum = ByteOperations.ReadUInt8(Image, Offset + 0x11);
@@ -524,13 +570,17 @@ namespace WPinternals
// Calculate file checksum
byte CalculatedFileChecksum = ByteOperations.CalculateChecksum8(Image, Offset + FileHeaderSize, FileSize - FileHeaderSize);
if (CurrentFileChecksum != CalculatedFileChecksum)
{
return false;
}
}
else
{
// Fixed file checksum
if ((CurrentFileChecksum != 0xAA) && (CurrentFileChecksum != 0x55))
{
return false;
}
}
return true;
@@ -554,7 +604,9 @@ namespace WPinternals
null);
if (PatchOffset == null)
{
throw new BadImageFormatException();
}
Buffer.BlockCopy(new byte[] { 0x00, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1 }, 0, SecurityDxe, (int)PatchOffset, 8);
@@ -569,7 +621,9 @@ namespace WPinternals
null);
if (PatchOffset == null)
{
throw new BadImageFormatException();
}
ByteOperations.WriteUInt8(SecurityServicesDxe, (UInt32)PatchOffset + 0x0B, 0xEA);
@@ -579,7 +633,9 @@ namespace WPinternals
null);
if (PatchOffset == null)
{
throw new BadImageFormatException();
}
ByteOperations.WriteUInt8(SecurityServicesDxe, (UInt32)PatchOffset + 0x0B, 0xEA);