// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. using Microsoft.Win32; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace WPinternals { // Create this class on the UI thread, after the main-window of the application is initialized. // It is necessary to create the object on the UI thread, because notification events to the View need to be fired on that thread. // The Model for this ViewModel communicates over USB and for that it uses the hWnd of the main window. // Therefore the main window must be created before the ViewModel is created. internal enum MachineState { Default, LumiaUnlockBoot }; internal class LumiaUnlockBootViewModel : ContextViewModel { private PhoneNotifierViewModel PhoneNotifier; private Action Callback; private string FFUPath; private string LoadersPath; private string SBL3Path; private string ProfileFFUPath; private string EDEPath; private string SupportedFFUPath; private bool IsBootLoaderUnlocked; private byte[] RootKeyHash = null; private Action SwitchToFlashRom; private Action SwitchToUndoRoot; private Action SwitchToDownload; private bool DoUnlock; private MachineState State; private object EvaluateViewStateLockObject = new object(); internal LumiaUnlockBootViewModel(PhoneNotifierViewModel PhoneNotifier, Action SwitchToFlashRom, Action SwitchToUndoRoot, Action SwitchToDownload, bool DoUnlock, Action Callback) : base() { IsSwitchingInterface = false; IsFlashModeOperation = true; this.PhoneNotifier = PhoneNotifier; this.SwitchToFlashRom = SwitchToFlashRom; this.SwitchToUndoRoot = SwitchToUndoRoot; this.SwitchToDownload = SwitchToDownload; this.DoUnlock = DoUnlock; this.Callback = Callback; State = MachineState.Default; this.PhoneNotifier.NewDeviceArrived += NewDeviceArrived; // ViewState will be evaluated as soon as this object is set as DataContext } ~LumiaUnlockBootViewModel() { PhoneNotifier.NewDeviceArrived -= NewDeviceArrived; } // Potentially blocking UI. Threadsafe. internal override void EvaluateViewState() { if (!IsActive) return; if (State == MachineState.LumiaUnlockBoot) return; lock (EvaluateViewStateLockObject) { switch (PhoneNotifier.CurrentInterface) { case PhoneInterfaces.Lumia_Normal: case PhoneInterfaces.Lumia_Label: IsSwitchingInterface = false; if (DoUnlock) { // Display View to switch to Flash mode LogFile.Log("Start unlock. Phone needs to switch to Flash-mode"); ActivateSubContext(new MessageViewModel("In order to start unlocking the bootloader, the phone needs to be switched to Flash-mode.", SwitchToFlashMode, Exit)); } else { // Display View to switch to Flash mode LogFile.Log("Start boot restore. Phone needs to switch to Flash-mode"); ActivateSubContext(new MessageViewModel("In order to start restoring the bootloader, the phone needs to be switched to Flash-mode.", SwitchToFlashMode, Exit)); } break; case PhoneInterfaces.Lumia_Flash: // Display View with device info and request for resources // Click on "Continue" will start processing all resources // Processing may fail with error message // Or processing will succeed and user will again be asked to continue with Bricking-procedure (to switch to emergency mode) // This code is not always invoked by OnArrival event. // So this is not always in a thread from the threadpool. // So we need to avoid UI blocking code here. IsSwitchingInterface = false; int TestPos = 0; try // In case phone reboots during the time that status is being read { // Some phones, like Lumia 928 verizon, do not support the Terminal interface! // To read the RootKeyHash we use ReadParam("RRKH"), instead of GetTerminalResponse().RootKeyHash. RootKeyHash = ((NokiaFlashModel)PhoneNotifier.CurrentModel).ReadParam("RRKH"); TestPos = 1; UefiSecurityStatusResponse SecurityStatus = ((NokiaFlashModel)PhoneNotifier.CurrentModel).ReadSecurityStatus(); if (SecurityStatus != null) IsBootLoaderUnlocked = (SecurityStatus.AuthenticationStatus || SecurityStatus.RdcStatus || !SecurityStatus.SecureFfuEfuseStatus); TestPos = 2; PhoneInfo Info = ((NokiaFlashModel)PhoneNotifier.CurrentModel).ReadPhoneInfo(); if (SecurityStatus == null) IsBootLoaderUnlocked = !Info.IsBootloaderSecure; if (RootKeyHash == null) { RootKeyHash = Info.RKH; if (RootKeyHash == null) RootKeyHash = new byte[32]; } TestPos = 3; if (Info.FlashAppProtocolVersionMajor < 2) { // This action is executed after the resources are selected by the user. Action ReturnFunction = (FFUPath, LoadersPath, SBL3Path, ProfileFFUPath, EDEPath, SupportedFFUPath, DoFixBoot) => { // Stop responding to device arrival here, because all connections are handled by subfunctions, not here. IsSwitchingInterface = true; State = MachineState.LumiaUnlockBoot; // This is a callback on the UI thread // Resources are confirmed by user this.FFUPath = FFUPath; this.LoadersPath = LoadersPath; this.SBL3Path = SBL3Path; this.SupportedFFUPath = SupportedFFUPath; StorePaths(); LogFile.Log("Processing resources:"); LogFile.Log("FFU: " + FFUPath); LogFile.Log("Loaders: " + LoadersPath); if (SBL3Path == null) LogFile.Log("No SBL3 specified"); else LogFile.Log("SBL3: " + SBL3Path); ActivateSubContext(new BusyViewModel("Processing resources...")); if (DoUnlock) { Task.Run(async () => { await LumiaUnlockBootloaderViewModel.LumiaV1UnlockFirmware(PhoneNotifier, FFUPath, LoadersPath, SBL3Path, SupportedFFUPath, SetWorkingStatus, UpdateWorkingStatus, ExitMessage, ExitMessage); }); } else { Task.Run(async () => { await LumiaUnlockBootloaderViewModel.LumiaV1RelockFirmware(PhoneNotifier, FFUPath, LoadersPath, SetWorkingStatus, UpdateWorkingStatus, ExitMessage, ExitMessage); }); } }; if (DoUnlock) ActivateSubContext(new BootUnlockResourcesViewModel("Lumia Flash mode", RootKeyHash, SwitchToFlashRom, SwitchToUndoRoot, SwitchToDownload, ReturnFunction, Abort, IsBootLoaderUnlocked, false)); else ActivateSubContext(new BootRestoreResourcesViewModel("Lumia Flash mode", RootKeyHash, SwitchToFlashRom, SwitchToUndoRoot, SwitchToDownload, ReturnFunction, Abort, IsBootLoaderUnlocked, false)); } else { bool AlreadyUnlocked = false; if (DoUnlock) { NokiaFlashModel FlashModel = (NokiaFlashModel)PhoneNotifier.CurrentModel; GPT GPT = FlashModel.ReadGPT(); if ((GPT.GetPartition("IS_UNLOCKED") != null) || (GPT.GetPartition("BACKUP_EFIESP") != null)) { ExitMessage("Phone is already unlocked", null); return; //AlreadyUnlocked = true; } } TestPos = 4; // Stop responding to device arrival here, because all connections are handled by subfunctions, not here. IsSwitchingInterface = true; // This action is executed after the resources are selected by the user. Action ReturnFunction = (FFUPath, LoadersPath, SBL3Path, ProfileFFUPath, EDEPath, SupportedFFUPath, DoFixBoot) => { IsSwitchingInterface = true; State = MachineState.LumiaUnlockBoot; if (DoUnlock) { // This is a callback on the UI thread // Resources are confirmed by user this.ProfileFFUPath = ProfileFFUPath; this.EDEPath = EDEPath; this.SupportedFFUPath = SupportedFFUPath; StorePaths(); if (DoFixBoot) LogFile.Log("Fix Boot"); else LogFile.Log("Unlock Bootloader"); LogFile.Log("Processing resources:"); LogFile.Log("Profile FFU: " + ProfileFFUPath); LogFile.Log("EDE file: " + EDEPath); if (SupportedFFUPath != null) LogFile.Log("Donor-FFU with supported OS version: " + SupportedFFUPath); Task.Run(async () => { if (DoFixBoot) await LumiaV2UnlockBootViewModel.LumiaV2FixBoot(PhoneNotifier, SetWorkingStatus, UpdateWorkingStatus, ExitMessage, ExitMessage); else if (!AlreadyUnlocked) await LumiaUnlockBootloaderViewModel.LumiaV2UnlockUEFI(PhoneNotifier, ProfileFFUPath, EDEPath, SupportedFFUPath, SetWorkingStatus, UpdateWorkingStatus, ExitMessage, ExitMessage); else await LumiaUnlockBootloaderViewModel.LumiaV2UnlockUEFI(PhoneNotifier, ProfileFFUPath, EDEPath, SupportedFFUPath, SetWorkingStatus, UpdateWorkingStatus, ExitMessage, ExitMessage, true); }); } else { Task.Run(async () => { FFU ProfileFFU = null; List FFUs = App.Config.FFURepository.Where(e => (Info.PlatformID.StartsWith(e.PlatformID, StringComparison.OrdinalIgnoreCase) && e.Exists())).ToList(); if (FFUs.Count() > 0) ProfileFFU = new FFU(FFUs[0].Path); else throw new WPinternalsException("Profile FFU missing", "No profile FFU has been found in the repository for your device. You can add a profile FFU within the download section of the tool or by using the command line."); LogFile.Log("Profile FFU: " + ProfileFFU.Path); await LumiaUnlockBootloaderViewModel.LumiaV2RelockUEFI(PhoneNotifier, ProfileFFU.Path, true, SetWorkingStatus, UpdateWorkingStatus, ExitMessage, ExitMessage); }); } }; TestPos = 5; if (DoUnlock) ActivateSubContext(new BootUnlockResourcesViewModel("Lumia Flash mode", RootKeyHash, SwitchToFlashRom, SwitchToUndoRoot, SwitchToDownload, ReturnFunction, Abort, IsBootLoaderUnlocked, true, Info.PlatformID, Info.Type)); else ActivateSubContext(new BootRestoreResourcesViewModel("Lumia Flash mode", RootKeyHash, SwitchToFlashRom, SwitchToUndoRoot, SwitchToDownload, ReturnFunction, Abort, IsBootLoaderUnlocked, true, Info.PlatformID, Info.Type)); } } catch (Exception Ex) { LogFile.LogException(Ex, LogType.FileAndConsole, TestPos.ToString()); } break; case PhoneInterfaces.Qualcomm_Download: IsSwitchingInterface = false; // If resources are not confirmed yet, then display view with device info and request for resources. QualcommDownload Download = new QualcommDownload((QualcommSerial)PhoneNotifier.CurrentModel); byte[] QualcommRootKeyHash; try { QualcommRootKeyHash = Download.GetRKH(); } catch (BadConnectionException) { // This is a Spec B device break; } if (RootKeyHash == null) RootKeyHash = QualcommRootKeyHash; else if (!StructuralComparisons.StructuralEqualityComparer.Equals(RootKeyHash, QualcommRootKeyHash)) { LogFile.Log("Error: Root Key Hash in Qualcomm Emergency mode does not match!"); ActivateSubContext(new MessageViewModel("Error: Root Key Hash in Qualcomm Emergency mode does not match!", Callback)); return; } // This action is executed after the user selected the resources. Action ReturnFunctionD = (FFUPath, LoadersPath, SBL3Path, ProfileFFUPath, EDEPath, SupportedFFUPath, DoFixBoot) => { IsSwitchingInterface = true; State = MachineState.LumiaUnlockBoot; // This is a callback on the UI thread // Resources are confirmed by user this.FFUPath = FFUPath; this.LoadersPath = LoadersPath; this.SBL3Path = SBL3Path; StorePaths(); LogFile.Log("Processing resources:"); LogFile.Log("FFU: " + FFUPath); LogFile.Log("Loaders: " + LoadersPath); if (SBL3Path == null) LogFile.Log("No SBL3 specified"); else LogFile.Log("SBL3: " + SBL3Path); ActivateSubContext(new BusyViewModel("Processing resources...")); if (DoUnlock) { Task.Run(async () => { await LumiaUnlockBootloaderViewModel.LumiaV1UnlockFirmware(PhoneNotifier, FFUPath, LoadersPath, SBL3Path, SupportedFFUPath, SetWorkingStatus, UpdateWorkingStatus, ExitMessage, ExitMessage); }); } else { Task.Run(async () => { await LumiaUnlockBootloaderViewModel.LumiaV1RelockFirmware(PhoneNotifier, FFUPath, LoadersPath, SetWorkingStatus, UpdateWorkingStatus, ExitMessage, ExitMessage); }); } }; if (DoUnlock) ActivateSubContext(new BootUnlockResourcesViewModel("Qualcomm Emergency Download mode", RootKeyHash, SwitchToFlashRom, SwitchToUndoRoot, SwitchToDownload, ReturnFunctionD, Abort, IsBootLoaderUnlocked, false)); else ActivateSubContext(new BootRestoreResourcesViewModel("Qualcomm Emergency Download mode", RootKeyHash, SwitchToFlashRom, SwitchToUndoRoot, SwitchToDownload, ReturnFunctionD, Abort, IsBootLoaderUnlocked, false)); break; case PhoneInterfaces.Qualcomm_Flash: { IsSwitchingInterface = true; State = MachineState.LumiaUnlockBoot; ActivateSubContext(new BusyViewModel("Recovering resources...")); LogFile.Log("Phone was unexpectedly detected in this mode while resources were not loaded yet."); LogFile.Log("WPInternals tool probably crashed in previous session."); LogFile.Log("Trying to recover resources from the registry."); FFUPath = (string)Registry.GetValue(@"HKEY_CURRENT_USER\Software\WPInternals", "FFUPath", null); SupportedFFUPath = (string)Registry.GetValue(@"HKEY_CURRENT_USER\Software\WPInternals", "SupportedFFUPath", null); LoadersPath = (string)Registry.GetValue(@"HKEY_CURRENT_USER\Software\WPInternals", "LoadersPath", null); if (DoUnlock) SBL3Path = (string)Registry.GetValue(@"HKEY_CURRENT_USER\Software\WPInternals", "SBL3Path", null); else SBL3Path = null; if (DoUnlock) { Task.Run(async () => { await LumiaUnlockBootloaderViewModel.LumiaV1UnlockFirmware(PhoneNotifier, FFUPath, LoadersPath, SBL3Path, SupportedFFUPath, SetWorkingStatus, UpdateWorkingStatus, ExitMessage, ExitMessage); }); } else { Task.Run(async () => { await LumiaUnlockBootloaderViewModel.LumiaV1RelockFirmware(PhoneNotifier, FFUPath, LoadersPath, SetWorkingStatus, UpdateWorkingStatus, ExitMessage, ExitMessage); }); } break; } default: // Show View "Waiting for connection" IsSwitchingInterface = false; ActivateSubContext(null); break; } } } private void SwitchToFlashMode() { // SwitchModeViewModel must be created on the UI thread IsSwitchingInterface = true; UIContext.Post(async (t) => { LogFile.Log("Switching to Flash-mode"); try { await SwitchModeViewModel.SwitchToWithProgress(PhoneNotifier, PhoneInterfaces.Lumia_Flash, (msg, sub) => ActivateSubContext(new BusyViewModel(msg, sub))); } catch (Exception Ex) { ActivateSubContext(new MessageViewModel(Ex.Message, Callback)); } }, null); } private void Abort() { // SwitchModeViewModel must be created on the UI thread IsSwitchingInterface = false; UIContext.Post((t) => { StorePaths(); LogFile.Log("Aborting."); Exit(); }, null); } private void StorePaths() { RegistryKey Key = Registry.CurrentUser.OpenSubKey(@"Software\WPInternals", true); if (Key == null) Key = Registry.CurrentUser.CreateSubKey(@"Software\WPInternals"); if (FFUPath == null) { if (Key.GetValue("FFUPath") != null) Key.DeleteValue("FFUPath"); } else Key.SetValue("FFUPath", FFUPath); if (LoadersPath == null) { if (Key.GetValue("LoadersPath") != null) Key.DeleteValue("LoadersPath"); } else Key.SetValue("LoadersPath", LoadersPath); if (DoUnlock) { if (SBL3Path == null) { if (Key.GetValue("SBL3Path") != null) Key.DeleteValue("SBL3Path"); } else Key.SetValue("SBL3Path", SBL3Path); } if (ProfileFFUPath == null) { if (Key.GetValue("ProfileFFUPath") != null) Key.DeleteValue("ProfileFFUPath"); } else { Key.SetValue("ProfileFFUPath", ProfileFFUPath); App.Config.AddFfuToRepository(ProfileFFUPath); } if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Qualcomm_Download && PhoneNotifier.CurrentInterface != PhoneInterfaces.Qualcomm_Flash) { NokiaFlashModel Model = (NokiaFlashModel)PhoneNotifier.CurrentModel; PhoneInfo Info = Model.ReadPhoneInfo(); if (EDEPath == null) { if (Key.GetValue("EDEPath") != null) Key.DeleteValue("EDEPath"); } else { Key.SetValue("EDEPath", EDEPath); App.Config.AddEmergencyToRepository(Info.Type, EDEPath, null); } } if (SupportedFFUPath != null) { Key.SetValue("SupportedFFUPath", SupportedFFUPath); App.Config.AddFfuToRepository(SupportedFFUPath); } Key.Close(); } private void Exit() { IsSwitchingInterface = false; // From here on a device will be forced to Flash mode again on this screen which is meant for flashing FFUPath = null; LoadersPath = null; SBL3Path = null; Callback(); ActivateSubContext(null); } internal void ExitMessage(string Message, string SubMessage) { // SecureBoot Unlock v2 is done. Reactivate phone arrival events. MessageViewModel SuccessMessageViewModel = new MessageViewModel(Message, () => { State = MachineState.Default; Exit(); }); SuccessMessageViewModel.SubMessage = SubMessage; ActivateSubContext(SuccessMessageViewModel); } void NewDeviceArrived(ArrivalEventArgs Args) { // Do not start on a new thread, because EvaluateViewState will also create new ViewModels and those should be created on the UI thread. EvaluateViewState(); } } internal class BootUnlockResourcesViewModel : FlashResourcesViewModel { internal BootUnlockResourcesViewModel(string CurrentMode, byte[] RootKeyHash, Action SwitchToFlashRom, Action SwitchToUndoRoot, Action SwitchToDownload, Action Result, Action Abort, bool IsBootLoaderUnlocked, bool TargetHasNewFlashProtocol, string PlatformID = null, string ProductType = null) : base(CurrentMode, RootKeyHash, SwitchToFlashRom, SwitchToUndoRoot, SwitchToDownload, Result, Abort, IsBootLoaderUnlocked, TargetHasNewFlashProtocol, PlatformID, ProductType) { SBL3Path = (string)Registry.GetValue(@"HKEY_CURRENT_USER\Software\WPInternals", "SBL3Path", null); } } internal class BootRestoreResourcesViewModel : FlashResourcesViewModel { internal BootRestoreResourcesViewModel(string CurrentMode, byte[] RootKeyHash, Action SwitchToFlashRom, Action SwitchToUndoRoot, Action SwitchToDownload, Action Result, Action Abort, bool IsBootLoaderUnlocked, bool TargetHasNewFlashProtocol, string PlatformID = null, string ProductType = null) : base(CurrentMode, RootKeyHash, SwitchToFlashRom, SwitchToUndoRoot, SwitchToDownload, Result, Abort, IsBootLoaderUnlocked, TargetHasNewFlashProtocol, PlatformID, ProductType) { SBL3Path = null; } } internal class FlashResourcesViewModel : ContextViewModel { internal Action SwitchToFlashRom; internal Action SwitchToUndoRoot; internal Action SwitchToDownload; private string PlatformID; private string ProductType; private string ValidatedSupportedFfuPath = null; internal FlashResourcesViewModel(string CurrentMode, byte[] RootKeyHash, Action SwitchToFlashRom, Action SwitchToUndoRoot, Action SwitchToDownload, Action Result, Action Abort, bool IsBootLoaderUnlocked, bool TargetHasNewFlashProtocol, string PlatformID = null, string ProductType = null) : base() { IsSwitchingInterface = true; this.CurrentMode = CurrentMode; this.RootKeyHash = RootKeyHash; this.PlatformID = PlatformID; this.ProductType = ProductType; this.SwitchToFlashRom = SwitchToFlashRom; this.SwitchToUndoRoot = SwitchToUndoRoot; this.SwitchToDownload = SwitchToDownload; this.IsBootLoaderUnlocked = IsBootLoaderUnlocked; OkCommand = new DelegateCommand(() => Result(FFUPath, LoadersPath, SBL3Path, ProfileFFUPath, EDEPath, IsSupportedFfuNeeded ? SupportedFFUPath : null, false), () => (!TargetHasNewFlashProtocol && (!IsSupportedFfuNeeded || (IsSupportedFfuValid && (SupportedFFUPath != null))) || ((ProfileFFUPath != null) && (!IsSupportedFfuNeeded || (IsSupportedFfuValid && (SupportedFFUPath != null)))))); FixCommand = new DelegateCommand(() => Result(null, null, null, null, null, null, true)); CancelCommand = new DelegateCommand(Abort); this.TargetHasNewFlashProtocol = TargetHasNewFlashProtocol; if (TargetHasNewFlashProtocol) { SetProfileFFUPath(); SetEDEPath(); } else { FFUPath = (string)Registry.GetValue(@"HKEY_CURRENT_USER\Software\WPInternals", "FFUPath", null); SupportedFFUPath = (string)Registry.GetValue(@"HKEY_CURRENT_USER\Software\WPInternals", "SupportedFFUPath", null); LoadersPath = (string)Registry.GetValue(@"HKEY_CURRENT_USER\Software\WPInternals", "LoadersPath", null); } } private void SetProfileFFUPath() { FFU ProfileFFU; try { if (_ProfileFFUPath != null) { ProfileFFU = new FFU(_ProfileFFUPath); if (PlatformID.StartsWith(ProfileFFU.PlatformID, StringComparison.OrdinalIgnoreCase)) { IsProfileFfuValid = true; return; } } } catch { } try { string TempProfileFFUPath = (string)Registry.GetValue(@"HKEY_CURRENT_USER\Software\WPInternals", "ProfileFFUPath", null); if (TempProfileFFUPath != null) { ProfileFFU = new FFU(TempProfileFFUPath); if (PlatformID.StartsWith(ProfileFFU.PlatformID, StringComparison.OrdinalIgnoreCase)) { ProfileFFUPath = TempProfileFFUPath; IsProfileFfuValid = true; return; } } } catch { } List FFUs = App.Config.FFURepository.Where(e => (PlatformID.StartsWith(e.PlatformID, StringComparison.OrdinalIgnoreCase) && e.Exists())).ToList(); if (FFUs.Count() > 0) { IsProfileFfuValid = true; ProfileFFUPath = FFUs[0].Path; } else IsProfileFfuValid = false; } private void SetEDEPath() { QualcommPartition Programmer; string TempEDEPath; try { if (_EDEPath != null) { Programmer = new QualcommPartition(_EDEPath); if (ByteOperations.Compare(Programmer.RootKeyHash, RootKeyHash)) return; } } catch { } try { TempEDEPath = (string)Registry.GetValue(@"HKEY_CURRENT_USER\Software\WPInternals", "EDEPath", null); if (TempEDEPath != null) { Programmer = new QualcommPartition(TempEDEPath); if (ByteOperations.Compare(Programmer.RootKeyHash, RootKeyHash)) { EDEPath = TempEDEPath; return; } } } catch { } TempEDEPath = LumiaV2UnlockBootViewModel.GetProgrammerPath(RootKeyHash, ProductType); if (TempEDEPath != null) { Programmer = new QualcommPartition(TempEDEPath); if (ByteOperations.Compare(Programmer.RootKeyHash, RootKeyHash)) { EDEPath = TempEDEPath; return; } } } private void SetSupportedFFUPath() { if (!TargetHasNewFlashProtocol) { if (this is BootRestoreResourcesViewModel) { IsSupportedFfuNeeded = false; return; } try { FFU FFU = new FFU(_FFUPath); IsSupportedFfuNeeded = !(App.PatchEngine.PatchDefinitions.Where(p => p.Name == "SecureBootHack-V1.1-EFIESP").First().TargetVersions.Any(v => v.Description == FFU.GetOSVersion())); } catch { IsSupportedFfuNeeded = false; return; } if (IsSupportedFfuNeeded) { FFU SupportedFFU; try { if (_SupportedFFUPath != null) { SupportedFFU = new FFU(_SupportedFFUPath); if (App.PatchEngine.PatchDefinitions.Where(p => p.Name == "SecureBootHack-V1.1-EFIESP").First().TargetVersions.Any(v => v.Description == SupportedFFU.GetOSVersion())) return; } } catch { } try { string TempSupportedFFUPath = (string)Registry.GetValue(@"HKEY_CURRENT_USER\Software\WPInternals", "SupportedFFUPath", null); if (TempSupportedFFUPath != null) { SupportedFFU = new FFU(TempSupportedFFUPath); if (App.PatchEngine.PatchDefinitions.Where(p => p.Name == "SecureBootHack-V1.1-EFIESP").First().TargetVersions.Any(v => v.Description == SupportedFFU.GetOSVersion())) { ValidatedSupportedFfuPath = TempSupportedFFUPath; SupportedFFUPath = TempSupportedFFUPath; IsSupportedFfuValid = true; return; } } } catch { } List FFUs = App.Config.FFURepository.Where(e => App.PatchEngine.PatchDefinitions.Where(p => p.Name == "SecureBootHack-V1.1-EFIESP").First().TargetVersions.Any(v => v.Description == e.OSVersion)).ToList(); if (FFUs.Count() > 0) { ValidatedSupportedFfuPath = FFUs[0].Path; SupportedFFUPath = FFUs[0].Path; IsSupportedFfuValid = true; } } } else { if ((this is BootRestoreResourcesViewModel) || (_ProfileFFUPath == null)) { IsSupportedFfuNeeded = false; return; } try { FFU ProfileFFU = new FFU(_ProfileFFUPath); IsSupportedFfuNeeded = !(App.PatchEngine.PatchDefinitions.Where(p => p.Name == "SecureBootHack-V2-EFIESP").First().TargetVersions.Any(v => v.Description == ProfileFFU.GetOSVersion())); } catch { IsSupportedFfuNeeded = false; return; } if (IsSupportedFfuNeeded) { FFU SupportedFFU; try { if (_SupportedFFUPath != null) { SupportedFFU = new FFU(_SupportedFFUPath); if (App.PatchEngine.PatchDefinitions.Where(p => p.Name == "SecureBootHack-V2-EFIESP").First().TargetVersions.Any(v => v.Description == SupportedFFU.GetOSVersion())) return; } } catch { } try { string TempSupportedFFUPath = (string)Registry.GetValue(@"HKEY_CURRENT_USER\Software\WPInternals", "SupportedFFUPath", null); if (TempSupportedFFUPath != null) { SupportedFFU = new FFU(TempSupportedFFUPath); if (App.PatchEngine.PatchDefinitions.Where(p => p.Name == "SecureBootHack-V2-EFIESP").First().TargetVersions.Any(v => v.Description == SupportedFFU.GetOSVersion())) { ValidatedSupportedFfuPath = TempSupportedFFUPath; SupportedFFUPath = TempSupportedFFUPath; IsSupportedFfuValid = true; return; } } } catch { } List FFUs = App.Config.FFURepository.Where(e => App.PatchEngine.PatchDefinitions.Where(p => p.Name == "SecureBootHack-V2-EFIESP").First().TargetVersions.Any(v => v.Description == e.OSVersion)).ToList(); if (FFUs.Count() > 0) { ValidatedSupportedFfuPath = FFUs[0].Path; SupportedFFUPath = FFUs[0].Path; IsSupportedFfuValid = true; } } } } private void ValidateSupportedFfuPath() { try { if (IsSupportedFfuNeeded) { if (SupportedFFUPath == null) { IsSupportedFfuValid = true; // No visible warning when there is no SupportedFFU selected yet. } else { if (!TargetHasNewFlashProtocol) { if (App.Config.FFURepository.Any(e => ((e.Path == SupportedFFUPath) && (App.PatchEngine.PatchDefinitions.Where(p => p.Name == "SecureBootHack-V1.1-EFIESP").First().TargetVersions.Any(v => v.Description == e.OSVersion))))) { IsSupportedFfuValid = true; } else { FFU SupportedFFU = new FFU(SupportedFFUPath); if (App.PatchEngine.PatchDefinitions.Where(p => p.Name == "SecureBootHack-V1.1-EFIESP").First().TargetVersions.Any(v => v.Description == SupportedFFU.GetOSVersion())) { IsSupportedFfuValid = true; } else { IsSupportedFfuValid = false; } } } else { if (App.Config.FFURepository.Any(e => ((e.Path == SupportedFFUPath) && (App.PatchEngine.PatchDefinitions.Where(p => p.Name == "SecureBootHack-V2-EFIESP").First().TargetVersions.Any(v => v.Description == e.OSVersion))))) { IsSupportedFfuValid = true; } else { FFU SupportedFFU = new FFU(SupportedFFUPath); if (App.PatchEngine.PatchDefinitions.Where(p => p.Name == "SecureBootHack-V2-EFIESP").First().TargetVersions.Any(v => v.Description == SupportedFFU.GetOSVersion())) { IsSupportedFfuValid = true; } else { IsSupportedFfuValid = false; } } } } } else { IsSupportedFfuValid = true; } if (IsSupportedFfuValid && (SupportedFFUPath != null)) ValidatedSupportedFfuPath = SupportedFFUPath; } catch { IsSupportedFfuValid = false; } } private bool _IsSupportedFfuNeeded = false; public bool IsSupportedFfuNeeded { get { return _IsSupportedFfuNeeded; } set { _IsSupportedFfuNeeded = value; OnPropertyChanged("IsSupportedFfuNeeded"); OkCommand.RaiseCanExecuteChanged(); } } private bool _IsSupportedFfuValid = true; public bool IsSupportedFfuValid { get { return _IsSupportedFfuValid; } set { _IsSupportedFfuValid = value; OnPropertyChanged("IsSupportedFfuValid"); OkCommand.RaiseCanExecuteChanged(); } } private bool _IsProfileFfuValid = true; public bool IsProfileFfuValid { get { return _IsProfileFfuValid; } set { _IsProfileFfuValid = value; OnPropertyChanged("IsProfileFfuValid"); } } private bool _TargetHasNewFlashProtocol = false; public bool TargetHasNewFlashProtocol { get { return _TargetHasNewFlashProtocol; } set { _TargetHasNewFlashProtocol = value; OnPropertyChanged("TargetHasNewFlashProtocol"); OkCommand.RaiseCanExecuteChanged(); } } private bool _IsBootLoaderUnlocked = false; public bool IsBootLoaderUnlocked { get { return _IsBootLoaderUnlocked; } set { _IsBootLoaderUnlocked = value; OnPropertyChanged("IsBootLoaderUnlocked"); } } private string _FFUPath = null; public string FFUPath { get { return _FFUPath; } set { _FFUPath = value; OnPropertyChanged("FFUPath"); SetSupportedFFUPath(); OkCommand.RaiseCanExecuteChanged(); } } private string _ProfileFFUPath = null; public string ProfileFFUPath { get { return _ProfileFFUPath; } set { if (_ProfileFFUPath != value) { _ProfileFFUPath = value; OnPropertyChanged("ProfileFFUPath"); SetSupportedFFUPath(); OkCommand.RaiseCanExecuteChanged(); } } } private string _SupportedFFUPath = null; public string SupportedFFUPath { get { return _SupportedFFUPath; } set { if (_SupportedFFUPath != value) { _SupportedFFUPath = value; OnPropertyChanged("SupportedFFUPath"); if (value != ValidatedSupportedFfuPath) ValidateSupportedFfuPath(); } } } private string _LoadersPath = null; public string LoadersPath { get { return _LoadersPath; } set { _LoadersPath = value; OnPropertyChanged("LoadersPath"); } } private string _EDEPath = null; public string EDEPath { get { return _EDEPath; } set { _EDEPath = value; OnPropertyChanged("EDEPath"); } } private string _SBL3Path = null; public string SBL3Path { get { return _SBL3Path; } set { _SBL3Path = value; OnPropertyChanged("SBL3Path"); } } private string _CurrentMode = null; public string CurrentMode { get { return _CurrentMode; } set { _CurrentMode = value; OnPropertyChanged("CurrentMode"); } } private byte[] _RootKeyHash = null; public byte[] RootKeyHash { get { return _RootKeyHash; } set { _RootKeyHash = value; OnPropertyChanged("RootKeyHash"); } } private DelegateCommand _OkCommand = null; public DelegateCommand OkCommand { get { return _OkCommand; } private set { _OkCommand = value; } } private DelegateCommand _CancelCommand = null; public DelegateCommand CancelCommand { get { return _CancelCommand; } private set { _CancelCommand = value; } } private DelegateCommand _FixCommand = null; public DelegateCommand FixCommand { get { return _FixCommand; } private set { _FixCommand = value; } } } }