Beispiel #1
0
        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;
                }
            }
        }