Project Maintenance

This commit is contained in:
Gustave Monce
2021-08-09 20:21:09 +02:00
parent 9865ef7f79
commit 847ce0506d
411 changed files with 5922 additions and 54941 deletions
+119 -47
View File
@@ -31,18 +31,18 @@ namespace WPinternals
public class GPT
{
private byte[] GPTBuffer;
private UInt32 HeaderOffset;
private UInt32 HeaderSize;
private readonly UInt32 HeaderOffset;
private readonly UInt32 HeaderSize;
private UInt32 TableOffset;
private UInt32 TableSize;
private UInt32 PartitionEntrySize;
private UInt32 MaxPartitions;
private readonly UInt32 PartitionEntrySize;
private readonly UInt32 MaxPartitions;
internal UInt64 FirstUsableSector;
internal UInt64 LastUsableSector;
internal bool HasChanged = false;
[XmlElement("Partition")]
public List<Partition> Partitions = new List<Partition>();
public List<Partition> Partitions = new();
public GPT() // Only for serialization
{
@@ -53,7 +53,10 @@ namespace WPinternals
this.GPTBuffer = GPTBuffer;
UInt32? TempHeaderOffset = ByteOperations.FindAscii(GPTBuffer, "EFI PART");
if (TempHeaderOffset == null)
{
throw new WPinternalsException("Bad GPT", "The GPT read isn't valid. Couldn't find the text \"EFI PART\".");
}
HeaderOffset = (UInt32)TempHeaderOffset;
HeaderSize = ByteOperations.ReadUInt32(GPTBuffer, HeaderOffset + 0x0C);
TableOffset = HeaderOffset + 0x200;
@@ -63,7 +66,9 @@ namespace WPinternals
PartitionEntrySize = ByteOperations.ReadUInt32(GPTBuffer, HeaderOffset + 0x54);
TableSize = MaxPartitions * PartitionEntrySize;
if ((TableOffset + TableSize) > GPTBuffer.Length)
{
throw new WPinternalsException("Bad GPT", "The GPT read isn't valid. The sizes defined in the GPT header exceed the provided GPT size.");
}
UInt32 PartitionOffset = TableOffset;
@@ -71,8 +76,11 @@ namespace WPinternals
{
string Name = ByteOperations.ReadUnicodeString(GPTBuffer, PartitionOffset + 0x38, 0x48).TrimEnd(new char[] { (char)0, ' ' });
if (Name.Length == 0)
{
break;
Partition CurrentPartition = new Partition();
}
Partition CurrentPartition = new();
CurrentPartition.Name = Name;
CurrentPartition.FirstSector = ByteOperations.ReadUInt64(GPTBuffer, PartitionOffset + 0x20);
CurrentPartition.LastSector = ByteOperations.ReadUInt64(GPTBuffer, PartitionOffset + 0x28);
@@ -88,30 +96,34 @@ namespace WPinternals
internal Partition GetPartition(string Name)
{
return Partitions.Where(p => (string.Compare(p.Name, Name, true) == 0)).FirstOrDefault();
return Partitions.Find(p => (string.Compare(p.Name, Name, true) == 0));
}
// Magic!
// SecureBoot hack for Bootloader Spec A starts here
internal byte[] InsertHack()
{
Partition HackPartition = Partitions.Where(p => (p.Name == "HACK")).FirstOrDefault();
Partition SBL1 = Partitions.Where(p => (p.Name == "SBL1")).FirstOrDefault();
Partition SBL2 = Partitions.Where(p => (p.Name == "SBL2")).FirstOrDefault();
Partition HackPartition = Partitions.Find(p => (p.Name == "HACK"));
Partition SBL1 = Partitions.Find(p => (p.Name == "SBL1"));
Partition SBL2 = Partitions.Find(p => (p.Name == "SBL2"));
if ((SBL1 == null) || (SBL2 == null))
{
throw new WPinternalsException("Bad GPT", "Can't patch GPT for the Secure Boot hack for Spec A devices. The provided GPT does not include a SBL1 and/or SBL2 partition.");
}
if (HackPartition == null)
{
HackPartition = new Partition();
HackPartition.Name = "HACK";
HackPartition.Attributes = SBL2.Attributes;
HackPartition.FirstSector = SBL1.LastSector;
HackPartition.LastSector = SBL1.LastSector;
HackPartition = new Partition
{
Name = "HACK",
Attributes = SBL2.Attributes,
FirstSector = SBL1.LastSector,
LastSector = SBL1.LastSector,
HackPartition.PartitionTypeGuid = SBL2.PartitionTypeGuid;
HackPartition.PartitionGuid = SBL2.PartitionGuid;
PartitionTypeGuid = SBL2.PartitionTypeGuid,
PartitionGuid = SBL2.PartitionGuid
};
Partitions.Add(HackPartition);
@@ -128,12 +140,14 @@ namespace WPinternals
internal byte[] RemoveHack()
{
Partition HackPartition = Partitions.Where(p => (p.Name == "HACK")).FirstOrDefault();
Partition SBL1 = Partitions.Where(p => (p.Name == "SBL1")).FirstOrDefault();
Partition SBL2 = Partitions.Where(p => (p.Name == "SBL2")).FirstOrDefault();
Partition HackPartition = Partitions.Find(p => (p.Name == "HACK"));
Partition SBL1 = Partitions.Find(p => (p.Name == "SBL1"));
Partition SBL2 = Partitions.Find(p => (p.Name == "SBL2"));
if ((SBL1 == null) || (SBL2 == null))
{
throw new WPinternalsException("Bad GPT", "Can't un-patch GPT for the Secure Boot hack for Spec A devices. The provided GPT does not include a SBL1 and/or SBL2 partition.");
}
if (HackPartition != null)
{
@@ -159,7 +173,9 @@ namespace WPinternals
GPTBuffer = new byte[TableSize];
}
else
{
Array.Clear(GPTBuffer, (int)TableOffset, (int)TableSize);
}
UInt32 PartitionOffset = TableOffset;
foreach (Partition CurrentPartition in Partitions)
@@ -188,21 +204,21 @@ namespace WPinternals
internal void MergePartitionsFromStream(Stream Partitions, bool RoundToChunks)
{
using (TextReader tr = new StreamReader(Partitions))
{
MergePartitions(tr.ReadToEnd(), RoundToChunks);
}
using TextReader tr = new StreamReader(Partitions);
MergePartitions(tr.ReadToEnd(), RoundToChunks);
}
internal void MergePartitions(string Xml, bool RoundToChunks, ZipArchive Archive = null)
{
GPT GptToMerge;
if (Xml == null)
{
GptToMerge = new GPT();
}
else
{
XmlSerializer x = new XmlSerializer(typeof(GPT), "");
MemoryStream s = new MemoryStream(System.Text.Encoding.ASCII.GetBytes(Xml));
XmlSerializer x = new(typeof(GPT), "");
MemoryStream s = new(System.Text.Encoding.ASCII.GetBytes(Xml));
GptToMerge = (GPT)x.Deserialize(s);
s.Dispose();
}
@@ -211,7 +227,7 @@ namespace WPinternals
{
foreach (Partition NewPartition in GptToMerge.Partitions)
{
ZipArchiveEntry Entry = Archive.Entries.Where(e => ((string.Compare(e.Name, NewPartition.Name, true) == 0) || (e.Name.StartsWith(NewPartition.Name + ".", true, System.Globalization.CultureInfo.GetCultureInfo("en-US"))))).FirstOrDefault();
ZipArchiveEntry Entry = Archive.Entries.FirstOrDefault(e => ((string.Compare(e.Name, NewPartition.Name, true) == 0) || (e.Name.StartsWith(NewPartition.Name + ".", true, System.Globalization.CultureInfo.GetCultureInfo("en-US")))));
if (Entry == null)
{
// There is a partition entry in the xml, but this partition is not present in the archive.
@@ -234,9 +250,14 @@ namespace WPinternals
// If the location of the new partition is specified, it must be the same as the current partition.
if ((NewPartition.FirstSector != 0) && (NewPartition.FirstSector != OldPartition.FirstSector))
{
throw new WPinternalsException("Incorrect location for partition \"" + NewPartition.Name + "\". A partition defined in the xml file got its boundaries updated, but as the partition isn't provided in the archive, it is not possible to relocate it.");
}
if ((NewPartition.LastSector != 0) && (NewPartition.LastSector != OldPartition.LastSector))
{
throw new WPinternalsException("Incorrect length for partition \"" + NewPartition.Name + "\". A partition defined in the xml file got its boundaries updated, but as the partition isn't provided in the archive, it is not possible to relocate it.");
}
NewPartition.FirstSector = OldPartition.FirstSector;
NewPartition.LastSector = OldPartition.LastSector;
@@ -248,7 +269,7 @@ namespace WPinternals
// If the length is specified in the xml, it must match the file in the archive.
ulong StreamLengthInSectors = (ulong)Entry.Length / 0x200;
using (DecompressedStream DecompressedStream = new DecompressedStream(Entry.Open()))
using (DecompressedStream DecompressedStream = new(Entry.Open()))
{
try
{
@@ -264,7 +285,9 @@ namespace WPinternals
else
{
if (NewPartition.SizeInSectors != StreamLengthInSectors)
{
throw new WPinternalsException("Inconsistent length specified for partition \"" + NewPartition.Name + "\". The provided partition in the archive does not match the length specified in the xml file.");
}
}
}
}
@@ -293,9 +316,14 @@ namespace WPinternals
// If the location of the new partition is specified, it must be the same as the current partition.
if ((NewPartition.FirstSector != 0) && (NewPartition.FirstSector != OldPartition.FirstSector))
{
throw new WPinternalsException("Incorrect location for partition \"" + NewPartition.Name + "\". A partition defined in the xml file got its boundaries updated, but as the partition isn't provided in the archive, it is not possible to relocate it.");
}
if ((NewPartition.LastSector != 0) && (NewPartition.LastSector != OldPartition.LastSector))
{
throw new WPinternalsException("Incorrect length for partition \"" + NewPartition.Name + "\". A partition defined in the xml file got its boundaries updated, but as the partition isn't provided in the archive, it is not possible to relocate it.");
}
NewPartition.FirstSector = OldPartition.FirstSector;
NewPartition.LastSector = OldPartition.LastSector;
@@ -303,7 +331,7 @@ namespace WPinternals
}
}
List<Partition> DynamicPartitions = new List<Partition>();
List<Partition> DynamicPartitions = new();
if (Archive != null)
{
// Partitions which are present in the archive, and which have no start-sector in the new GPT data (dynamic relocation),
@@ -314,7 +342,7 @@ namespace WPinternals
Partition OldPartition = SortedPartitions.ElementAt(i);
// Present in archive?
ZipArchiveEntry Entry = Archive.Entries.Where(e => ((string.Compare(e.Name, OldPartition.Name, true) == 0) || (e.Name.StartsWith(OldPartition.Name + ".", true, System.Globalization.CultureInfo.GetCultureInfo("en-US"))))).FirstOrDefault();
ZipArchiveEntry Entry = Archive.Entries.FirstOrDefault(e => ((string.Compare(e.Name, OldPartition.Name, true) == 0) || (e.Name.StartsWith(OldPartition.Name + ".", true, System.Globalization.CultureInfo.GetCultureInfo("en-US")))));
if (Entry != null)
{
// Not present in new GPT or present in GPT without FirstSector?
@@ -325,10 +353,14 @@ namespace WPinternals
this.Partitions.Remove(OldPartition);
}
else
{
break;
}
}
else
{
break;
}
}
}
@@ -339,22 +371,31 @@ namespace WPinternals
UInt64 LowestSector = 0;
Partition DPP = this.GetPartition("DPP");
if (DPP != null)
{
LowestSector = DPP.LastSector + 1;
}
foreach (Partition NewPartition in GptToMerge.Partitions)
{
// If the new partition is a dynamic partition, then skip it here. It will be added later.
if (DynamicPartitions.Select(p => p.Name).Any(n => string.Compare(n, NewPartition.Name, true) == 0))
{
continue;
}
// Sanity check
if (NewPartition.FirstSector < LowestSector)
{
throw new WPinternalsException("Bad sector alignment for partition: " + NewPartition.Name + ". The partition is located before DPP.");
}
Partition CurrentPartition = this.GetPartition(NewPartition.Name);
if (CurrentPartition == null)
{
CurrentPartition = new Partition();
CurrentPartition.Name = NewPartition.Name;
CurrentPartition = new Partition
{
Name = NewPartition.Name
};
this.Partitions.Add(CurrentPartition);
HasChanged = true;
}
@@ -376,18 +417,34 @@ namespace WPinternals
}
if ((NewPartition.PartitionGuid != Guid.Empty) || (NewPartition.PartitionGuid != CurrentPartition.PartitionGuid))
{
HasChanged = true;
}
if (NewPartition.PartitionGuid != Guid.Empty)
{
CurrentPartition.PartitionGuid = NewPartition.PartitionGuid;
}
if (CurrentPartition.PartitionGuid != Guid.Empty)
{
CurrentPartition.PartitionGuid = Guid.NewGuid();
}
if ((NewPartition.PartitionTypeGuid != Guid.Empty) || (NewPartition.PartitionTypeGuid != CurrentPartition.PartitionTypeGuid))
{
HasChanged = true;
}
if (NewPartition.PartitionTypeGuid != Guid.Empty)
{
CurrentPartition.PartitionTypeGuid = NewPartition.PartitionTypeGuid;
}
if (CurrentPartition.PartitionTypeGuid != Guid.Empty)
{
CurrentPartition.PartitionTypeGuid = Guid.NewGuid();
}
for (int i = this.Partitions.Count - 1; i >= 0; i--)
{
@@ -408,10 +465,10 @@ namespace WPinternals
// Check if the sizes of the partitions in the archive do not exceed the size of the partition, as listed in the GPT.
foreach (Partition OldPartition in this.Partitions)
{
ZipArchiveEntry Entry = Archive.Entries.Where(e => ((string.Compare(e.Name, OldPartition.Name, true) == 0) || (e.Name.StartsWith(OldPartition.Name + ".", true, System.Globalization.CultureInfo.GetCultureInfo("en-US"))))).FirstOrDefault();
ZipArchiveEntry Entry = Archive.Entries.FirstOrDefault(e => ((string.Compare(e.Name, OldPartition.Name, true) == 0) || (e.Name.StartsWith(OldPartition.Name + ".", true, System.Globalization.CultureInfo.GetCultureInfo("en-US")))));
if (Entry != null)
{
DecompressedStream DecompressedStream = new DecompressedStream(Entry.Open());
DecompressedStream DecompressedStream = new(Entry.Open());
ulong StreamLengthInSectors = (ulong)Entry.Length / 0x200;
try
{
@@ -423,7 +480,10 @@ namespace WPinternals
UInt64 MaxPartitionSizeInSectors = OldPartition.SizeInSectors;
Partition NextPartition = this.Partitions.Where(p => p.FirstSector > OldPartition.FirstSector).OrderBy(p => p.FirstSector).FirstOrDefault();
if (NextPartition != null)
{
MaxPartitionSizeInSectors = NextPartition.FirstSector - OldPartition.FirstSector;
}
if (StreamLengthInSectors > MaxPartitionSizeInSectors)
{
throw new WPinternalsException("Incorrect length for partition \"" + OldPartition.Name + "\". The provided partition in the archive does not match the length specified in the xml file.");
@@ -446,8 +506,9 @@ namespace WPinternals
// Always start a new partition on a new chunk (0x100 sector boundary), to be more flexible during custom flash
if (RoundToChunks && (((double)FirstFreeSector % 0x100) != 0))
{
FirstFreeSector = (UInt64)(Math.Ceiling((double)FirstFreeSector / 0x100) * 0x100);
}
}
foreach (Partition NewPartition in DynamicPartitions)
{
@@ -456,8 +517,8 @@ namespace WPinternals
NewPartition.FirstSector = FirstFreeSector;
HasChanged = true;
}
ZipArchiveEntry Entry = Archive.Entries.Where(e => ((string.Compare(e.Name, NewPartition.Name, true) == 0) || (e.Name.StartsWith(NewPartition.Name + ".", true, System.Globalization.CultureInfo.GetCultureInfo("en-US"))))).FirstOrDefault();
DecompressedStream DecompressedStream = new DecompressedStream(Entry.Open());
ZipArchiveEntry Entry = Archive.Entries.FirstOrDefault(e => ((string.Compare(e.Name, NewPartition.Name, true) == 0) || (e.Name.StartsWith(NewPartition.Name + ".", true, System.Globalization.CultureInfo.GetCultureInfo("en-US")))));
DecompressedStream DecompressedStream = new(Entry.Open());
ulong StreamLengthInSectors = (ulong)Entry.Length / 0x200;
try
{
@@ -475,7 +536,9 @@ namespace WPinternals
// Always start a new partition on a new chunk (0x100 sector boundary), to be more flexible during custom flash
if (RoundToChunks && (((double)FirstFreeSector % 0x100) != 0))
{
FirstFreeSector = (UInt64)(Math.Ceiling((double)FirstFreeSector / 0x100) * 0x100);
}
}
}
@@ -486,31 +549,31 @@ namespace WPinternals
{
string DirPath = System.IO.Path.GetDirectoryName(Path);
if (!Directory.Exists(DirPath))
{
Directory.CreateDirectory(DirPath);
}
XmlSerializer x = new XmlSerializer(typeof(GPT), "");
XmlSerializer x = new(typeof(GPT), "");
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
XmlSerializerNamespaces ns = new();
ns.Add("", "");
System.IO.StreamWriter FileWriter = new System.IO.StreamWriter(Path);
StreamWriter FileWriter = new(Path);
x.Serialize(FileWriter, this, ns);
FileWriter.Close();
}
internal static GPT ReadPartitions(string Path)
{
XmlSerializer x = new XmlSerializer(typeof(GPT), "");
using (FileStream s = new FileStream(Path, FileMode.Open))
{
return (GPT)x.Deserialize(s);
}
XmlSerializer x = new(typeof(GPT), "");
using FileStream s = new(Path, FileMode.Open);
return (GPT)x.Deserialize(s);
}
internal void RestoreBackupPartitions()
{
// This is necessary, because the partitions and backup-partitions can exchange.
// This may cause the startsector to be higher than the maximum allowed sector for flashing with a Lumia V1 programmer (hardcoded in programmer)
List<string> RevisePartitions = new List<string>(new string[] { "SBL1", "SBL2", "SBL3", "UEFI", "TZ", "RPM", "WINSECAPP" });
List<string> RevisePartitions = new(new string[] { "SBL1", "SBL2", "SBL3", "UEFI", "TZ", "RPM", "WINSECAPP" });
foreach (string RevisePartitionName in RevisePartitions)
{
Partition RevisePartition = GetPartition(RevisePartitionName);
@@ -528,9 +591,10 @@ namespace WPinternals
}
if (RevisePartition.LastSector >= 0xF400)
{
throw new WPinternalsException("Unsupported partition layout!", "The last sector of one of the BACKUP partitions defined in GPT exceeds the maximum threshold expected in order to restore BACKUP partitions to the device.");
}
}
}
}
@@ -552,15 +616,21 @@ namespace WPinternals
get
{
if (_SizeInSectors != 0)
{
return _SizeInSectors;
}
else
{
return LastSector - FirstSector + 1;
}
}
set
{
_SizeInSectors = value;
if (FirstSector != 0)
{
LastSector = FirstSector + _SizeInSectors - 1;
}
}
}
@@ -575,7 +645,9 @@ namespace WPinternals
{
_FirstSector = value;
if (_SizeInSectors != 0)
{
_LastSector = FirstSector + _SizeInSectors - 1;
}
}
}