mirror of
https://github.com/ReneLergner/WPinternals.git
synced 2026-06-14 03:16:40 +10:00
774ff9956f
This new flashing hack exploits a bug in flash app where it will not properly check the integrity of catalog files used in FFU files
1112 lines
49 KiB
C#
1112 lines
49 KiB
C#
// 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<string, string, string, string, string, string, bool> 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))
|
|
{
|
|
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<string, string, string, string, string, string, bool> 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<FFUEntry> 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<string, string, string, string, string, string, bool> 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<string, string, string, string, string, string, bool> 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<string, string, string, string, string, string, bool> 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<string, string, string, string, string, string, bool> 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<FFUEntry> 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<FFUEntry> 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<FFUEntry> 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;
|
|
}
|
|
}
|
|
}
|
|
}
|