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 <QualcommPartition> 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(); }
// 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)) { 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 <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; } } }