mirror of
https://github.com/ReneLergner/WPinternals.git
synced 2026-06-14 03:16:40 +10:00
wip: Refactor FlashApp Logic to account for the 3 split app states
This commit is contained in:
+37
-29
@@ -83,7 +83,8 @@ namespace WPinternals
|
||||
{
|
||||
FFU FFU = null;
|
||||
PhoneNotifierViewModel Notifier;
|
||||
NokiaFlashModel FlashModel;
|
||||
LumiaFlashAppModel FlashModel;
|
||||
LumiaBootManagerAppModel BootMgrModel;
|
||||
NokiaPhoneModel NormalModel;
|
||||
PhoneInfo Info;
|
||||
string ProductType;
|
||||
@@ -182,23 +183,14 @@ namespace WPinternals
|
||||
Notifier = new PhoneNotifierViewModel();
|
||||
UIContext.Send(s => Notifier.Start(), null);
|
||||
|
||||
FlashModel = (NokiaFlashModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Bootloader); // This also works for Bootloader Spec A
|
||||
BootMgrModel = (LumiaBootManagerAppModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Bootloader); // This also works for Bootloader Spec A
|
||||
|
||||
GPT GPT = FlashModel.ReadGPT(); // May throw NotSupportedException
|
||||
GPT GPT = BootMgrModel.ReadGPT(); // May throw NotSupportedException
|
||||
foreach (Partition Partition in GPT.Partitions)
|
||||
{
|
||||
LogFile.Log(Partition.Name.PadRight(20) + "0x" + Partition.FirstSector.ToString("X8") + " - 0x" + Partition.LastSector.ToString("X8") + " " + Partition.Volume, LogType.ConsoleOnly);
|
||||
}
|
||||
|
||||
if (FlashModel.ReadPhoneInfo(false).FlashAppProtocolVersionMajor >= 2)
|
||||
{
|
||||
FlashModel.SwitchToFlashAppContext();
|
||||
}
|
||||
else
|
||||
{
|
||||
await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
}
|
||||
|
||||
Notifier.Stop();
|
||||
}
|
||||
catch (Exception Ex)
|
||||
@@ -221,15 +213,14 @@ namespace WPinternals
|
||||
{
|
||||
Notifier = new PhoneNotifierViewModel();
|
||||
UIContext.Send(s => Notifier.Start(), null);
|
||||
FlashModel = (NokiaFlashModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
GPT GPT = FlashModel.ReadGPT(); // May throw NotSupportedException
|
||||
BootMgrModel = (LumiaBootManagerAppModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Bootloader);
|
||||
GPT GPT = BootMgrModel.ReadGPT(); // May throw NotSupportedException
|
||||
string DirPath = Path.GetDirectoryName(args[2]);
|
||||
if (!string.IsNullOrEmpty(DirPath) && !Directory.Exists(DirPath))
|
||||
{
|
||||
Directory.CreateDirectory(DirPath);
|
||||
}
|
||||
GPT.WritePartitions(args[2]);
|
||||
FlashModel.SwitchToFlashAppContext();
|
||||
Notifier.Stop();
|
||||
}
|
||||
catch (Exception Ex)
|
||||
@@ -281,14 +272,13 @@ namespace WPinternals
|
||||
{
|
||||
Notifier = new PhoneNotifierViewModel();
|
||||
UIContext.Send(s => Notifier.Start(), null);
|
||||
FlashModel = (NokiaFlashModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
byte[] GptChunk = LumiaUnlockBootloaderViewModel.GetGptChunk(FlashModel, 0x20000);
|
||||
BootMgrModel = (LumiaBootManagerAppModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Bootloader);
|
||||
byte[] GptChunk = BootMgrModel.GetGptChunk(0x20000);
|
||||
GPT GPT = new(GptChunk);
|
||||
string Xml = File.ReadAllText(args[2]);
|
||||
GPT.MergePartitions(Xml, false);
|
||||
GPT.Rebuild();
|
||||
await LumiaV2UnlockBootViewModel.LumiaV2CustomFlash(Notifier, null, false, false, 0, GptChunk, true, true);
|
||||
FlashModel.SwitchToFlashAppContext();
|
||||
Notifier.Stop();
|
||||
}
|
||||
catch (Exception Ex)
|
||||
@@ -552,7 +542,7 @@ namespace WPinternals
|
||||
try
|
||||
{
|
||||
UIContext.Send(s => Notifier.Start(), null);
|
||||
FlashModel = (NokiaFlashModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
FlashModel = (LumiaFlashAppModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
Info = FlashModel.ReadPhoneInfo();
|
||||
Info.Log(LogType.ConsoleOnly);
|
||||
|
||||
@@ -701,7 +691,7 @@ namespace WPinternals
|
||||
LogFile.Log("Command: Show phone info", LogType.FileAndConsole);
|
||||
Notifier = new PhoneNotifierViewModel();
|
||||
UIContext.Send(s => Notifier.Start(), null);
|
||||
FlashModel = (NokiaFlashModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
FlashModel = (LumiaFlashAppModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
Info = FlashModel.ReadPhoneInfo();
|
||||
Info.Log(LogType.ConsoleOnly);
|
||||
Notifier.Stop();
|
||||
@@ -713,7 +703,7 @@ namespace WPinternals
|
||||
LogFile.Log("Command: Unlock Bootloader", LogType.FileAndConsole);
|
||||
Notifier = new PhoneNotifierViewModel();
|
||||
UIContext.Send(s => Notifier.Start(), null);
|
||||
FlashModel = (NokiaFlashModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
FlashModel = (LumiaFlashAppModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
Info = FlashModel.ReadPhoneInfo();
|
||||
Info.Log(LogType.ConsoleOnly);
|
||||
|
||||
@@ -786,7 +776,7 @@ namespace WPinternals
|
||||
LogFile.Log("Custom ROM: " + CustomRomPath, LogType.FileAndConsole);
|
||||
Notifier = new PhoneNotifierViewModel();
|
||||
UIContext.Send(s => Notifier.Start(), null);
|
||||
FlashModel = (NokiaFlashModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
FlashModel = (LumiaFlashAppModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
Info = FlashModel.ReadPhoneInfo();
|
||||
Info.Log(LogType.ConsoleOnly);
|
||||
LogFile.Log("Preparing to flash Custom ROM", LogType.FileAndConsole);
|
||||
@@ -817,7 +807,7 @@ namespace WPinternals
|
||||
LogFile.Log("FFU file: " + FFUPath, LogType.FileAndConsole);
|
||||
Notifier = new PhoneNotifierViewModel();
|
||||
UIContext.Send(s => Notifier.Start(), null);
|
||||
FlashModel = (NokiaFlashModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
FlashModel = (LumiaFlashAppModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
Info = FlashModel.ReadPhoneInfo();
|
||||
Info.Log(LogType.ConsoleOnly);
|
||||
LogFile.Log("Flashing FFU...", LogType.FileAndConsole);
|
||||
@@ -1283,9 +1273,15 @@ namespace WPinternals
|
||||
NormalModel = (NokiaPhoneModel)Notifier.CurrentModel;
|
||||
ProductCode = NormalModel.ExecuteJsonMethodAsString("ReadProductCode", "ProductCode");
|
||||
}
|
||||
else if ((Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) || (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Flash))
|
||||
else if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
FlashModel = (NokiaFlashModel)Notifier.CurrentModel;
|
||||
BootMgrModel = (LumiaBootManagerAppModel)Notifier.CurrentModel;
|
||||
Info = BootMgrModel.ReadPhoneInfo();
|
||||
ProductCode = Info.ProductCode;
|
||||
}
|
||||
else if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Flash)
|
||||
{
|
||||
FlashModel = (LumiaFlashAppModel)Notifier.CurrentModel;
|
||||
Info = FlashModel.ReadPhoneInfo();
|
||||
ProductCode = Info.ProductCode;
|
||||
}
|
||||
@@ -1448,9 +1444,15 @@ namespace WPinternals
|
||||
ProductType = ProductType.Substring(0, ProductType.IndexOf('_'));
|
||||
}
|
||||
}
|
||||
else if ((Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) || (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Flash))
|
||||
else if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
FlashModel = (NokiaFlashModel)Notifier.CurrentModel;
|
||||
BootMgrModel = (LumiaBootManagerAppModel)Notifier.CurrentModel;
|
||||
Info = BootMgrModel.ReadPhoneInfo();
|
||||
ProductType = Info.Type;
|
||||
}
|
||||
else if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Flash)
|
||||
{
|
||||
FlashModel = (LumiaFlashAppModel)Notifier.CurrentModel;
|
||||
Info = FlashModel.ReadPhoneInfo();
|
||||
ProductType = Info.Type;
|
||||
}
|
||||
@@ -1559,9 +1561,15 @@ namespace WPinternals
|
||||
NormalModel = (NokiaPhoneModel)Notifier.CurrentModel;
|
||||
ProductCode = NormalModel.ExecuteJsonMethodAsString("ReadProductCode", "ProductCode");
|
||||
}
|
||||
else if ((Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) || (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Flash))
|
||||
else if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
FlashModel = (NokiaFlashModel)Notifier.CurrentModel;
|
||||
BootMgrModel = (LumiaBootManagerAppModel)Notifier.CurrentModel;
|
||||
Info = BootMgrModel.ReadPhoneInfo();
|
||||
ProductCode = Info.ProductCode;
|
||||
}
|
||||
else if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Flash)
|
||||
{
|
||||
FlashModel = (LumiaFlashAppModel)Notifier.CurrentModel;
|
||||
Info = FlashModel.ReadPhoneInfo();
|
||||
ProductCode = Info.ProductCode;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2018, Rene Lergner - @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.
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal enum FlashAppType
|
||||
{
|
||||
BootManager = 1,
|
||||
FlashApp = 2,
|
||||
PhoneInfoApp = 3
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2018, Rene Lergner - @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.
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class FlashVersion
|
||||
{
|
||||
public int ApplicationMajor;
|
||||
public int ApplicationMinor;
|
||||
public int ProtocolMajor;
|
||||
public int ProtocolMinor;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,392 @@
|
||||
// Copyright (c) 2018, Rene Lergner - @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 System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class LumiaBootManagerAppModel : NokiaFlashModel
|
||||
{
|
||||
private readonly PhoneInfo Info = new();
|
||||
|
||||
internal enum SecureBootKeyType : byte
|
||||
{
|
||||
Retail = 0,
|
||||
Engineering = 1
|
||||
}
|
||||
|
||||
//
|
||||
// Not valid commands
|
||||
//
|
||||
/* NOK */
|
||||
private const string Signature = "NOK";
|
||||
/* NOKX */
|
||||
private const string ExtendedMessageSignature = $"{Signature}X";
|
||||
/* NOKXB */
|
||||
private const string LumiaBootManagerExtendedMessageSignature = $"{ExtendedMessageSignature}B";
|
||||
|
||||
//
|
||||
// Normal commands
|
||||
//
|
||||
/* NOKA */
|
||||
private const string ContinueBootSignature = $"{Signature}A";
|
||||
/* NOKB */
|
||||
private const string RPMBSignature = $"{Signature}B";
|
||||
/* NOKC */
|
||||
private const string BatteryStatusSignature = $"{Signature}C";
|
||||
/* NOKD */
|
||||
private const string DisableTimeoutsSignature = $"{Signature}D";
|
||||
/* NOKI */
|
||||
private const string HelloSignature = $"{Signature}I";
|
||||
/* NOKM */
|
||||
private const string RebootToMassStorageSignature = $"{Signature}M";
|
||||
/* NOKP */
|
||||
private const string RebootToPhoneInfoAppSignature = $"{Signature}P";
|
||||
/* NOKR */
|
||||
private const string RebootSignature = $"{Signature}R";
|
||||
/* NOKS */
|
||||
private const string RebootToFlashAppSignature = $"{Signature}S";
|
||||
/* NOKT */
|
||||
private const string GetGPTSignature = $"{Signature}T";
|
||||
/* NOKV */
|
||||
private const string InfoQuerySignature = $"{Signature}V";
|
||||
/* NOKW */
|
||||
private const string WriteBootFlagFileSignature = $"{Signature}W";
|
||||
/* NOKY */
|
||||
private const string MMOSStartCommandSignature = $"{Signature}Y";
|
||||
/* NOKZ */
|
||||
private const string ShutdownSignature = $"{Signature}Z";
|
||||
|
||||
//
|
||||
// Lumia Boot Manager extended commands
|
||||
//
|
||||
/* NOKXBD */
|
||||
private const string PlatformSecureBootEnableSignature = $"{LumiaBootManagerExtendedMessageSignature}D";
|
||||
/* NOKXBH */
|
||||
private const string WriteRootCertificateHashSignature = $"{LumiaBootManagerExtendedMessageSignature}H";
|
||||
/* NOKXBK */
|
||||
private const string UEFIKeysProvisionSignature = $"{LumiaBootManagerExtendedMessageSignature}K";
|
||||
/* NOKXBR */
|
||||
private const string ReadManufacturingStateSignature = $"{LumiaBootManagerExtendedMessageSignature}R";
|
||||
/* NOKXBU */
|
||||
private const string FlushVariablesSignature = $"{LumiaBootManagerExtendedMessageSignature}U";
|
||||
/* NOKXBW */
|
||||
private const string WriteManufacturingStateSignature = $"{LumiaBootManagerExtendedMessageSignature}W";
|
||||
|
||||
public LumiaBootManagerAppModel(string DevicePath) : base(DevicePath)
|
||||
{
|
||||
}
|
||||
|
||||
internal void ContinueBoot()
|
||||
{
|
||||
LogFile.Log("Continue boot...");
|
||||
byte[] Request = new byte[4];
|
||||
ByteOperations.WriteAsciiString(Request, 0, ContinueBootSignature);
|
||||
ExecuteRawVoidMethod(Request);
|
||||
}
|
||||
|
||||
internal PhoneInfo ReadPhoneInfo(bool ExtendedInfo = true)
|
||||
{
|
||||
// NOKH = Get Phone Info (IMEI and info from Product.dat) - Not available on some phones, like Lumia 640.
|
||||
// NOKV = Info Query
|
||||
|
||||
bool PhoneInfoLogged = Info.State != PhoneInfoState.Empty;
|
||||
PhoneInfo Result = Info;
|
||||
|
||||
if (Result.State == PhoneInfoState.Empty)
|
||||
{
|
||||
byte[] Request = new byte[4];
|
||||
ByteOperations.WriteAsciiString(Request, 0, InfoQuerySignature);
|
||||
byte[] Response = ExecuteRawMethod(Request);
|
||||
if ((Response != null) && (ByteOperations.ReadAsciiString(Response, 0, 4) != "NOKU"))
|
||||
{
|
||||
Result.App = (FlashAppType)Response[5];
|
||||
|
||||
switch (Result.App)
|
||||
{
|
||||
case FlashAppType.BootManager:
|
||||
Result.BootManagerProtocolVersionMajor = Response[6];
|
||||
Result.BootManagerProtocolVersionMinor = Response[7];
|
||||
Result.BootManagerVersionMajor = Response[8];
|
||||
Result.BootManagerVersionMinor = Response[9];
|
||||
break;
|
||||
case FlashAppType.FlashApp:
|
||||
Result.FlashAppProtocolVersionMajor = Response[6];
|
||||
Result.FlashAppProtocolVersionMinor = Response[7];
|
||||
Result.FlashAppVersionMajor = Response[8];
|
||||
Result.FlashAppVersionMinor = Response[9];
|
||||
break;
|
||||
case FlashAppType.PhoneInfoApp:
|
||||
Result.PhoneInfoAppProtocolVersionMajor = Response[6];
|
||||
Result.PhoneInfoAppProtocolVersionMinor = Response[7];
|
||||
Result.PhoneInfoAppVersionMajor = Response[8];
|
||||
Result.PhoneInfoAppVersionMinor = Response[9];
|
||||
break;
|
||||
}
|
||||
|
||||
byte SubblockCount = Response[10];
|
||||
int SubblockOffset = 11;
|
||||
|
||||
for (int i = 0; i < SubblockCount; i++)
|
||||
{
|
||||
byte SubblockID = Response[SubblockOffset + 0x00];
|
||||
UInt16 SubblockLength = BigEndian.ToUInt16(Response, SubblockOffset + 0x01);
|
||||
int SubblockPayloadOffset = SubblockOffset + 3;
|
||||
byte SubblockVersion;
|
||||
switch (SubblockID)
|
||||
{
|
||||
case 0x01:
|
||||
Result.TransferSize = BigEndian.ToUInt32(Response, SubblockPayloadOffset);
|
||||
break;
|
||||
case 0x02:
|
||||
Result.WriteBufferSize = BigEndian.ToUInt32(Response, SubblockPayloadOffset);
|
||||
break;
|
||||
case 0x03:
|
||||
Result.EmmcSizeInSectors = BigEndian.ToUInt32(Response, SubblockPayloadOffset);
|
||||
break;
|
||||
case 0x04:
|
||||
if (Result.App == FlashAppType.BootManager)
|
||||
{
|
||||
Result.FlashAppProtocolVersionMajor = Response[SubblockPayloadOffset + 0x00];
|
||||
Result.FlashAppProtocolVersionMinor = Response[SubblockPayloadOffset + 0x01];
|
||||
Result.FlashAppVersionMajor = Response[SubblockPayloadOffset + 0x02];
|
||||
Result.FlashAppVersionMinor = Response[SubblockPayloadOffset + 0x03];
|
||||
}
|
||||
else if (Result.App == FlashAppType.FlashApp)
|
||||
{
|
||||
Result.SdCardSizeInSectors = BigEndian.ToUInt32(Response, SubblockPayloadOffset);
|
||||
}
|
||||
break;
|
||||
case 0x05:
|
||||
Result.PlatformID = ByteOperations.ReadAsciiString(Response, (uint)SubblockPayloadOffset, SubblockLength).Trim([' ', '\0']);
|
||||
break;
|
||||
case 0x0D:
|
||||
Result.AsyncSupport = Response[SubblockPayloadOffset + 1] == 1;
|
||||
break;
|
||||
case 0x0F:
|
||||
SubblockVersion = Response[SubblockPayloadOffset]; // 0x03
|
||||
Result.PlatformSecureBootEnabled = Response[SubblockPayloadOffset + 0x01] == 0x01;
|
||||
Result.SecureFfuEnabled = Response[SubblockPayloadOffset + 0x02] == 0x01;
|
||||
Result.JtagDisabled = Response[SubblockPayloadOffset + 0x03] == 0x01;
|
||||
Result.RdcPresent = Response[SubblockPayloadOffset + 0x04] == 0x01;
|
||||
Result.Authenticated = (Response[SubblockPayloadOffset + 0x05] == 0x01) || (Response[SubblockPayloadOffset + 0x05] == 0x02);
|
||||
Result.UefiSecureBootEnabled = Response[SubblockPayloadOffset + 0x06] == 0x01;
|
||||
Result.SecondaryHardwareKeyPresent = Response[SubblockPayloadOffset + 0x07] == 0x01;
|
||||
break;
|
||||
case 0x10:
|
||||
SubblockVersion = Response[SubblockPayloadOffset]; // 0x01
|
||||
Result.SecureFfuSupportedProtocolMask = BigEndian.ToUInt16(Response, SubblockPayloadOffset + 0x01);
|
||||
break;
|
||||
case 0x1F:
|
||||
Result.MmosOverUsbSupported = Response[SubblockPayloadOffset] == 1;
|
||||
break;
|
||||
case 0x20:
|
||||
// CRC header info
|
||||
break;
|
||||
}
|
||||
SubblockOffset += SubblockLength + 3;
|
||||
}
|
||||
}
|
||||
|
||||
Result.State = PhoneInfoState.Basic;
|
||||
}
|
||||
|
||||
Result.IsBootloaderSecure = !(Info.Authenticated || Info.RdcPresent || !Info.SecureFfuEnabled);
|
||||
|
||||
if (!PhoneInfoLogged)
|
||||
{
|
||||
Result.Log(LogType.FileOnly);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal GPT ReadGPT()
|
||||
{
|
||||
// If this function is used with a locked BootMgr v1,
|
||||
// then the mode-switching should be done outside this function,
|
||||
// because the context-switches that are used here are not supported on BootMgr v1.
|
||||
|
||||
// Only works in BootLoader-mode or on unlocked bootloaders in Flash-mode!!
|
||||
|
||||
byte[] Request = new byte[0x04];
|
||||
const string Header = GetGPTSignature;
|
||||
|
||||
System.Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
|
||||
|
||||
byte[] Buffer = ExecuteRawMethod(Request);
|
||||
if ((Buffer == null) || (Buffer.Length < 0x4408))
|
||||
{
|
||||
throw new InvalidOperationException("Unable to read GPT!");
|
||||
}
|
||||
|
||||
UInt16 Error = (UInt16)((Buffer[6] << 8) + Buffer[7]);
|
||||
if (Error > 0)
|
||||
{
|
||||
throw new NotSupportedException("ReadGPT: Error 0x" + Error.ToString("X4"));
|
||||
}
|
||||
|
||||
byte[] GPTBuffer = new byte[Buffer.Length - 0x208];
|
||||
System.Buffer.BlockCopy(Buffer, 0x208, GPTBuffer, 0, 0x4200);
|
||||
|
||||
return new GPT(GPTBuffer); // NOKT message header and MBR are ignored
|
||||
}
|
||||
|
||||
internal byte[] GetGptChunk(UInt32 Size) // TODO!
|
||||
{
|
||||
// This function is also used to generate a dummy chunk to flash for testing.
|
||||
// The dummy chunk will contain the GPT, so it can be flashed to the first sectors for testing.
|
||||
byte[] GPTChunk = new byte[Size];
|
||||
|
||||
byte[] Request = new byte[0x04];
|
||||
const string Header = "NOKT";
|
||||
|
||||
System.Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
|
||||
|
||||
byte[] Buffer = ExecuteRawMethod(Request);
|
||||
if ((Buffer == null) || (Buffer.Length < 0x4408))
|
||||
{
|
||||
throw new InvalidOperationException("Unable to read GPT!");
|
||||
}
|
||||
|
||||
UInt16 Error = (UInt16)((Buffer[6] << 8) + Buffer[7]);
|
||||
if (Error > 0)
|
||||
{
|
||||
throw new NotSupportedException("ReadGPT: Error 0x" + Error.ToString("X4"));
|
||||
}
|
||||
|
||||
System.Buffer.BlockCopy(Buffer, 8, GPTChunk, 0, 0x4400);
|
||||
|
||||
return GPTChunk;
|
||||
}
|
||||
|
||||
internal void ProvisionSecureBootKeys(SecureBootKeyType KeyType) // Only for Flashmode, not BootManager mode.
|
||||
{
|
||||
byte[] Request = new byte[8];
|
||||
ByteOperations.WriteAsciiString(Request, 0, UEFIKeysProvisionSignature);
|
||||
Request[6] = 0; // Options
|
||||
Request[7] = (byte)KeyType;
|
||||
byte[] Response = ExecuteRawMethod(Request);
|
||||
UInt32 Status = ByteOperations.ReadUInt32(Response, 6);
|
||||
if (Status != 0)
|
||||
{
|
||||
ThrowFlashError((int)Status);
|
||||
}
|
||||
}
|
||||
|
||||
private void ThrowFlashError(int ErrorCode)
|
||||
{
|
||||
string SubMessage = ErrorCode switch
|
||||
{
|
||||
0x0008 => "Unsupported protocol / Invalid options",
|
||||
0x000F => "Invalid sub block count",
|
||||
0x0010 => "Invalid sub block length",
|
||||
0x0012 => "Authentication required",
|
||||
0x000E => "Invalid sub block type",
|
||||
0x0013 => "Failed async message",
|
||||
0x1000 => "Invalid header type",
|
||||
0x1001 => "FFU header contain unknown extra data",
|
||||
0x0001 => "Couldn't allocate memory",
|
||||
0x1106 => "Security header validation failed",
|
||||
0x1105 => "Invalid hash table size",
|
||||
0x1104 => "Invalid catalog size",
|
||||
0x1103 => "Invalid chunk size",
|
||||
0x1102 => "Unsupported algorithm",
|
||||
0x1101 => "Invalid struct size",
|
||||
0x1100 => "Invalid signature",
|
||||
0x1202 => "Invalid struct size",
|
||||
0x1203 => "Unsupported algorithm",
|
||||
0x1204 => "Invalid chunk size",
|
||||
0x1005 => "Data not aligned correctly",
|
||||
0x0009 => "Locate protocol failed",
|
||||
0x1003 => "Hash mismatch",
|
||||
0x1006 => "Couldn't find hash from security header for index",
|
||||
0x1004 => "Security header import missing / All FFU headers have not been imported",
|
||||
0x1304 => "Invalid platform ID",
|
||||
0x1307 => "Invalid write descriptor info",
|
||||
0x1306 => "Invalid write descriptor info",
|
||||
0x1305 => "Invalid block size",
|
||||
0x1303 => "Unsupported FFU version",
|
||||
0x1302 => "Unsupported struct version",
|
||||
0x1301 => "Invalid update type",
|
||||
0x100B => "Too much payload data, all data has already been written",
|
||||
0x1008 => "Internal error",
|
||||
0x1007 => "Payload data does not contain all data",
|
||||
0x0004 => "Flash write failed",
|
||||
0x000D => "Flash verify failed",
|
||||
0x0002 => "Flash read failed",
|
||||
_ => "Unknown error",
|
||||
};
|
||||
WPinternalsException Ex = new("Flash failed!");
|
||||
Ex.SubMessage = "Error 0x" + ErrorCode.ToString("X4") + ": " + SubMessage;
|
||||
|
||||
throw Ex;
|
||||
}
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
byte[] Request = new byte[4];
|
||||
const string Header = ShutdownSignature;
|
||||
Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
|
||||
ExecuteRawMethod(Request);
|
||||
}
|
||||
|
||||
internal void ResetPhone()
|
||||
{
|
||||
LogFile.Log("Rebooting phone", LogType.FileAndConsole);
|
||||
try
|
||||
{
|
||||
byte[] Request = new byte[4];
|
||||
ByteOperations.WriteAsciiString(Request, 0, RebootSignature);
|
||||
ExecuteRawVoidMethod(Request);
|
||||
}
|
||||
catch
|
||||
{
|
||||
LogFile.Log("Sending reset-request failed", LogType.FileOnly);
|
||||
LogFile.Log("Assuming automatic reset already in progress", LogType.FileOnly);
|
||||
}
|
||||
}
|
||||
|
||||
internal void ResetPhoneToFlashMode()
|
||||
{
|
||||
// This only works when the phone is in BootMgr mode. If it is already in FlashApp, it will not reboot. It only makes the phone unresponsive.
|
||||
LogFile.Log("Rebooting phone to Flash mode...");
|
||||
byte[] Request = new byte[4];
|
||||
ByteOperations.WriteAsciiString(Request, 0, RebootToFlashAppSignature);
|
||||
ExecuteRawVoidMethod(Request);
|
||||
}
|
||||
|
||||
internal void SwitchToPhoneInfoAppContextLegacy()
|
||||
{
|
||||
byte[] Request = new byte[4];
|
||||
ByteOperations.WriteAsciiString(Request, 0, RebootToPhoneInfoAppSignature);
|
||||
ExecuteRawVoidMethod(Request);
|
||||
}
|
||||
|
||||
internal void RebootToFlashApp()
|
||||
{
|
||||
byte[] Request = new byte[4];
|
||||
ByteOperations.WriteAsciiString(Request, 0, "NOKS"); // This will let the phone charge
|
||||
ExecuteRawVoidMethod(Request); // On phone with bootloader Spec A this triggers a reboot, so DisableRebootTimeOut() cannot be called immediately.
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,248 @@
|
||||
// Copyright (c) 2018, Rene Lergner - @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 System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class LumiaPhoneInfoAppModel : NokiaFlashModel
|
||||
{
|
||||
private readonly PhoneInfo Info = new();
|
||||
|
||||
//
|
||||
// Not valid commands
|
||||
//
|
||||
/* NOK */
|
||||
private const string Signature = "NOK";
|
||||
/* NOKX */
|
||||
private const string ExtendedMessageSignature = $"{Signature}X";
|
||||
/* NOKXP */
|
||||
private const string PhoneInfoAppExtendedMessageSignature = $"{ExtendedMessageSignature}P";
|
||||
|
||||
//
|
||||
// Normal commands
|
||||
//
|
||||
/* NOKA */
|
||||
private const string ContinueBootSignature = $"{Signature}A";
|
||||
/* NOKD */
|
||||
private const string DisableTimeoutsSignature = $"{Signature}D";
|
||||
/* NOKH */
|
||||
private const string GetPhoneInfoSignature = $"{Signature}H";
|
||||
/* NOKI */
|
||||
private const string HelloSignature = $"{Signature}I";
|
||||
/* NOKV */
|
||||
private const string InfoQuerySignature = $"{Signature}V";
|
||||
|
||||
//
|
||||
// Phone Info App extended commands
|
||||
//
|
||||
/* NOKXPH */
|
||||
private const string GetVariableSignature = $"{PhoneInfoAppExtendedMessageSignature}H";
|
||||
|
||||
public LumiaPhoneInfoAppModel(string DevicePath) : base(DevicePath)
|
||||
{
|
||||
}
|
||||
|
||||
internal void ContinueBoot()
|
||||
{
|
||||
LogFile.Log("Continue boot...");
|
||||
byte[] Request = new byte[4];
|
||||
ByteOperations.WriteAsciiString(Request, 0, ContinueBootSignature);
|
||||
ExecuteRawVoidMethod(Request);
|
||||
}
|
||||
|
||||
internal string GetPhoneInfo()
|
||||
{
|
||||
// NOKH = Get Phone Info (IMEI and info from Product.dat) - Not available on some phones, like Lumia 640.
|
||||
// NOKV = Info Query
|
||||
|
||||
if (Info.FlashAppProtocolVersionMajor >= 2)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] Request = new byte[4];
|
||||
ByteOperations.WriteAsciiString(Request, 0, GetPhoneInfoSignature);
|
||||
byte[] Response = ExecuteRawMethod(Request);
|
||||
if ((Response == null) || (ByteOperations.ReadAsciiString(Response, 0, 4) == "NOKU"))
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
UInt16 Length = BigEndian.ToUInt16(Response, 0x04);
|
||||
|
||||
string PhoneInfoData = ByteOperations.ReadAsciiString(Response, 0x8, Length);
|
||||
|
||||
return PhoneInfoData;
|
||||
}
|
||||
|
||||
internal PhoneInfo ReadPhoneInfo(bool ExtendedInfo = true)
|
||||
{
|
||||
// NOKH = Get Phone Info (IMEI and info from Product.dat) - Not available on some phones, like Lumia 640.
|
||||
// NOKV = Info Query
|
||||
|
||||
bool PhoneInfoLogged = Info.State != PhoneInfoState.Empty;
|
||||
PhoneInfo Result = Info;
|
||||
|
||||
if (Result.State == PhoneInfoState.Empty)
|
||||
{
|
||||
byte[] Request = new byte[4];
|
||||
ByteOperations.WriteAsciiString(Request, 0, InfoQuerySignature);
|
||||
byte[] Response = ExecuteRawMethod(Request);
|
||||
if ((Response != null) && (ByteOperations.ReadAsciiString(Response, 0, 4) != "NOKU"))
|
||||
{
|
||||
Result.App = (FlashAppType)Response[5];
|
||||
|
||||
switch (Result.App)
|
||||
{
|
||||
case FlashAppType.BootManager:
|
||||
Result.BootManagerProtocolVersionMajor = Response[6];
|
||||
Result.BootManagerProtocolVersionMinor = Response[7];
|
||||
Result.BootManagerVersionMajor = Response[8];
|
||||
Result.BootManagerVersionMinor = Response[9];
|
||||
break;
|
||||
case FlashAppType.FlashApp:
|
||||
Result.FlashAppProtocolVersionMajor = Response[6];
|
||||
Result.FlashAppProtocolVersionMinor = Response[7];
|
||||
Result.FlashAppVersionMajor = Response[8];
|
||||
Result.FlashAppVersionMinor = Response[9];
|
||||
break;
|
||||
case FlashAppType.PhoneInfoApp:
|
||||
Result.PhoneInfoAppProtocolVersionMajor = Response[6];
|
||||
Result.PhoneInfoAppProtocolVersionMinor = Response[7];
|
||||
Result.PhoneInfoAppVersionMajor = Response[8];
|
||||
Result.PhoneInfoAppVersionMinor = Response[9];
|
||||
break;
|
||||
}
|
||||
|
||||
byte SubblockCount = Response[10];
|
||||
int SubblockOffset = 11;
|
||||
|
||||
for (int i = 0; i < SubblockCount; i++)
|
||||
{
|
||||
byte SubblockID = Response[SubblockOffset + 0x00];
|
||||
UInt16 SubblockLength = BigEndian.ToUInt16(Response, SubblockOffset + 0x01);
|
||||
int SubblockPayloadOffset = SubblockOffset + 3;
|
||||
byte SubblockVersion;
|
||||
switch (SubblockID)
|
||||
{
|
||||
case 0x01:
|
||||
Result.TransferSize = BigEndian.ToUInt32(Response, SubblockPayloadOffset);
|
||||
break;
|
||||
case 0x02:
|
||||
Result.WriteBufferSize = BigEndian.ToUInt32(Response, SubblockPayloadOffset);
|
||||
break;
|
||||
case 0x03:
|
||||
Result.EmmcSizeInSectors = BigEndian.ToUInt32(Response, SubblockPayloadOffset);
|
||||
break;
|
||||
case 0x04:
|
||||
if (Result.App == FlashAppType.BootManager)
|
||||
{
|
||||
Result.FlashAppProtocolVersionMajor = Response[SubblockPayloadOffset + 0x00];
|
||||
Result.FlashAppProtocolVersionMinor = Response[SubblockPayloadOffset + 0x01];
|
||||
Result.FlashAppVersionMajor = Response[SubblockPayloadOffset + 0x02];
|
||||
Result.FlashAppVersionMinor = Response[SubblockPayloadOffset + 0x03];
|
||||
}
|
||||
else if (Result.App == FlashAppType.FlashApp)
|
||||
{
|
||||
Result.SdCardSizeInSectors = BigEndian.ToUInt32(Response, SubblockPayloadOffset);
|
||||
}
|
||||
break;
|
||||
case 0x05:
|
||||
Result.PlatformID = ByteOperations.ReadAsciiString(Response, (uint)SubblockPayloadOffset, SubblockLength).Trim([' ', '\0']);
|
||||
break;
|
||||
case 0x0D:
|
||||
Result.AsyncSupport = Response[SubblockPayloadOffset + 1] == 1;
|
||||
break;
|
||||
case 0x0F:
|
||||
SubblockVersion = Response[SubblockPayloadOffset]; // 0x03
|
||||
Result.PlatformSecureBootEnabled = Response[SubblockPayloadOffset + 0x01] == 0x01;
|
||||
Result.SecureFfuEnabled = Response[SubblockPayloadOffset + 0x02] == 0x01;
|
||||
Result.JtagDisabled = Response[SubblockPayloadOffset + 0x03] == 0x01;
|
||||
Result.RdcPresent = Response[SubblockPayloadOffset + 0x04] == 0x01;
|
||||
Result.Authenticated = (Response[SubblockPayloadOffset + 0x05] == 0x01) || (Response[SubblockPayloadOffset + 0x05] == 0x02);
|
||||
Result.UefiSecureBootEnabled = Response[SubblockPayloadOffset + 0x06] == 0x01;
|
||||
Result.SecondaryHardwareKeyPresent = Response[SubblockPayloadOffset + 0x07] == 0x01;
|
||||
break;
|
||||
case 0x10:
|
||||
SubblockVersion = Response[SubblockPayloadOffset]; // 0x01
|
||||
Result.SecureFfuSupportedProtocolMask = BigEndian.ToUInt16(Response, SubblockPayloadOffset + 0x01);
|
||||
break;
|
||||
case 0x1F:
|
||||
Result.MmosOverUsbSupported = Response[SubblockPayloadOffset] == 1;
|
||||
break;
|
||||
case 0x20:
|
||||
// CRC header info
|
||||
break;
|
||||
}
|
||||
SubblockOffset += SubblockLength + 3;
|
||||
}
|
||||
}
|
||||
|
||||
Result.State = PhoneInfoState.Basic;
|
||||
}
|
||||
|
||||
if (ExtendedInfo && (Result.State == PhoneInfoState.Basic))
|
||||
{
|
||||
try
|
||||
{
|
||||
Result.Type = ReadPhoneInfoVariable("TYPE");
|
||||
Result.ProductCode = ReadPhoneInfoVariable("CTR");
|
||||
Result.Imei = ReadPhoneInfoVariable("IMEI");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogFile.LogException(ex, LogType.FileOnly);
|
||||
}
|
||||
|
||||
Result.State = PhoneInfoState.Extended;
|
||||
}
|
||||
|
||||
Result.IsBootloaderSecure = !(Info.Authenticated || Info.RdcPresent || !Info.SecureFfuEnabled);
|
||||
|
||||
if (!PhoneInfoLogged)
|
||||
{
|
||||
Result.Log(LogType.FileOnly);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal string ReadPhoneInfoVariable(string VariableName)
|
||||
{
|
||||
// This function assumes the phone is in Phone Info App context
|
||||
|
||||
byte[] Request = new byte[16];
|
||||
ByteOperations.WriteAsciiString(Request, 0, GetVariableSignature + VariableName + "\0"); // BTR or CTR, CTR is public ProductCode
|
||||
byte[] Response = ExecuteRawMethod(Request);
|
||||
UInt16 Length = BigEndian.ToUInt16(Response, 6);
|
||||
return ByteOperations.ReadAsciiString(Response, 8, Length).Trim([' ', '\0']);
|
||||
}
|
||||
|
||||
internal string ReadProductCode()
|
||||
{
|
||||
string Result = ReadPhoneInfoVariable("CTR");
|
||||
SwitchToFlashAppContext();
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
}
|
||||
+102
-1419
File diff suppressed because it is too large
Load Diff
@@ -176,6 +176,11 @@ namespace WPinternals
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Token.Value.ValueKind == JsonValueKind.String)
|
||||
{
|
||||
return Token.Value.GetString().Equals("true", StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
return Token.Value.GetBoolean();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
// Copyright (c) 2018, Rene Lergner - @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 System;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class PhoneInfo
|
||||
{
|
||||
public PhoneInfoState State = PhoneInfoState.Empty;
|
||||
|
||||
public string Type; // Extended info
|
||||
public string ProductCode; // Extended info
|
||||
public string Imei; // Extended info
|
||||
public string Firmware; // Extended info
|
||||
public byte[] RKH; // Extended info
|
||||
|
||||
public FlashAppType App;
|
||||
|
||||
public byte FlashAppVersionMajor;
|
||||
public byte FlashAppVersionMinor;
|
||||
public byte FlashAppProtocolVersionMajor;
|
||||
public byte FlashAppProtocolVersionMinor;
|
||||
|
||||
public byte BootManagerVersionMajor;
|
||||
public byte BootManagerVersionMinor;
|
||||
public byte BootManagerProtocolVersionMajor;
|
||||
public byte BootManagerProtocolVersionMinor;
|
||||
|
||||
public byte PhoneInfoAppVersionMajor;
|
||||
public byte PhoneInfoAppVersionMinor;
|
||||
public byte PhoneInfoAppProtocolVersionMajor;
|
||||
public byte PhoneInfoAppProtocolVersionMinor;
|
||||
|
||||
public UInt32 TransferSize;
|
||||
public bool MmosOverUsbSupported;
|
||||
public UInt32 SdCardSizeInSectors;
|
||||
public UInt32 WriteBufferSize;
|
||||
public UInt32 EmmcSizeInSectors;
|
||||
public string PlatformID;
|
||||
public UInt16 SecureFfuSupportedProtocolMask;
|
||||
public bool AsyncSupport;
|
||||
|
||||
public bool PlatformSecureBootEnabled;
|
||||
public bool SecureFfuEnabled;
|
||||
public bool JtagDisabled;
|
||||
public bool RdcPresent;
|
||||
public bool Authenticated;
|
||||
public bool UefiSecureBootEnabled;
|
||||
public bool SecondaryHardwareKeyPresent;
|
||||
|
||||
public bool IsBootloaderSecure;
|
||||
|
||||
internal void Log(LogType Type)
|
||||
{
|
||||
if (State == PhoneInfoState.Extended)
|
||||
{
|
||||
if (this.Type != null)
|
||||
{
|
||||
LogFile.Log("Phone type: " + this.Type, Type);
|
||||
}
|
||||
|
||||
if (ProductCode != null)
|
||||
{
|
||||
LogFile.Log("Product code: " + ProductCode, Type);
|
||||
}
|
||||
|
||||
if (RKH != null)
|
||||
{
|
||||
LogFile.Log("Root key hash: " + Converter.ConvertHexToString(RKH, ""), Type);
|
||||
}
|
||||
|
||||
if (Firmware?.Length > 0)
|
||||
{
|
||||
LogFile.Log("Firmware version: " + Firmware, Type);
|
||||
}
|
||||
|
||||
if (Type != LogType.ConsoleOnly && (Imei != null))
|
||||
{
|
||||
LogFile.Log("IMEI: " + Imei, LogType.FileOnly);
|
||||
}
|
||||
}
|
||||
|
||||
switch (App)
|
||||
{
|
||||
case FlashAppType.BootManager:
|
||||
LogFile.Log("Bootmanager: " + BootManagerVersionMajor + "." + BootManagerVersionMinor, Type);
|
||||
LogFile.Log("Bootmanager protocol: " + BootManagerProtocolVersionMajor + "." + BootManagerProtocolVersionMinor, Type);
|
||||
LogFile.Log("Flash app: " + FlashAppVersionMajor + "." + FlashAppVersionMinor, Type);
|
||||
LogFile.Log("Flash protocol: " + FlashAppProtocolVersionMajor + "." + FlashAppProtocolVersionMinor, Type);
|
||||
break;
|
||||
case FlashAppType.FlashApp:
|
||||
LogFile.Log("Flash app: " + FlashAppVersionMajor + "." + FlashAppVersionMinor, Type);
|
||||
LogFile.Log("Flash protocol: " + FlashAppProtocolVersionMajor + "." + FlashAppProtocolVersionMinor, Type);
|
||||
break;
|
||||
case FlashAppType.PhoneInfoApp:
|
||||
LogFile.Log("Phone info app: " + PhoneInfoAppVersionMajor + "." + PhoneInfoAppVersionMinor, Type);
|
||||
LogFile.Log("Phone info protocol: " + PhoneInfoAppProtocolVersionMajor + "." + PhoneInfoAppProtocolVersionMinor, Type);
|
||||
break;
|
||||
}
|
||||
|
||||
LogFile.Log("SecureBoot: " + ((!PlatformSecureBootEnabled || !UefiSecureBootEnabled) ? "Disabled" : "Enabled") + " (Platform Secure Boot: " + (PlatformSecureBootEnabled ? "Enabled" : "Disabled") + ", UEFI Secure Boot: " + (UefiSecureBootEnabled ? "Enabled" : "Disabled") + ")", Type);
|
||||
|
||||
if ((Type == LogType.ConsoleOnly) || (Type == LogType.FileAndConsole))
|
||||
{
|
||||
LogFile.Log("Flash app security: " + (!IsBootloaderSecure ? "Disabled" : "Enabled"), LogType.ConsoleOnly);
|
||||
}
|
||||
|
||||
if ((Type == LogType.FileOnly) || (Type == LogType.FileAndConsole))
|
||||
{
|
||||
LogFile.Log("Flash app security: " + (!IsBootloaderSecure ? "Disabled" : "Enabled") + " (FFU security: " + (SecureFfuEnabled ? "Enabled" : "Disabled") + ", RDC: " + (RdcPresent ? "Present" : "Not found") + ", Authenticated: " + (Authenticated ? "True" : "False") + ")", LogType.FileOnly);
|
||||
}
|
||||
|
||||
LogFile.Log("JTAG: " + (JtagDisabled ? "Disabled" : "Enabled"), Type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2018, Rene Lergner - @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.
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal enum PhoneInfoState
|
||||
{
|
||||
Empty,
|
||||
Basic,
|
||||
Extended
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2018, Rene Lergner - @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.
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class UefiSecurityStatusResponse
|
||||
{
|
||||
public byte IsTestDevice;
|
||||
public bool PlatformSecureBootStatus;
|
||||
public bool SecureFfuEfuseStatus;
|
||||
public bool DebugStatus;
|
||||
public bool RdcStatus;
|
||||
public bool AuthenticationStatus;
|
||||
public bool UefiSecureBootStatus;
|
||||
public bool CryptoHardwareKey;
|
||||
}
|
||||
}
|
||||
@@ -258,7 +258,7 @@ namespace WPinternals
|
||||
{
|
||||
LogFile.Log("Phone needs to be switched to emergency mode.", LogType.FileAndConsole);
|
||||
await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
PhoneInfo Info = ((NokiaFlashModel)Notifier.CurrentModel).ReadPhoneInfo();
|
||||
PhoneInfo Info = ((LumiaFlashAppModel)Notifier.CurrentModel).ReadPhoneInfo();
|
||||
Info.Log(LogType.ConsoleOnly);
|
||||
await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Qualcomm_Download);
|
||||
if (Notifier.CurrentInterface != PhoneInterfaces.Qualcomm_Download)
|
||||
|
||||
@@ -469,7 +469,7 @@ namespace WPinternals
|
||||
|
||||
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Flash)
|
||||
{
|
||||
NokiaFlashModel LumiaFlashModel = (NokiaFlashModel)Notifier.CurrentModel;
|
||||
LumiaFlashAppModel LumiaFlashModel = (LumiaFlashAppModel)Notifier.CurrentModel;
|
||||
PhoneInfo Info = LumiaFlashModel.ReadPhoneInfo();
|
||||
ProductType = Info.Type;
|
||||
OperatorCode = "";
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace WPinternals
|
||||
await SwitchModeViewModel.SwitchToWithProgress(PhoneNotifier, PhoneInterfaces.Lumia_Flash,
|
||||
(msg, sub) =>
|
||||
ActivateSubContext(new BusyViewModel(msg, sub)));
|
||||
if (((NokiaFlashModel)PhoneNotifier.CurrentModel).ReadPhoneInfo(ExtendedInfo: false).FlashAppProtocolVersionMajor < 2)
|
||||
if (((LumiaFlashAppModel)PhoneNotifier.CurrentModel).ReadPhoneInfo(ExtendedInfo: false).FlashAppProtocolVersionMajor < 2)
|
||||
{
|
||||
FlashPartitionsTask(EFIESPPath, MainOSPath, DataPath);
|
||||
}
|
||||
@@ -96,7 +96,7 @@ namespace WPinternals
|
||||
|
||||
ActivateSubContext(new BusyViewModel("Initializing flash..."));
|
||||
|
||||
NokiaFlashModel Phone = (NokiaFlashModel)PhoneNotifier.CurrentModel;
|
||||
LumiaFlashAppModel Phone = (LumiaFlashAppModel)PhoneNotifier.CurrentModel;
|
||||
|
||||
GPT GPT = Phone.ReadGPT();
|
||||
|
||||
@@ -268,7 +268,7 @@ namespace WPinternals
|
||||
await SwitchModeViewModel.SwitchToWithProgress(PhoneNotifier, PhoneInterfaces.Lumia_Flash,
|
||||
(msg, sub) =>
|
||||
ActivateSubContext(new BusyViewModel(msg, sub)));
|
||||
if (((NokiaFlashModel)PhoneNotifier.CurrentModel).ReadPhoneInfo(ExtendedInfo: false).FlashAppProtocolVersionMajor < 2)
|
||||
if (((LumiaFlashAppModel)PhoneNotifier.CurrentModel).ReadPhoneInfo(ExtendedInfo: false).FlashAppProtocolVersionMajor < 2)
|
||||
{
|
||||
FlashArchiveTask(ArchivePath);
|
||||
}
|
||||
@@ -289,7 +289,7 @@ namespace WPinternals
|
||||
{
|
||||
ActivateSubContext(new BusyViewModel("Initializing flash..."));
|
||||
|
||||
NokiaFlashModel Phone = (NokiaFlashModel)PhoneNotifier.CurrentModel;
|
||||
LumiaFlashAppModel Phone = (LumiaFlashAppModel)PhoneNotifier.CurrentModel;
|
||||
|
||||
ulong TotalSizeSectors = 0;
|
||||
int PartitionCount = 0;
|
||||
@@ -505,7 +505,7 @@ namespace WPinternals
|
||||
{
|
||||
bool Result = true;
|
||||
|
||||
NokiaFlashModel Phone = (NokiaFlashModel)PhoneNotifier.CurrentModel;
|
||||
LumiaFlashAppModel Phone = (LumiaFlashAppModel)PhoneNotifier.CurrentModel;
|
||||
PhoneInfo Info = Phone.ReadPhoneInfo(false);
|
||||
|
||||
#region Remove bootloader changes
|
||||
@@ -519,7 +519,7 @@ namespace WPinternals
|
||||
|
||||
if (Info.FlashAppProtocolVersionMajor >= 2)
|
||||
{
|
||||
byte[] GPTChunk = LumiaUnlockBootloaderViewModel.GetGptChunk(Phone, 0x20000); // TODO: Get proper profile FFU and get ChunkSizeInBytes
|
||||
byte[] GPTChunk = Phone.GetGptChunk(0x20000); // TODO: Get proper profile FFU and get ChunkSizeInBytes
|
||||
GPT GPT = new(GPTChunk);
|
||||
FlashPart Part;
|
||||
List<FlashPart> FlashParts = new();
|
||||
@@ -598,14 +598,14 @@ namespace WPinternals
|
||||
|
||||
if (PhoneNotifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
((NokiaFlashModel)PhoneNotifier.CurrentModel).SwitchToFlashAppContext();
|
||||
((LumiaBootManagerAppModel)PhoneNotifier.CurrentModel).SwitchToFlashAppContext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
Phone = (NokiaFlashModel)PhoneNotifier.CurrentModel;
|
||||
Phone = (LumiaFlashAppModel)PhoneNotifier.CurrentModel;
|
||||
|
||||
ActivateSubContext(new BusyViewModel("Initializing flash..."));
|
||||
|
||||
@@ -664,12 +664,13 @@ namespace WPinternals
|
||||
|
||||
internal void FlashMMOSTask(string MMOSPath)
|
||||
{
|
||||
NokiaFlashModel Phone = (NokiaFlashModel)PhoneNotifier.CurrentModel;
|
||||
if (PhoneNotifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
Phone.SwitchToFlashAppContext();
|
||||
((LumiaBootManagerAppModel)PhoneNotifier.CurrentModel).SwitchToFlashAppContext();
|
||||
}
|
||||
|
||||
LumiaFlashAppModel Phone = (LumiaFlashAppModel)PhoneNotifier.CurrentModel;
|
||||
|
||||
new Thread(() =>
|
||||
{
|
||||
bool Result = true;
|
||||
|
||||
@@ -66,18 +66,19 @@ namespace WPinternals
|
||||
switch (CurrentInterface)
|
||||
{
|
||||
case null:
|
||||
case PhoneInterfaces.Lumia_Bootloader:
|
||||
ActivateSubContext(null);
|
||||
//ActivateSubContext(new NokiaBootloaderViewModel((NokiaFlashModel)CurrentModel, ModeSwitchRequestCallback, SwitchToGettingStarted));
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Bootloader:
|
||||
ActivateSubContext(new NokiaBootloaderViewModel((LumiaBootManagerAppModel)CurrentModel, ModeSwitchRequestCallback, SwitchToGettingStarted));
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_PhoneInfo:
|
||||
ActivateSubContext(new NokiaPhoneInfoViewModel((NokiaFlashModel)CurrentModel, ModeSwitchRequestCallback, SwitchToGettingStarted));
|
||||
ActivateSubContext(new NokiaPhoneInfoViewModel((LumiaPhoneInfoAppModel)CurrentModel, ModeSwitchRequestCallback, SwitchToGettingStarted));
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Normal:
|
||||
ActivateSubContext(new NokiaNormalViewModel((NokiaPhoneModel)CurrentModel, ModeSwitchRequestCallback));
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Flash:
|
||||
ActivateSubContext(new NokiaFlashViewModel((NokiaFlashModel)CurrentModel, ModeSwitchRequestCallback, SwitchToGettingStarted));
|
||||
ActivateSubContext(new NokiaFlashViewModel((LumiaFlashAppModel)CurrentModel, ModeSwitchRequestCallback, SwitchToGettingStarted));
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Label:
|
||||
ActivateSubContext(new NokiaLabelViewModel((NokiaPhoneModel)CurrentModel, ModeSwitchRequestCallback));
|
||||
|
||||
@@ -87,17 +87,16 @@ namespace WPinternals
|
||||
ActivateSubContext(null);
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Bootloader:
|
||||
ActivateSubContext(null);
|
||||
//ActivateSubContext(new NokiaModeBootloaderViewModel((NokiaFlashModel)CurrentModel, OnModeSwitchRequested));
|
||||
ActivateSubContext(new NokiaModeBootloaderViewModel((LumiaBootManagerAppModel)CurrentModel, OnModeSwitchRequested));
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_PhoneInfo:
|
||||
ActivateSubContext(new NokiaModePhoneInfoViewModel((NokiaFlashModel)CurrentModel, OnModeSwitchRequested));
|
||||
ActivateSubContext(new NokiaModePhoneInfoViewModel((LumiaPhoneInfoAppModel)CurrentModel, OnModeSwitchRequested));
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Normal:
|
||||
ActivateSubContext(new NokiaModeNormalViewModel((NokiaPhoneModel)CurrentModel, OnModeSwitchRequested));
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Flash:
|
||||
ActivateSubContext(new NokiaModeFlashViewModel((NokiaFlashModel)CurrentModel, OnModeSwitchRequested));
|
||||
ActivateSubContext(new NokiaModeFlashViewModel((LumiaFlashAppModel)CurrentModel, OnModeSwitchRequested));
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Label:
|
||||
ActivateSubContext(new NokiaModeLabelViewModel((NokiaPhoneModel)CurrentModel, OnModeSwitchRequested));
|
||||
|
||||
@@ -133,11 +133,11 @@ namespace WPinternals
|
||||
{
|
||||
// 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");
|
||||
RootKeyHash = ((LumiaFlashAppModel)PhoneNotifier.CurrentModel).ReadParam("RRKH");
|
||||
|
||||
TestPos = 1;
|
||||
|
||||
UefiSecurityStatusResponse SecurityStatus = ((NokiaFlashModel)PhoneNotifier.CurrentModel).ReadSecurityStatus();
|
||||
UefiSecurityStatusResponse SecurityStatus = ((LumiaFlashAppModel)PhoneNotifier.CurrentModel).ReadSecurityStatus();
|
||||
if (SecurityStatus != null)
|
||||
{
|
||||
IsBootLoaderUnlocked = SecurityStatus.AuthenticationStatus || SecurityStatus.RdcStatus || !SecurityStatus.SecureFfuEfuseStatus;
|
||||
@@ -145,7 +145,7 @@ namespace WPinternals
|
||||
|
||||
TestPos = 2;
|
||||
|
||||
PhoneInfo Info = ((NokiaFlashModel)PhoneNotifier.CurrentModel).ReadPhoneInfo();
|
||||
PhoneInfo Info = ((LumiaFlashAppModel)PhoneNotifier.CurrentModel).ReadPhoneInfo();
|
||||
if (SecurityStatus == null)
|
||||
{
|
||||
IsBootLoaderUnlocked = !Info.IsBootloaderSecure;
|
||||
@@ -213,7 +213,7 @@ namespace WPinternals
|
||||
bool AlreadyUnlocked = false;
|
||||
if (DoUnlock)
|
||||
{
|
||||
NokiaFlashModel FlashModel = (NokiaFlashModel)PhoneNotifier.CurrentModel;
|
||||
LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)PhoneNotifier.CurrentModel;
|
||||
GPT GPT = FlashModel.ReadGPT();
|
||||
if ((GPT.GetPartition("IS_UNLOCKED") != null) || (GPT.GetPartition("BACKUP_EFIESP") != null))
|
||||
{
|
||||
@@ -510,7 +510,7 @@ namespace WPinternals
|
||||
|
||||
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Qualcomm_Download && PhoneNotifier.CurrentInterface != PhoneInterfaces.Qualcomm_Flash)
|
||||
{
|
||||
NokiaFlashModel Model = (NokiaFlashModel)PhoneNotifier.CurrentModel;
|
||||
LumiaFlashAppModel Model = (LumiaFlashAppModel)PhoneNotifier.CurrentModel;
|
||||
PhoneInfo Info = Model.ReadPhoneInfo();
|
||||
|
||||
if (EDEPath == null)
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace WPinternals
|
||||
// TODO: Add logging
|
||||
private static void PerformSoftBrick(PhoneNotifierViewModel Notifier, FFU FFU)
|
||||
{
|
||||
NokiaFlashModel FlashModel = (NokiaFlashModel)Notifier.CurrentModel;
|
||||
LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)Notifier.CurrentModel;
|
||||
|
||||
// Send FFU headers
|
||||
UInt64 CombinedFFUHeaderSize = FFU.HeaderSize;
|
||||
@@ -139,7 +139,7 @@ namespace WPinternals
|
||||
|
||||
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot();
|
||||
((LumiaBootManagerAppModel)Notifier.CurrentModel).ContinueBoot();
|
||||
}
|
||||
|
||||
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal)
|
||||
@@ -149,7 +149,7 @@ namespace WPinternals
|
||||
|
||||
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot();
|
||||
((LumiaBootManagerAppModel)Notifier.CurrentModel).ContinueBoot();
|
||||
}
|
||||
|
||||
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal)
|
||||
@@ -159,7 +159,7 @@ namespace WPinternals
|
||||
|
||||
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot();
|
||||
((LumiaBootManagerAppModel)Notifier.CurrentModel).ContinueBoot();
|
||||
}
|
||||
|
||||
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal)
|
||||
@@ -205,7 +205,7 @@ namespace WPinternals
|
||||
|
||||
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot();
|
||||
((LumiaBootManagerAppModel)Notifier.CurrentModel).ContinueBoot();
|
||||
}
|
||||
|
||||
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal)
|
||||
@@ -215,7 +215,7 @@ namespace WPinternals
|
||||
|
||||
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot();
|
||||
((LumiaBootManagerAppModel)Notifier.CurrentModel).ContinueBoot();
|
||||
}
|
||||
|
||||
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal)
|
||||
@@ -225,7 +225,7 @@ namespace WPinternals
|
||||
|
||||
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot();
|
||||
((LumiaBootManagerAppModel)Notifier.CurrentModel).ContinueBoot();
|
||||
}
|
||||
|
||||
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal)
|
||||
@@ -273,7 +273,7 @@ namespace WPinternals
|
||||
|
||||
try
|
||||
{
|
||||
if (Notifier.CurrentModel is NokiaFlashModel)
|
||||
if (Notifier.CurrentModel is LumiaFlashAppModel)
|
||||
{
|
||||
await LumiaRelockUEFI(Notifier, FFUPath, true, SetWorkingStatus, UpdateWorkingStatus, null, (string Message, string SubMessage) =>
|
||||
{
|
||||
@@ -320,9 +320,9 @@ namespace WPinternals
|
||||
throw new Exception("Error: Parsing FFU-file failed.");
|
||||
}
|
||||
|
||||
if (Notifier.CurrentModel is NokiaFlashModel)
|
||||
if (Notifier.CurrentModel is LumiaFlashAppModel)
|
||||
{
|
||||
FlashVersion FlashVersion = ((NokiaFlashModel)Notifier.CurrentModel).GetFlashVersion();
|
||||
FlashVersion FlashVersion = ((LumiaFlashAppModel)Notifier.CurrentModel).GetFlashVersion();
|
||||
if (FlashVersion == null)
|
||||
{
|
||||
throw new Exception("Error: The version of the Flash Application on the phone could not be determined.");
|
||||
@@ -333,7 +333,7 @@ namespace WPinternals
|
||||
throw new Exception("Error: The version of the Flash Application on the phone is too old. Update your phone using Windows Updates or flash a newer ROM to your phone. Then try again.");
|
||||
}
|
||||
|
||||
UefiSecurityStatusResponse SecurityStatus = ((NokiaFlashModel)Notifier.CurrentModel).ReadSecurityStatus();
|
||||
UefiSecurityStatusResponse SecurityStatus = ((LumiaFlashAppModel)Notifier.CurrentModel).ReadSecurityStatus();
|
||||
IsBootLoaderUnlocked = SecurityStatus.AuthenticationStatus || SecurityStatus.RdcStatus || !SecurityStatus.SecureFfuEfuseStatus;
|
||||
}
|
||||
|
||||
@@ -350,9 +350,9 @@ namespace WPinternals
|
||||
#endif
|
||||
|
||||
GPT NewGPT = null;
|
||||
if (Notifier.CurrentModel is NokiaFlashModel)
|
||||
if (Notifier.CurrentModel is LumiaFlashAppModel)
|
||||
{
|
||||
((NokiaFlashModel)Notifier.CurrentModel).ResetPhone();
|
||||
((LumiaFlashAppModel)Notifier.CurrentModel).ResetPhone();
|
||||
|
||||
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
@@ -364,7 +364,7 @@ namespace WPinternals
|
||||
throw new WPinternalsException("Phone is in an unexpected mode.", "The phone should have been detected in bootloader mode. Instead it has been detected in " + Notifier.CurrentInterface.ToString() + " mode.");
|
||||
}
|
||||
|
||||
NewGPT = ((NokiaFlashModel)Notifier.CurrentModel).ReadGPT();
|
||||
NewGPT = ((LumiaBootManagerAppModel)Notifier.CurrentModel).ReadGPT();
|
||||
|
||||
await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
|
||||
@@ -448,7 +448,7 @@ namespace WPinternals
|
||||
}
|
||||
else if (Notifier.CurrentInterface != PhoneInterfaces.Qualcomm_Flash)
|
||||
{
|
||||
RootKeyHash = ((NokiaFlashModel)Notifier.CurrentModel).ReadParam("RRKH");
|
||||
RootKeyHash = ((LumiaFlashAppModel)Notifier.CurrentModel).ReadParam("RRKH");
|
||||
}
|
||||
|
||||
if (Notifier.CurrentInterface != PhoneInterfaces.Qualcomm_Flash)
|
||||
@@ -573,7 +573,7 @@ namespace WPinternals
|
||||
if (IsBootLoaderUnlocked)
|
||||
// Flash phone in Flash app
|
||||
{
|
||||
NokiaFlashModel CurrentModel = (NokiaFlashModel)Notifier.CurrentModel;
|
||||
LumiaFlashAppModel CurrentModel = (LumiaFlashAppModel)Notifier.CurrentModel;
|
||||
LogFile.Log("Start flashing in Custom Flash mode");
|
||||
|
||||
UInt64 TotalSectorCount = (UInt64)0x21 + 1 +
|
||||
@@ -732,7 +732,7 @@ namespace WPinternals
|
||||
throw new WPinternalsException("Phone is in an unexpected mode.", "The phone should have been detected in flash mode. Instead it has been detected in " + Notifier.CurrentInterface.ToString() + " mode.");
|
||||
}
|
||||
|
||||
NokiaFlashModel FlashModel = (NokiaFlashModel)Notifier.CurrentModel;
|
||||
LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)Notifier.CurrentModel;
|
||||
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Flash && FlashModel.ReadParam("FS")[3] > 0)
|
||||
{
|
||||
ExitSuccess("Bootloader is restored", "NOTE: You need to flash a stock ROM because you recovered a phone from a bootloader unlock failure.");
|
||||
@@ -743,7 +743,7 @@ namespace WPinternals
|
||||
|
||||
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot();
|
||||
((LumiaBootManagerAppModel)Notifier.CurrentModel).ContinueBoot();
|
||||
}
|
||||
|
||||
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal)
|
||||
@@ -753,7 +753,7 @@ namespace WPinternals
|
||||
|
||||
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot();
|
||||
((LumiaBootManagerAppModel)Notifier.CurrentModel).ContinueBoot();
|
||||
}
|
||||
|
||||
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal)
|
||||
@@ -763,7 +763,7 @@ namespace WPinternals
|
||||
|
||||
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot();
|
||||
((LumiaBootManagerAppModel)Notifier.CurrentModel).ContinueBoot();
|
||||
}
|
||||
|
||||
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal)
|
||||
@@ -843,9 +843,9 @@ namespace WPinternals
|
||||
throw new Exception("Error: Parsing FFU-file failed.");
|
||||
}
|
||||
|
||||
if (Notifier.CurrentModel is NokiaFlashModel)
|
||||
if (Notifier.CurrentModel is LumiaFlashAppModel)
|
||||
{
|
||||
FlashVersion FlashVersion = ((NokiaFlashModel)Notifier.CurrentModel).GetFlashVersion();
|
||||
FlashVersion FlashVersion = ((LumiaFlashAppModel)Notifier.CurrentModel).GetFlashVersion();
|
||||
if (FlashVersion == null)
|
||||
{
|
||||
throw new Exception("Error: The version of the Flash Application on the phone could not be determined.");
|
||||
@@ -856,7 +856,7 @@ namespace WPinternals
|
||||
throw new Exception("Error: The version of the Flash Application on the phone is too old. Update your phone using Windows Updates or flash a newer ROM to your phone. Then try again.");
|
||||
}
|
||||
|
||||
UefiSecurityStatusResponse SecurityStatus = ((NokiaFlashModel)Notifier.CurrentModel).ReadSecurityStatus();
|
||||
UefiSecurityStatusResponse SecurityStatus = ((LumiaFlashAppModel)Notifier.CurrentModel).ReadSecurityStatus();
|
||||
IsBootLoaderUnlocked = SecurityStatus.AuthenticationStatus || SecurityStatus.RdcStatus || !SecurityStatus.SecureFfuEfuseStatus;
|
||||
}
|
||||
|
||||
@@ -904,9 +904,9 @@ namespace WPinternals
|
||||
#endif
|
||||
|
||||
GPT NewGPT = null;
|
||||
if (Notifier.CurrentModel is NokiaFlashModel)
|
||||
if (Notifier.CurrentModel is LumiaFlashAppModel)
|
||||
{
|
||||
((NokiaFlashModel)Notifier.CurrentModel).ResetPhone();
|
||||
((LumiaFlashAppModel)Notifier.CurrentModel).ResetPhone();
|
||||
|
||||
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
@@ -918,7 +918,7 @@ namespace WPinternals
|
||||
throw new WPinternalsException("Phone is in an unexpected mode.", "The phone should have been detected in bootloader mode. Instead it has been detected in " + Notifier.CurrentInterface.ToString() + " mode.");
|
||||
}
|
||||
|
||||
NewGPT = ((NokiaFlashModel)Notifier.CurrentModel).ReadGPT();
|
||||
NewGPT = ((LumiaBootManagerAppModel)Notifier.CurrentModel).ReadGPT();
|
||||
|
||||
await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
|
||||
@@ -1013,7 +1013,7 @@ namespace WPinternals
|
||||
}
|
||||
else if (Notifier.CurrentInterface != PhoneInterfaces.Qualcomm_Flash)
|
||||
{
|
||||
RootKeyHash = ((NokiaFlashModel)Notifier.CurrentModel).ReadParam("RRKH");
|
||||
RootKeyHash = ((LumiaFlashAppModel)Notifier.CurrentModel).ReadParam("RRKH");
|
||||
}
|
||||
|
||||
if (Notifier.CurrentInterface != PhoneInterfaces.Qualcomm_Flash)
|
||||
@@ -1252,7 +1252,7 @@ namespace WPinternals
|
||||
if (IsBootLoaderUnlocked)
|
||||
// Flash phone in Flash app
|
||||
{
|
||||
NokiaFlashModel CurrentModel = (NokiaFlashModel)Notifier.CurrentModel;
|
||||
LumiaFlashAppModel CurrentModel = (LumiaFlashAppModel)Notifier.CurrentModel;
|
||||
LogFile.Log("Start flashing in Custom Flash mode");
|
||||
|
||||
UInt64 TotalSectorCount = (UInt64)0x21 + 1 +
|
||||
@@ -1423,7 +1423,7 @@ namespace WPinternals
|
||||
|
||||
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot();
|
||||
((LumiaBootManagerAppModel)Notifier.CurrentModel).ContinueBoot();
|
||||
}
|
||||
|
||||
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal)
|
||||
@@ -1433,7 +1433,7 @@ namespace WPinternals
|
||||
|
||||
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot();
|
||||
((LumiaBootManagerAppModel)Notifier.CurrentModel).ContinueBoot();
|
||||
}
|
||||
|
||||
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal)
|
||||
@@ -1443,7 +1443,7 @@ namespace WPinternals
|
||||
|
||||
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot();
|
||||
((LumiaBootManagerAppModel)Notifier.CurrentModel).ContinueBoot();
|
||||
}
|
||||
|
||||
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal)
|
||||
@@ -1467,54 +1467,6 @@ namespace WPinternals
|
||||
}
|
||||
}
|
||||
|
||||
internal static byte[] GetGptChunk(NokiaFlashModel FlashModel, UInt32 Size)
|
||||
{
|
||||
// This function is also used to generate a dummy chunk to flash for testing.
|
||||
// The dummy chunk will contain the GPT, so it can be flashed to the first sectors for testing.
|
||||
byte[] GPTChunk = new byte[Size];
|
||||
|
||||
PhoneInfo Info = FlashModel.ReadPhoneInfo(ExtendedInfo: false);
|
||||
FlashAppType OriginalAppType = Info.App;
|
||||
bool Switch = (Info.App != FlashAppType.BootManager) && Info.IsBootloaderSecure;
|
||||
if (Switch)
|
||||
{
|
||||
FlashModel.SwitchToBootManagerContext();
|
||||
}
|
||||
|
||||
byte[] Request = new byte[0x04];
|
||||
const string Header = "NOKT";
|
||||
|
||||
System.Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
|
||||
|
||||
byte[] Buffer = FlashModel.ExecuteRawMethod(Request);
|
||||
if ((Buffer == null) || (Buffer.Length < 0x4408))
|
||||
{
|
||||
throw new InvalidOperationException("Unable to read GPT!");
|
||||
}
|
||||
|
||||
UInt16 Error = (UInt16)((Buffer[6] << 8) + Buffer[7]);
|
||||
if (Error > 0)
|
||||
{
|
||||
throw new NotSupportedException("ReadGPT: Error 0x" + Error.ToString("X4"));
|
||||
}
|
||||
|
||||
System.Buffer.BlockCopy(Buffer, 8, GPTChunk, 0, 0x4400);
|
||||
|
||||
if (Switch)
|
||||
{
|
||||
if (OriginalAppType == FlashAppType.FlashApp)
|
||||
{
|
||||
FlashModel.SwitchToFlashAppContext();
|
||||
}
|
||||
else
|
||||
{
|
||||
FlashModel.SwitchToPhoneInfoAppContext();
|
||||
}
|
||||
}
|
||||
|
||||
return GPTChunk;
|
||||
}
|
||||
|
||||
// Magic!
|
||||
// UEFI Secure Boot Hack for Spec A and Spec B devices
|
||||
//
|
||||
@@ -1547,7 +1499,7 @@ namespace WPinternals
|
||||
{
|
||||
GPT GPT = null;
|
||||
Partition Target = null;
|
||||
NokiaFlashModel FlashModel = null;
|
||||
LumiaFlashAppModel FlashModel = null;
|
||||
|
||||
LogFile.Log("Command: Relock phone", LogType.FileAndConsole);
|
||||
|
||||
@@ -1558,13 +1510,13 @@ namespace WPinternals
|
||||
|
||||
byte[] EFIESPBackup = null;
|
||||
|
||||
PhoneInfo Info = ((NokiaFlashModel)Notifier.CurrentModel).ReadPhoneInfo();
|
||||
PhoneInfo Info = ((LumiaFlashAppModel)Notifier.CurrentModel).ReadPhoneInfo();
|
||||
bool IsSpecB = Info.FlashAppProtocolVersionMajor >= 2;
|
||||
bool UndoEFIESPPadding = false;
|
||||
|
||||
if (!IsSpecB)
|
||||
{
|
||||
((NokiaFlashModel)Notifier.CurrentModel).ResetPhone();
|
||||
((LumiaFlashAppModel)Notifier.CurrentModel).ResetPhone();
|
||||
|
||||
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
@@ -1577,7 +1529,7 @@ namespace WPinternals
|
||||
}
|
||||
}
|
||||
|
||||
byte[] GPTChunk = GetGptChunk((NokiaFlashModel)Notifier.CurrentModel, 0x20000);
|
||||
byte[] GPTChunk = ((LumiaBootManagerAppModel)Notifier.CurrentModel).GetGptChunk(0x20000);
|
||||
GPT = new GPT(GPTChunk);
|
||||
bool GPTChanged = false;
|
||||
Partition IsUnlockedPartitionSBL3 = GPT.GetPartition("IS_UNLOCKED_SBL3");
|
||||
@@ -1719,7 +1671,7 @@ namespace WPinternals
|
||||
|
||||
SetWorkingStatus("Flashing...", "The phone may reboot a couple of times. Just wait for it.", null, Status: WPinternalsStatus.Initializing);
|
||||
|
||||
((NokiaFlashModel)Notifier.CurrentModel).SwitchToFlashAppContext();
|
||||
((LumiaBootManagerAppModel)Notifier.CurrentModel).SwitchToFlashAppContext();
|
||||
|
||||
List<FlashPart> FlashParts = new();
|
||||
|
||||
@@ -1730,7 +1682,7 @@ namespace WPinternals
|
||||
|
||||
FlashPart Part;
|
||||
|
||||
FlashModel = (NokiaFlashModel)Notifier.CurrentModel;
|
||||
FlashModel = (LumiaFlashAppModel)Notifier.CurrentModel;
|
||||
|
||||
// Remove IS_UNLOCKED flag in GPT
|
||||
Partition IsUnlockedPartition = GPT.GetPartition("IS_UNLOCKED");
|
||||
@@ -1788,7 +1740,7 @@ namespace WPinternals
|
||||
|
||||
// We should only clear NV if there was no backup NV to be restored and the current NV contains the SB unlock.
|
||||
bool NvCleared = false;
|
||||
Info = ((NokiaFlashModel)Notifier.CurrentModel).ReadPhoneInfo();
|
||||
Info = ((LumiaFlashAppModel)Notifier.CurrentModel).ReadPhoneInfo();
|
||||
if ((NvBackupPartition == null) && !Info.UefiSecureBootEnabled)
|
||||
{
|
||||
// ClearNV
|
||||
@@ -1857,7 +1809,7 @@ namespace WPinternals
|
||||
|
||||
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
((NokiaFlashModel)Notifier.CurrentModel).SwitchToFlashAppContext();
|
||||
((LumiaBootManagerAppModel)Notifier.CurrentModel).SwitchToFlashAppContext();
|
||||
}
|
||||
|
||||
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Flash)
|
||||
@@ -1886,7 +1838,7 @@ namespace WPinternals
|
||||
internal static async Task LumiaUnlockUEFI(PhoneNotifierViewModel Notifier, string ProfileFFUPath, string EDEPath, string SupportedFFUPath, SetWorkingStatus SetWorkingStatus = null, UpdateWorkingStatus UpdateWorkingStatus = null, ExitSuccess ExitSuccess = null, ExitFailure ExitFailure = null, bool ExperimentalSpecBEFIESPUnlock = false, bool ExperimentalSpecAEFIESPUnlock = true, bool ReUnlockDevice = false)
|
||||
{
|
||||
LogFile.BeginAction("UnlockBootloader");
|
||||
NokiaFlashModel FlashModel = (NokiaFlashModel)Notifier.CurrentModel;
|
||||
LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)Notifier.CurrentModel;
|
||||
|
||||
if (SetWorkingStatus == null)
|
||||
{
|
||||
@@ -1957,7 +1909,7 @@ namespace WPinternals
|
||||
|
||||
LumiaPatchEFIESP(SupportedFFU, UnlockedEFIESP, IsSpecB);
|
||||
|
||||
byte[] GPTChunk = GetGptChunk(FlashModel, (UInt32)ProfileFFU.ChunkSize);
|
||||
byte[] GPTChunk = FlashModel.GetGptChunk((UInt32)ProfileFFU.ChunkSize);
|
||||
byte[] GPTChunkBackup = new byte[GPTChunk.Length];
|
||||
Buffer.BlockCopy(GPTChunk, 0, GPTChunkBackup, 0, GPTChunk.Length);
|
||||
GPT GPT = new(GPTChunk);
|
||||
@@ -2042,8 +1994,8 @@ namespace WPinternals
|
||||
|
||||
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
FlashModel = (NokiaFlashModel)Notifier.CurrentModel;
|
||||
FlashModel.SwitchToFlashAppContext();
|
||||
((LumiaBootManagerAppModel)Notifier.CurrentModel).SwitchToFlashAppContext();
|
||||
FlashModel = ((LumiaFlashAppModel)Notifier.CurrentModel);
|
||||
}
|
||||
|
||||
GPTChanged = false;
|
||||
@@ -2208,7 +2160,7 @@ namespace WPinternals
|
||||
|
||||
if (!IsSpecB && !SBL3Eng)
|
||||
{
|
||||
((NokiaFlashModel)Notifier.CurrentModel).ResetPhone();
|
||||
((LumiaFlashAppModel)Notifier.CurrentModel).ResetPhone();
|
||||
|
||||
LogFile.Log("Bootloader unlocked!", LogType.FileAndConsole);
|
||||
ExitSuccess("Bootloader unlocked successfully!", null);
|
||||
@@ -2344,7 +2296,7 @@ namespace WPinternals
|
||||
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
throw new WPinternalsException("Phone is in wrong mode", "The phone should have been detected in bootloader mode. Instead it has been detected in " + Notifier.CurrentInterface.ToString() + " mode.");
|
||||
} ((NokiaFlashModel)Notifier.CurrentModel).SwitchToFlashAppContext();
|
||||
} ((LumiaBootManagerAppModel)Notifier.CurrentModel).SwitchToFlashAppContext();
|
||||
|
||||
UInt32 OriginalEfiespFirstSector;
|
||||
if (!ReUnlockDevice)
|
||||
@@ -2504,7 +2456,7 @@ namespace WPinternals
|
||||
throw new WPinternalsException("Phone is in wrong mode", "The phone should have been detected in bootloader mode. Instead it has been detected in " + Notifier.CurrentInterface.ToString() + " mode.");
|
||||
}
|
||||
}
|
||||
((NokiaFlashModel)Notifier.CurrentModel).SwitchToFlashAppContext();
|
||||
((LumiaBootManagerAppModel)Notifier.CurrentModel).SwitchToFlashAppContext();
|
||||
|
||||
Parts = LumiaGenerateEFIESPFlashPayload(UnlockedEFIESP, GPT, ProfileFFU, IsSpecB);
|
||||
|
||||
@@ -2517,7 +2469,7 @@ namespace WPinternals
|
||||
|
||||
if (!IsSpecB)
|
||||
{
|
||||
((NokiaFlashModel)Notifier.CurrentModel).ResetPhone();
|
||||
((LumiaFlashAppModel)Notifier.CurrentModel).ResetPhone();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2637,7 +2589,7 @@ namespace WPinternals
|
||||
|
||||
private static async Task LumiaFlashParts(PhoneNotifierViewModel Notifier, string FFUPath, bool PerformFullFlashFirst, bool SkipWrite, List<FlashPart> Parts, bool DoResetFirst = true, bool ClearFlashingStatusAtEnd = true, bool CheckSectorAlignment = true, bool ShowProgress = true, bool Experimental = false, SetWorkingStatus SetWorkingStatus = null, UpdateWorkingStatus UpdateWorkingStatus = null, ExitSuccess ExitSuccess = null, ExitFailure ExitFailure = null, string EDEPath = null)
|
||||
{
|
||||
PhoneInfo Info = ((NokiaFlashModel)Notifier.CurrentModel).ReadPhoneInfo();
|
||||
PhoneInfo Info = ((LumiaFlashAppModel)Notifier.CurrentModel).ReadPhoneInfo();
|
||||
bool IsSpecA = Info.FlashAppProtocolVersionMajor < 2;
|
||||
|
||||
if (IsSpecA)
|
||||
@@ -2654,7 +2606,7 @@ namespace WPinternals
|
||||
{
|
||||
SetWorkingStatus("Initializing flash...", null, 100, Status: WPinternalsStatus.Initializing);
|
||||
|
||||
NokiaFlashModel FlashModel = (NokiaFlashModel)Notifier.CurrentModel;
|
||||
LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)Notifier.CurrentModel;
|
||||
|
||||
UInt64 InputStreamLength = 0;
|
||||
UInt64 totalwritten = 0;
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace WPinternals
|
||||
{
|
||||
LogFile.Log("Find Flashing Profile", LogType.FileAndConsole);
|
||||
|
||||
NokiaFlashModel FlashModel = (NokiaFlashModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
|
||||
PhoneInfo Info;
|
||||
if (DoResetFirst)
|
||||
@@ -125,14 +125,14 @@ namespace WPinternals
|
||||
LogFile.Log("Command: Enable testsigning", LogType.FileAndConsole);
|
||||
PhoneNotifierViewModel Notifier = new();
|
||||
UIContext.Send(s => Notifier.Start(), null);
|
||||
NokiaFlashModel FlashModel = (NokiaFlashModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
|
||||
List<FlashPart> Parts = new();
|
||||
FlashPart Part;
|
||||
|
||||
// Use GetGptChunk() here instead of ReadGPT(), because ReadGPT() skips the first sector.
|
||||
// We need the fist sector if we want to write back the GPT.
|
||||
byte[] GPTChunk = LumiaUnlockBootloaderViewModel.GetGptChunk(FlashModel, 0x20000);
|
||||
byte[] GPTChunk = FlashModel.GetGptChunk(0x20000);
|
||||
GPT GPT = new(GPTChunk);
|
||||
bool GPTChanged = false;
|
||||
|
||||
@@ -228,7 +228,7 @@ namespace WPinternals
|
||||
return ((MassStorage)Notifier.CurrentModel).Drive;
|
||||
}
|
||||
|
||||
NokiaFlashModel FlashModel = (NokiaFlashModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
if (DoResetFirst)
|
||||
{
|
||||
// The phone will be reset before flashing, so we have the opportunity to get some more info from the phone
|
||||
@@ -260,12 +260,12 @@ namespace WPinternals
|
||||
LogFile.Log("Command: Clear NV", LogType.FileAndConsole);
|
||||
PhoneNotifierViewModel Notifier = new();
|
||||
UIContext.Send(s => Notifier.Start(), null);
|
||||
NokiaFlashModel FlashModel = (NokiaFlashModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
List<FlashPart> Parts = new();
|
||||
|
||||
// Use GetGptChunk() here instead of ReadGPT(), because ReadGPT() skips the first sector.
|
||||
// We need the fist sector if we want to write back the GPT.
|
||||
byte[] GPTChunk = LumiaUnlockBootloaderViewModel.GetGptChunk(FlashModel, 0x20000);
|
||||
byte[] GPTChunk = FlashModel.GetGptChunk(0x20000);
|
||||
GPT GPT = new(GPTChunk);
|
||||
bool GPTChanged = false;
|
||||
Partition BACKUP_BS_NV = GPT.GetPartition("BACKUP_BS_NV");
|
||||
@@ -336,13 +336,13 @@ namespace WPinternals
|
||||
PhoneNotifierViewModel Notifier = new();
|
||||
UIContext.Send(s => Notifier.Start(), null);
|
||||
|
||||
NokiaFlashModel FlashModel = (NokiaFlashModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
|
||||
PhoneInfo Info = FlashModel.ReadPhoneInfo();
|
||||
|
||||
// Use GetGptChunk() here instead of ReadGPT(), because ReadGPT() skips the first sector.
|
||||
// We need the fist sector if we want to write back the GPT.
|
||||
byte[] GPTChunk = LumiaUnlockBootloaderViewModel.GetGptChunk(FlashModel, 0x20000);
|
||||
byte[] GPTChunk = FlashModel.GetGptChunk(0x20000);
|
||||
GPT GPT = new(GPTChunk);
|
||||
|
||||
Partition TargetPartition = GPT.GetPartition(PartitionName);
|
||||
@@ -445,7 +445,7 @@ namespace WPinternals
|
||||
PhoneNotifierViewModel Notifier = new();
|
||||
UIContext.Send(s => Notifier.Start(), null);
|
||||
|
||||
NokiaFlashModel FlashModel = (NokiaFlashModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
|
||||
PhoneInfo Info = FlashModel.ReadPhoneInfo();
|
||||
|
||||
@@ -483,10 +483,10 @@ namespace WPinternals
|
||||
|
||||
internal async static Task LumiaV2CustomFlash(PhoneNotifierViewModel Notifier, string FFUPath, bool PerformFullFlashFirst, bool SkipWrite, List<FlashPart> FlashParts, bool DoResetFirst = true, bool ClearFlashingStatusAtEnd = true, bool CheckSectorAlignment = true, bool ShowProgress = true, bool Experimental = false, SetWorkingStatus SetWorkingStatus = null, UpdateWorkingStatus UpdateWorkingStatus = null, ExitSuccess ExitSuccess = null, ExitFailure ExitFailure = null, string ProgrammerPath = null)
|
||||
{
|
||||
NokiaFlashModel Model = (NokiaFlashModel)Notifier.CurrentModel;
|
||||
LumiaFlashAppModel Model = (LumiaFlashAppModel)Notifier.CurrentModel;
|
||||
PhoneInfo Info = Model.ReadPhoneInfo();
|
||||
|
||||
byte[] GPTChunk = LumiaUnlockBootloaderViewModel.GetGptChunk(Model, 131072u);
|
||||
byte[] GPTChunk = Model.GetGptChunk(131072u);
|
||||
|
||||
GPT GPT = new(GPTChunk);
|
||||
|
||||
@@ -554,7 +554,7 @@ namespace WPinternals
|
||||
ExitFailure = (m, s) => { };
|
||||
}
|
||||
|
||||
NokiaFlashModel Model = (NokiaFlashModel)Notifier.CurrentModel;
|
||||
LumiaFlashAppModel Model = (LumiaFlashAppModel)Notifier.CurrentModel;
|
||||
PhoneInfo Info = Model.ReadPhoneInfo();
|
||||
|
||||
string Type = Info.Type;
|
||||
@@ -673,7 +673,7 @@ namespace WPinternals
|
||||
MaximumAttempts = (int)(((MaximumGapFill / FFU.ChunkSize) + 1) * 8);
|
||||
}
|
||||
|
||||
byte[] GPTChunk = LumiaUnlockBootloaderViewModel.GetGptChunk(Model, (UInt32)FFU.ChunkSize);
|
||||
byte[] GPTChunk = Model.GetGptChunk((UInt32)FFU.ChunkSize);
|
||||
|
||||
// Start with a reset
|
||||
if (DoResetFirst)
|
||||
@@ -818,23 +818,12 @@ namespace WPinternals
|
||||
throw new WPinternalsException("Phone is in wrong mode", "The phone should have been detected in bootloader or flash mode. Instead it has been detected in " + Notifier.CurrentInterface.ToString() + " mode.");
|
||||
}
|
||||
|
||||
Model = (NokiaFlashModel)Notifier.CurrentModel;
|
||||
UpdateWorkingStatus("Initializing flash...", null, null);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// This will succeed on new models
|
||||
Model.SwitchToFlashAppContext();
|
||||
Model.DisableRebootTimeOut();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// This will succeed on old models
|
||||
Model.ResetPhoneToFlashMode();
|
||||
await Notifier.WaitForArrival();
|
||||
Model = (NokiaFlashModel)Notifier.CurrentModel;
|
||||
}
|
||||
((LumiaBootManagerAppModel)Notifier.CurrentModel).ResetPhoneToFlashMode();
|
||||
await Notifier.WaitForArrival();
|
||||
Model = (LumiaFlashAppModel)Notifier.CurrentModel;
|
||||
|
||||
// The payloads must be ordered by the number of locations
|
||||
//
|
||||
@@ -1516,10 +1505,9 @@ namespace WPinternals
|
||||
break;
|
||||
}
|
||||
|
||||
Model = (NokiaFlashModel)Notifier.CurrentModel;
|
||||
|
||||
// In case we are on an Engineering phone which isn't stuck in flashmode and booted to BootMgrApp
|
||||
Model.SwitchToFlashAppContext();
|
||||
((LumiaBootManagerAppModel)Notifier.CurrentModel).SwitchToFlashAppContext();
|
||||
Model = (LumiaFlashAppModel)Notifier.CurrentModel;
|
||||
Model.DisableRebootTimeOut();
|
||||
}
|
||||
|
||||
@@ -1644,7 +1632,7 @@ namespace WPinternals
|
||||
}
|
||||
|
||||
// Do the actual reset, which will result in a crash while cleaning up memory
|
||||
((NokiaFlashModel)Notifier.CurrentModel).ResetPhone();
|
||||
((LumiaFlashAppModel)Notifier.CurrentModel).ResetPhone();
|
||||
|
||||
LogFile.Log("Phone performs hard exit", LogType.FileAndConsole);
|
||||
|
||||
@@ -1782,7 +1770,7 @@ namespace WPinternals
|
||||
else
|
||||
{
|
||||
// If we didn't do a hard exit, we need to do a normal reboot
|
||||
((NokiaFlashModel)Notifier.CurrentModel).ResetPhone();
|
||||
((LumiaFlashAppModel)Notifier.CurrentModel).ResetPhone();
|
||||
}
|
||||
|
||||
if (Success)
|
||||
@@ -1964,11 +1952,11 @@ namespace WPinternals
|
||||
{
|
||||
LogFile.BeginAction("FlashCustomROM");
|
||||
|
||||
NokiaFlashModel FlashModel = (NokiaFlashModel)Notifier.CurrentModel;
|
||||
LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)Notifier.CurrentModel;
|
||||
|
||||
// Use GetGptChunk() here instead of ReadGPT(), because ReadGPT() skips the first sector.
|
||||
// We need the fist sector if we want to write back the GPT.
|
||||
byte[] GPTChunk = LumiaUnlockBootloaderViewModel.GetGptChunk(FlashModel, 0x20000);
|
||||
byte[] GPTChunk = FlashModel.GetGptChunk(0x20000);
|
||||
GPT GPT = new(GPTChunk);
|
||||
|
||||
Partition Target;
|
||||
@@ -2357,11 +2345,11 @@ namespace WPinternals
|
||||
// Assumes phone is in flash mode
|
||||
internal async static Task LumiaV2FlashPartitions(PhoneNotifierViewModel Notifier, string EFIESPPath, string MainOSPath, string DataPath, SetWorkingStatus SetWorkingStatus = null, UpdateWorkingStatus UpdateWorkingStatus = null, ExitSuccess ExitSuccess = null, ExitFailure ExitFailure = null)
|
||||
{
|
||||
NokiaFlashModel FlashModel = (NokiaFlashModel)Notifier.CurrentModel;
|
||||
LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)Notifier.CurrentModel;
|
||||
|
||||
// Use GetGptChunk() here instead of ReadGPT(), because ReadGPT() skips the first sector.
|
||||
// We need the fist sector if we want to write back the GPT.
|
||||
byte[] GPTChunk = LumiaUnlockBootloaderViewModel.GetGptChunk(FlashModel, 0x20000);
|
||||
byte[] GPTChunk = FlashModel.GetGptChunk(0x20000);
|
||||
GPT GPT = new(GPTChunk);
|
||||
|
||||
Partition Target;
|
||||
|
||||
@@ -192,7 +192,7 @@ namespace WPinternals
|
||||
|
||||
try
|
||||
{
|
||||
NokiaFlashModel Model = (NokiaFlashModel)Notifier.CurrentModel;
|
||||
LumiaFlashAppModel Model = (LumiaFlashAppModel)Notifier.CurrentModel;
|
||||
PhoneInfo Info = Model.ReadPhoneInfo();
|
||||
|
||||
if ((Info.SecureFfuSupportedProtocolMask & ((ushort)FfuProtocol.ProtocolSyncV2)) == 0) // Exploit needs protocol v2 -> This check is not conclusive, because old phones also report support for this protocol, although it is really not supported.
|
||||
@@ -282,7 +282,7 @@ namespace WPinternals
|
||||
store.WriteDescriptorLength += payload.GetStoreHeaderSize();
|
||||
}
|
||||
|
||||
byte[] GPTChunk = LumiaUnlockBootloaderViewModel.GetGptChunk(Model, 0x20000);
|
||||
byte[] GPTChunk = Model.GetGptChunk(0x20000);
|
||||
GPT GPT = new(GPTChunk);
|
||||
UInt64 PlatEnd = 0;
|
||||
if (GPT.Partitions.Any(x => x.Name == "PLAT"))
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace WPinternals
|
||||
|
||||
internal class NokiaBootloaderViewModel : ContextViewModel
|
||||
{
|
||||
private readonly NokiaFlashModel CurrentModel;
|
||||
private readonly LumiaBootManagerAppModel CurrentModel;
|
||||
private readonly Action<PhoneInterfaces> RequestModeSwitch;
|
||||
internal Action SwitchToGettingStarted;
|
||||
private readonly object LockDeviceInfo = new();
|
||||
@@ -38,7 +38,7 @@ namespace WPinternals
|
||||
internal NokiaBootloaderViewModel(NokiaPhoneModel CurrentModel, Action<PhoneInterfaces> RequestModeSwitch, Action SwitchToGettingStarted)
|
||||
: base()
|
||||
{
|
||||
this.CurrentModel = (NokiaFlashModel)CurrentModel;
|
||||
this.CurrentModel = (LumiaBootManagerAppModel)CurrentModel;
|
||||
this.RequestModeSwitch = RequestModeSwitch;
|
||||
this.SwitchToGettingStarted = SwitchToGettingStarted;
|
||||
}
|
||||
@@ -63,6 +63,9 @@ namespace WPinternals
|
||||
case "Normal":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Normal);
|
||||
break;
|
||||
case "PhoneInfo":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_PhoneInfo);
|
||||
break;
|
||||
case "Label":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Label);
|
||||
break;
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace WPinternals
|
||||
|
||||
internal class NokiaFlashViewModel : ContextViewModel
|
||||
{
|
||||
private readonly NokiaFlashModel CurrentModel;
|
||||
private readonly LumiaFlashAppModel CurrentModel;
|
||||
private readonly Action<PhoneInterfaces> RequestModeSwitch;
|
||||
internal Action SwitchToGettingStarted;
|
||||
private readonly object LockDeviceInfo = new();
|
||||
@@ -39,7 +39,7 @@ namespace WPinternals
|
||||
internal NokiaFlashViewModel(NokiaPhoneModel CurrentModel, Action<PhoneInterfaces> RequestModeSwitch, Action SwitchToGettingStarted)
|
||||
: base()
|
||||
{
|
||||
this.CurrentModel = (NokiaFlashModel)CurrentModel;
|
||||
this.CurrentModel = (LumiaFlashAppModel)CurrentModel;
|
||||
this.RequestModeSwitch = RequestModeSwitch;
|
||||
this.SwitchToGettingStarted = SwitchToGettingStarted;
|
||||
}
|
||||
@@ -95,21 +95,21 @@ namespace WPinternals
|
||||
SecurityFlags = (UInt32)CurrentModel.ReadSecurityFlags();
|
||||
LogFile.Log("Security flags: 0x" + SecurityFlags.ToString("X8"));
|
||||
|
||||
FinalConfigDakStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.Dak);
|
||||
FinalConfigFastBootStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.FastBoot);
|
||||
FinalConfigFfuVerifyStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.FfuVerify);
|
||||
FinalConfigJtagStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.Jtag);
|
||||
FinalConfigOemIdStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.OemId);
|
||||
FinalConfigProductionDoneStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.ProductionDone);
|
||||
FinalConfigPublicIdStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.PublicId);
|
||||
FinalConfigRkhStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.Rkh);
|
||||
FinalConfigRpmWdogStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.RpmWdog);
|
||||
FinalConfigSecGenStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.SecGen);
|
||||
FinalConfigSecureBootStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.SecureBoot);
|
||||
FinalConfigShkStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.Shk);
|
||||
FinalConfigSimlockStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.Simlock);
|
||||
FinalConfigSpdmSecModeStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.SpdmSecMode);
|
||||
FinalConfigSsmStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.Ssm);
|
||||
FinalConfigDakStatus = CurrentModel.ReadFuseStatus(Fuse.Dak);
|
||||
FinalConfigFastBootStatus = CurrentModel.ReadFuseStatus(Fuse.FastBoot);
|
||||
FinalConfigFfuVerifyStatus = CurrentModel.ReadFuseStatus(Fuse.FfuVerify);
|
||||
FinalConfigJtagStatus = CurrentModel.ReadFuseStatus(Fuse.Jtag);
|
||||
FinalConfigOemIdStatus = CurrentModel.ReadFuseStatus(Fuse.OemId);
|
||||
FinalConfigProductionDoneStatus = CurrentModel.ReadFuseStatus(Fuse.ProductionDone);
|
||||
FinalConfigPublicIdStatus = CurrentModel.ReadFuseStatus(Fuse.PublicId);
|
||||
FinalConfigRkhStatus = CurrentModel.ReadFuseStatus(Fuse.Rkh);
|
||||
FinalConfigRpmWdogStatus = CurrentModel.ReadFuseStatus(Fuse.RpmWdog);
|
||||
FinalConfigSecGenStatus = CurrentModel.ReadFuseStatus(Fuse.SecGen);
|
||||
FinalConfigSecureBootStatus = CurrentModel.ReadFuseStatus(Fuse.SecureBoot);
|
||||
FinalConfigShkStatus = CurrentModel.ReadFuseStatus(Fuse.Shk);
|
||||
FinalConfigSimlockStatus = CurrentModel.ReadFuseStatus(Fuse.Simlock);
|
||||
FinalConfigSpdmSecModeStatus = CurrentModel.ReadFuseStatus(Fuse.SpdmSecMode);
|
||||
FinalConfigSsmStatus = CurrentModel.ReadFuseStatus(Fuse.Ssm);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -748,6 +748,9 @@ namespace WPinternals
|
||||
case "Normal":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Normal);
|
||||
break;
|
||||
case "PhoneInfo":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_PhoneInfo);
|
||||
break;
|
||||
case "Label":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Label);
|
||||
break;
|
||||
|
||||
@@ -292,6 +292,9 @@ namespace WPinternals
|
||||
case "Flash":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Flash);
|
||||
break;
|
||||
case "PhoneInfo":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_PhoneInfo);
|
||||
break;
|
||||
case "Label":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Label);
|
||||
break;
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace WPinternals
|
||||
{
|
||||
internal class NokiaModeBootloaderViewModel : ContextViewModel
|
||||
{
|
||||
private readonly NokiaFlashModel CurrentModel;
|
||||
private readonly LumiaBootManagerAppModel CurrentModel;
|
||||
private readonly Action<PhoneInterfaces?> RequestModeSwitch;
|
||||
private readonly object LockDeviceInfo = new();
|
||||
private bool DeviceInfoLoaded = false;
|
||||
@@ -33,7 +33,7 @@ namespace WPinternals
|
||||
internal NokiaModeBootloaderViewModel(NokiaPhoneModel CurrentModel, Action<PhoneInterfaces?> RequestModeSwitch)
|
||||
: base()
|
||||
{
|
||||
this.CurrentModel = (NokiaFlashModel)CurrentModel;
|
||||
this.CurrentModel = (LumiaBootManagerAppModel)CurrentModel;
|
||||
this.RequestModeSwitch = RequestModeSwitch;
|
||||
}
|
||||
|
||||
@@ -69,19 +69,7 @@ namespace WPinternals
|
||||
{
|
||||
PhoneInfo Info = CurrentModel.ReadPhoneInfo();
|
||||
|
||||
if (Info.FlashAppProtocolVersionMajor < 2)
|
||||
{
|
||||
UefiSecurityStatusResponse SecurityStatus = CurrentModel.ReadSecurityStatus();
|
||||
|
||||
if (SecurityStatus != null)
|
||||
{
|
||||
EffectiveBootloaderSecurityStatus = SecurityStatus.SecureFfuEfuseStatus && !SecurityStatus.AuthenticationStatus && !SecurityStatus.RdcStatus;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EffectiveBootloaderSecurityStatus = Info.UefiSecureBootEnabled;
|
||||
}
|
||||
EffectiveBootloaderSecurityStatus = Info.UefiSecureBootEnabled;
|
||||
|
||||
LogFile.Log("Effective Bootloader Security Status: " + EffectiveBootloaderSecurityStatus.ToString());
|
||||
}
|
||||
@@ -101,6 +89,9 @@ namespace WPinternals
|
||||
case "Normal":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Normal);
|
||||
break;
|
||||
case "PhoneInfo":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_PhoneInfo);
|
||||
break;
|
||||
case "Flash":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Flash);
|
||||
break;
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace WPinternals
|
||||
{
|
||||
internal class NokiaModeFlashViewModel : ContextViewModel
|
||||
{
|
||||
private readonly NokiaFlashModel CurrentModel;
|
||||
private readonly LumiaFlashAppModel CurrentModel;
|
||||
private readonly Action<PhoneInterfaces?> RequestModeSwitch;
|
||||
private readonly object LockDeviceInfo = new();
|
||||
private bool DeviceInfoLoaded = false;
|
||||
@@ -33,7 +33,7 @@ namespace WPinternals
|
||||
internal NokiaModeFlashViewModel(NokiaPhoneModel CurrentModel, Action<PhoneInterfaces?> RequestModeSwitch)
|
||||
: base()
|
||||
{
|
||||
this.CurrentModel = (NokiaFlashModel)CurrentModel;
|
||||
this.CurrentModel = (LumiaFlashAppModel)CurrentModel;
|
||||
this.RequestModeSwitch = RequestModeSwitch;
|
||||
}
|
||||
|
||||
@@ -103,6 +103,12 @@ namespace WPinternals
|
||||
case "Flash":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Flash);
|
||||
break;
|
||||
case "PhoneInfo":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_PhoneInfo);
|
||||
break;
|
||||
case "BootMgr":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Bootloader);
|
||||
break;
|
||||
case "Label":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Label);
|
||||
break;
|
||||
|
||||
@@ -41,6 +41,12 @@ namespace WPinternals
|
||||
case "Normal":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Normal);
|
||||
break;
|
||||
case "PhoneInfo":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_PhoneInfo);
|
||||
break;
|
||||
case "BootMgr":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Bootloader);
|
||||
break;
|
||||
case "Flash":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Flash);
|
||||
break;
|
||||
|
||||
@@ -63,6 +63,12 @@ namespace WPinternals
|
||||
case "Normal":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Normal);
|
||||
break;
|
||||
case "PhoneInfo":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_PhoneInfo);
|
||||
break;
|
||||
case "BootMgr":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Bootloader);
|
||||
break;
|
||||
case "Label":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Label);
|
||||
break;
|
||||
|
||||
@@ -41,6 +41,12 @@ namespace WPinternals
|
||||
case "Flash":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Flash);
|
||||
break;
|
||||
case "PhoneInfo":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_PhoneInfo);
|
||||
break;
|
||||
case "BootMgr":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Bootloader);
|
||||
break;
|
||||
case "Label":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Label);
|
||||
break;
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace WPinternals
|
||||
{
|
||||
internal class NokiaModePhoneInfoViewModel : ContextViewModel
|
||||
{
|
||||
private readonly NokiaFlashModel CurrentModel;
|
||||
private readonly LumiaPhoneInfoAppModel CurrentModel;
|
||||
private readonly Action<PhoneInterfaces?> RequestModeSwitch;
|
||||
private readonly object LockDeviceInfo = new();
|
||||
private bool DeviceInfoLoaded = false;
|
||||
@@ -33,7 +33,7 @@ namespace WPinternals
|
||||
internal NokiaModePhoneInfoViewModel(NokiaPhoneModel CurrentModel, Action<PhoneInterfaces?> RequestModeSwitch)
|
||||
: base()
|
||||
{
|
||||
this.CurrentModel = (NokiaFlashModel)CurrentModel;
|
||||
this.CurrentModel = (LumiaPhoneInfoAppModel)CurrentModel;
|
||||
this.RequestModeSwitch = RequestModeSwitch;
|
||||
}
|
||||
|
||||
@@ -69,19 +69,7 @@ namespace WPinternals
|
||||
{
|
||||
PhoneInfo Info = CurrentModel.ReadPhoneInfo();
|
||||
|
||||
if (Info.FlashAppProtocolVersionMajor < 2)
|
||||
{
|
||||
UefiSecurityStatusResponse SecurityStatus = CurrentModel.ReadSecurityStatus();
|
||||
|
||||
if (SecurityStatus != null)
|
||||
{
|
||||
EffectivePhoneInfoSecurityStatus = SecurityStatus.SecureFfuEfuseStatus && !SecurityStatus.AuthenticationStatus && !SecurityStatus.RdcStatus;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EffectivePhoneInfoSecurityStatus = Info.UefiSecureBootEnabled;
|
||||
}
|
||||
EffectivePhoneInfoSecurityStatus = Info.UefiSecureBootEnabled;
|
||||
|
||||
LogFile.Log("Effective PhoneInfo Security Status: " + EffectivePhoneInfoSecurityStatus.ToString());
|
||||
}
|
||||
@@ -104,6 +92,9 @@ namespace WPinternals
|
||||
case "Flash":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Flash);
|
||||
break;
|
||||
case "BootMgr":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Bootloader);
|
||||
break;
|
||||
case "Label":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Label);
|
||||
break;
|
||||
|
||||
@@ -384,6 +384,12 @@ namespace WPinternals
|
||||
case "Flash":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Flash);
|
||||
break;
|
||||
case "PhoneInfo":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_PhoneInfo);
|
||||
break;
|
||||
case "BootMgr":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Bootloader);
|
||||
break;
|
||||
case "Label":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Label);
|
||||
break;
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace WPinternals
|
||||
|
||||
internal class NokiaPhoneInfoViewModel : ContextViewModel
|
||||
{
|
||||
private readonly NokiaFlashModel CurrentModel;
|
||||
private readonly LumiaPhoneInfoAppModel CurrentModel;
|
||||
private readonly Action<PhoneInterfaces> RequestModeSwitch;
|
||||
internal Action SwitchToGettingStarted;
|
||||
private readonly object LockDeviceInfo = new();
|
||||
@@ -41,7 +41,7 @@ namespace WPinternals
|
||||
internal NokiaPhoneInfoViewModel(NokiaPhoneModel CurrentModel, Action<PhoneInterfaces> RequestModeSwitch, Action SwitchToGettingStarted)
|
||||
: base()
|
||||
{
|
||||
this.CurrentModel = (NokiaFlashModel)CurrentModel;
|
||||
this.CurrentModel = (LumiaPhoneInfoAppModel)CurrentModel;
|
||||
this.RequestModeSwitch = RequestModeSwitch;
|
||||
this.SwitchToGettingStarted = SwitchToGettingStarted;
|
||||
}
|
||||
@@ -192,6 +192,12 @@ namespace WPinternals
|
||||
case "Normal":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Normal);
|
||||
break;
|
||||
case "Flash":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Flash);
|
||||
break;
|
||||
case "BootMgr":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Bootloader);
|
||||
break;
|
||||
case "Label":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Label);
|
||||
break;
|
||||
|
||||
@@ -237,13 +237,12 @@ namespace WPinternals
|
||||
e.DevicePath.Contains("&PID_0A02", StringComparison.OrdinalIgnoreCase) || // VID_045E&PID_0A02 is for Lumia 950
|
||||
e.DevicePath.Contains("&PID_05EE", StringComparison.OrdinalIgnoreCase)) // VID_0421&PID_05EE is for early RX100
|
||||
{
|
||||
CurrentModel = new NokiaFlashModel(e.DevicePath);
|
||||
((NokiaFlashModel)CurrentModel).InterfaceChanged += InterfaceChanged;
|
||||
|
||||
FlashAppType type = FlashAppType.FlashApp;
|
||||
try
|
||||
{
|
||||
type = ((NokiaFlashModel)CurrentModel).GetFlashAppType();
|
||||
NokiaFlashModel tmpModel = new NokiaFlashModel(e.DevicePath);
|
||||
type = tmpModel.GetFlashAppType();
|
||||
tmpModel.Dispose();
|
||||
LogFile.Log("Flash App Type: " + type.ToString(), LogType.FileOnly);
|
||||
}
|
||||
catch
|
||||
@@ -255,6 +254,9 @@ namespace WPinternals
|
||||
{
|
||||
case FlashAppType.BootManager:
|
||||
{
|
||||
CurrentModel = new LumiaBootManagerAppModel(e.DevicePath);
|
||||
((NokiaFlashModel)CurrentModel).InterfaceChanged += InterfaceChanged;
|
||||
|
||||
CurrentInterface = PhoneInterfaces.Lumia_Bootloader;
|
||||
LogFile.Log("Found device on interface: " + ((USBNotifier)sender).Guid.ToString(), LogType.FileOnly);
|
||||
LogFile.Log("Device path: " + e.DevicePath, LogType.FileOnly);
|
||||
@@ -265,6 +267,9 @@ namespace WPinternals
|
||||
}
|
||||
case FlashAppType.FlashApp:
|
||||
{
|
||||
CurrentModel = new LumiaFlashAppModel(e.DevicePath);
|
||||
((NokiaFlashModel)CurrentModel).InterfaceChanged += InterfaceChanged;
|
||||
|
||||
((NokiaFlashModel)CurrentModel).DisableRebootTimeOut();
|
||||
CurrentInterface = PhoneInterfaces.Lumia_Flash;
|
||||
LogFile.Log("Found device on interface: " + ((USBNotifier)sender).Guid.ToString(), LogType.FileOnly);
|
||||
@@ -276,6 +281,9 @@ namespace WPinternals
|
||||
}
|
||||
case FlashAppType.PhoneInfoApp:
|
||||
{
|
||||
CurrentModel = new LumiaPhoneInfoAppModel(e.DevicePath);
|
||||
((NokiaFlashModel)CurrentModel).InterfaceChanged += InterfaceChanged;
|
||||
|
||||
((NokiaFlashModel)CurrentModel).DisableRebootTimeOut();
|
||||
CurrentInterface = PhoneInterfaces.Lumia_PhoneInfo;
|
||||
LogFile.Log("Found device on interface: " + ((USBNotifier)sender).Guid.ToString(), LogType.FileOnly);
|
||||
@@ -415,9 +423,80 @@ namespace WPinternals
|
||||
}
|
||||
}
|
||||
|
||||
private void InterfaceChanged(PhoneInterfaces NewInterface)
|
||||
private void InterfaceChanged(PhoneInterfaces NewInterface, string DevicePath)
|
||||
{
|
||||
CurrentInterface = NewInterface;
|
||||
LastInterface = CurrentInterface;
|
||||
CurrentInterface = null;
|
||||
|
||||
if (CurrentModel != null)
|
||||
{
|
||||
CurrentModel.Dispose();
|
||||
CurrentModel = null;
|
||||
LogFile.Log("Lumia disconnected", LogType.FileAndConsole);
|
||||
}
|
||||
|
||||
DeviceRemoved();
|
||||
|
||||
switch (NewInterface)
|
||||
{
|
||||
case PhoneInterfaces.Lumia_Bootloader:
|
||||
{
|
||||
CurrentModel = new LumiaBootManagerAppModel(DevicePath);
|
||||
((NokiaFlashModel)CurrentModel).InterfaceChanged += InterfaceChanged;
|
||||
|
||||
CurrentInterface = PhoneInterfaces.Lumia_Bootloader;
|
||||
LogFile.Log("Found device on interface: " + LumiaFlashInterfaceGuid.ToString(), LogType.FileOnly);
|
||||
LogFile.Log("Device path: " + DevicePath, LogType.FileOnly);
|
||||
LogFile.Log("Connected device: Lumia", LogType.FileAndConsole);
|
||||
LogFile.Log("Mode: Bootloader", LogType.FileAndConsole);
|
||||
NewDeviceArrived(new ArrivalEventArgs((PhoneInterfaces)CurrentInterface, CurrentModel));
|
||||
break;
|
||||
}
|
||||
case PhoneInterfaces.Lumia_Flash:
|
||||
{
|
||||
CurrentModel = new LumiaFlashAppModel(DevicePath);
|
||||
((NokiaFlashModel)CurrentModel).InterfaceChanged += InterfaceChanged;
|
||||
|
||||
((NokiaFlashModel)CurrentModel).DisableRebootTimeOut();
|
||||
CurrentInterface = PhoneInterfaces.Lumia_Flash;
|
||||
LogFile.Log("Found device on interface: " + LumiaFlashInterfaceGuid.ToString(), LogType.FileOnly);
|
||||
LogFile.Log("Device path: " + DevicePath, LogType.FileOnly);
|
||||
LogFile.Log("Connected device: Lumia", LogType.FileAndConsole);
|
||||
LogFile.Log("Mode: Flash", LogType.FileAndConsole);
|
||||
NewDeviceArrived(new ArrivalEventArgs((PhoneInterfaces)CurrentInterface, CurrentModel));
|
||||
break;
|
||||
}
|
||||
case PhoneInterfaces.Lumia_PhoneInfo:
|
||||
{
|
||||
CurrentModel = new LumiaPhoneInfoAppModel(DevicePath);
|
||||
((NokiaFlashModel)CurrentModel).InterfaceChanged += InterfaceChanged;
|
||||
|
||||
((NokiaFlashModel)CurrentModel).DisableRebootTimeOut();
|
||||
CurrentInterface = PhoneInterfaces.Lumia_PhoneInfo;
|
||||
LogFile.Log("Found device on interface: " + LumiaFlashInterfaceGuid.ToString(), LogType.FileOnly);
|
||||
LogFile.Log("Device path: " + DevicePath, LogType.FileOnly);
|
||||
LogFile.Log("Connected device: Lumia", LogType.FileAndConsole);
|
||||
LogFile.Log("Mode: Bootloader (Phone Info)", LogType.FileAndConsole);
|
||||
NewDeviceArrived(new ArrivalEventArgs((PhoneInterfaces)CurrentInterface, CurrentModel));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
LogFile.Log("Flash App Type could not be determined, assuming FlashApp", LogType.FileOnly);
|
||||
|
||||
CurrentModel = new LumiaFlashAppModel(DevicePath);
|
||||
((NokiaFlashModel)CurrentModel).InterfaceChanged += InterfaceChanged;
|
||||
|
||||
((NokiaFlashModel)CurrentModel).DisableRebootTimeOut();
|
||||
CurrentInterface = PhoneInterfaces.Lumia_Flash;
|
||||
LogFile.Log("Found device on interface: " + LumiaFlashInterfaceGuid.ToString(), LogType.FileOnly);
|
||||
LogFile.Log("Device path: " + DevicePath, LogType.FileOnly);
|
||||
LogFile.Log("Connected device: Lumia", LogType.FileAndConsole);
|
||||
LogFile.Log("Mode: Flash", LogType.FileAndConsole);
|
||||
NewDeviceArrived(new ArrivalEventArgs((PhoneInterfaces)CurrentInterface, CurrentModel));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LumiaNotifier_Removal(object sender, USBEvent e)
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace WPinternals
|
||||
Result = false;
|
||||
}
|
||||
|
||||
NokiaFlashModel Phone = (NokiaFlashModel)PhoneNotifier.CurrentModel;
|
||||
LumiaFlashAppModel Phone = (LumiaFlashAppModel)PhoneNotifier.CurrentModel;
|
||||
|
||||
BusyViewModel Busy = new("Restoring...", MaxProgressValue: TotalSizeSectors, UIContext: UIContext);
|
||||
ProgressUpdater Updater = Busy.ProgressUpdater;
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace WPinternals
|
||||
{
|
||||
if ((PhoneNotifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) && (TargetMode == PhoneInterfaces.Lumia_Flash))
|
||||
{
|
||||
PhoneInfo Info = ((NokiaFlashModel)PhoneNotifier.CurrentModel).ReadPhoneInfo(false);
|
||||
PhoneInfo Info = ((LumiaBootManagerAppModel)PhoneNotifier.CurrentModel).ReadPhoneInfo(false);
|
||||
if (Info.BootManagerProtocolVersionMajor >= 2)
|
||||
{
|
||||
try
|
||||
@@ -95,7 +95,7 @@ namespace WPinternals
|
||||
// It does not disconnect / reconnect anymore and the apptype is changed immediately
|
||||
// NOKS still doesnt return a status
|
||||
// BootMgr v1 uses normal NOKS and waits for arrival of FlashApp
|
||||
((NokiaFlashModel)PhoneNotifier.CurrentModel).SwitchToFlashAppContext();
|
||||
((LumiaBootManagerAppModel)PhoneNotifier.CurrentModel).SwitchToFlashAppContext();
|
||||
|
||||
// But this was called as a real switch, so we will raise an arrival event.
|
||||
PhoneNotifier.CurrentInterface = PhoneInterfaces.Lumia_Flash;
|
||||
@@ -233,6 +233,12 @@ namespace WPinternals
|
||||
{
|
||||
IsSwitching = true;
|
||||
|
||||
byte[] BootModeFlagCommand = [0x4E, 0x4F, 0x4B, 0x58, 0x46, 0x57, 0x00, 0x55, 0x42, 0x46, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00]; // NOKFW UBF
|
||||
byte[] RebootCommand = [0x4E, 0x4F, 0x4B, 0x52]; // NOKR
|
||||
byte[] RebootCommandResult;
|
||||
|
||||
bool ModernFlashApp;
|
||||
|
||||
// Make switch and set message or navigate to error
|
||||
switch (CurrentMode)
|
||||
{
|
||||
@@ -298,15 +304,11 @@ namespace WPinternals
|
||||
}
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Flash:
|
||||
case PhoneInterfaces.Lumia_Bootloader:
|
||||
byte[] BootModeFlagCommand = [0x4E, 0x4F, 0x4B, 0x58, 0x46, 0x57, 0x00, 0x55, 0x42, 0x46, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00]; // NOKFW UBF
|
||||
byte[] RebootCommand = [0x4E, 0x4F, 0x4B, 0x52]; // NOKR
|
||||
byte[] RebootCommandResult;
|
||||
IsSwitchingInterface = true;
|
||||
switch (TargetMode)
|
||||
{
|
||||
case null:
|
||||
((NokiaFlashModel)CurrentModel).Shutdown();
|
||||
((LumiaFlashAppModel)CurrentModel).Shutdown();
|
||||
ModeSwitchProgressWrapper("Please disconnect your device. Waiting...", null);
|
||||
LogFile.Log("Please disconnect your device. Waiting...", LogType.FileAndConsole);
|
||||
new Thread(() =>
|
||||
@@ -316,13 +318,154 @@ namespace WPinternals
|
||||
}).Start();
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Normal:
|
||||
((NokiaPhoneModel)CurrentModel).ExecuteRawVoidMethod(RebootCommand);
|
||||
((LumiaFlashAppModel)CurrentModel).ExecuteRawVoidMethod(RebootCommand);
|
||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
ModeSwitchProgressWrapper("Rebooting phone to Normal mode...", null);
|
||||
LogFile.Log("Rebooting phone to Normal mode", LogType.FileAndConsole);
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Bootloader:
|
||||
((NokiaPhoneModel)CurrentModel).ExecuteRawVoidMethod(RebootCommand);
|
||||
((LumiaFlashAppModel)CurrentModel).ExecuteRawVoidMethod(RebootCommand);
|
||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
ModeSwitchProgressWrapper("Rebooting phone to Bootloader mode...", null);
|
||||
LogFile.Log("Rebooting phone to Bootloader mode", LogType.FileAndConsole);
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_PhoneInfo:
|
||||
ModernFlashApp = ((LumiaFlashAppModel)CurrentModel).ReadPhoneInfo().FlashAppProtocolVersionMajor >= 2;
|
||||
if (ModernFlashApp)
|
||||
{
|
||||
((LumiaFlashAppModel)CurrentModel).SwitchToPhoneInfoAppContext();
|
||||
}
|
||||
else
|
||||
{
|
||||
((LumiaFlashAppModel)CurrentModel).SwitchToPhoneInfoAppContextLegacy();
|
||||
}
|
||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
ModeSwitchProgressWrapper("Rebooting phone to Phone Info mode...", null);
|
||||
LogFile.Log("Rebooting phone to Phone Info mode", LogType.FileAndConsole);
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Label:
|
||||
SwitchFromFlashToLabelMode();
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Flash: // attempt to boot from limited flash to full flash
|
||||
byte[] RebootToFlashCommand = [0x4E, 0x4F, 0x4B, 0x53]; // NOKS
|
||||
((LumiaFlashAppModel)CurrentModel).ExecuteRawVoidMethod(RebootToFlashCommand);
|
||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
ModeSwitchProgressWrapper("Rebooting phone to Flash mode...", null);
|
||||
LogFile.Log("Rebooting phone to Flash mode", LogType.FileAndConsole);
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_MassStorage:
|
||||
SwitchFromFlashToMassStorageMode();
|
||||
break;
|
||||
case PhoneInterfaces.Qualcomm_Download:
|
||||
byte[] RebootToQualcommDownloadCommand = [0x4E, 0x4F, 0x4B, 0x58, 0x43, 0x42, 0x45]; // NOKXCBE // TODO
|
||||
RebootCommandResult = ((LumiaFlashAppModel)CurrentModel).ExecuteRawMethod(RebootToQualcommDownloadCommand);
|
||||
if (RebootCommandResult?.Length == 4) // This means fail: NOKU (unknow command)
|
||||
{
|
||||
IsSwitchingInterface = false;
|
||||
ModeSwitchErrorWrapper("Failed to switch to Qualcomm Download mode");
|
||||
}
|
||||
else
|
||||
{
|
||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
ModeSwitchProgressWrapper("Rebooting phone to Qualcomm Download mode...", null);
|
||||
LogFile.Log("Rebooting phone to Qualcomm Download mode", LogType.FileAndConsole);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_PhoneInfo:
|
||||
IsSwitchingInterface = true;
|
||||
switch (TargetMode)
|
||||
{
|
||||
case PhoneInterfaces.Lumia_Normal:
|
||||
((LumiaPhoneInfoAppModel)CurrentModel).ExecuteRawVoidMethod(RebootCommand);
|
||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
ModeSwitchProgressWrapper("Rebooting phone to Normal mode...", null);
|
||||
LogFile.Log("Rebooting phone to Normal mode", LogType.FileAndConsole);
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Bootloader:
|
||||
ModernFlashApp = ((LumiaPhoneInfoAppModel)CurrentModel).ReadPhoneInfo().FlashAppProtocolVersionMajor >= 2;
|
||||
if (ModernFlashApp)
|
||||
{
|
||||
((LumiaPhoneInfoAppModel)CurrentModel).SwitchToBootManagerContext();
|
||||
}
|
||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
ModeSwitchProgressWrapper("Rebooting phone to Bootloader mode...", null);
|
||||
LogFile.Log("Rebooting phone to Bootloader mode", LogType.FileAndConsole);
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_PhoneInfo: // attempt to boot from limited phone info to full phone info
|
||||
ModernFlashApp = ((LumiaPhoneInfoAppModel)CurrentModel).ReadPhoneInfo().FlashAppProtocolVersionMajor >= 2;
|
||||
if (ModernFlashApp)
|
||||
{
|
||||
((LumiaPhoneInfoAppModel)CurrentModel).SwitchToPhoneInfoAppContext();
|
||||
}
|
||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
ModeSwitchProgressWrapper("Rebooting phone to Phone Info mode...", null);
|
||||
LogFile.Log("Rebooting phone to Phone Info mode", LogType.FileAndConsole);
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Label:
|
||||
SwitchFromPhoneInfoToLabelMode();
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Flash:
|
||||
ModernFlashApp = ((LumiaPhoneInfoAppModel)CurrentModel).ReadPhoneInfo().FlashAppProtocolVersionMajor >= 2;
|
||||
if (ModernFlashApp)
|
||||
{
|
||||
((LumiaPhoneInfoAppModel)CurrentModel).SwitchToFlashAppContext();
|
||||
}
|
||||
else
|
||||
{
|
||||
((LumiaPhoneInfoAppModel)CurrentModel).ContinueBoot();
|
||||
}
|
||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
ModeSwitchProgressWrapper("Rebooting phone to Flash mode...", null);
|
||||
LogFile.Log("Rebooting phone to Flash mode", LogType.FileAndConsole);
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_MassStorage:
|
||||
SwitchFromPhoneInfoToMassStorageMode();
|
||||
break;
|
||||
case PhoneInterfaces.Qualcomm_Download:
|
||||
byte[] RebootToQualcommDownloadCommand = [0x4E, 0x4F, 0x4B, 0x58, 0x43, 0x42, 0x45]; // NOKXCBE // TODO
|
||||
RebootCommandResult = ((LumiaPhoneInfoAppModel)CurrentModel).ExecuteRawMethod(RebootToQualcommDownloadCommand);
|
||||
if (RebootCommandResult?.Length == 4) // This means fail: NOKU (unknow command)
|
||||
{
|
||||
IsSwitchingInterface = false;
|
||||
ModeSwitchErrorWrapper("Failed to switch to Qualcomm Download mode");
|
||||
}
|
||||
else
|
||||
{
|
||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
ModeSwitchProgressWrapper("Rebooting phone to Qualcomm Download mode...", null);
|
||||
LogFile.Log("Rebooting phone to Qualcomm Download mode", LogType.FileAndConsole);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Bootloader:
|
||||
IsSwitchingInterface = true;
|
||||
switch (TargetMode)
|
||||
{
|
||||
case null:
|
||||
((LumiaBootManagerAppModel)CurrentModel).Shutdown();
|
||||
ModeSwitchProgressWrapper("Please disconnect your device. Waiting...", null);
|
||||
LogFile.Log("Please disconnect your device. Waiting...", LogType.FileAndConsole);
|
||||
new Thread(() =>
|
||||
{
|
||||
PhoneNotifier.WaitForRemoval().Wait();
|
||||
ModeSwitchSuccessWrapper();
|
||||
}).Start();
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Normal:
|
||||
((LumiaBootManagerAppModel)CurrentModel).ExecuteRawVoidMethod(RebootCommand);
|
||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
ModeSwitchProgressWrapper("Rebooting phone to Normal mode...", null);
|
||||
LogFile.Log("Rebooting phone to Normal mode", LogType.FileAndConsole);
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Bootloader:
|
||||
((LumiaBootManagerAppModel)CurrentModel).ExecuteRawVoidMethod(RebootCommand);
|
||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
ModeSwitchProgressWrapper("Rebooting phone to Bootloader mode...", null);
|
||||
LogFile.Log("Rebooting phone to Bootloader mode", LogType.FileAndConsole);
|
||||
@@ -332,7 +475,7 @@ namespace WPinternals
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Flash: // attempt to boot from limited flash to full flash
|
||||
byte[] RebootToFlashCommand = [0x4E, 0x4F, 0x4B, 0x53]; // NOKS
|
||||
((NokiaPhoneModel)CurrentModel).ExecuteRawVoidMethod(RebootToFlashCommand);
|
||||
((LumiaBootManagerAppModel)CurrentModel).ExecuteRawVoidMethod(RebootToFlashCommand);
|
||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
ModeSwitchProgressWrapper("Rebooting phone to Flash mode...", null);
|
||||
LogFile.Log("Rebooting phone to Flash mode", LogType.FileAndConsole);
|
||||
@@ -341,8 +484,8 @@ namespace WPinternals
|
||||
SwitchFromFlashToMassStorageMode();
|
||||
break;
|
||||
case PhoneInterfaces.Qualcomm_Download:
|
||||
byte[] RebootToQualcommDownloadCommand = [0x4E, 0x4F, 0x4B, 0x58, 0x43, 0x42, 0x45]; // NOKXCBE
|
||||
RebootCommandResult = ((NokiaPhoneModel)CurrentModel).ExecuteRawMethod(RebootToQualcommDownloadCommand);
|
||||
byte[] RebootToQualcommDownloadCommand = [0x4E, 0x4F, 0x4B, 0x58, 0x43, 0x42, 0x45]; // NOKXCBE // TODO
|
||||
RebootCommandResult = ((LumiaBootManagerAppModel)CurrentModel).ExecuteRawMethod(RebootToQualcommDownloadCommand);
|
||||
if (RebootCommandResult?.Length == 4) // This means fail: NOKU (unknow command)
|
||||
{
|
||||
IsSwitchingInterface = false;
|
||||
@@ -423,6 +566,12 @@ namespace WPinternals
|
||||
case PhoneInterfaces.Lumia_Flash:
|
||||
ModeSwitchErrorWrapper("Failed to switch to Flash mode");
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Bootloader:
|
||||
ModeSwitchErrorWrapper("Failed to switch to Boot Manager mode");
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_PhoneInfo:
|
||||
ModeSwitchErrorWrapper("Failed to switch to Phone Info mode");
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Label:
|
||||
ModeSwitchErrorWrapper("Failed to switch to Label mode");
|
||||
break;
|
||||
@@ -443,6 +592,12 @@ namespace WPinternals
|
||||
case PhoneInterfaces.Lumia_Flash:
|
||||
ModeSwitchErrorWrapper("Failed to switch to Flash mode");
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Bootloader:
|
||||
ModeSwitchErrorWrapper("Failed to switch to Boot Manager mode");
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_PhoneInfo:
|
||||
ModeSwitchErrorWrapper("Failed to switch to Phone Info mode");
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Label:
|
||||
ModeSwitchErrorWrapper("Failed to switch to Label mode");
|
||||
break;
|
||||
@@ -471,7 +626,7 @@ namespace WPinternals
|
||||
// SwitchToFlashAppContext() will only switch context. Phone will not charge.
|
||||
// ResetPhoneToFlashMode() reboots to real flash app. Phone will charge. Works when in BootMgrApp, not when already in FlashApp.
|
||||
|
||||
((NokiaFlashModel)CurrentModel).ResetPhoneToFlashMode();
|
||||
((LumiaBootManagerAppModel)CurrentModel).ResetPhoneToFlashMode();
|
||||
CurrentMode = PhoneInterfaces.Lumia_Flash;
|
||||
PhoneNotifier.NotifyArrival();
|
||||
}
|
||||
@@ -511,7 +666,7 @@ namespace WPinternals
|
||||
else if ((CurrentMode == PhoneInterfaces.Lumia_Flash) && (TargetMode == PhoneInterfaces.Qualcomm_Download))
|
||||
{
|
||||
byte[] RebootCommand = [0x4E, 0x4F, 0x4B, 0x52];
|
||||
byte[] RebootToQualcommDownloadCommand = [0x4E, 0x4F, 0x4B, 0x58, 0x43, 0x42, 0x45]; // NOKXCBE
|
||||
byte[] RebootToQualcommDownloadCommand = [0x4E, 0x4F, 0x4B, 0x58, 0x43, 0x42, 0x45]; // NOKXCBE // TODO
|
||||
IsSwitchingInterface = true;
|
||||
LogFile.Log("Sending command for rebooting to Emergency Download mode");
|
||||
byte[] RebootCommandResult = ((NokiaPhoneModel)CurrentModel).ExecuteRawMethod(RebootToQualcommDownloadCommand);
|
||||
@@ -542,6 +697,12 @@ namespace WPinternals
|
||||
case PhoneInterfaces.Lumia_Flash:
|
||||
ModeSwitchErrorWrapper("Failed to switch to Flash mode");
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Bootloader:
|
||||
ModeSwitchErrorWrapper("Failed to switch to Boot Manager mode");
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_PhoneInfo:
|
||||
ModeSwitchErrorWrapper("Failed to switch to Phone Info mode");
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Label:
|
||||
ModeSwitchErrorWrapper("Failed to switch to Label mode");
|
||||
break;
|
||||
@@ -552,21 +713,14 @@ namespace WPinternals
|
||||
}
|
||||
}
|
||||
|
||||
private void SwitchFromFlashToLabelMode(bool Continuation = false)
|
||||
private async void SwitchFromPhoneInfoToLabelMode(bool Continuation = false)
|
||||
{
|
||||
string ProgressText = Continuation ? "And now preparing to boot the phone to Label mode..." : "Preparing to boot the phone to Label mode...";
|
||||
NokiaFlashModel FlashModel = (NokiaFlashModel)CurrentModel;
|
||||
if (CurrentMode == PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
try
|
||||
{
|
||||
FlashModel.SwitchToFlashAppContext();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogFile.LogException(ex, LogType.FileOnly);
|
||||
}
|
||||
}
|
||||
|
||||
((LumiaBootManagerAppModel)CurrentModel).SwitchToFlashAppContext();
|
||||
await PhoneNotifier.WaitForArrival();
|
||||
|
||||
LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)CurrentModel;
|
||||
PhoneInfo Info = FlashModel.ReadPhoneInfo(ExtendedInfo: true);
|
||||
|
||||
if (Info.MmosOverUsbSupported)
|
||||
@@ -632,29 +786,306 @@ namespace WPinternals
|
||||
byte[] RebootCommand = [0x4E, 0x4F, 0x4B, 0x52]; // NOKR
|
||||
|
||||
BootModeFlagCommand[0x0F] = 0x59;
|
||||
((NokiaPhoneModel)CurrentModel).ExecuteRawMethod(BootModeFlagCommand);
|
||||
((NokiaPhoneModel)CurrentModel).ExecuteRawVoidMethod(RebootCommand);
|
||||
((LumiaFlashAppModel)CurrentModel).ExecuteRawMethod(BootModeFlagCommand);
|
||||
((LumiaFlashAppModel)CurrentModel).ExecuteRawVoidMethod(RebootCommand);
|
||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
ModeSwitchProgressWrapper("Rebooting phone to Label mode", null);
|
||||
LogFile.Log("Rebooting phone to Label mode", LogType.FileAndConsole);
|
||||
}
|
||||
}
|
||||
|
||||
private void SwitchFromFlashToLabelMode(bool Continuation = false)
|
||||
{
|
||||
string ProgressText = Continuation ? "And now preparing to boot the phone to Label mode..." : "Preparing to boot the phone to Label mode...";
|
||||
|
||||
LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)CurrentModel;
|
||||
PhoneInfo Info = FlashModel.ReadPhoneInfo(ExtendedInfo: true);
|
||||
|
||||
if (Info.MmosOverUsbSupported)
|
||||
{
|
||||
new Thread(() =>
|
||||
{
|
||||
LogFile.BeginAction("SwitchToLabelMode");
|
||||
|
||||
try
|
||||
{
|
||||
ModeSwitchProgressWrapper(ProgressText, null);
|
||||
string TempFolder = Environment.GetEnvironmentVariable("TEMP") + @"\WPInternals";
|
||||
if (Info.Type == "RM-1152")
|
||||
{
|
||||
Info.Type = "RM-1151";
|
||||
}
|
||||
string ENOSWPackage = LumiaDownloadModel.SearchENOSW(Info.Type, Info.Firmware);
|
||||
SetWorkingStatus("Downloading " + Info.Type + " Test Mode package...", MaxProgressValue: 100);
|
||||
DownloadEntry downloadEntry = new(ENOSWPackage, TempFolder, null, null, null);
|
||||
|
||||
downloadEntry.PropertyChanged += (object sender, System.ComponentModel.PropertyChangedEventArgs e) =>
|
||||
{
|
||||
if (e.PropertyName == "Progress")
|
||||
{
|
||||
int progress = (sender as DownloadEntry)?.Progress ?? 0;
|
||||
ulong.TryParse(progress.ToString(), out ulong progressret);
|
||||
UpdateWorkingStatus(null, CurrentProgressValue: progressret);
|
||||
|
||||
if (progress == 100)
|
||||
{
|
||||
ModeSwitchProgressWrapper("Initializing Flash...", null);
|
||||
|
||||
string MMOSPath = TempFolder + "\\" + (sender as DownloadEntry)?.Name;
|
||||
|
||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
FileInfo info = new(MMOSPath);
|
||||
uint length = uint.Parse(info.Length.ToString());
|
||||
const int maximumbuffersize = 0x00240000;
|
||||
uint totalcounts = (uint)Math.Truncate((decimal)length / maximumbuffersize);
|
||||
|
||||
SetWorkingStatus("Flashing Test Mode package...", MaxProgressValue: 100);
|
||||
|
||||
ProgressUpdater progressUpdater = new(totalcounts + 1, (int i, TimeSpan? time) => UpdateWorkingStatus(null, CurrentProgressValue: (ulong)i));
|
||||
FlashModel.FlashMMOS(MMOSPath, progressUpdater);
|
||||
|
||||
SetWorkingStatus("And now booting phone to MMOS...", "If the phone stays on the lightning cog screen for a while, you may need to unplug and replug the phone to continue the boot process.");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
ModeSwitchErrorWrapper(Ex.Message);
|
||||
}
|
||||
|
||||
LogFile.EndAction("SwitchToLabelMode");
|
||||
}).Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] BootModeFlagCommand = [0x4E, 0x4F, 0x4B, 0x58, 0x46, 0x57, 0x00, 0x55, 0x42, 0x46, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00]; // NOKFW UBF
|
||||
byte[] RebootCommand = [0x4E, 0x4F, 0x4B, 0x52]; // NOKR
|
||||
|
||||
BootModeFlagCommand[0x0F] = 0x59;
|
||||
((LumiaFlashAppModel)CurrentModel).ExecuteRawMethod(BootModeFlagCommand);
|
||||
((LumiaFlashAppModel)CurrentModel).ExecuteRawVoidMethod(RebootCommand);
|
||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
ModeSwitchProgressWrapper("Rebooting phone to Label mode", null);
|
||||
LogFile.Log("Rebooting phone to Label mode", LogType.FileAndConsole);
|
||||
}
|
||||
}
|
||||
|
||||
private async void SwitchFromPhoneInfoToMassStorageMode(bool Continuation = false)
|
||||
{
|
||||
string ProgressText = Continuation ? "And now rebooting phone to Mass Storage mode..." : "Rebooting phone to Mass Storage mode...";
|
||||
|
||||
((LumiaBootManagerAppModel)CurrentModel).SwitchToFlashAppContext();
|
||||
await PhoneNotifier.WaitForArrival();
|
||||
|
||||
LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)CurrentModel;
|
||||
PhoneInfo Info = FlashModel.ReadPhoneInfo(ExtendedInfo: false);
|
||||
|
||||
MassStorageWarning = null;
|
||||
if (Info.FlashAppProtocolVersionMajor < 2)
|
||||
{
|
||||
MassStorageWarning = "Switching to Mass Storage mode should take about 10 seconds. The phone should be unlocked using an Engineering SBL3 to enable Mass Storage mode. When you unlocked the bootloader, but you did not use an Engineering SBL3, an attempt to boot to Mass Storage mode may result in an unresponsive state. Installing drivers for this interface may also cause to hang the PC. So when this switch is taking too long, you should reboot both the PC and the phone. To reboot the phone, you have to perform a soft-reset. Press and hold the volume-down-button and the power-button at the same time for at least 10 seconds. This will trigger a power-cycle and the phone will reboot. Once fully booted, the phone may show strange behavior, like complaining about mail-accounts, showing old text-messages, inability to load https-websites, etc. This is expected behavior, because the time-settings of the phone are incorrect. Just wait a few seconds for the phone to get a data-connection and have the date/time synced. After that the strange behavior will stop automatically and normal operation is resumed.";
|
||||
}
|
||||
else
|
||||
{
|
||||
MassStorageWarning = "When the screen of the phone is black for a while, it could be that the phone is already in Mass Storage Mode, but there is no drive-letter assigned. To resolve this issue, open Device Manager and manually assign a drive-letter to the MainOS partition of your phone, or open a command-prompt and type: diskpart automount enable.";
|
||||
if (App.IsPnPEventLogMissing)
|
||||
{
|
||||
MassStorageWarning += " It is also possible that the phone is in Mass Storage mode, but the Mass Storage driver on this PC failed. Your PC does not have an eventlog to detect this misbehaviour. But in this case you will see a device with an exclamation mark in Device Manager and then you need to manually reset the phone by pressing and holding the power-button for at least 10 seconds until it vibrates and reboots. After that Windows Phone Internals will revert the changes. After the phone has rebooted to the OS, you can retry to unlock the bootloader.";
|
||||
}
|
||||
}
|
||||
|
||||
bool IsOldLumia = Info.FlashAppProtocolVersionMajor < 2;
|
||||
bool IsNewLumia = Info.FlashAppProtocolVersionMajor >= 2;
|
||||
bool IsUnlockedNew = false;
|
||||
if (IsNewLumia)
|
||||
{
|
||||
GPT GPT = FlashModel.ReadGPT();
|
||||
IsUnlockedNew = (GPT.GetPartition("IS_UNLOCKED") != null) || (GPT.GetPartition("BACKUP_EFIESP") != null) || (GPT.GetPartition("BACKUP_BS_NV") != null);
|
||||
}
|
||||
bool IsOriginalEngineeringLumia = !Info.IsBootloaderSecure && !IsUnlockedNew;
|
||||
|
||||
if (IsOldLumia || IsOriginalEngineeringLumia)
|
||||
{
|
||||
byte[] BootModeFlagCommand = [0x4E, 0x4F, 0x4B, 0x58, 0x46, 0x57, 0x00, 0x55, 0x42, 0x46, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00]; // NOKFW UBF
|
||||
byte[] RebootCommand = [0x4E, 0x4F, 0x4B, 0x52];
|
||||
byte[] RebootToMassStorageCommand = [0x4E, 0x4F, 0x4B, 0x4D]; // NOKM
|
||||
IsSwitchingInterface = true;
|
||||
byte[] RebootCommandResult = ((NokiaPhoneModel)CurrentModel).ExecuteRawMethod(RebootToMassStorageCommand);
|
||||
if (RebootCommandResult?.Length == 4) // This means fail: NOKU (unknown command)
|
||||
{
|
||||
BootModeFlagCommand[0x0F] = 0x4D;
|
||||
byte[] BootFlagResult = ((NokiaPhoneModel)CurrentModel).ExecuteRawMethod(BootModeFlagCommand);
|
||||
UInt16 ResultCode = BitConverter.ToUInt16(BootFlagResult, 6);
|
||||
if (ResultCode == 0)
|
||||
{
|
||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
((NokiaPhoneModel)CurrentModel).ExecuteRawVoidMethod(RebootCommand);
|
||||
ModeSwitchProgressWrapper(ProgressText, MassStorageWarning);
|
||||
LogFile.Log("Rebooting phone to Mass Storage mode");
|
||||
}
|
||||
else
|
||||
{
|
||||
ModeSwitchErrorWrapper("Failed to switch to Mass Storage mode");
|
||||
IsSwitchingInterface = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
ModeSwitchProgressWrapper(ProgressText, MassStorageWarning);
|
||||
LogFile.Log("Rebooting phone to Mass Storage mode");
|
||||
}
|
||||
}
|
||||
else if (IsUnlockedNew)
|
||||
{
|
||||
new Thread(async () =>
|
||||
{
|
||||
LogFile.BeginAction("SwitchToMassStorageMode");
|
||||
|
||||
try
|
||||
{
|
||||
// Implementation of writing a partition with SecureBoot variable to the phone
|
||||
ModeSwitchProgressWrapper(ProgressText, MassStorageWarning);
|
||||
LogFile.Log("Preparing phone for Mass Storage Mode", LogType.FileAndConsole);
|
||||
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
|
||||
|
||||
// Magic!
|
||||
// The SBMSM resource is a compressed version of a raw NV-variable-partition.
|
||||
// In this partition the SecureBoot variable is disabled and an extra variable is added which triggers Mass Storage Mode on next reboot.
|
||||
// It overwrites the variable in a different NV-partition than where this variable is stored usually.
|
||||
// This normally leads to endless-loops when the NV-variables are enumerated.
|
||||
// But the partition contains an extra hack to break out the endless loops.
|
||||
using (var stream = assembly.GetManifestResourceStream("WPinternals.SBMSM"))
|
||||
{
|
||||
using DecompressedStream dec = new(stream);
|
||||
using MemoryStream SB = new(); // Must be a seekable stream!
|
||||
dec.CopyTo(SB);
|
||||
|
||||
// We don't need to check for the BACKUP_BS_NV partition here,
|
||||
// because the SecureBoot flag is disabled here.
|
||||
// So either the NV was already backupped or already overwritten.
|
||||
|
||||
GPT GPT = FlashModel.ReadGPT();
|
||||
Partition Target = GPT.GetPartition("UEFI_BS_NV");
|
||||
|
||||
// We've been reading the GPT, so we let the phone reset once more to be sure that memory maps are the same
|
||||
WPinternalsStatus LastStatus = WPinternalsStatus.Undefined;
|
||||
List<FlashPart> Parts = new();
|
||||
FlashPart Part = new();
|
||||
Part.StartSector = (uint)Target.FirstSector;
|
||||
Part.Stream = SB;
|
||||
Parts.Add(Part);
|
||||
await LumiaV2UnlockBootViewModel.LumiaV2CustomFlash(PhoneNotifier, null, false, false, Parts, DoResetFirst: true, ClearFlashingStatusAtEnd: false, ShowProgress: false,
|
||||
SetWorkingStatus: (m, s, v, a, st) =>
|
||||
{
|
||||
if (SetWorkingStatus != null)
|
||||
{
|
||||
if ((st == WPinternalsStatus.Scanning) || (st == WPinternalsStatus.WaitingForManualReset))
|
||||
{
|
||||
SetWorkingStatus(m, s, v, a, st);
|
||||
}
|
||||
else if ((LastStatus == WPinternalsStatus.Scanning) || (LastStatus == WPinternalsStatus.WaitingForManualReset))
|
||||
{
|
||||
SetWorkingStatus(ProgressText, MassStorageWarning);
|
||||
}
|
||||
|
||||
LastStatus = st;
|
||||
}
|
||||
},
|
||||
UpdateWorkingStatus: (m, s, v, st) =>
|
||||
{
|
||||
if (UpdateWorkingStatus != null)
|
||||
{
|
||||
if ((st == WPinternalsStatus.Scanning) || (st == WPinternalsStatus.WaitingForManualReset))
|
||||
{
|
||||
UpdateWorkingStatus(m, s, v, st);
|
||||
}
|
||||
else if ((LastStatus == WPinternalsStatus.Scanning) || (LastStatus == WPinternalsStatus.WaitingForManualReset))
|
||||
{
|
||||
SetWorkingStatus(ProgressText, MassStorageWarning);
|
||||
}
|
||||
|
||||
LastStatus = st;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (PhoneNotifier.CurrentInterface == PhoneInterfaces.Lumia_BadMassStorage)
|
||||
{
|
||||
throw new WPinternalsException("Phone is in Mass Storage mode, but the driver on PC failed to start");
|
||||
}
|
||||
|
||||
// Wait for bootloader
|
||||
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_MassStorage)
|
||||
{
|
||||
LogFile.Log("Waiting for Mass Storage Mode (1)...", LogType.FileOnly);
|
||||
await PhoneNotifier.WaitForArrival();
|
||||
}
|
||||
|
||||
if (PhoneNotifier.CurrentInterface == PhoneInterfaces.Lumia_BadMassStorage)
|
||||
{
|
||||
throw new WPinternalsException("Phone is in Mass Storage mode, but the driver on PC failed to start");
|
||||
}
|
||||
|
||||
// Wait for mass storage mode
|
||||
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_MassStorage)
|
||||
{
|
||||
LogFile.Log("Waiting for Mass Storage Mode (2)...", LogType.FileOnly);
|
||||
await PhoneNotifier.WaitForArrival();
|
||||
}
|
||||
|
||||
if (PhoneNotifier.CurrentInterface == PhoneInterfaces.Lumia_BadMassStorage)
|
||||
{
|
||||
throw new WPinternalsException("Phone is in Mass Storage mode, but the driver on PC failed to start");
|
||||
}
|
||||
|
||||
MassStorage Storage = null;
|
||||
if (PhoneNotifier.CurrentModel is MassStorage)
|
||||
{
|
||||
Storage = (MassStorage)PhoneNotifier.CurrentModel;
|
||||
}
|
||||
|
||||
if (Storage == null)
|
||||
{
|
||||
ModeSwitchErrorWrapper("Failed to switch to Mass Storage Mode");
|
||||
}
|
||||
else
|
||||
{
|
||||
ModeSwitchSuccessWrapper();
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
ModeSwitchErrorWrapper(Ex.Message);
|
||||
}
|
||||
|
||||
LogFile.EndAction("SwitchToMassStorageMode");
|
||||
}).Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
ModeSwitchErrorWrapper("Bootloader was not unlocked. First unlock bootloader before you try to switch to Mass Storage Mode.");
|
||||
}
|
||||
}
|
||||
|
||||
private void SwitchFromFlashToMassStorageMode(bool Continuation = false)
|
||||
{
|
||||
string ProgressText = Continuation ? "And now rebooting phone to Mass Storage mode..." : "Rebooting phone to Mass Storage mode...";
|
||||
NokiaFlashModel FlashModel = (NokiaFlashModel)CurrentModel;
|
||||
if (CurrentMode == PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
try
|
||||
{
|
||||
FlashModel.SwitchToFlashAppContext();
|
||||
((LumiaBootManagerAppModel)CurrentModel).SwitchToFlashAppContext();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogFile.LogException(ex, LogType.FileOnly);
|
||||
}
|
||||
}
|
||||
LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)CurrentModel;
|
||||
PhoneInfo Info = FlashModel.ReadPhoneInfo(ExtendedInfo: false);
|
||||
|
||||
MassStorageWarning = null;
|
||||
|
||||
@@ -99,9 +99,38 @@ DEALINGS IN THE SOFTWARE.
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border BorderThickness="1" BorderBrush="#FFD4D4D4" HorizontalAlignment="Stretch" VerticalAlignment="Center" Padding="25" Margin="0,0,0,20">
|
||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
|
||||
<local:GifImage x:Name="GifImage" Stretch="None"/>
|
||||
<Label Content="Phone is booting..." FontSize="20" Margin="10,0,0,0" VerticalContentAlignment="Center"/>
|
||||
<StackPanel>
|
||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
|
||||
<local:GifImage x:Name="GifImage" Stretch="None"/>
|
||||
<Label Content="Phone is booting..." FontSize="20" Margin="10,0,0,0" VerticalContentAlignment="Center"/>
|
||||
</StackPanel>
|
||||
<local:FlowDocumentScrollViewerNoMouseWheel Margin="20,0,20,0" VerticalScrollBarVisibility="Auto">
|
||||
<FlowDocument FontFamily="Segoe UI" FontSize="12" Loaded="Document_Loaded">
|
||||
<local:Paragraph TextAlignment="Center">
|
||||
<Run Text="When you connect the phone, it can take a moment before it is recognized. If it still isn't recognized after a while, you might need to install the necessary drivers first. For more information about the drivers, read the " />
|
||||
<Hyperlink NavigateUri="Getting started">Getting started</Hyperlink>
|
||||
<Run Text=" section. If the drivers are installed, but the phone is still not recognized, then try to perform a soft-reset, while the USB of the phone is connected. On Lumia phones you have to press-and-hold the power-button and volume-down-button at the same time for at least 10 seconds. If the tool detects the bootloader of the phone it will try to connect to the phone at this early boot-stage." />
|
||||
</local:Paragraph>
|
||||
</FlowDocument>
|
||||
</local:FlowDocumentScrollViewerNoMouseWheel>
|
||||
<local:FlowDocumentScrollViewerNoMouseWheel Grid.Column="1" Margin="20,-20,20,0" VerticalScrollBarVisibility="Auto" Visibility="{Binding InterruptBoot, RelativeSource={RelativeSource AncestorType={x:Type local:NokiaBootloaderView}}, Converter={StaticResource InverseVisibilityConverter}}">
|
||||
<FlowDocument FontFamily="Segoe UI" FontSize="12" Loaded="Document_Loaded">
|
||||
<local:Paragraph TextAlignment="Center">
|
||||
<Run Text="You can "/>
|
||||
<Hyperlink NavigateUri="Interrupt boot">interrupt the boot-process</Hyperlink>
|
||||
<Run Text=" as soon as the bootloader is detected. This allows you to configure the phone or flash a ROM before it boots to the OS. You can also try this when the phone is not booting properly. When you unlocked the bootloader and the phone boots to a Blue Screen, you can still enter Mass Storage Mode if you want. To boot properly again, restore the bootloader. You can update to a supported OS version and try again after that."/>
|
||||
</local:Paragraph>
|
||||
</FlowDocument>
|
||||
</local:FlowDocumentScrollViewerNoMouseWheel>
|
||||
<local:FlowDocumentScrollViewerNoMouseWheel Grid.Column="1" Margin="20,-20,20,0" VerticalScrollBarVisibility="Auto" Visibility="{Binding InterruptBoot, RelativeSource={RelativeSource AncestorType={x:Type local:NokiaBootloaderView}}, Converter={StaticResource VisibilityConverter}}">
|
||||
<FlowDocument FontFamily="Segoe UI" FontSize="12" Loaded="Document_Loaded">
|
||||
<local:Paragraph TextAlignment="Center">
|
||||
<Run Text="Windows Phone Internals is set to interrupt the boot-process as soon as the bootloader is detected. You can also allow the phone to "/>
|
||||
<Hyperlink NavigateUri="Normal boot">boot normally</Hyperlink>
|
||||
<Run Text="."/>
|
||||
</local:Paragraph>
|
||||
</FlowDocument>
|
||||
</local:FlowDocumentScrollViewerNoMouseWheel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border BorderThickness="1" BorderBrush="#FFD4D4D4" HorizontalAlignment="Stretch" VerticalAlignment="Center" Padding="25">
|
||||
|
||||
@@ -18,9 +18,13 @@
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Media;
|
||||
using System;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
@@ -29,13 +33,41 @@ namespace WPinternals
|
||||
/// </summary>
|
||||
public partial class NokiaBootloaderView : UserControl
|
||||
{
|
||||
private static PhoneNotifierViewModel PhoneNotifier;
|
||||
private static SynchronizationContext UIContext;
|
||||
|
||||
public NokiaBootloaderView()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
InterruptBoot = App.InterruptBoot;
|
||||
UIContext = SynchronizationContext.Current;
|
||||
|
||||
// Setting these properties in XAML results in an error. Why?
|
||||
GifImage.GifSource = "/aerobusy.gif";
|
||||
GifImage.AutoStart = true;
|
||||
|
||||
Loaded += NokiaBootloaderView_Loaded;
|
||||
Unloaded += NokiaBootloaderView_Unloaded;
|
||||
}
|
||||
|
||||
private void NokiaBootloaderView_Unloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
PhoneNotifier.NewDeviceArrived -= PhoneNotifier_NewDeviceArrived;
|
||||
}
|
||||
|
||||
private void NokiaBootloaderView_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Find the phone notifier
|
||||
DependencyObject obj = (DependencyObject)sender;
|
||||
while (!(obj is MainWindow))
|
||||
{
|
||||
obj = VisualTreeHelper.GetParent(obj);
|
||||
}
|
||||
|
||||
PhoneNotifier = ((MainViewModel)((MainWindow)obj).DataContext).PhoneNotifier;
|
||||
|
||||
PhoneNotifier.NewDeviceArrived += PhoneNotifier_NewDeviceArrived;
|
||||
}
|
||||
|
||||
private void HandleHyperlinkClick(object sender, RoutedEventArgs args)
|
||||
@@ -43,10 +75,24 @@ namespace WPinternals
|
||||
Hyperlink link = args.Source as Hyperlink;
|
||||
if (link?.NavigateUri != null)
|
||||
{
|
||||
if (link.NavigateUri.ToString() == "GettingStarted")
|
||||
if (link.NavigateUri.ToString() == "Getting started")
|
||||
{
|
||||
(this.DataContext as NokiaBootloaderViewModel)?.SwitchToGettingStarted();
|
||||
} (this.DataContext as NokiaBootloaderViewModel)?.RebootTo(link.NavigateUri.ToString());
|
||||
App.NavigateToGettingStarted();
|
||||
}
|
||||
else if (link.NavigateUri.ToString() == "Unlock boot")
|
||||
{
|
||||
App.NavigateToUnlockBoot();
|
||||
}
|
||||
else if (link.NavigateUri.ToString() == "Interrupt boot")
|
||||
{
|
||||
InterruptBoot = true;
|
||||
}
|
||||
else if (link.NavigateUri.ToString() == "Normal boot")
|
||||
{
|
||||
InterruptBoot = false;
|
||||
}
|
||||
|
||||
(this.DataContext as NokiaBootloaderViewModel)?.RebootTo(link.NavigateUri.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,5 +100,41 @@ namespace WPinternals
|
||||
{
|
||||
(sender as FlowDocument)?.AddHandler(Hyperlink.ClickEvent, new RoutedEventHandler(HandleHyperlinkClick));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty InterruptBootProperty =
|
||||
DependencyProperty.Register("InterruptBoot", typeof(Boolean), typeof(NokiaBootloaderView), new FrameworkPropertyMetadata(InterruptBootChanged));
|
||||
public bool InterruptBoot
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)GetValue(InterruptBootProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue(InterruptBootProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void InterruptBootChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
App.InterruptBoot = (bool)e.NewValue;
|
||||
|
||||
if ((bool)e.NewValue && PhoneNotifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
App.InterruptBoot = false;
|
||||
LogFile.Log("Found Lumia BootMgr and user forced to interrupt the boot process. Force to Flash-mode.");
|
||||
Task.Run(() => SwitchModeViewModel.SwitchTo(PhoneNotifier, PhoneInterfaces.Lumia_Flash));
|
||||
}
|
||||
}
|
||||
|
||||
internal void PhoneNotifier_NewDeviceArrived(ArrivalEventArgs Args)
|
||||
{
|
||||
if (App.InterruptBoot && Args.NewInterface == PhoneInterfaces.Lumia_Bootloader)
|
||||
{
|
||||
App.InterruptBoot = false;
|
||||
LogFile.Log("Found Lumia BootMgr and user forced to interrupt the boot process. Force to Flash-mode.");
|
||||
Task.Run(() => SwitchModeViewModel.SwitchTo(PhoneNotifier, PhoneInterfaces.Lumia_Flash));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,16 @@ DEALINGS IN THE SOFTWARE.
|
||||
<Run Text="This will switch back to Windows Phone OS." />
|
||||
<LineBreak />
|
||||
<LineBreak />
|
||||
<Hyperlink NavigateUri="PhoneInfo">Switch to Phone-Info-mode</Hyperlink>
|
||||
<LineBreak />
|
||||
<Run Text="This will switch to Phone Info Mode." />
|
||||
<LineBreak />
|
||||
<LineBreak />
|
||||
<Hyperlink NavigateUri="BootMgr">Switch to Boot-Manager-mode</Hyperlink>
|
||||
<LineBreak />
|
||||
<Run Text="This will switch to Boot Manager Mode." />
|
||||
<LineBreak />
|
||||
<LineBreak />
|
||||
<Hyperlink NavigateUri="Label">Switch to Label-mode</Hyperlink>
|
||||
<LineBreak />
|
||||
<Run Text="This interface is meant for querying and provisioning the phone. This is normally used for configuring the phone during manufacturing." />
|
||||
|
||||
@@ -58,6 +58,16 @@ DEALINGS IN THE SOFTWARE.
|
||||
<Run Text="This will switch back to Windows Phone OS." />
|
||||
<LineBreak />
|
||||
<LineBreak />
|
||||
<Hyperlink NavigateUri="Flash">Switch to Flash-mode</Hyperlink>
|
||||
<LineBreak />
|
||||
<Run Text="This is the interface that can be used to flash a new ROM image. It can also be used to retrieve additional info and security status." />
|
||||
<LineBreak />
|
||||
<LineBreak />
|
||||
<Hyperlink NavigateUri="BootMgr">Switch to Boot-Manager-mode</Hyperlink>
|
||||
<LineBreak />
|
||||
<Run Text="This will switch to Boot Manager Mode." />
|
||||
<LineBreak />
|
||||
<LineBreak />
|
||||
<Hyperlink NavigateUri="Label">Switch to Label-mode</Hyperlink>
|
||||
<LineBreak />
|
||||
<Run Text="This interface is meant for querying and provisioning the phone. This is normally used for configuring the phone during manufacturing." />
|
||||
|
||||
@@ -82,12 +82,6 @@ DEALINGS IN THE SOFTWARE.
|
||||
</local:FlowDocumentScrollViewerNoMouseWheel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border BorderThickness="1" BorderBrush="#FFD4D4D4" HorizontalAlignment="Stretch" VerticalAlignment="Center" Padding="25" Margin="0,0,0,20">
|
||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
|
||||
<local:GifImage x:Name="GifImage" Stretch="None"/>
|
||||
<Label Content="Phone is booting..." FontSize="20" Margin="10,0,0,0" VerticalContentAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border BorderThickness="1" BorderBrush="#FFD4D4D4" HorizontalAlignment="Stretch" VerticalAlignment="Center" Padding="25">
|
||||
<Expander Header="Phone identity" HorizontalContentAlignment="Stretch" Template="{DynamicResource TopicExpanderTemplate}" Margin="20,0">
|
||||
<local:FlowDocumentScrollViewerNoMouseWheel Grid.Column="1" VerticalScrollBarVisibility="Auto" >
|
||||
|
||||
@@ -32,10 +32,6 @@ namespace WPinternals
|
||||
public NokiaPhoneInfoView()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// Setting these properties in XAML results in an error. Why?
|
||||
GifImage.GifSource = "/aerobusy.gif";
|
||||
GifImage.AutoStart = true;
|
||||
}
|
||||
|
||||
private void HandleHyperlinkClick(object sender, RoutedEventArgs args)
|
||||
|
||||
Reference in New Issue
Block a user