mirror of
https://github.com/ReneLergner/WPinternals.git
synced 2026-06-17 04:40:12 +10:00
Project Maintenance
This commit is contained in:
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
@@ -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()
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user