diff --git a/CommandLine.cs b/CommandLine.cs index b4b8176..9d39dcc 100644 --- a/CommandLine.cs +++ b/CommandLine.cs @@ -670,7 +670,7 @@ namespace WPinternals Info = FlashModel.ReadPhoneInfo(); Info.Log(LogType.ConsoleOnly); LogFile.Log("Flashing FFU...", LogType.FileAndConsole); - await Task.Run(() => FlashModel.FlashFFU(new FFU(FFUPath), true, (byte)((Info.RdcPresent || !Info.SecureFfuEnabled || Info.Authenticated) ? FlashOptions.SkipSignatureCheck : 0))); + await Task.Run(() => FlashModel.FlashFFU(new FFU(FFUPath), true, (byte)(!Info.IsBootloaderSecure ? FlashOptions.SkipSignatureCheck : 0))); LogFile.Log("FFU flashed successfully", LogType.FileAndConsole); Notifier.Stop(); } @@ -1608,6 +1608,24 @@ namespace WPinternals throw new WPinternalsException("Unable to find compatible FFU", "No donor-FFU has been found in the repository with a supported OS version. You can add a donor-FFU within the download section of the tool or by using the command line. A donor-FFU can be for a different device and a different CPU than your device. It is only used to gather Operating System specific binaries to be patched and used as part of the unlock process."); } break; + case "rewritepartitionsfrommassstorage": + if (args.Length < 2) + throw new ArgumentException("Wrong number of arguments. Usage: WPinternals.exe -RewritePartitionsFromMassStorage \n The name of the imgs must be the partition names. For example, DPP.img will get written to the DPP partition."); + + await TestCode.RewriteParts(args[2]); + break; + case "restoregptusingedl": + if (args.Length < 3) + throw new ArgumentException("Wrong number of arguments. Usage: WPinternals.exe -RestoreGPTUsingEDL "); + + await TestCode.RecoverBadGPT(args[2], args[3]); + break; + case "restoregptusingmassstorage": + if (args.Length < 2) + throw new ArgumentException("Wrong number of arguments. Usage: WPinternals.exe -RestoreGPTUsingMassStorage "); + + await TestCode.RewriteGPT(args[2]); + break; default: LogFile.Log("", LogType.ConsoleOnly); LogFile.Log("WPinternals commandline usage:", LogType.ConsoleOnly); @@ -1671,6 +1689,9 @@ namespace WPinternals LogFile.Log(" ", LogType.ConsoleOnly); LogFile.Log("WPinternals -DumpUEFI ", LogType.ConsoleOnly); LogFile.Log("WPinternals -TestProgrammer ", LogType.ConsoleOnly); + LogFile.Log("WPinternals -RewritePartitionsFromMassStorage ", LogType.ConsoleOnly); + LogFile.Log("WPinternals -RestoreGPTUsingEDL ", LogType.ConsoleOnly); + LogFile.Log("WPinternals -RestoreGPTUsingMassStorage ", LogType.ConsoleOnly); break; } } diff --git a/Models/NokiaFlashModel.cs b/Models/NokiaFlashModel.cs index 108d8a2..04a77b0 100644 --- a/Models/NokiaFlashModel.cs +++ b/Models/NokiaFlashModel.cs @@ -620,7 +620,7 @@ namespace WPinternals PhoneInfo Info = ReadPhoneInfo(ExtendedInfo: false); FlashAppType OriginalAppType = Info.App; - bool Switch = ((Info.App != FlashAppType.BootManager) && Info.SecureFfuEnabled && !Info.Authenticated && !Info.RdcPresent); + bool Switch = ((Info.App != FlashAppType.BootManager) && Info.IsBootloaderSecure); if (Switch) SwitchToBootManagerContext(); @@ -943,6 +943,8 @@ namespace WPinternals Result.State = PhoneInfoState.Extended; } + Result.IsBootloaderSecure = !(Info.Authenticated || Info.RdcPresent || !Info.SecureFfuEnabled); + if (!PhoneInfoLogged) Result.Log(LogType.FileOnly); @@ -1193,6 +1195,8 @@ namespace WPinternals public bool UefiSecureBootEnabled; public bool SecondaryHardwareKeyPresent; + public bool IsBootloaderSecure; + internal void Log(LogType Type) { if (State == PhoneInfoState.Extended) @@ -1227,12 +1231,12 @@ namespace WPinternals break; } - LogFile.Log("SecureBoot: " + ((!PlatformSecureBootEnabled || !UefiSecureBootEnabled) ? "Disabled" : "Enabled"), Type); + 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: " + ((!SecureFfuEnabled || RdcPresent || Authenticated) ? "Disabled" : "Enabled"), LogType.ConsoleOnly); + LogFile.Log("Flash app security: " + (!IsBootloaderSecure ? "Disabled" : "Enabled"), LogType.ConsoleOnly); if ((Type == LogType.FileOnly) || (Type == LogType.FileAndConsole)) - LogFile.Log("Flash app security: " + ((!SecureFfuEnabled || RdcPresent || Authenticated) ? "Disabled" : "Enabled") + " (FFU security: " + (SecureFfuEnabled ? "Enabled" : "Disabled") + ", RDC: " + (RdcPresent ? "Present" : "Not found") + ", Authenticated: " + (Authenticated ? "True" : "False") + ")", LogType.FileOnly); + 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); } diff --git a/TestCode.cs b/TestCode.cs index b5d3cb5..a11c31f 100644 --- a/TestCode.cs +++ b/TestCode.cs @@ -19,6 +19,9 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; using System.Threading.Tasks; namespace WPinternals @@ -36,6 +39,204 @@ namespace WPinternals // MassStorage MassStorage = (MassStorage)Notifier.CurrentModel; } + internal static async Task RecoverBadGPT(string GPTPath, string LoadersPath) + { + byte[] GPT = File.ReadAllBytes(GPTPath); + + PhoneNotifierViewModel PhoneNotifier = new PhoneNotifierViewModel(); + PhoneNotifier.Start(); + await SwitchModeViewModel.SwitchTo(PhoneNotifier, PhoneInterfaces.Qualcomm_Download); + + byte[] RootKeyHash = null; + if (PhoneNotifier.CurrentInterface == PhoneInterfaces.Qualcomm_Download) + { + QualcommDownload Download2 = new QualcommDownload((QualcommSerial)PhoneNotifier.CurrentModel); + RootKeyHash = Download2.GetRKH(); + } + + List PossibleLoaders = null; + if (PhoneNotifier.CurrentInterface == PhoneInterfaces.Qualcomm_Download) + { + try + { + PossibleLoaders = QualcommLoaders.GetPossibleLoadersForRootKeyHash(LoadersPath, RootKeyHash); + if (PossibleLoaders.Count == 0) + { + throw new Exception("Error: No matching loaders found for RootKeyHash."); + } + } + catch (Exception Ex) + { + LogFile.LogException(Ex); + throw new Exception("Error: Unexpected error during scanning for loaders."); + } + } + + QualcommSerial Serial = (QualcommSerial)PhoneNotifier.CurrentModel; + QualcommDownload Download = new QualcommDownload(Serial); + if (Download.IsAlive()) + { + int Attempt = 1; + bool Result = false; + foreach (QualcommPartition Loader in PossibleLoaders) + { + LogFile.Log("Attempt " + Attempt.ToString(), LogType.ConsoleOnly); + + try + { + Download.SendToPhoneMemory(0x2A000000, Loader.Binary); + Download.StartBootloader(0x2A000000); + Result = true; + LogFile.Log("Loader sent successfully", LogType.ConsoleOnly); + } + catch { } + + if (Result) + break; + + Attempt++; + } + Serial.Close(); + + if (!Result) + LogFile.Log("Loader failed", LogType.ConsoleOnly); + } + else + { + LogFile.Log("Failed to communicate to Qualcomm Emergency Download mode", LogType.ConsoleOnly); + throw new BadConnectionException(); + } + + if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Qualcomm_Flash) + await PhoneNotifier.WaitForArrival(); + if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Qualcomm_Flash) + throw new WPinternalsException("Phone failed to switch to emergency flash mode."); + + // Flash bootloader + QualcommSerial Serial2 = (QualcommSerial)PhoneNotifier.CurrentModel; + Serial2.EncodeCommands = false; + + QualcommFlasher Flasher = new QualcommFlasher(Serial2); + + Flasher.Hello(); + Flasher.SetSecurityMode(0); + Flasher.OpenPartition(0x21); + + LogFile.Log("Partition opened.", LogType.ConsoleOnly); + + LogFile.Log("Flash GPT at 0x" + ((UInt32)0x200).ToString("X8"), LogType.ConsoleOnly); + Flasher.Flash(0x200, GPT, 0, 0x41FF); // Bad bounds-check in the flash-loader prohibits to write the last byte. + + Flasher.ClosePartition(); + + LogFile.Log("Partition closed. Flashing ready. Rebooting."); + + Flasher.Reboot(); + + Flasher.CloseSerial(); + } + + internal static async Task RewriteGPT(string GPTPath) + { + PhoneNotifierViewModel Notifier = new PhoneNotifierViewModel(); + Notifier.Start(); + await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_MassStorage); + MassStorage MassStorage = (MassStorage)Notifier.CurrentModel; + + LogFile.Log("Writing GPT to the device.", LogType.ConsoleOnly); + MassStorage.WriteSectors(1, GPTPath); + } + + internal static async Task RewriteMBRGPT() + { + FFU FFU = new FFU(@"E:\Device Backups\Alpha\9200_1230.0025.9200.9825\RX100_9825.ffu"); + string GPTPath = @"E:\Device Backups\Alpha\9200_1230.0025.9200.9825\CorrectGPT.bin"; + + PhoneNotifierViewModel Notifier = new PhoneNotifierViewModel(); + Notifier.Start(); + await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_MassStorage); + MassStorage MassStorage = (MassStorage)Notifier.CurrentModel; + + byte[] MBR = FFU.GetSectors(0, 1); + LogFile.Log("Writing MBR to the device.", LogType.ConsoleOnly); + MassStorage.WriteSectors(0, MBR); + + LogFile.Log("Writing GPT to the device.", LogType.ConsoleOnly); + MassStorage.WriteSectors(1, GPTPath); + } + + internal static async Task RewriteParts(string PartPath) + { + PhoneNotifierViewModel Notifier = new PhoneNotifierViewModel(); + Notifier.Start(); + await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_MassStorage); + MassStorage MassStorage = (MassStorage)Notifier.CurrentModel; + + foreach (var part in Directory.EnumerateFiles(PartPath)) + { + var partname = part.Split('\\').Last().Replace(".img", ""); + try + { + LogFile.Log($"Writing {partname} to the device.", LogType.ConsoleOnly); + + LogFile.Log("", LogType.ConsoleOnly); + + MassStorage.RestorePartition(part, partname, (v, t) => + { + LogFile.Log("Progress: " + v + "%", LogType.ConsoleOnly); + }); + LogFile.Log("", LogType.ConsoleOnly); + } + catch + { + LogFile.Log("", LogType.ConsoleOnly); + LogFile.Log($"Failed writing {partname} to the device.", LogType.ConsoleOnly); + }; + } + } + + internal static void PatchImg(string dump) + { + using (var fil = File.Open(dump, FileMode.Open)) + { + byte[] gptbuffer = new byte[0x4200]; + + fil.Seek(0x200, SeekOrigin.Begin); + fil.Read(gptbuffer, 0, 0x4200); + + uint BackupLBA = ByteOperations.ReadUInt32(gptbuffer, 0x20); + uint LastUsableLBA = ByteOperations.ReadUInt32(gptbuffer, 0x30); + + LogFile.Log("Previous BackupLBA: " + BackupLBA, LogType.ConsoleOnly); + LogFile.Log("Previous LastUsableLBA: " + LastUsableLBA, LogType.ConsoleOnly); + + uint NewBackupLBA = 62078975u; + uint NewLastUsableLBA = 62078942u; + + ByteOperations.WriteUInt32(gptbuffer, 0x20, NewBackupLBA); + ByteOperations.WriteUInt32(gptbuffer, 0x30, NewLastUsableLBA); + + uint HeaderSize = ByteOperations.ReadUInt32(gptbuffer, 0x0C); + uint PrevCRC = ByteOperations.ReadUInt32(gptbuffer, 0x10); + + LogFile.Log("Previous CRC: " + PrevCRC, LogType.ConsoleOnly); + + ByteOperations.WriteUInt32(gptbuffer, 0x10, 0); + uint NewCRC = ByteOperations.CRC32(gptbuffer, 0, HeaderSize); + + LogFile.Log("New CRC: " + NewCRC, LogType.ConsoleOnly); + + ByteOperations.WriteUInt32(gptbuffer, 0x10, NewCRC); + + LogFile.Log("Writing", LogType.ConsoleOnly); + + fil.Seek(0x200, SeekOrigin.Begin); + fil.Write(gptbuffer, 0, 0x4200); + + LogFile.Log("Done!", LogType.ConsoleOnly); + } + } + internal static async Task TestProgrammer(System.Threading.SynchronizationContext UIContext, string ProgrammerPath) { LogFile.BeginAction("TestProgrammer"); diff --git a/ViewModels/LumiaFlashRomViewModel.cs b/ViewModels/LumiaFlashRomViewModel.cs index 3899969..d6484f6 100644 --- a/ViewModels/LumiaFlashRomViewModel.cs +++ b/ViewModels/LumiaFlashRomViewModel.cs @@ -527,6 +527,8 @@ namespace WPinternals FlashParts.Add(Part); } + bool ClearFlashingStatus = true; + // We should only clear NV if there was no backup NV to be restored and the current NV contains the SB unlock. if ((NvBackupPartition == null) && !Info.UefiSecureBootEnabled) { @@ -536,13 +538,15 @@ namespace WPinternals Part.StartSector = (UInt32)Target.FirstSector; Part.Stream = new MemoryStream(new byte[0x40000]); FlashParts.Add(Part); + + ClearFlashingStatus = false; } if (FlashParts.Count > 0) { ActivateSubContext(new BusyViewModel("Restoring bootloader...")); WPinternalsStatus LastStatus = WPinternalsStatus.Undefined; - LumiaV2UnlockBootViewModel.LumiaV2CustomFlash(PhoneNotifier, FFUPath, false, false, FlashParts, true, ClearFlashingStatusAtEnd: false, + LumiaV2UnlockBootViewModel.LumiaV2CustomFlash(PhoneNotifier, FFUPath, false, false, FlashParts, true, ClearFlashingStatusAtEnd: ClearFlashingStatus, SetWorkingStatus: (m, s, v, a, st) => { if ((st == WPinternalsStatus.Scanning) || (st == WPinternalsStatus.WaitingForManualReset)) @@ -583,7 +587,7 @@ namespace WPinternals BusyViewModel Busy = new BusyViewModel("Flashing original FFU...", MaxProgressValue: FFU.TotalChunkCount, UIContext: UIContext); ActivateSubContext(Busy); byte Options = 0; - if (!Info.SecureFfuEnabled || Info.Authenticated || Info.RdcPresent) + if (!Info.IsBootloaderSecure) Options = (byte)((FlashOptions)Options | FlashOptions.SkipSignatureCheck); Phone.FlashFFU(FFU, Busy.ProgressUpdater, true, Options); } diff --git a/ViewModels/LumiaUnlockBootViewModel.cs b/ViewModels/LumiaUnlockBootViewModel.cs index 1bda8ab..4a92792 100644 --- a/ViewModels/LumiaUnlockBootViewModel.cs +++ b/ViewModels/LumiaUnlockBootViewModel.cs @@ -141,7 +141,7 @@ namespace WPinternals PhoneInfo Info = ((NokiaFlashModel)PhoneNotifier.CurrentModel).ReadPhoneInfo(); if (SecurityStatus == null) - IsBootLoaderUnlocked = (Info.Authenticated || Info.RdcPresent || !Info.SecureFfuEnabled); + IsBootLoaderUnlocked = !Info.IsBootloaderSecure; if (RootKeyHash == null) { @@ -210,8 +210,6 @@ namespace WPinternals GPT GPT = FlashModel.ReadGPT(); if ((GPT.GetPartition("IS_UNLOCKED") != null) || (GPT.GetPartition("BACKUP_EFIESP") != null)) { - //ExitMessage("Phone is already unlocked", null); - //return; AlreadyUnlocked = true; } } diff --git a/ViewModels/LumiaUnlockBootloaderViewModel.cs b/ViewModels/LumiaUnlockBootloaderViewModel.cs index 51c6851..ec787e4 100644 --- a/ViewModels/LumiaUnlockBootloaderViewModel.cs +++ b/ViewModels/LumiaUnlockBootloaderViewModel.cs @@ -104,33 +104,42 @@ namespace WPinternals if (ExitSuccess == null) ExitSuccess = (m, s) => { }; if (ExitFailure == null) ExitFailure = (m, s) => { }; - await LumiaUnlockBootloaderViewModel.LumiaRelockUEFI(Notifier, FFUPath, DoResetFirst, SetWorkingStatus, UpdateWorkingStatus, ExitSuccess, ExitFailure); - - SetWorkingStatus("Booting phone..."); - await Notifier.WaitForArrival(); - - if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) - ((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot(); - - if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal) - await Notifier.WaitForArrival(); - - if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) - ((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot(); - - if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal) - await Notifier.WaitForArrival(); - - if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) - ((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot(); - - if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal) + ExitFailure tmpExitFailure = (m, s) => { - ExitFailure("Failed to relock phone", "Your phone is half relocked. You may need to reflash a stock ROM"); - return; - } + ExitFailure(m, s); + }; + + ExitSuccess tmpExitSuccess = async (m, s) => + { + SetWorkingStatus("Booting phone..."); + await Notifier.WaitForArrival(); + + if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) + ((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot(); + + if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal) + await Notifier.WaitForArrival(); + + if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) + ((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot(); + + if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal) + await Notifier.WaitForArrival(); + + if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) + ((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot(); + + if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal) + { + ExitFailure("Failed to relock phone", "Your phone is half relocked. You may need to reflash a stock ROM"); + return; + } + + ExitSuccess("Bootloader restored successfully!"); + }; + + await LumiaUnlockBootloaderViewModel.LumiaRelockUEFI(Notifier, FFUPath, DoResetFirst, SetWorkingStatus, UpdateWorkingStatus, tmpExitSuccess, tmpExitFailure); - ExitSuccess("Bootloader restored successfully!"); } internal static async Task LumiaV2UnlockUEFI(PhoneNotifierViewModel Notifier, string ProfileFFUPath, string EDEPath, string SupportedFFUPath, SetWorkingStatus SetWorkingStatus = null, UpdateWorkingStatus UpdateWorkingStatus = null, ExitSuccess ExitSuccess = null, ExitFailure ExitFailure = null, bool ReUnlockDevice = false) @@ -140,33 +149,42 @@ namespace WPinternals if (ExitSuccess == null) ExitSuccess = (m, s) => { }; if (ExitFailure == null) ExitFailure = (m, s) => { }; - await LumiaUnlockBootloaderViewModel.LumiaUnlockUEFI(Notifier, ProfileFFUPath, EDEPath, SupportedFFUPath, SetWorkingStatus, UpdateWorkingStatus, ExitSuccess, ExitFailure, ReUnlockDevice: ReUnlockDevice); - - SetWorkingStatus("Booting phone..."); - await Notifier.WaitForArrival(); - - if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) - ((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot(); - - if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal) - await Notifier.WaitForArrival(); - - if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) - ((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot(); - - if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal) - await Notifier.WaitForArrival(); - - if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) - ((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot(); - - if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal) + ExitFailure tmpExitFailure = (m, s) => { - ExitFailure("Failed to unlock phone", "Your phone is half unlocked. You may need to reflash a stock ROM"); - return; - } + ExitFailure(m, s); + }; + + ExitSuccess tmpExitSuccess = async (m, s) => + { + SetWorkingStatus("Booting phone..."); + await Notifier.WaitForArrival(); + + if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) + ((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot(); + + if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal) + await Notifier.WaitForArrival(); + + if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) + ((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot(); + + if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal) + await Notifier.WaitForArrival(); + + if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) + ((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot(); + + if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal) + { + ExitFailure("Failed to unlock phone", "Your phone is half unlocked. You may need to reflash a stock ROM"); + return; + } + + ExitSuccess("Bootloader unlocked successfully!", null); + }; + + await LumiaUnlockBootloaderViewModel.LumiaUnlockUEFI(Notifier, ProfileFFUPath, EDEPath, SupportedFFUPath, SetWorkingStatus, UpdateWorkingStatus, tmpExitSuccess, tmpExitFailure, ReUnlockDevice: ReUnlockDevice); - ExitSuccess("Bootloader unlocked successfully!", null); } // Magic! @@ -1278,7 +1296,7 @@ namespace WPinternals PhoneInfo Info = FlashModel.ReadPhoneInfo(ExtendedInfo: false); FlashAppType OriginalAppType = Info.App; - bool Switch = ((Info.App != FlashAppType.BootManager) && Info.SecureFfuEnabled && !Info.Authenticated && !Info.RdcPresent); + bool Switch = ((Info.App != FlashAppType.BootManager) && Info.IsBootloaderSecure); if (Switch) FlashModel.SwitchToBootManagerContext(); @@ -1608,15 +1626,14 @@ namespace WPinternals } LogFile.Log("Phone is relocked", LogType.FileAndConsole); + LogFile.EndAction("RelockPhone"); + ExitSuccess("Phone is relocked", null); } catch (Exception Ex) { LogFile.LogException(Ex); - ExitFailure("Error: " + Ex.Message, null); - } - finally - { LogFile.EndAction("RelockPhone"); + ExitFailure("Error: " + Ex.Message, null); } } @@ -1640,14 +1657,12 @@ namespace WPinternals PhoneInfo Info = FlashModel.ReadPhoneInfo(); bool IsSpecB = Info.FlashAppProtocolVersionMajor >= 2; - bool IsBootLoaderSecure = !Info.Authenticated && !Info.RdcPresent && Info.SecureFfuEnabled; - if (ProfileFFUPath == null) throw new ArgumentNullException("Profile FFU path is missing"); FFU ProfileFFU = new FFU(ProfileFFUPath); - if (IsBootLoaderSecure) + if (Info.IsBootloaderSecure) { if (!Info.PlatformID.StartsWith(ProfileFFU.PlatformID, StringComparison.OrdinalIgnoreCase)) throw new ArgumentNullException("Profile FFU has wrong Platform ID for connected phone"); @@ -1677,13 +1692,91 @@ namespace WPinternals LumiaUnlockBootloaderViewModel.LumiaPatchEFIESP(SupportedFFU, UnlockedEFIESP, IsSpecB); - // Create backup-partition for EFIESP byte[] GPTChunk = GetGptChunk(FlashModel, (UInt32)ProfileFFU.ChunkSize); byte[] GPTChunkBackup = new byte[GPTChunk.Length]; Buffer.BlockCopy(GPTChunk, 0, GPTChunkBackup, 0, GPTChunk.Length); GPT GPT = new GPT(GPTChunk); bool GPTChanged = false; + LogFile.Log("Enabling Test Signing", LogType.FileAndConsole); + SetWorkingStatus("Enabling Test Signing", null, null); + + List Parts = new List(); + FlashPart Part; + + // Now add NV partition + Partition BACKUP_BS_NV = GPT.GetPartition("BACKUP_BS_NV"); + Partition UEFI_BS_NV; + if (BACKUP_BS_NV == null) + { + BACKUP_BS_NV = GPT.GetPartition("UEFI_BS_NV"); + Guid OriginalPartitionTypeGuid = BACKUP_BS_NV.PartitionTypeGuid; + Guid OriginalPartitionGuid = BACKUP_BS_NV.PartitionGuid; + BACKUP_BS_NV.Name = "BACKUP_BS_NV"; + BACKUP_BS_NV.PartitionGuid = Guid.NewGuid(); + BACKUP_BS_NV.PartitionTypeGuid = Guid.NewGuid(); + UEFI_BS_NV = new Partition(); + UEFI_BS_NV.Name = "UEFI_BS_NV"; + UEFI_BS_NV.Attributes = BACKUP_BS_NV.Attributes; + UEFI_BS_NV.PartitionGuid = OriginalPartitionGuid; + UEFI_BS_NV.PartitionTypeGuid = OriginalPartitionTypeGuid; + UEFI_BS_NV.FirstSector = BACKUP_BS_NV.LastSector + 1; + UEFI_BS_NV.LastSector = UEFI_BS_NV.FirstSector + BACKUP_BS_NV.LastSector - BACKUP_BS_NV.FirstSector; + GPT.Partitions.Add(UEFI_BS_NV); + GPTChanged = true; + } + Part = new FlashPart(); + Partition TargetPartition = GPT.GetPartition("UEFI_BS_NV"); + Part.StartSector = (UInt32)TargetPartition.FirstSector; // GPT is prepared for 64-bit sector-offset, but flash app isn't. + string SBRes = IsSpecB ? "WPinternals.SB" : "WPinternals.SBA"; + Part.Stream = new SeekableStream(() => + { + var assembly = System.Reflection.Assembly.GetExecutingAssembly(); + + // Magic! + // The SB(A) resource is a compressed version of a raw NV-variable-partition. + // In this partition the SecureBoot variable is disabled. + // It overwrites the variable in a different NV-partition than where this variable is stored usually. + // This normally leads to endless-loops when the NV-variables are enumerated. + // But the partition contains an extra hack to break out the endless loops. + var stream = assembly.GetManifestResourceStream(SBRes); + + return new DecompressedStream(stream); + }); + Parts.Add(Part); + + if (GPTChanged) + { + GPT.Rebuild(); + Part = new FlashPart(); + Part.StartSector = 0; + Part.Stream = new MemoryStream(GPTChunk); + Parts.Add(Part); + } + + foreach (FlashPart _part in Parts) + { + _part.ProgressText = "Enabling Test Signing..."; + } + + await LumiaUnlockBootloaderViewModel.LumiaFlashParts(Notifier, ProfileFFU.Path, false, false, Parts, true, false, true, true, false, SetWorkingStatus, UpdateWorkingStatus, null, null, EDEPath); + + if ((Notifier.CurrentInterface != PhoneInterfaces.Lumia_Bootloader) && (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)) + await Notifier.WaitForArrival(); + + if ((Notifier.CurrentInterface != PhoneInterfaces.Lumia_Bootloader) && (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)) + throw new WPinternalsException("Error: Phone is in wrong mode", "The phone should have been detected in bootloader or flash mode. Instead it has been detected in " + Notifier.CurrentInterface.ToString() + " mode."); + + if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) + { + FlashModel = (NokiaFlashModel)Notifier.CurrentModel; + FlashModel.SwitchToFlashAppContext(); + } + + GPTChanged = false; + + // Create backup-partition for EFIESP + bool SBL3Eng = GPT.GetPartition("IS_UNLOCKED_SBL3") != null; bool ShouldApplyOldEFIESPMethod = true; @@ -1695,8 +1788,8 @@ namespace WPinternals if (!IsSpecB && !SBL3Eng) ShouldApplyOldEFIESPMethod = false; - List Parts = ShouldApplyOldEFIESPMethod ? new List() : LumiaUnlockBootloaderViewModel.LumiaGenerateEFIESPFlashPayload(UnlockedEFIESP, GPT, ProfileFFU, IsSpecB); - FlashPart Part; + Parts = ShouldApplyOldEFIESPMethod ? new List() : LumiaUnlockBootloaderViewModel.LumiaGenerateEFIESPFlashPayload(UnlockedEFIESP, GPT, ProfileFFU, IsSpecB); + Part = null; UInt32 OriginalEfiespSizeInSectors = (UInt32)GPT.GetPartition("EFIESP").SizeInSectors; UInt32 OriginalEfiespLastSector = (UInt32)GPT.GetPartition("EFIESP").LastSector; @@ -1805,52 +1898,6 @@ namespace WPinternals Parts.Add(Part); } - if (IsSpecB) - Parts[0].ProgressText = "Flashing unlocked bootloader (part 1)..."; - else - Parts[0].ProgressText = "Flashing unlocked bootloader (part 2)..."; - - // Now add NV partition - Partition BACKUP_BS_NV = GPT.GetPartition("BACKUP_BS_NV"); - Partition UEFI_BS_NV; - if (BACKUP_BS_NV == null) - { - BACKUP_BS_NV = GPT.GetPartition("UEFI_BS_NV"); - Guid OriginalPartitionTypeGuid = BACKUP_BS_NV.PartitionTypeGuid; - Guid OriginalPartitionGuid = BACKUP_BS_NV.PartitionGuid; - BACKUP_BS_NV.Name = "BACKUP_BS_NV"; - BACKUP_BS_NV.PartitionGuid = Guid.NewGuid(); - BACKUP_BS_NV.PartitionTypeGuid = Guid.NewGuid(); - UEFI_BS_NV = new Partition(); - UEFI_BS_NV.Name = "UEFI_BS_NV"; - UEFI_BS_NV.Attributes = BACKUP_BS_NV.Attributes; - UEFI_BS_NV.PartitionGuid = OriginalPartitionGuid; - UEFI_BS_NV.PartitionTypeGuid = OriginalPartitionTypeGuid; - UEFI_BS_NV.FirstSector = BACKUP_BS_NV.LastSector + 1; - UEFI_BS_NV.LastSector = UEFI_BS_NV.FirstSector + BACKUP_BS_NV.LastSector - BACKUP_BS_NV.FirstSector; - GPT.Partitions.Add(UEFI_BS_NV); - GPTChanged = true; - } - Part = new FlashPart(); - Partition TargetPartition = GPT.GetPartition("UEFI_BS_NV"); - Part.StartSector = (UInt32)TargetPartition.FirstSector; // GPT is prepared for 64-bit sector-offset, but flash app isn't. - string SBRes = IsSpecB ? "WPinternals.SB" : "WPinternals.SBA"; - Part.Stream = new SeekableStream(() => - { - var assembly = System.Reflection.Assembly.GetExecutingAssembly(); - - // Magic! - // The SB(A) resource is a compressed version of a raw NV-variable-partition. - // In this partition the SecureBoot variable is disabled. - // It overwrites the variable in a different NV-partition than where this variable is stored usually. - // This normally leads to endless-loops when the NV-variables are enumerated. - // But the partition contains an extra hack to break out the endless loops. - var stream = assembly.GetManifestResourceStream(SBRes); - - return new DecompressedStream(stream); - }); - Parts.Add(Part); - if (GPTChanged) { GPT.Rebuild(); @@ -1860,7 +1907,19 @@ namespace WPinternals Parts.Add(Part); } - await LumiaUnlockBootloaderViewModel.LumiaFlashParts(Notifier, ProfileFFU.Path, false, false, Parts, true, false, true, true, false, SetWorkingStatus, UpdateWorkingStatus, null, null, EDEPath); + foreach (FlashPart _part in Parts) + { + if (IsSpecB) + { + _part.ProgressText = "Flashing unlocked bootloader (part 1)..."; + } + else + { + _part.ProgressText = "Flashing unlocked bootloader (part 2)..."; + } + } + + await LumiaUnlockBootloaderViewModel.LumiaFlashParts(Notifier, ProfileFFU.Path, false, false, Parts, true, true, true, true, false, SetWorkingStatus, UpdateWorkingStatus, null, null, EDEPath); if ((Notifier.CurrentInterface != PhoneInterfaces.Lumia_Bootloader) && (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)) await Notifier.WaitForArrival(); @@ -1969,7 +2028,7 @@ namespace WPinternals // Copy the backed up unlocked EFIESP for future use BackupUnlockedEFIESP = new byte[UnlockedEFIESP.Length]; - Buffer.BlockCopy(BackupEFIESP, 0, BackupUnlockedEFIESP, 0, BackupEFIESP.Length); + Buffer.BlockCopy(BackupEFIESP, 0, BackupUnlockedEFIESP, 0, UnlockedEFIESP.Length); LumiaUnlockBootloaderViewModel.LumiaPatchEFIESP(SupportedFFU, BackupUnlockedEFIESP, IsSpecB); } @@ -2083,7 +2142,6 @@ namespace WPinternals Part = new FlashPart(); Part.StartSector = 0; Part.Stream = new MemoryStream(GPTChunk); - Part.ProgressText = "Flashing unlocked bootloader (part 2)..."; Parts.Add(Part); Part = new FlashPart(); Part.StartSector = OriginalEfiespFirstSector; @@ -2094,6 +2152,11 @@ namespace WPinternals Part.Stream = new MemoryStream(BackupEFIESP); Parts.Add(Part); + foreach (FlashPart _part in Parts) + { + _part.ProgressText = "Flashing unlocked bootloader (part 2)..."; + } + await LumiaUnlockBootloaderViewModel.LumiaFlashParts(Notifier, ProfileFFU.Path, false, false, Parts, true, true, true, true, false, SetWorkingStatus, UpdateWorkingStatus, null, null, EDEPath); } else @@ -2146,10 +2209,17 @@ namespace WPinternals Parts = LumiaUnlockBootloaderViewModel.LumiaGenerateEFIESPFlashPayload(UnlockedEFIESP, GPT, ProfileFFU, IsSpecB); - if (IsSpecB) - Parts[0].ProgressText = "Flashing unlocked bootloader (part 2)..."; - else - Parts[0].ProgressText = "Flashing unlocked bootloader (part 3)..."; + foreach (FlashPart _part in Parts) + { + if (IsSpecB) + { + _part.ProgressText = "Flashing unlocked bootloader (part 2)..."; + } + else + { + _part.ProgressText = "Flashing unlocked bootloader (part 3)..."; + } + } await LumiaUnlockBootloaderViewModel.LumiaFlashParts(Notifier, ProfileFFU.Path, false, false, Parts, true, true, true, true, false, SetWorkingStatus, UpdateWorkingStatus, null, null, EDEPath); @@ -2157,14 +2227,22 @@ namespace WPinternals ((NokiaFlashModel)Notifier.CurrentModel).ResetPhone(); } + if ((Notifier.CurrentInterface != PhoneInterfaces.Lumia_Bootloader) && (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)) + await Notifier.WaitForArrival(); + + if ((Notifier.CurrentInterface != PhoneInterfaces.Lumia_Bootloader) && (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)) + throw new WPinternalsException("Error: Phone is in wrong mode", "The phone should have been detected in bootloader or flash mode. Instead it has been detected in " + Notifier.CurrentInterface.ToString() + " mode."); + LogFile.Log("Bootloader unlocked!", LogType.FileAndConsole); + LogFile.EndAction("UnlockBootloader"); + ExitSuccess("Bootloader unlocked!", null); } catch (Exception Ex) { LogFile.LogException(Ex); + LogFile.EndAction("UnlockBootloader"); ExitFailure(Ex.Message, Ex is WPinternalsException ? ((WPinternalsException)Ex).SubMessage : null); } - LogFile.EndAction("UnlockBootloader"); } // Magic! diff --git a/ViewModels/LumiaV2UnlockBootViewModel.cs b/ViewModels/LumiaV2UnlockBootViewModel.cs index 491bb46..c8c45d4 100644 --- a/ViewModels/LumiaV2UnlockBootViewModel.cs +++ b/ViewModels/LumiaV2UnlockBootViewModel.cs @@ -72,7 +72,7 @@ namespace WPinternals SetWorkingStatus("Scanning for flashing-profile", "Your phone may appear to be in a reboot-loop. This is expected behavior. Don't interfere this process.", null, Status: WPinternalsStatus.Scanning); - await LumiaV2CustomFlash(Notifier, FFUPath, false, !Info.SecureFfuEnabled || Info.RdcPresent || Info.Authenticated, null, DoResetFirst, Experimental: Experimental, SetWorkingStatus: + await LumiaV2CustomFlash(Notifier, FFUPath, false, !Info.IsBootloaderSecure, null, DoResetFirst, Experimental: Experimental, SetWorkingStatus: (m, s, v, a, st) => { if (st == WPinternalsStatus.SwitchingMode) @@ -440,8 +440,47 @@ namespace WPinternals await LumiaV2CustomFlash(Notifier, FFUPath, PerformFullFlashFirst, SkipWrite, Parts, DoResetFirst, ClearFlashingStatusAtEnd, CheckSectorAlignment, ShowProgress, Experimental); } + internal async static Task LumiaV2CustomFlash(PhoneNotifierViewModel Notifier, string FFUPath, bool PerformFullFlashFirst, bool SkipWrite, List FlashParts, bool DoResetFirst = true, bool ClearFlashingStatusAtEnd = true, bool CheckSectorAlignment = true, bool ShowProgress = true, bool Experimental = false, SetWorkingStatus SetWorkingStatus = null, UpdateWorkingStatus UpdateWorkingStatus = null, ExitSuccess ExitSuccess = null, ExitFailure ExitFailure = null, string ProgrammerPath = null) + { + NokiaFlashModel Model = (NokiaFlashModel)Notifier.CurrentModel; + PhoneInfo Info = Model.ReadPhoneInfo(); + + + byte[] GPTChunk = LumiaUnlockBootloaderViewModel.GetGptChunk(Model, 131072u); + + GPT GPT = new GPT(GPTChunk); + + Partition UefiBSNV = GPT.GetPartition("UEFI_BS_NV"); + + bool UseOlderExploit = Info.UefiSecureBootEnabled; + + if (!UseOlderExploit && ClearFlashingStatusAtEnd) + { + if (FlashParts == null) + { + UseOlderExploit = true; + } + else + { + foreach (var part in FlashParts) + { + if (part.StartSector >= UefiBSNV.FirstSector && part.StartSector <= UefiBSNV.LastSector) + { + UseOlderExploit = true; + break; + } + } + } + } + + if (UseOlderExploit || !ClearFlashingStatusAtEnd) + await LumiaV20CustomFlash(Notifier, FFUPath, PerformFullFlashFirst, SkipWrite, FlashParts, DoResetFirst, ClearFlashingStatusAtEnd, CheckSectorAlignment, ShowProgress, Experimental, SetWorkingStatus, UpdateWorkingStatus, ExitSuccess, ExitFailure, ProgrammerPath); + else + await LumiaV3FlashRomViewModel.LumiaV3CustomFlash(Notifier, FlashParts, CheckSectorAlignment, SetWorkingStatus, UpdateWorkingStatus, ExitSuccess, ExitFailure); + } + // Magic! - internal async static Task LumiaV2CustomFlash(PhoneNotifierViewModel Notifier, string FFUPath, bool PerformFullFlashFirst, bool SkipWrite, List FlashParts, bool DoResetFirst = true, bool ClearFlashingStatusAtEnd = true, bool CheckSectorAlignment = true, bool ShowProgress = true, bool Experimental = false, SetWorkingStatus SetWorkingStatus = null, UpdateWorkingStatus UpdateWorkingStatus = null, ExitSuccess ExitSuccess = null, ExitFailure ExitFailure = null, string ProgrammerPath = null) //, string LoaderPath = null) + internal async static Task LumiaV20CustomFlash(PhoneNotifierViewModel Notifier, string FFUPath, bool PerformFullFlashFirst, bool SkipWrite, List FlashParts, bool DoResetFirst = true, bool ClearFlashingStatusAtEnd = true, bool CheckSectorAlignment = true, bool ShowProgress = true, bool Experimental = false, SetWorkingStatus SetWorkingStatus = null, UpdateWorkingStatus UpdateWorkingStatus = null, ExitSuccess ExitSuccess = null, ExitFailure ExitFailure = null, string ProgrammerPath = null) //, string LoaderPath = null) { // Both SecurityHeader and StoreHeader need to be modified. // Those should both not fall in a memory-gap to allow modification. @@ -528,7 +567,7 @@ namespace WPinternals byte Options = 0; if (SkipWrite) Options = (byte)FlashOptions.SkipWrite; - if (!Info.SecureFfuEnabled || Info.Authenticated || Info.RdcPresent) + if (!Info.IsBootloaderSecure) Options = (byte)((FlashOptions)Options | FlashOptions.SkipSignatureCheck); // Gap fill calculation: @@ -1801,6 +1840,8 @@ namespace WPinternals bool IsUnlocked = false; bool GPTChanged = false; + bool ClearFlashingStatus = true; + if (SetWorkingStatus == null) SetWorkingStatus = (m, s, v, a, st) => { }; if (UpdateWorkingStatus == null) UpdateWorkingStatus = (m, s, v, st) => { }; if (ExitSuccess == null) ExitSuccess = (m, s) => { }; @@ -1896,6 +1937,7 @@ namespace WPinternals IsUnlockedFlag.LastSector = 0x40; GPT.Partitions.Add(IsUnlockedFlag); GPTChanged = true; + ClearFlashingStatus = false; } } else @@ -1905,6 +1947,7 @@ namespace WPinternals { GPT.Partitions.Remove(IsUnlockedFlag); GPTChanged = true; + ClearFlashingStatus = false; } } } @@ -1952,46 +1995,81 @@ namespace WPinternals return; } - // Now add NV partition - Partition BACKUP_BS_NV = GPT.GetPartition("BACKUP_BS_NV"); - Partition UEFI_BS_NV; - if (BACKUP_BS_NV == null) + if (!ClearFlashingStatus) { - BACKUP_BS_NV = GPT.GetPartition("UEFI_BS_NV"); - Guid OriginalPartitionTypeGuid = BACKUP_BS_NV.PartitionTypeGuid; - Guid OriginalPartitionGuid = BACKUP_BS_NV.PartitionGuid; - BACKUP_BS_NV.Name = "BACKUP_BS_NV"; - BACKUP_BS_NV.PartitionGuid = Guid.NewGuid(); - BACKUP_BS_NV.PartitionTypeGuid = Guid.NewGuid(); - UEFI_BS_NV = new Partition(); - UEFI_BS_NV.Name = "UEFI_BS_NV"; - UEFI_BS_NV.Attributes = BACKUP_BS_NV.Attributes; - UEFI_BS_NV.PartitionGuid = OriginalPartitionGuid; - UEFI_BS_NV.PartitionTypeGuid = OriginalPartitionTypeGuid; - UEFI_BS_NV.FirstSector = BACKUP_BS_NV.LastSector + 1; - UEFI_BS_NV.LastSector = UEFI_BS_NV.FirstSector + BACKUP_BS_NV.LastSector - BACKUP_BS_NV.FirstSector; - GPT.Partitions.Add(UEFI_BS_NV); - GPTChanged = true; + if (!IsUnlocked) + { + // Undo secure boot exploit + Partition NvBackupPartition = GPT.GetPartition("BACKUP_BS_NV"); + if (NvBackupPartition != null) + { + // This must be a left over of a half unlocked bootloader + Partition NvPartition = GPT.GetPartition("UEFI_BS_NV"); + NvBackupPartition.Name = "UEFI_BS_NV"; + NvBackupPartition.PartitionGuid = NvPartition.PartitionGuid; + NvBackupPartition.PartitionTypeGuid = NvPartition.PartitionTypeGuid; + GPT.Partitions.Remove(NvPartition); + GPTChanged = true; + } + + PhoneInfo Info = FlashModel.ReadPhoneInfo(false); + + // We should only clear NV if there was no backup NV to be restored and the current NV contains the SB unlock. + if ((NvBackupPartition == null) && !Info.UefiSecureBootEnabled) + { + // ClearNV + Part = new FlashPart(); + Partition Target2 = GPT.GetPartition("UEFI_BS_NV"); + Part.StartSector = (UInt32)Target2.FirstSector; + Part.Stream = new MemoryStream(new byte[0x40000]); + Parts.Add(Part); + } + } + else + { + // Now add NV partition + Partition BACKUP_BS_NV = GPT.GetPartition("BACKUP_BS_NV"); + Partition UEFI_BS_NV; + if (BACKUP_BS_NV == null) + { + BACKUP_BS_NV = GPT.GetPartition("UEFI_BS_NV"); + Guid OriginalPartitionTypeGuid = BACKUP_BS_NV.PartitionTypeGuid; + Guid OriginalPartitionGuid = BACKUP_BS_NV.PartitionGuid; + BACKUP_BS_NV.Name = "BACKUP_BS_NV"; + BACKUP_BS_NV.PartitionGuid = Guid.NewGuid(); + BACKUP_BS_NV.PartitionTypeGuid = Guid.NewGuid(); + UEFI_BS_NV = new Partition(); + UEFI_BS_NV.Name = "UEFI_BS_NV"; + UEFI_BS_NV.Attributes = BACKUP_BS_NV.Attributes; + UEFI_BS_NV.PartitionGuid = OriginalPartitionGuid; + UEFI_BS_NV.PartitionTypeGuid = OriginalPartitionTypeGuid; + UEFI_BS_NV.FirstSector = BACKUP_BS_NV.LastSector + 1; + UEFI_BS_NV.LastSector = UEFI_BS_NV.FirstSector + BACKUP_BS_NV.LastSector - BACKUP_BS_NV.FirstSector; + GPT.Partitions.Add(UEFI_BS_NV); + GPTChanged = true; + } + + Part = new FlashPart(); + Target = GPT.GetPartition("UEFI_BS_NV"); + Part.StartSector = (UInt32)Target.FirstSector; // GPT is prepared for 64-bit sector-offset, but flash app isn't. + Part.Stream = new SeekableStream(() => + { + var assembly = System.Reflection.Assembly.GetExecutingAssembly(); + + + // Magic! + // The SB resource is a compressed version of a raw NV-variable-partition. + // In this partition the SecureBoot variable is disabled. + // It overwrites the variable in a different NV-partition than where this variable is stored usually. + // This normally leads to endless-loops when the NV-variables are enumerated. + // But the partition contains an extra hack to break out the endless loops. + var stream = assembly.GetManifestResourceStream("WPinternals.SB"); + + return new DecompressedStream(stream); + }); + Parts.Add(Part); + } } - Part = new FlashPart(); - Target = GPT.GetPartition("UEFI_BS_NV"); - Part.StartSector = (UInt32)Target.FirstSector; // GPT is prepared for 64-bit sector-offset, but flash app isn't. - Part.Stream = new SeekableStream(() => - { - var assembly = System.Reflection.Assembly.GetExecutingAssembly(); - - - // Magic! - // The SB resource is a compressed version of a raw NV-variable-partition. - // In this partition the SecureBoot variable is disabled. - // It overwrites the variable in a different NV-partition than where this variable is stored usually. - // This normally leads to endless-loops when the NV-variables are enumerated. - // But the partition contains an extra hack to break out the endless loops. - var stream = assembly.GetManifestResourceStream("WPinternals.SB"); - - return new DecompressedStream(stream); - }); - Parts.Add(Part); if (GPTChanged) { @@ -2037,7 +2115,7 @@ namespace WPinternals }); // Do actual flashing! - await LumiaV2CustomFlash(Notifier, null, false, false, Parts, true, false, false, true, false, SetWorkingStatus, UpdateWorkingStatus, ExitSuccess, ExitFailure); + await LumiaV2CustomFlash(Notifier, null, false, false, Parts, true, ClearFlashingStatus, false, true, false, SetWorkingStatus, UpdateWorkingStatus, ExitSuccess, ExitFailure); } else { @@ -2116,6 +2194,7 @@ namespace WPinternals Partition Partition; bool IsUnlocked = false; bool GPTChanged = false; + bool ClearFlashingStatus = true; if (SetWorkingStatus == null) SetWorkingStatus = (m, s, v, a, st) => { }; if (UpdateWorkingStatus == null) UpdateWorkingStatus = (m, s, v, st) => { }; @@ -2155,6 +2234,7 @@ namespace WPinternals IsUnlockedFlag.LastSector = 0x40; GPT.Partitions.Add(IsUnlockedFlag); GPTChanged = true; + ClearFlashingStatus = false; } } else @@ -2164,6 +2244,7 @@ namespace WPinternals { GPT.Partitions.Remove(IsUnlockedFlag); GPTChanged = true; + ClearFlashingStatus = false; } } } @@ -2230,45 +2311,81 @@ namespace WPinternals return; } - // Now add NV partition - Partition BACKUP_BS_NV = GPT.GetPartition("BACKUP_BS_NV"); - Partition UEFI_BS_NV; - if (BACKUP_BS_NV == null) + if (!ClearFlashingStatus) { - BACKUP_BS_NV = GPT.GetPartition("UEFI_BS_NV"); - Guid OriginalPartitionTypeGuid = BACKUP_BS_NV.PartitionTypeGuid; - Guid OriginalPartitionGuid = BACKUP_BS_NV.PartitionGuid; - BACKUP_BS_NV.Name = "BACKUP_BS_NV"; - BACKUP_BS_NV.PartitionGuid = Guid.NewGuid(); - BACKUP_BS_NV.PartitionTypeGuid = Guid.NewGuid(); - UEFI_BS_NV = new Partition(); - UEFI_BS_NV.Name = "UEFI_BS_NV"; - UEFI_BS_NV.Attributes = BACKUP_BS_NV.Attributes; - UEFI_BS_NV.PartitionGuid = OriginalPartitionGuid; - UEFI_BS_NV.PartitionTypeGuid = OriginalPartitionTypeGuid; - UEFI_BS_NV.FirstSector = BACKUP_BS_NV.LastSector + 1; - UEFI_BS_NV.LastSector = UEFI_BS_NV.FirstSector + BACKUP_BS_NV.LastSector - BACKUP_BS_NV.FirstSector; - GPT.Partitions.Add(UEFI_BS_NV); - GPTChanged = true; + if (!IsUnlocked) + { + // Undo secure boot exploit + Partition NvBackupPartition = GPT.GetPartition("BACKUP_BS_NV"); + if (NvBackupPartition != null) + { + // This must be a left over of a half unlocked bootloader + Partition NvPartition = GPT.GetPartition("UEFI_BS_NV"); + NvBackupPartition.Name = "UEFI_BS_NV"; + NvBackupPartition.PartitionGuid = NvPartition.PartitionGuid; + NvBackupPartition.PartitionTypeGuid = NvPartition.PartitionTypeGuid; + GPT.Partitions.Remove(NvPartition); + GPTChanged = true; + } + + PhoneInfo Info = FlashModel.ReadPhoneInfo(false); + + // We should only clear NV if there was no backup NV to be restored and the current NV contains the SB unlock. + if ((NvBackupPartition == null) && !Info.UefiSecureBootEnabled) + { + // ClearNV + Part = new FlashPart(); + Partition Target2 = GPT.GetPartition("UEFI_BS_NV"); + Part.StartSector = (UInt32)Target2.FirstSector; + Part.Stream = new MemoryStream(new byte[0x40000]); + Parts.Add(Part); + } + } + else + { + // Now add NV partition + Partition BACKUP_BS_NV = GPT.GetPartition("BACKUP_BS_NV"); + Partition UEFI_BS_NV; + if (BACKUP_BS_NV == null) + { + BACKUP_BS_NV = GPT.GetPartition("UEFI_BS_NV"); + Guid OriginalPartitionTypeGuid = BACKUP_BS_NV.PartitionTypeGuid; + Guid OriginalPartitionGuid = BACKUP_BS_NV.PartitionGuid; + BACKUP_BS_NV.Name = "BACKUP_BS_NV"; + BACKUP_BS_NV.PartitionGuid = Guid.NewGuid(); + BACKUP_BS_NV.PartitionTypeGuid = Guid.NewGuid(); + UEFI_BS_NV = new Partition(); + UEFI_BS_NV.Name = "UEFI_BS_NV"; + UEFI_BS_NV.Attributes = BACKUP_BS_NV.Attributes; + UEFI_BS_NV.PartitionGuid = OriginalPartitionGuid; + UEFI_BS_NV.PartitionTypeGuid = OriginalPartitionTypeGuid; + UEFI_BS_NV.FirstSector = BACKUP_BS_NV.LastSector + 1; + UEFI_BS_NV.LastSector = UEFI_BS_NV.FirstSector + BACKUP_BS_NV.LastSector - BACKUP_BS_NV.FirstSector; + GPT.Partitions.Add(UEFI_BS_NV); + GPTChanged = true; + } + + Part = new FlashPart(); + Target = GPT.GetPartition("UEFI_BS_NV"); + Part.StartSector = (UInt32)Target.FirstSector; // GPT is prepared for 64-bit sector-offset, but flash app isn't. + Part.Stream = new SeekableStream(() => + { + var assembly = System.Reflection.Assembly.GetExecutingAssembly(); + + + // Magic! + // The SB resource is a compressed version of a raw NV-variable-partition. + // In this partition the SecureBoot variable is disabled. + // It overwrites the variable in a different NV-partition than where this variable is stored usually. + // This normally leads to endless-loops when the NV-variables are enumerated. + // But the partition contains an extra hack to break out the endless loops. + var stream = assembly.GetManifestResourceStream("WPinternals.SB"); + + return new DecompressedStream(stream); + }); + Parts.Add(Part); + } } - Part = new FlashPart(); - Target = GPT.GetPartition("UEFI_BS_NV"); - Part.StartSector = (UInt32)Target.FirstSector; // GPT is prepared for 64-bit sector-offset, but flash app isn't. - Part.Stream = new SeekableStream(() => - { - var assembly = System.Reflection.Assembly.GetExecutingAssembly(); - - // Magic! - // The SB resource is a compressed version of a raw NV-variable-partition. - // In this partition the SecureBoot variable is disabled. - // It overwrites the variable in a different NV-partition than where this variable is stored usually. - // This normally leads to endless-loops when the NV-variables are enumerated. - // But the partition contains an extra hack to break out the endless loops. - var stream = assembly.GetManifestResourceStream("WPinternals.SB"); - - return new DecompressedStream(stream); - }); - Parts.Add(Part); if (GPTChanged) { @@ -2318,7 +2435,7 @@ namespace WPinternals } // Do actual flashing! - await LumiaV2CustomFlash(Notifier, null, false, false, Parts, true, false, false, true, false, SetWorkingStatus, UpdateWorkingStatus, ExitSuccess, ExitFailure); + await LumiaV2CustomFlash(Notifier, null, false, false, Parts, true, ClearFlashingStatus, false, true, false, SetWorkingStatus, UpdateWorkingStatus, ExitSuccess, ExitFailure); } else { diff --git a/ViewModels/LumiaV3FlashRomViewModel.cs b/ViewModels/LumiaV3FlashRomViewModel.cs new file mode 100644 index 0000000..8a9c2e5 --- /dev/null +++ b/ViewModels/LumiaV3FlashRomViewModel.cs @@ -0,0 +1,435 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace WPinternals +{ + internal class LumiaV3FlashRomViewModel : ContextViewModel + { + + private static void RoundUpToChunks(Stream stream, UInt32 chunkSize) + { + Int64 Size = stream.Length; + if ((Size % chunkSize) > 0) + { + Int64 padding = (UInt32)(((Size / chunkSize) + 1) * chunkSize) - Size; + stream.Write(new byte[padding], 0, (Int32)padding); + } + } + + internal class ImageHeader + { + public UInt32 Size = 24; + public string Signature = "ImageFlash "; + public UInt32 ManifestLength; + public UInt32 ChunkSize = 128; + } + + public class StoreHeader + { + public UInt32 UpdateType = 0; // Full update + + public UInt16 MajorVersion = 1; + public UInt16 MinorVersion = 0; + public UInt16 FullFlashMajorVersion = 2; + public UInt16 FullFlashMinorVersion = 0; + + // Size is 0xC0 + public string PlatformId; + + public UInt32 BlockSizeInBytes = 131072; + public UInt32 WriteDescriptorCount; + public UInt32 WriteDescriptorLength; + public UInt32 ValidateDescriptorCount = 0; + public UInt32 ValidateDescriptorLength = 0; + public UInt32 InitialTableIndex = 0; + public UInt32 InitialTableCount = 0; + public UInt32 FlashOnlyTableIndex = 0; // Should be the index of the critical partitions, but for now we don't implement that + public UInt32 FlashOnlyTableCount = 1; + public UInt32 FinalTableIndex; //= WriteDescriptorCount - FinalTableCount; + public UInt32 FinalTableCount = 0; + } + + public class SecurityHeader + { + public UInt32 Size = 32; + public string Signature = "SignedImage "; + public UInt32 ChunkSizeInKb = 128; + public UInt32 HashAlgorithm = 32780; // SHA256 algorithm id + public UInt32 CatalogSize; + public UInt32 HashTableSize; + } + + internal class ManifestIni + { + internal static string BuildUpManifest(FullFlash fullFlash, Store store) + { + string Manifest = "[FullFlash]\r\n"; + if (!string.IsNullOrEmpty(fullFlash.AntiTheftVersion)) + Manifest += "AntiTheftVersion = " + fullFlash.AntiTheftVersion + "\r\n"; + if (!string.IsNullOrEmpty(fullFlash.OSVersion)) + Manifest += "OSVersion = " + fullFlash.OSVersion + "\r\n"; + if (!string.IsNullOrEmpty(fullFlash.Description)) + Manifest += "Description = " + fullFlash.Description + "\r\n"; + if (!string.IsNullOrEmpty(fullFlash.Version)) + Manifest += "Version = " + fullFlash.Version + "\r\n"; + if (!string.IsNullOrEmpty(fullFlash.DevicePlatformId0)) + Manifest += "DevicePlatformId0 = " + fullFlash.DevicePlatformId0 + "\r\n"; + + Manifest += "\r\n[Store]\r\n"; + Manifest += "SectorSize = " + store.SectorSize + "\r\n"; + Manifest += "MinSectorCount = " + store.MinSectorCount + "\r\n"; + Manifest += "\r\n"; + + return Manifest; + } + } + + internal class FullFlash + { + public string AntiTheftVersion = "1.1"; // Allow flashing on all devices + public string OSVersion; + public string Description = "Update on: " + DateTime.Now.ToString("u") + "::\r\n"; + public string Version = "2.0"; + public string DevicePlatformId0; + } + + internal class Store + { + public UInt32 SectorSize; + public UInt32 MinSectorCount; + } + + // V3 exploit + // Magic + // + private static byte[] GenerateCatalogFile(byte[] hashData) + { + byte[] catalog_first_part = new byte[] { 0x30, 0x82, 0x01, 0x44, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02, 0xA0, 0x82, 0x01, 0x35, 0x30, 0x82, 0x01, 0x31, 0x02, 0x01, 0x01, 0x31, 0x00, 0x30, 0x82, 0x01, 0x26, 0x06, 0x09, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0A, 0x01, 0xA0, 0x82, 0x01, 0x17, 0x30, 0x82, 0x01, 0x13, 0x30, 0x0C, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0C, 0x01, 0x01, 0x04, 0x10, 0xA8, 0xCA, 0xD9, 0x7D, 0xBF, 0x6D, 0x67, 0x4D, 0xB1, 0x4D, 0x62, 0xFB, 0xE6, 0x26, 0x22, 0xD4, 0x17, 0x0D, 0x32, 0x30, 0x30, 0x31, 0x31, 0x30, 0x31, 0x32, 0x31, 0x32, 0x32, 0x37, 0x5A, 0x30, 0x0E, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0C, 0x01, 0x02, 0x05, 0x00, 0x30, 0x81, 0xD1, 0x30, 0x81, 0xCE, 0x04, 0x1E, 0x48, 0x00, 0x61, 0x00, 0x73, 0x00, 0x68, 0x00, 0x54, 0x00, 0x61, 0x00, 0x62, 0x00, 0x6C, 0x00, 0x65, 0x00, 0x2E, 0x00, 0x62, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x62, 0x00, 0x00, 0x00, 0x31, 0x81, 0xAB, 0x30, 0x45, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x01, 0x04, 0x31, 0x37, 0x30, 0x35, 0x30, 0x10, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x01, 0x19, 0xA2, 0x02, 0x80, 0x00, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14 }; + byte[] catalog_second_part = new byte[] { 0x30, 0x62, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0C, 0x02, 0x02, 0x31, 0x54, 0x30, 0x52, 0x1E, 0x4C, 0x00, 0x7B, 0x00, 0x44, 0x00, 0x45, 0x00, 0x33, 0x00, 0x35, 0x00, 0x31, 0x00, 0x41, 0x00, 0x34, 0x00, 0x32, 0x00, 0x2D, 0x00, 0x38, 0x00, 0x45, 0x00, 0x35, 0x00, 0x39, 0x00, 0x2D, 0x00, 0x31, 0x00, 0x31, 0x00, 0x44, 0x00, 0x30, 0x00, 0x2D, 0x00, 0x38, 0x00, 0x43, 0x00, 0x34, 0x00, 0x37, 0x00, 0x2D, 0x00, 0x30, 0x00, 0x30, 0x00, 0x43, 0x00, 0x30, 0x00, 0x34, 0x00, 0x46, 0x00, 0x43, 0x00, 0x32, 0x00, 0x39, 0x00, 0x35, 0x00, 0x45, 0x00, 0x45, 0x00, 0x7D, 0x02, 0x02, 0x02, 0x00, 0x31, 0x00 }; + + byte[] hash = new SHA1Managed().ComputeHash(hashData); + + byte[] catalog = new byte[catalog_first_part.Length + hash.Length + catalog_second_part.Length]; + System.Buffer.BlockCopy(catalog_first_part, 0, catalog, 0, catalog_first_part.Length); + System.Buffer.BlockCopy(hash, 0, catalog, catalog_first_part.Length, hash.Length); + System.Buffer.BlockCopy(catalog_second_part, 0, catalog, catalog_first_part.Length + hash.Length, catalog_second_part.Length); + + return catalog; + } + + // V3 exploit + // Magic + // + internal async static Task LumiaV3CustomFlash(PhoneNotifierViewModel Notifier, List FlashParts, bool CheckSectorAlignment = true, SetWorkingStatus SetWorkingStatus = null, UpdateWorkingStatus UpdateWorkingStatus = null, ExitSuccess ExitSuccess = null, ExitFailure ExitFailure = null) + { + if (SetWorkingStatus == null) SetWorkingStatus = (m, s, v, a, st) => { }; + if (UpdateWorkingStatus == null) UpdateWorkingStatus = (m, s, v, st) => { }; + if (ExitSuccess == null) ExitSuccess = (m, s) => { }; + if (ExitFailure == null) ExitFailure = (m, s) => { }; + + uint chunkSize = 131072u; + int chunkSizes = 131072; + + if (FlashParts != null) + { + foreach (FlashPart Part in FlashParts) + { + if (Part.Stream == null) + throw new ArgumentException("Stream is null"); + if (!Part.Stream.CanSeek) + throw new ArgumentException("Streams must be seekable"); + if (((Part.StartSector * 0x200) % chunkSize) != 0) + throw new ArgumentException("Invalid StartSector alignment"); + if (CheckSectorAlignment) + { + if ((Part.Stream.Length % chunkSize) != 0) + throw new ArgumentException("Invalid Data length"); + } + } + } + + try + { + NokiaFlashModel Model = (NokiaFlashModel)Notifier.CurrentModel; + PhoneInfo Info = Model.ReadPhoneInfo(); + + if ((Info.SecureFfuSupportedProtocolMask & ((ushort)FfuProtocol.ProtocolSyncV2)) == 0) // Exploit needs protocol v2 -> This check is not conclusive, because old phones also report support for this protocol, although it is really not supported. + throw new WPinternalsException("Flash failed!", "Protocols not supported. The phone reports that it does not support the Protocol Sync V2."); + if (Info.FlashAppProtocolVersionMajor < 2) // Old phones do not support the hack. These phones have Flash protocol 1.x. + throw new WPinternalsException("Flash failed!", "Protocols not supported. The phone reports that Flash App communication protocol is lower than 2. Reported version by the phone: " + Info.FlashAppProtocolVersionMajor + "."); + + if (Info.UefiSecureBootEnabled) + throw new WPinternalsException("Flash failed!", "UEFI Secureboot must be disabled for the Flash V3 exploit to work."); + + // The payloads must be ordered by the number of locations + // + // FlashApp processes payloads like this: + // - First payloads which are with one location, those can be sent in bulk + // - Then payloads with more than one location, those should not be sent in bulk + // + // If you do not order payloads like this, you will get an error, most likely hash mismatch + // + LumiaV2UnlockBootViewModel.FlashingPayload[] payloads = new LumiaV2UnlockBootViewModel.FlashingPayload[0]; + if (FlashParts != null) + { + payloads = LumiaV2UnlockBootViewModel.GetNonOptimizedPayloads(FlashParts, chunkSizes, (uint)(Info.WriteBufferSize / chunkSize), SetWorkingStatus, UpdateWorkingStatus).OrderBy(x => x.TargetLocations.Count()).ToArray(); + } + + MemoryStream Headerstream1 = new MemoryStream(); + + // ============================== + // Header 1 start + + ImageHeader image = new ImageHeader(); + FullFlash ffimage = new FullFlash(); + Store simage = new Store(); + + // Todo make this read the image itself + ffimage.OSVersion = "10.0.11111.0"; + ffimage.DevicePlatformId0 = Info.PlatformID; + ffimage.AntiTheftVersion = "1.1"; + + simage.SectorSize = 512; + simage.MinSectorCount = Info.EmmcSizeInSectors; + + //Logging.Log("Generating image manifest..."); + string manifest = ManifestIni.BuildUpManifest(ffimage, simage);//, partitions); + + byte[] TextBytes = System.Text.Encoding.ASCII.GetBytes(manifest); + + image.ManifestLength = (UInt32)TextBytes.Length; + + byte[] ImageHeaderBuffer = new byte[0x18]; + + ByteOperations.WriteUInt32(ImageHeaderBuffer, 0, image.Size); + ByteOperations.WriteAsciiString(ImageHeaderBuffer, 0x04, image.Signature); + ByteOperations.WriteUInt32(ImageHeaderBuffer, 0x10, image.ManifestLength); + ByteOperations.WriteUInt32(ImageHeaderBuffer, 0x14, image.ChunkSize); + + Headerstream1.Write(ImageHeaderBuffer, 0, 0x18); + Headerstream1.Write(TextBytes, 0, TextBytes.Length); + + RoundUpToChunks(Headerstream1, chunkSize); + + // Header 1 stop + round + // ============================== + + MemoryStream Headerstream2 = new MemoryStream(); + + // ============================== + // Header 2 start + + StoreHeader store = new StoreHeader(); + + store.WriteDescriptorCount = (UInt32)payloads.Count(); + store.FinalTableIndex = (UInt32)payloads.Count() - store.FinalTableCount; + store.PlatformId = Info.PlatformID; + + foreach (LumiaV2UnlockBootViewModel.FlashingPayload payload in payloads) + { + store.WriteDescriptorLength += payload.GetStoreHeaderSize(); + } + + foreach (LumiaV2UnlockBootViewModel.FlashingPayload payload in payloads) + { + /*if (payload.TargetLocations.First() > PlatEnd) + break;*/ + store.FlashOnlyTableIndex += 1; + } + + byte[] StoreHeaderBuffer = new byte[0xF8]; + ByteOperations.WriteUInt32(StoreHeaderBuffer, 0, store.UpdateType); + ByteOperations.WriteUInt16(StoreHeaderBuffer, 0x04, store.MajorVersion); + ByteOperations.WriteUInt16(StoreHeaderBuffer, 0x06, store.MinorVersion); + ByteOperations.WriteUInt16(StoreHeaderBuffer, 0x08, store.FullFlashMajorVersion); + ByteOperations.WriteUInt16(StoreHeaderBuffer, 0x0A, store.FullFlashMinorVersion); + ByteOperations.WriteAsciiString(StoreHeaderBuffer, 0x0C, store.PlatformId); + ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xCC, store.BlockSizeInBytes); + ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xD0, store.WriteDescriptorCount); + ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xD4, store.WriteDescriptorLength); + ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xD8, store.ValidateDescriptorCount); + ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xDC, store.ValidateDescriptorLength); + ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xE0, store.InitialTableIndex); + ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xE4, store.InitialTableCount); + ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xE8, store.FlashOnlyTableIndex); + ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xEC, store.FlashOnlyTableCount); + ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xF0, store.FinalTableIndex); + ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xF4, store.FinalTableCount); + Headerstream2.Write(StoreHeaderBuffer, 0, 0xF8); + + byte[] descriptorsBuffer = new byte[store.WriteDescriptorLength]; + + UInt32 NewWriteDescriptorOffset = 0; + foreach (LumiaV2UnlockBootViewModel.FlashingPayload payload in payloads) + { + ByteOperations.WriteUInt32(descriptorsBuffer, NewWriteDescriptorOffset + 0x00, (UInt32)payload.TargetLocations.Count()); // Location count + ByteOperations.WriteUInt32(descriptorsBuffer, NewWriteDescriptorOffset + 0x04, payload.ChunkCount); // Chunk count + NewWriteDescriptorOffset += 0x08; + + foreach (UInt32 location in payload.TargetLocations) + { + ByteOperations.WriteUInt32(descriptorsBuffer, NewWriteDescriptorOffset + 0x00, 0x00000000); // Disk access method (0 = Begin, 2 = End) + ByteOperations.WriteUInt32(descriptorsBuffer, NewWriteDescriptorOffset + 0x04, location); // Chunk index + NewWriteDescriptorOffset += 0x08; + } + } + + Headerstream2.Write(descriptorsBuffer, 0, (Int32)store.WriteDescriptorLength); + + RoundUpToChunks(Headerstream2, chunkSize); + + // Header 2 stop + round + // ============================== + + SecurityHeader security = new SecurityHeader(); + + Headerstream1.Seek(0, SeekOrigin.Begin); + Headerstream2.Seek(0, SeekOrigin.Begin); + + security.HashTableSize = 0x20 * (UInt32)((Headerstream1.Length + Headerstream2.Length) / chunkSize); + + foreach (LumiaV2UnlockBootViewModel.FlashingPayload payload in payloads) + { + security.HashTableSize += payload.GetSecurityHeaderSize(); + } + + byte[] HashTable = new byte[security.HashTableSize]; + BinaryWriter bw = new BinaryWriter(new MemoryStream(HashTable)); + + SHA256 crypto = SHA256.Create(); + for (int i = 0; i < Headerstream1.Length / chunkSize; i++) + { + byte[] buffer = new byte[chunkSize]; + Headerstream1.Read(buffer, 0, (Int32)chunkSize); + byte[] hash = crypto.ComputeHash(buffer); + bw.Write(hash, 0, hash.Length); + } + + for (int i = 0; i < Headerstream2.Length / chunkSize; i++) + { + byte[] buffer = new byte[chunkSize]; + Headerstream2.Read(buffer, 0, (Int32)chunkSize); + byte[] hash = crypto.ComputeHash(buffer); + bw.Write(hash, 0, hash.Length); + } + + foreach (LumiaV2UnlockBootViewModel.FlashingPayload payload in payloads) + { + bw.Write(payload.ChunkHashes[0], 0, payload.ChunkHashes[0].Length); + } + + bw.Close(); + + //Logging.Log("Generating image catalog..."); + byte[] catalog = GenerateCatalogFile(HashTable); + + security.CatalogSize = (UInt32)catalog.Length; + + byte[] SecurityHeaderBuffer = new byte[0x20]; + + ByteOperations.WriteUInt32(SecurityHeaderBuffer, 0, security.Size); + ByteOperations.WriteAsciiString(SecurityHeaderBuffer, 0x04, security.Signature); + ByteOperations.WriteUInt32(SecurityHeaderBuffer, 0x10, security.ChunkSizeInKb); + ByteOperations.WriteUInt32(SecurityHeaderBuffer, 0x14, security.HashAlgorithm); + ByteOperations.WriteUInt32(SecurityHeaderBuffer, 0x18, security.CatalogSize); + ByteOperations.WriteUInt32(SecurityHeaderBuffer, 0x1C, security.HashTableSize); + + MemoryStream retstream = new MemoryStream(); + + retstream.Write(SecurityHeaderBuffer, 0, 0x20); + + retstream.Write(catalog, 0, (Int32)security.CatalogSize); + retstream.Write(HashTable, 0, (Int32)security.HashTableSize); + + RoundUpToChunks(retstream, chunkSize); + + Headerstream1.Seek(0, SeekOrigin.Begin); + Headerstream2.Seek(0, SeekOrigin.Begin); + + byte[] buff = new byte[Headerstream1.Length]; + Headerstream1.Read(buff, 0, (Int32)Headerstream1.Length); + + Headerstream1.Close(); + + retstream.Write(buff, 0, buff.Length); + + buff = new byte[Headerstream2.Length]; + Headerstream2.Read(buff, 0, (Int32)Headerstream2.Length); + + Headerstream2.Close(); + + retstream.Write(buff, 0, buff.Length); + + // -------- + + // Go back to the beginning + retstream.Seek(0, SeekOrigin.Begin); + + byte[] FfuHeader = new byte[retstream.Length]; + await retstream.ReadAsync(FfuHeader, 0, (int)retstream.Length); + retstream.Close(); + + byte Options = 0; + if (!Info.IsBootloaderSecure) + Options = (byte)((FlashOptions)Options | FlashOptions.SkipSignatureCheck); + + LogFile.Log("Flash in progress...", LogType.ConsoleOnly); + SetWorkingStatus("Flashing...", null, (UInt64?)payloads.Count(), Status: WPinternalsStatus.Flashing); + + Model.SendFfuHeaderV1(FfuHeader, Options); + + UInt64 counter = 0; + + int numberOfPayloadsToSendAtOnce = (int)Math.Round((double)Info.WriteBufferSize / chunkSize); + byte[] payloadBuffer; + + for (int i = 0; i < payloads.Count(); i+= numberOfPayloadsToSendAtOnce) + { + if (i + numberOfPayloadsToSendAtOnce - 1 >= payloads.Count()) + { + numberOfPayloadsToSendAtOnce = payloads.Count() - i; + } + + payloadBuffer = new byte[numberOfPayloadsToSendAtOnce * chunkSizes]; + + string ProgressText = "Flashing resources"; + + for (int j = 0; j < numberOfPayloadsToSendAtOnce; j++) + { + LumiaV2UnlockBootViewModel.FlashingPayload payload = payloads[i + j]; + + UInt32 StreamIndex = payload.StreamIndexes.First(); + FlashPart flashPart = FlashParts[(int)StreamIndex]; + + if (flashPart.ProgressText != null) + ProgressText = flashPart.ProgressText; + + Stream Stream = flashPart.Stream; + Stream.Seek(payload.StreamLocations.First(), SeekOrigin.Begin); + Stream.Read(payloadBuffer, j * chunkSizes, chunkSizes); + counter++; + } + + Model.SendFfuPayloadV2(payloadBuffer, int.Parse((counter * 100 / (ulong)payloads.Count()).ToString())); + UpdateWorkingStatus(ProgressText, null, counter, WPinternalsStatus.Flashing); + } + + Model.ResetPhone(); + + await Notifier.WaitForRemoval(); + + ExitSuccess("Flash succeeded!", null); + } + catch + { + throw new WPinternalsException("Custom flash failed"); + } + } + } +} diff --git a/ViewModels/NokiaFlashViewModel.cs b/ViewModels/NokiaFlashViewModel.cs index 15401c0..4976017 100644 --- a/ViewModels/NokiaFlashViewModel.cs +++ b/ViewModels/NokiaFlashViewModel.cs @@ -272,7 +272,7 @@ namespace WPinternals LogFile.Log("Bootloader Security Authentication Status: " + BootloaderSecurityAuthenticationStatus.ToString()); BootloaderSecurityRdcStatus = Info.RdcPresent; LogFile.Log("Bootloader Security Rdc Status: " + BootloaderSecurityRdcStatus.ToString()); - EffectiveBootloaderSecurityStatus = Info.SecureFfuEnabled && !Info.Authenticated && !Info.RdcPresent; + EffectiveBootloaderSecurityStatus = !Info.IsBootloaderSecure; LogFile.Log("Effective Bootloader Security Status: " + EffectiveBootloaderSecurityStatus.ToString()); NativeDebugStatus = !Info.JtagDisabled; diff --git a/ViewModels/NokiaModeFlashViewModel.cs b/ViewModels/NokiaModeFlashViewModel.cs index 52a04ec..592db30 100644 --- a/ViewModels/NokiaModeFlashViewModel.cs +++ b/ViewModels/NokiaModeFlashViewModel.cs @@ -77,7 +77,7 @@ namespace WPinternals } else { - EffectiveBootloaderSecurityStatus = Info.SecureFfuEnabled && !Info.Authenticated && !Info.RdcPresent; + EffectiveBootloaderSecurityStatus = !Info.IsBootloaderSecure; } } else diff --git a/ViewModels/PhoneNotifierViewModel.cs b/ViewModels/PhoneNotifierViewModel.cs index 5fd3f00..e8a591e 100644 --- a/ViewModels/PhoneNotifierViewModel.cs +++ b/ViewModels/PhoneNotifierViewModel.cs @@ -229,13 +229,22 @@ namespace WPinternals } else if ((e.DevicePath.IndexOf("&PID_066E", StringComparison.OrdinalIgnoreCase) >= 0) || (e.DevicePath.IndexOf("&PID_0714", StringComparison.OrdinalIgnoreCase) >= 0) || // VID_0421&PID_0714 is for Lumia 930 - (e.DevicePath.IndexOf("&PID_0A02", StringComparison.OrdinalIgnoreCase) >= 0)) // VID_045E&PID_0A02 is for Lumia 950 + (e.DevicePath.IndexOf("&PID_0A02", StringComparison.OrdinalIgnoreCase) >= 0) || // VID_045E&PID_0A02 is for Lumia 950 + (e.DevicePath.IndexOf("&PID_05EE", StringComparison.OrdinalIgnoreCase) >= 0)) // VID_0421&PID_05EE is for early RX100 { CurrentModel = new NokiaFlashModel(e.DevicePath); ((NokiaFlashModel)CurrentModel).InterfaceChanged += InterfaceChanged; - FlashAppType type = ((NokiaFlashModel)CurrentModel).GetFlashAppType(); - LogFile.Log("Flash App Type: " + type.ToString(), LogType.FileOnly); + FlashAppType type = FlashAppType.FlashApp; + try + { + type = ((NokiaFlashModel)CurrentModel).GetFlashAppType(); + LogFile.Log("Flash App Type: " + type.ToString(), LogType.FileOnly); + } + catch + { + LogFile.Log("Flash App Type could not be determined, assuming " + type.ToString(), LogType.FileOnly); + } switch (type) { @@ -406,6 +415,7 @@ namespace WPinternals (e.DevicePath.IndexOf("VID_0421&PID_06FC", StringComparison.OrdinalIgnoreCase) >= 0) || (e.DevicePath.IndexOf("VID_0421&PID_066E", StringComparison.OrdinalIgnoreCase) >= 0) || (e.DevicePath.IndexOf("VID_0421&PID_0714", StringComparison.OrdinalIgnoreCase) >= 0) || + (e.DevicePath.IndexOf("VID_0421&PID_05EE", StringComparison.OrdinalIgnoreCase) >= 0) || (e.DevicePath.IndexOf("VID_045E&PID_0A00", StringComparison.OrdinalIgnoreCase) >= 0) || (e.DevicePath.IndexOf("VID_045E&PID_0A02", StringComparison.OrdinalIgnoreCase) >= 0) || (e.DevicePath.IndexOf("VID_05C6&PID_9008", StringComparison.OrdinalIgnoreCase) >= 0) || diff --git a/ViewModels/SwitchModeViewModel.cs b/ViewModels/SwitchModeViewModel.cs index f2d7c54..a862f15 100644 --- a/ViewModels/SwitchModeViewModel.cs +++ b/ViewModels/SwitchModeViewModel.cs @@ -641,7 +641,7 @@ namespace WPinternals GPT GPT = FlashModel.ReadGPT(); IsUnlockedNew = ((GPT.GetPartition("IS_UNLOCKED") != null) || (GPT.GetPartition("BACKUP_EFIESP") != null) || (GPT.GetPartition("BACKUP_BS_NV") != null)); } - bool IsOriginalEngineeringLumia = ((!Info.SecureFfuEnabled || Info.Authenticated || Info.RdcPresent) && !IsUnlockedNew); + bool IsOriginalEngineeringLumia = (!Info.IsBootloaderSecure && !IsUnlockedNew); if (IsOldLumia || IsOriginalEngineeringLumia) { @@ -650,7 +650,7 @@ namespace WPinternals byte[] RebootToMassStorageCommand = new byte[] { 0x4E, 0x4F, 0x4B, 0x4D }; // NOKM IsSwitchingInterface = true; byte[] RebootCommandResult = ((NokiaPhoneModel)CurrentModel).ExecuteRawMethod(RebootToMassStorageCommand); - if ((RebootCommandResult != null) && (RebootCommandResult.Length == 4)) // This means fail: NOKU (unknow command) + if ((RebootCommandResult != null) && (RebootCommandResult.Length == 4)) // This means fail: NOKU (unknown command) { BootModeFlagCommand[0x0F] = 0x4D; byte[] BootFlagResult = ((NokiaPhoneModel)CurrentModel).ExecuteRawMethod(BootModeFlagCommand); diff --git a/WPinternals.csproj b/WPinternals.csproj index 1bc1457..478b911 100644 --- a/WPinternals.csproj +++ b/WPinternals.csproj @@ -928,6 +928,7 @@ + diff --git a/WPinternals.sln b/WPinternals.sln index a21f15d..c75e285 100644 --- a/WPinternals.sln +++ b/WPinternals.sln @@ -4,6 +4,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 VisualStudioVersion = 16.0.29123.89 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WPinternals", "WPinternals.csproj", "{AED6DEB8-F54C-4B41-9655-793E7096AE6E}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WPinternals.Core", "WPinternals.Core.csproj", "{AED6DEB8-F54C-4B41-9655-793E7096AE6F}" EndProject Global @@ -54,6 +55,94 @@ Global Release-Test|Any CPU = Release-Test|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-AddEmergency|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-AddEmergency|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-BackupGPT|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-BackupGPT|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-ClearNV|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-ClearNV|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-CustomFlash-930|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-CustomFlash-930|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-CustomFlash-950 (no restart)|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-CustomFlash-950 (no restart)|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-CustomFlash-950|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-CustomFlash-950|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-DLall|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-DLall|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-DLEmergency|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-DLEmergency|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-DLFFU|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-DLFFU|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-DumpFFU|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-DumpFFU|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-DumpUEFI|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-DumpUEFI|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-EnableRootAccess|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-EnableRootAccess|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-EnableRootAccessOnImage|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-EnableRootAccessOnImage|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-EnableTestSigning (no restart)|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-EnableTestSigning (no restart)|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-EnableTestSigning|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-EnableTestSigning|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FindFlashingProfile|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FindFlashingProfile|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FindFlashingProfileNoRestart|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FindFlashingProfileNoRestart|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FixBoot|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FixBoot|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FlashCustomRom-640|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FlashCustomRom-640|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FlashFFU-RM1073|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FlashFFU-RM1073|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FlashFFU-RM1085|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FlashFFU-RM1085|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FlashRaw|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FlashRaw|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-Help|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-Help|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-MergeGptXmlXml|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-MergeGptXmlXml|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-MergeGptXmlZip|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-MergeGptXmlZip|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-MSM|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-MSM|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-ReadGPT|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-ReadGPT|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-RelockPhone|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-RelockPhone|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-RestoreGPT|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-RestoreGPT|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-ShowFFU|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-ShowFFU|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-ShowPhoneInfo|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-ShowPhoneInfo|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-Test|Any CPU.ActiveCfg = Debug-Test|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-Test|Any CPU.Build.0 = Debug-Test|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-TestProgrammer-550|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-TestProgrammer-550|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-TestProgrammer-630|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-TestProgrammer-630|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-TestProgrammer-640|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-TestProgrammer-640|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-TestProgrammer-650|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-TestProgrammer-650|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-TestProgrammer-930|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-TestProgrammer-930|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-TestProgrammer-950|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-TestProgrammer-950|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-UnlockBootloader|Any CPU.ActiveCfg = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-UnlockBootloader|Any CPU.Build.0 = Debug|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Preview|Any CPU.ActiveCfg = Release|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Preview|Any CPU.Build.0 = Release|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Preview-Test|Any CPU.ActiveCfg = Release|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Preview-Test|Any CPU.Build.0 = Release|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Release|Any CPU.Build.0 = Release|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Release-Test|Any CPU.ActiveCfg = Release|Any CPU + {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Release-Test|Any CPU.Build.0 = Release|Any CPU {AED6DEB8-F54C-4B41-9655-793E7096AE6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AED6DEB8-F54C-4B41-9655-793E7096AE6F}.Debug|Any CPU.Build.0 = Debug|Any CPU {AED6DEB8-F54C-4B41-9655-793E7096AE6F}.Debug-AddEmergency|Any CPU.ActiveCfg = Debug|Any CPU @@ -142,94 +231,6 @@ Global {AED6DEB8-F54C-4B41-9655-793E7096AE6F}.Release|Any CPU.Build.0 = Release|Any CPU {AED6DEB8-F54C-4B41-9655-793E7096AE6F}.Release-Test|Any CPU.ActiveCfg = Release|Any CPU {AED6DEB8-F54C-4B41-9655-793E7096AE6F}.Release-Test|Any CPU.Build.0 = Release|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-AddEmergency|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-AddEmergency|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-BackupGPT|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-BackupGPT|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-ClearNV|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-ClearNV|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-CustomFlash-930|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-CustomFlash-930|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-CustomFlash-950 (no restart)|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-CustomFlash-950 (no restart)|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-CustomFlash-950|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-CustomFlash-950|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-DLall|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-DLall|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-DLEmergency|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-DLEmergency|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-DLFFU|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-DLFFU|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-DumpFFU|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-DumpFFU|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-DumpUEFI|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-DumpUEFI|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-EnableRootAccess|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-EnableRootAccess|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-EnableRootAccessOnImage|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-EnableRootAccessOnImage|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-EnableTestSigning (no restart)|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-EnableTestSigning (no restart)|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-EnableTestSigning|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-EnableTestSigning|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FindFlashingProfile|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FindFlashingProfile|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FindFlashingProfileNoRestart|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FindFlashingProfileNoRestart|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FixBoot|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FixBoot|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FlashCustomRom-640|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FlashCustomRom-640|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FlashFFU-RM1073|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FlashFFU-RM1073|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FlashFFU-RM1085|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FlashFFU-RM1085|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FlashRaw|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-FlashRaw|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-Help|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-Help|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-MergeGptXmlXml|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-MergeGptXmlXml|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-MergeGptXmlZip|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-MergeGptXmlZip|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-MSM|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-MSM|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-ReadGPT|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-ReadGPT|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-RelockPhone|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-RelockPhone|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-RestoreGPT|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-RestoreGPT|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-ShowFFU|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-ShowFFU|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-ShowPhoneInfo|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-ShowPhoneInfo|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-Test|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-Test|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-TestProgrammer-550|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-TestProgrammer-550|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-TestProgrammer-630|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-TestProgrammer-630|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-TestProgrammer-640|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-TestProgrammer-640|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-TestProgrammer-650|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-TestProgrammer-650|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-TestProgrammer-930|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-TestProgrammer-930|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-TestProgrammer-950|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-TestProgrammer-950|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-UnlockBootloader|Any CPU.ActiveCfg = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Debug-UnlockBootloader|Any CPU.Build.0 = Debug|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Preview|Any CPU.ActiveCfg = Release|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Preview|Any CPU.Build.0 = Release|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Preview-Test|Any CPU.ActiveCfg = Release|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Preview-Test|Any CPU.Build.0 = Release|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Release|Any CPU.Build.0 = Release|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Release-Test|Any CPU.ActiveCfg = Release|Any CPU - {AED6DEB8-F54C-4B41-9655-793E7096AE6E}.Release-Test|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE