Author SHA1 Message Date
Gustave Monce a982c119fb Bump timebomb 2024-09-09 21:08:35 +02:00
Gustave Monce c6dee3fe33 workaround older phone fw issues when retrieving via json rpc and gpt get function failures 2024-09-01 16:49:36 +02:00
Gustave Monce 91961b0e7b fix issues with downloading files 2024-09-01 12:45:46 +02:00
Gustave Monce 29c6ab06d4 fix: Download issues with ENOSW 2024-09-01 10:38:47 +02:00
Gustave Monce b03b561724 fix a few TODOs 2024-08-31 23:17:34 +02:00
Gustave Monce 91f534a7c3 fix: Merge issues from previous commit 2024-08-31 21:58:23 +02:00
Gustave Monce f0f3268924 Split phone info structures for each app type 2024-08-31 21:52:20 +02:00
Gustave Monce c269cfe839 Enable downloading ENOSW via Download Page 2024-08-31 19:45:24 +02:00
Gustave Monce 7d8aad0e88 fix: Modern Flash App Label mode switching 2024-08-31 18:31:56 +02:00
Gustave Monce 310d0b97c5 fix: Mode change detection on specb
resolves a few issues but not all due to the combined app
2024-08-31 17:50:18 +02:00
Gustave Monce 8e50c46357 wip: Refactor FlashApp Logic to account for the 3 split app states 2024-08-31 16:39:44 +02:00
Gustave Monce e6555741b0 fix: PhoneInfo app handling + label parsing issues 2024-08-31 11:00:04 +02:00
Gustave Monce c21692491d fix: Log all silent exceptions 2024-08-30 21:43:30 +02:00
Gustave Monce 350b6e8f1e fix: add missing raise can execute changed for unlock v1 with supported ffu field 2024-08-30 20:42:52 +02:00
Gustave Monce 0101477830 fix: Handle empty flash part list
This is used to clear the red flashing status we need to handle this differently for spec A
2024-08-30 20:42:37 +02:00
Gustave Monce a6c017986b fix: Handle loaders with new lines at the top instead of intel hex style right at the start 2024-08-30 20:42:16 +02:00
Gustave Monce 0174fc8b30 QCParts: Check if signatures are available 2024-08-30 20:41:57 +02:00
Gustave Monce c6f6ef4429 Rework Qualcomm Partition to also work with modern day ed loaders 2024-08-27 10:08:47 +02:00
Gustave Monce ab0c35e879 fix: revert qualcomm partition code changes to account for older ed payloads 2024-08-27 09:55:52 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
676a95dd97 Bump System.Text.Json from 8.0.0 to 8.0.4 in /WPinternals (#74)
Bumps System.Text.Json from 8.0.0 to 8.0.4.

---
updated-dependencies:
- dependency-name: System.Text.Json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-13 14:53:12 +02:00
62 changed files with 5169 additions and 1408 deletions
+108 -52
View File
@@ -83,9 +83,13 @@ namespace WPinternals
{ {
FFU FFU = null; FFU FFU = null;
PhoneNotifierViewModel Notifier; PhoneNotifierViewModel Notifier;
NokiaFlashModel FlashModel; LumiaFlashAppModel FlashModel;
LumiaBootManagerAppModel BootMgrModel;
LumiaPhoneInfoAppModel PhoneInfoModel;
NokiaPhoneModel NormalModel; NokiaPhoneModel NormalModel;
PhoneInfo Info; LumiaFlashAppPhoneInfo FlashInfo;
LumiaPhoneInfoAppPhoneInfo PhoneInfo;
LumiaBootManagerPhoneInfo BootManagerInfo;
string ProductType; string ProductType;
string ProductCode; string ProductCode;
string OperatorCode; string OperatorCode;
@@ -182,23 +186,14 @@ namespace WPinternals
Notifier = new PhoneNotifierViewModel(); Notifier = new PhoneNotifierViewModel();
UIContext.Send(s => Notifier.Start(), null); 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) 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); 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(); Notifier.Stop();
} }
catch (Exception Ex) catch (Exception Ex)
@@ -221,15 +216,14 @@ namespace WPinternals
{ {
Notifier = new PhoneNotifierViewModel(); Notifier = new PhoneNotifierViewModel();
UIContext.Send(s => Notifier.Start(), null); UIContext.Send(s => Notifier.Start(), null);
FlashModel = (NokiaFlashModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash); BootMgrModel = (LumiaBootManagerAppModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Bootloader);
GPT GPT = FlashModel.ReadGPT(); // May throw NotSupportedException GPT GPT = BootMgrModel.ReadGPT(); // May throw NotSupportedException
string DirPath = Path.GetDirectoryName(args[2]); string DirPath = Path.GetDirectoryName(args[2]);
if (!string.IsNullOrEmpty(DirPath) && !Directory.Exists(DirPath)) if (!string.IsNullOrEmpty(DirPath) && !Directory.Exists(DirPath))
{ {
Directory.CreateDirectory(DirPath); Directory.CreateDirectory(DirPath);
} }
GPT.WritePartitions(args[2]); GPT.WritePartitions(args[2]);
FlashModel.SwitchToFlashAppContext();
Notifier.Stop(); Notifier.Stop();
} }
catch (Exception Ex) catch (Exception Ex)
@@ -281,14 +275,13 @@ namespace WPinternals
{ {
Notifier = new PhoneNotifierViewModel(); Notifier = new PhoneNotifierViewModel();
UIContext.Send(s => Notifier.Start(), null); UIContext.Send(s => Notifier.Start(), null);
FlashModel = (NokiaFlashModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash); BootMgrModel = (LumiaBootManagerAppModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Bootloader);
byte[] GptChunk = LumiaUnlockBootloaderViewModel.GetGptChunk(FlashModel, 0x20000); byte[] GptChunk = BootMgrModel.GetGptChunk(0x20000);
GPT GPT = new(GptChunk); GPT GPT = new(GptChunk);
string Xml = File.ReadAllText(args[2]); string Xml = File.ReadAllText(args[2]);
GPT.MergePartitions(Xml, false); GPT.MergePartitions(Xml, false);
GPT.Rebuild(); GPT.Rebuild();
await LumiaV2UnlockBootViewModel.LumiaV2CustomFlash(Notifier, null, false, false, 0, GptChunk, true, true); await LumiaV2UnlockBootViewModel.LumiaV2CustomFlash(Notifier, null, false, false, 0, GptChunk, true, true);
FlashModel.SwitchToFlashAppContext();
Notifier.Stop(); Notifier.Stop();
} }
catch (Exception Ex) catch (Exception Ex)
@@ -318,7 +311,10 @@ namespace WPinternals
s = new FileStream(args[3], FileMode.Open, FileAccess.Read); s = new FileStream(args[3], FileMode.Open, FileAccess.Read);
Archive = new ZipArchive(s); Archive = new ZipArchive(s);
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
if (Archive == null) if (Archive == null)
{ {
@@ -549,9 +545,9 @@ namespace WPinternals
try try
{ {
UIContext.Send(s => Notifier.Start(), null); 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(); FlashInfo = FlashModel.ReadPhoneInfo();
Info.Log(LogType.ConsoleOnly); FlashInfo.Log(LogType.ConsoleOnly);
FFU ProfileFFU = null; FFU ProfileFFU = null;
FFU CurrentFFU; FFU CurrentFFU;
@@ -564,7 +560,7 @@ namespace WPinternals
string PlatformID = CurrentFFU.PlatformID; string PlatformID = CurrentFFU.PlatformID;
// Check if the current FFU matches the connected phone, so that the FFU can be used for profiling. // Check if the current FFU matches the connected phone, so that the FFU can be used for profiling.
if (Info.PlatformID.StartsWith(PlatformID, StringComparison.OrdinalIgnoreCase)) if (FlashInfo.PlatformID.StartsWith(PlatformID, StringComparison.OrdinalIgnoreCase))
{ {
ProfileFFU = CurrentFFU; ProfileFFU = CurrentFFU;
} }
@@ -573,7 +569,7 @@ namespace WPinternals
if (ProfileFFU == null) if (ProfileFFU == null)
{ {
List<FFUEntry> FFUs = App.Config.FFURepository.Where(e => Info.PlatformID.StartsWith(e.PlatformID, StringComparison.OrdinalIgnoreCase) && e.Exists()).ToList(); List<FFUEntry> FFUs = App.Config.FFURepository.Where(e => FlashInfo.PlatformID.StartsWith(e.PlatformID, StringComparison.OrdinalIgnoreCase) && e.Exists()).ToList();
ProfileFFU = FFUs.Count > 0 ProfileFFU = FFUs.Count > 0
? new FFU(FFUs[0].Path) ? new FFU(FFUs[0].Path)
: throw new WPinternalsException("Profile FFU missing", "No profile FFU has been found in the repository for your device. You can add a profile FFU within the download section of the tool or by using the command line."); : throw new WPinternalsException("Profile FFU missing", "No profile FFU has been found in the repository for your device. You can add a profile FFU within the download section of the tool or by using the command line.");
@@ -698,9 +694,9 @@ namespace WPinternals
LogFile.Log("Command: Show phone info", LogType.FileAndConsole); LogFile.Log("Command: Show phone info", LogType.FileAndConsole);
Notifier = new PhoneNotifierViewModel(); Notifier = new PhoneNotifierViewModel();
UIContext.Send(s => Notifier.Start(), null); 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(); FlashInfo = FlashModel.ReadPhoneInfo();
Info.Log(LogType.ConsoleOnly); FlashInfo.Log(LogType.ConsoleOnly);
Notifier.Stop(); Notifier.Stop();
break; break;
case "unlockbootloader": case "unlockbootloader":
@@ -710,9 +706,9 @@ namespace WPinternals
LogFile.Log("Command: Unlock Bootloader", LogType.FileAndConsole); LogFile.Log("Command: Unlock Bootloader", LogType.FileAndConsole);
Notifier = new PhoneNotifierViewModel(); Notifier = new PhoneNotifierViewModel();
UIContext.Send(s => Notifier.Start(), null); 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(); FlashInfo = FlashModel.ReadPhoneInfo();
Info.Log(LogType.ConsoleOnly); FlashInfo.Log(LogType.ConsoleOnly);
FFU ProfileFFU = null; FFU ProfileFFU = null;
FFU SupportedFFU = null; FFU SupportedFFU = null;
@@ -726,7 +722,7 @@ namespace WPinternals
string PlatformID = CurrentFFU.PlatformID; string PlatformID = CurrentFFU.PlatformID;
// Check if the current FFU matches the connected phone, so that the FFU can be used for profiling. // Check if the current FFU matches the connected phone, so that the FFU can be used for profiling.
if (Info.PlatformID.StartsWith(PlatformID, StringComparison.OrdinalIgnoreCase)) if (FlashInfo.PlatformID.StartsWith(PlatformID, StringComparison.OrdinalIgnoreCase))
{ {
ProfileFFU = CurrentFFU; ProfileFFU = CurrentFFU;
} }
@@ -741,7 +737,7 @@ namespace WPinternals
if (ProfileFFU == null) if (ProfileFFU == null)
{ {
List<FFUEntry> FFUs = App.Config.FFURepository.Where(e => Info.PlatformID.StartsWith(e.PlatformID, StringComparison.OrdinalIgnoreCase) && e.Exists()).ToList(); List<FFUEntry> FFUs = App.Config.FFURepository.Where(e => FlashInfo.PlatformID.StartsWith(e.PlatformID, StringComparison.OrdinalIgnoreCase) && e.Exists()).ToList();
ProfileFFU = FFUs.Count > 0 ProfileFFU = FFUs.Count > 0
? new FFU(FFUs[0].Path) ? new FFU(FFUs[0].Path)
: throw new WPinternalsException("Profile FFU missing", "No profile FFU has been found in the repository for your device. You can add a profile FFU within the download section of the tool or by using the command line."); : throw new WPinternalsException("Profile FFU missing", "No profile FFU has been found in the repository for your device. You can add a profile FFU within the download section of the tool or by using the command line.");
@@ -783,9 +779,9 @@ namespace WPinternals
LogFile.Log("Custom ROM: " + CustomRomPath, LogType.FileAndConsole); LogFile.Log("Custom ROM: " + CustomRomPath, LogType.FileAndConsole);
Notifier = new PhoneNotifierViewModel(); Notifier = new PhoneNotifierViewModel();
UIContext.Send(s => Notifier.Start(), null); 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(); FlashInfo = FlashModel.ReadPhoneInfo();
Info.Log(LogType.ConsoleOnly); FlashInfo.Log(LogType.ConsoleOnly);
LogFile.Log("Preparing to flash Custom ROM", LogType.FileAndConsole); LogFile.Log("Preparing to flash Custom ROM", LogType.FileAndConsole);
await LumiaV2UnlockBootViewModel.LumiaV2FlashArchive(Notifier, CustomRomPath); await LumiaV2UnlockBootViewModel.LumiaV2FlashArchive(Notifier, CustomRomPath);
LogFile.Log("Custom ROM flashed successfully", LogType.FileAndConsole); LogFile.Log("Custom ROM flashed successfully", LogType.FileAndConsole);
@@ -814,11 +810,11 @@ namespace WPinternals
LogFile.Log("FFU file: " + FFUPath, LogType.FileAndConsole); LogFile.Log("FFU file: " + FFUPath, LogType.FileAndConsole);
Notifier = new PhoneNotifierViewModel(); Notifier = new PhoneNotifierViewModel();
UIContext.Send(s => Notifier.Start(), null); 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(); FlashInfo = FlashModel.ReadPhoneInfo();
Info.Log(LogType.ConsoleOnly); FlashInfo.Log(LogType.ConsoleOnly);
LogFile.Log("Flashing FFU...", LogType.FileAndConsole); LogFile.Log("Flashing FFU...", LogType.FileAndConsole);
await Task.Run(() => FlashModel.FlashFFU(new FFU(FFUPath), true, (byte)(!Info.IsBootloaderSecure ? FlashOptions.SkipSignatureCheck : 0))); await Task.Run(() => FlashModel.FlashFFU(new FFU(FFUPath), true, (byte)(!FlashInfo.IsBootloaderSecure ? FlashOptions.SkipSignatureCheck : 0)));
LogFile.Log("FFU flashed successfully", LogType.FileAndConsole); LogFile.Log("FFU flashed successfully", LogType.FileAndConsole);
Notifier.Stop(); Notifier.Stop();
} }
@@ -1280,11 +1276,55 @@ namespace WPinternals
NormalModel = (NokiaPhoneModel)Notifier.CurrentModel; NormalModel = (NokiaPhoneModel)Notifier.CurrentModel;
ProductCode = NormalModel.ExecuteJsonMethodAsString("ReadProductCode", "ProductCode"); 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; (Notifier.CurrentModel as LumiaBootManagerAppModel).SwitchToPhoneInfoAppContext();
Info = FlashModel.ReadPhoneInfo();
ProductCode = Info.ProductCode; if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_PhoneInfo)
{
await Notifier.WaitForArrival();
}
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_PhoneInfo)
{
throw new WPinternalsException("Unexpected Mode");
}
PhoneInfoModel = (LumiaPhoneInfoAppModel)Notifier.CurrentModel;
PhoneInfo = PhoneInfoModel.ReadPhoneInfo();
ProductCode = PhoneInfo.ProductCode;
}
else if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_PhoneInfo)
{
PhoneInfoModel = (LumiaPhoneInfoAppModel)Notifier.CurrentModel;
PhoneInfo = PhoneInfoModel.ReadPhoneInfo();
ProductCode = PhoneInfo.ProductCode;
}
else if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Flash)
{
bool ModernFlashApp = ((LumiaFlashAppModel)Notifier.CurrentModel).ReadPhoneInfo().FlashAppProtocolVersionMajor >= 2;
if (ModernFlashApp)
{
((LumiaFlashAppModel)Notifier.CurrentModel).SwitchToPhoneInfoAppContext();
}
else
{
((LumiaFlashAppModel)Notifier.CurrentModel).SwitchToPhoneInfoAppContextLegacy();
}
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_PhoneInfo)
{
await Notifier.WaitForArrival();
}
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_PhoneInfo)
{
throw new WPinternalsException("Unexpected Mode");
}
PhoneInfoModel = (LumiaPhoneInfoAppModel)Notifier.CurrentModel;
PhoneInfo = PhoneInfoModel.ReadPhoneInfo();
ProductCode = PhoneInfo.ProductCode;
} }
else else
{ {
@@ -1445,11 +1485,19 @@ namespace WPinternals
ProductType = ProductType.Substring(0, ProductType.IndexOf('_')); 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 = FlashModel.ReadPhoneInfo(); BootManagerInfo = BootMgrModel.ReadPhoneInfo();
ProductType = Info.Type; //ProductType = BootManagerInfo.Type; // TODO: FIXME
ProductType = "";
}
else if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Flash)
{
FlashModel = (LumiaFlashAppModel)Notifier.CurrentModel;
FlashInfo = FlashModel.ReadPhoneInfo();
//ProductType = FlashInfo.Type; // TODO: FIXME
ProductType = "";
} }
else else
{ {
@@ -1556,11 +1604,19 @@ namespace WPinternals
NormalModel = (NokiaPhoneModel)Notifier.CurrentModel; NormalModel = (NokiaPhoneModel)Notifier.CurrentModel;
ProductCode = NormalModel.ExecuteJsonMethodAsString("ReadProductCode", "ProductCode"); 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 = FlashModel.ReadPhoneInfo(); BootManagerInfo = BootMgrModel.ReadPhoneInfo();
ProductCode = Info.ProductCode; //ProductCode = BootManagerInfo.ProductCode; // TODO: FIXME
ProductCode = "";
}
else if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Flash)
{
FlashModel = (LumiaFlashAppModel)Notifier.CurrentModel;
FlashInfo = FlashModel.ReadPhoneInfo();
//ProductCode = FlashInfo.ProductCode; // TODO: FIXME
ProductCode = "";
} }
else else
{ {
+8 -2
View File
@@ -316,13 +316,19 @@ namespace WPinternals
{ {
filename = System.IO.Path.GetFileName(Text); filename = System.IO.Path.GetFileName(Text);
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
string directory = ""; string directory = "";
try try
{ {
directory = System.IO.Path.GetDirectoryName(Text); directory = System.IO.Path.GetDirectoryName(Text);
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
FormattedText formatted; FormattedText formatted;
bool widthOK = false; bool widthOK = false;
bool changedWidth = false; bool changedWidth = false;
+29
View File
@@ -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
};
}
+30
View File
@@ -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;
}
}
+12 -3
View File
@@ -275,7 +275,10 @@ namespace WPinternals
{ {
StreamLengthInSectors = (ulong)DecompressedStream.Length / 0x200; StreamLengthInSectors = (ulong)DecompressedStream.Length / 0x200;
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
} }
if (NewPartition.LastSector == 0) if (NewPartition.LastSector == 0)
@@ -471,7 +474,10 @@ namespace WPinternals
{ {
StreamLengthInSectors = (ulong)DecompressedStream.Length / 0x200; StreamLengthInSectors = (ulong)DecompressedStream.Length / 0x200;
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
DecompressedStream.Close(); DecompressedStream.Close();
UInt64 MaxPartitionSizeInSectors = OldPartition.SizeInSectors; UInt64 MaxPartitionSizeInSectors = OldPartition.SizeInSectors;
@@ -521,7 +527,10 @@ namespace WPinternals
{ {
StreamLengthInSectors = (ulong)DecompressedStream.Length / 0x200; StreamLengthInSectors = (ulong)DecompressedStream.Length / 0x200;
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
DecompressedStream.Close(); DecompressedStream.Close();
if (NewPartition.SizeInSectors != StreamLengthInSectors) if (NewPartition.SizeInSectors != StreamLengthInSectors)
{ {
+35 -36
View File
@@ -158,7 +158,7 @@ namespace WPinternals
return FfuUrl; return FfuUrl;
} }
internal static string SearchENOSW(string ProductType, string PhoneFirmwareRevision) internal static (string SecureWIMUrl, string DPLUrl) SearchENOSW(string ProductType, string PhoneFirmwareRevision)
{ {
if (ProductType?.Length == 0) if (ProductType?.Length == 0)
{ {
@@ -170,7 +170,7 @@ namespace WPinternals
ProductType = ProductType.ToUpper(); ProductType = ProductType.ToUpper();
if (ProductType.StartsWith("RM") && !ProductType.StartsWith("RM-")) if (ProductType.StartsWith("RM") && !ProductType.StartsWith("RM-"))
{ {
ProductType = "RM-" + ProductType[2..]; ProductType = $"RM-{ProductType[2..]}";
} }
} }
@@ -182,6 +182,7 @@ namespace WPinternals
packageClass = "Public", packageClass = "Public",
manufacturerHardwareModel = ProductType manufacturerHardwareModel = ProductType
}; };
DiscoveryParameters DiscoveryParams = new() DiscoveryParameters DiscoveryParams = new()
{ {
query = DiscoveryQueryParams query = DiscoveryQueryParams
@@ -212,10 +213,10 @@ namespace WPinternals
} }
SoftwarePackage Package = null; SoftwarePackage Package = null;
using (MemoryStream JsonStream2 = new(Encoding.UTF8.GetBytes(JsonResultString))) using MemoryStream JsonResultStream = new(Encoding.UTF8.GetBytes(JsonResultString));
{ DataContractJsonSerializer SoftwarePackagesJsonSerializer = new(typeof(SoftwarePackages));
DataContractJsonSerializer Serializer2 = new(typeof(SoftwarePackages)); SoftwarePackages SoftwarePackages = (SoftwarePackages)SoftwarePackagesJsonSerializer.ReadObject(JsonResultStream);
SoftwarePackages SoftwarePackages = (SoftwarePackages)Serializer2.ReadObject(JsonStream2);
if (SoftwarePackages != null) if (SoftwarePackages != null)
{ {
foreach (SoftwarePackage pkg in SoftwarePackages.softwarePackages) foreach (SoftwarePackage pkg in SoftwarePackages.softwarePackages)
@@ -223,48 +224,46 @@ namespace WPinternals
Package = SoftwarePackages.softwarePackages.FirstOrDefault(); Package = SoftwarePackages.softwarePackages.FirstOrDefault();
} }
} }
}
if (Package == null) if (Package == null)
{ {
throw new WPinternalsException("ENOSW package not found", "No ENOSW package has been found in the remote software repository for the requested model."); throw new WPinternalsException("ENOSW package not found", "No ENOSW package has been found in the remote software repository for the requested model.");
} }
SoftwareFile FileInfo = Package.files.First(f => f.fileName.EndsWith(".secwim", StringComparison.OrdinalIgnoreCase)); SoftwareFile SecureWimSoftwareFile = Package.files.First(f => f.fileName.EndsWith(".secwim", StringComparison.OrdinalIgnoreCase));
SoftwareFile DPLSoftwareFile = Package.files.First(f => f.fileName.EndsWith(".dpl", StringComparison.OrdinalIgnoreCase));
SoftwareFile DPLF = Package.files.First(f => f.fileName.EndsWith(".dpl", StringComparison.OrdinalIgnoreCase)); Uri DPLFileUrlUri = new($"https://api.swrepository.com/rest-api/discovery/fileurl/1/{Package.id}/{DPLSoftwareFile.fileName}");
Uri DPLUri = new("https://api.swrepository.com/rest-api/discovery/fileurl/1/" + Package.id + "/" + DPLF.fileName);
Task<string> GetDPLTask = HttpClient.GetStringAsync(DPLUri); Task<string> GetDPLTask = HttpClient.GetStringAsync(DPLFileUrlUri);
GetDPLTask.Wait(); GetDPLTask.Wait();
string DPLString = GetDPLTask.Result;
string DPLUrl = ""; string DPLFileUrlResultContent = GetDPLTask.Result;
FileUrlResult FileUrlDPL = null; FileUrlResult DPLFileUrlResult = null;
using (MemoryStream JsonStream3 = new(Encoding.UTF8.GetBytes(DPLString))) using MemoryStream DPLFileUrlResultStream = new(Encoding.UTF8.GetBytes(DPLFileUrlResultContent));
DataContractJsonSerializer DPLFileUrlResultSerializer = new(typeof(FileUrlResult));
DPLFileUrlResult = (FileUrlResult)DPLFileUrlResultSerializer.ReadObject(DPLFileUrlResultStream);
string DPLFileUrl = "";
if (DPLFileUrlResult != null)
{ {
DataContractJsonSerializer Serializer3 = new(typeof(FileUrlResult)); DPLFileUrl = DPLFileUrlResult.url.Replace("sr.azureedge.net", "softwarerepo.blob.core.windows.net");
FileUrlDPL = (FileUrlResult)Serializer3.ReadObject(JsonStream3);
if (FileUrlDPL != null)
{
DPLUrl = FileUrlDPL.url.Replace("sr.azureedge.net", "softwarerepo.blob.core.windows.net");
}
} }
if (DPLUrl?.Length == 0) if (DPLFileUrl?.Length == 0)
{ {
throw new WPinternalsException("DPL not found", "No DPL has been found in the remote software repository for the requested model."); throw new WPinternalsException("DPL not found", "No DPL has been found in the remote software repository for the requested model.");
} }
Task<string> GetDPLStrTask = HttpClient.GetStringAsync(DPLUrl); Task<string> GetDPLStrTask = HttpClient.GetStringAsync(DPLFileUrl);
GetDPLStrTask.Wait(); GetDPLStrTask.Wait();
string DPLStrString = GetDPLStrTask.Result; string DPLStrString = GetDPLStrTask.Result;
DPL.Package dpl; DPL.Package dpl;
XmlSerializer serializer = new(typeof(DPL.Package)); XmlSerializer serializer = new(typeof(DPL.Package));
using (StringReader reader = new(DPLStrString.Replace("ft:", "").Replace("dpl:", "").Replace("typedes:", ""))) using StringReader reader = new(DPLStrString.Replace("ft:", "").Replace("dpl:", "").Replace("typedes:", ""));
{
dpl = (DPL.Package)serializer.Deserialize(reader); dpl = (DPL.Package)serializer.Deserialize(reader);
}
foreach (DPL.File file in dpl.Content.Files.File) foreach (DPL.File file in dpl.Content.Files.File)
{ {
@@ -274,30 +273,30 @@ namespace WPinternals
if (IsFirmwareBetween(PhoneFirmwareRevision, range.From, range.To)) if (IsFirmwareBetween(PhoneFirmwareRevision, range.From, range.To))
{ {
FileInfo = Package.files.First(f => f.fileName.EndsWith(name, StringComparison.OrdinalIgnoreCase)); SecureWimSoftwareFile = Package.files.First(f => f.fileName.EndsWith(name, StringComparison.OrdinalIgnoreCase));
} }
} }
Uri FileInfoUri = new("https://api.swrepository.com/rest-api/discovery/fileurl/1/" + Package.id + "/" + FileInfo.fileName); Uri FileInfoUri = new("https://api.swrepository.com/rest-api/discovery/fileurl/1/" + Package.id + "/" + SecureWimSoftwareFile.fileName);
Task<string> GetFileInfoTask = HttpClient.GetStringAsync(FileInfoUri); Task<string> GetFileInfoTask = HttpClient.GetStringAsync(FileInfoUri);
GetFileInfoTask.Wait(); GetFileInfoTask.Wait();
string FileInfoString = GetFileInfoTask.Result; string FileInfoString = GetFileInfoTask.Result;
string ENOSWUrl = ""; string ENOSWFileUrl = "";
FileUrlResult FileUrl = null; FileUrlResult FileUrl = null;
using (MemoryStream JsonStream3 = new(Encoding.UTF8.GetBytes(FileInfoString)))
{ using MemoryStream JsonStream4 = new(Encoding.UTF8.GetBytes(FileInfoString));
DataContractJsonSerializer Serializer3 = new(typeof(FileUrlResult)); DataContractJsonSerializer Serializer4 = new(typeof(FileUrlResult));
FileUrl = (FileUrlResult)Serializer3.ReadObject(JsonStream3); FileUrl = (FileUrlResult)Serializer4.ReadObject(JsonStream4);
if (FileUrl != null) if (FileUrl != null)
{ {
ENOSWUrl = FileUrl.url.Replace("sr.azureedge.net", "softwarerepo.blob.core.windows.net"); ENOSWFileUrl = FileUrl.url.Replace("sr.azureedge.net", "softwarerepo.blob.core.windows.net");
}
} }
HttpClient.Dispose(); HttpClient.Dispose();
return ENOSWUrl; return (ENOSWFileUrl, DPLFileUrl);
} }
private static bool IsFirmwareBetween(string PhoneFirmwareRevision, string Limit1, string Limit2) private static bool IsFirmwareBetween(string PhoneFirmwareRevision, string Limit1, string Limit2)
+8 -2
View File
@@ -73,7 +73,10 @@ namespace WPinternals
} }
} }
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
} }
internal void AttachQualcommSerial(string DevicePath) internal void AttachQualcommSerial(string DevicePath)
@@ -119,7 +122,10 @@ namespace WPinternals
SerialDevice.Close(); SerialDevice.Close();
SerialDevice.Dispose(); SerialDevice.Dispose();
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
} }
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
+17 -3
View File
@@ -40,7 +40,10 @@ namespace WPinternals
{ {
Device = new USBDevice(DevicePath); Device = new USBDevice(DevicePath);
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
} }
private JsonElement? ExecuteJsonMethodAsJsonToken(string JsonMethod, Dictionary<string, object> Params, string ResultElement) private JsonElement? ExecuteJsonMethodAsJsonToken(string JsonMethod, Dictionary<string, object> Params, string ResultElement)
@@ -173,6 +176,11 @@ namespace WPinternals
return null; return null;
} }
if (Token.Value.ValueKind == JsonValueKind.String)
{
return Token.Value.GetString().Equals("true", StringComparison.InvariantCultureIgnoreCase);
}
return Token.Value.GetBoolean(); return Token.Value.GetBoolean();
} }
@@ -335,7 +343,10 @@ namespace WPinternals
Result = new byte[OutputLength]; Result = new byte[OutputLength];
System.Buffer.BlockCopy(Buffer, 0, Result, 0, OutputLength); System.Buffer.BlockCopy(Buffer, 0, Result, 0, OutputLength);
} }
catch { } // Reboot command looses connection catch (Exception ex) // Reboot command looses connection
{
LogFile.LogException(ex, LogType.FileOnly);
}
} }
return Result; return Result;
} }
@@ -363,7 +374,10 @@ namespace WPinternals
pipe.Reset(); pipe.Reset();
} }
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
} }
/// <summary> /// <summary>
@@ -0,0 +1,42 @@
// 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 CommonPhoneInfo
{
public PhoneInfoState State = PhoneInfoState.Empty;
public FlashAppType App;
public byte VersionMajor;
public byte VersionMinor;
public byte ProtocolVersionMajor;
public byte ProtocolVersionMinor;
internal void Log(LogType Type)
{
LogFile.Log($"App: {VersionMajor}.{VersionMinor}", Type);
LogFile.Log($"Protocol: {ProtocolVersionMajor}.{ProtocolVersionMinor}", Type);
}
}
}
@@ -0,0 +1,59 @@
// 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 LumiaBootManagerPhoneInfo
{
public PhoneInfoState State = PhoneInfoState.Empty;
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 UInt32 TransferSize;
public bool MmosOverUsbSupported;
internal void Log(LogType Type)
{
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);
LogFile.Log($"Flash app: {FlashAppVersionMajor}.{FlashAppVersionMinor}", Type);
LogFile.Log($"Flash protocol: {FlashAppProtocolVersionMajor}.{FlashAppProtocolVersionMinor}", Type);
break;
}
}
}
}
@@ -0,0 +1,96 @@
// 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 LumiaFlashAppPhoneInfo
{
public PhoneInfoState State = PhoneInfoState.Empty;
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 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 (RKH != null)
{
LogFile.Log($"Root key hash: {Converter.ConvertHexToString(RKH, "")}", Type);
}
if (Firmware?.Length > 0)
{
LogFile.Log($"Firmware version: {Firmware}", Type);
}
}
switch (App)
{
case FlashAppType.FlashApp:
LogFile.Log($"Flash app: {FlashAppVersionMajor}.{FlashAppVersionMinor}", Type);
LogFile.Log($"Flash protocol: {FlashAppProtocolVersionMajor}.{FlashAppProtocolVersionMinor}", 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,69 @@
// 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 LumiaPhoneInfoAppPhoneInfo
{
public PhoneInfoState State = PhoneInfoState.Empty;
public string Type; // Extended info
public string ProductCode; // Extended info
public string Imei; // Extended info
public FlashAppType App;
public byte PhoneInfoAppVersionMajor;
public byte PhoneInfoAppVersionMinor;
public byte PhoneInfoAppProtocolVersionMajor;
public byte PhoneInfoAppProtocolVersionMinor;
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 (Type != LogType.ConsoleOnly && (Imei != null))
{
LogFile.Log($"IMEI: {Imei}", LogType.FileOnly);
}
}
switch (App)
{
case FlashAppType.PhoneInfoApp:
LogFile.Log($"Phone info app: {PhoneInfoAppVersionMajor}.{PhoneInfoAppVersionMinor}", Type);
LogFile.Log($"Phone info protocol: {PhoneInfoAppProtocolVersionMajor}.{PhoneInfoAppProtocolVersionMinor}", Type);
break;
}
}
}
}
+29
View File
@@ -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
};
}
+5 -1
View File
@@ -18,6 +18,7 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System;
using System.Collections; using System.Collections;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@@ -100,7 +101,10 @@ namespace WPinternals
LogFile.Log("Programmer failed to authenticate Digital Signature", LogType.FileOnly); LogFile.Log("Programmer failed to authenticate Digital Signature", LogType.FileOnly);
} }
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
} }
while (!HandshakeCompleted && (HelloSendCount < 6)); while (!HandshakeCompleted && (HelloSendCount < 6));
+17 -3
View File
@@ -69,10 +69,16 @@ namespace WPinternals
} }
} }
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
} }
} }
catch { } }
catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
return Result; return Result;
} }
@@ -89,6 +95,11 @@ namespace WPinternals
foreach (string Line in Lines) foreach (string Line in Lines)
{ {
if (string.IsNullOrEmpty(Line))
{
continue;
}
if (Line[0] != ':') if (Line[0] != ':')
{ {
throw new BadImageFormatException(); throw new BadImageFormatException();
@@ -116,7 +127,10 @@ namespace WPinternals
Result = new byte[BufferSize]; Result = new byte[BufferSize];
System.Buffer.BlockCopy(Buffer, 0, Result, 0, BufferSize); System.Buffer.BlockCopy(Buffer, 0, Result, 0, BufferSize);
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
return Result; return Result;
} }
+49 -58
View File
@@ -19,6 +19,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Security.Cryptography; using System.Security.Cryptography;
@@ -105,8 +106,6 @@ namespace WPinternals
HeaderOffset = ImageOffset + (uint)LongHeaderPattern.Length; HeaderOffset = ImageOffset + (uint)LongHeaderPattern.Length;
} }
uint Version = ByteOperations.ReadUInt32(Binary, ImageOffset + 0X04);
if (ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X00) != 0) if (ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X00) != 0)
{ {
ImageOffset = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X00); ImageOffset = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X00);
@@ -125,72 +124,64 @@ namespace WPinternals
CodeSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X0C); CodeSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X0C);
SignatureAddress = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X10); SignatureAddress = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X10);
SignatureSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X14); SignatureSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X14);
SignatureOffset = SignatureAddress - ImageAddress + ImageOffset;
CertificatesAddress = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X18); CertificatesAddress = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X18);
CertificatesSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X1C); CertificatesSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X1C);
CertificatesOffset = CertificatesAddress - ImageAddress + ImageOffset;
if (SignatureAddress == 0xFFFFFFFF) using MemoryStream fileStream = new(Binary);
using BinaryReader reader = new(fileStream);
List<byte[]> Signatures = [];
uint LastOffset = 0;
for (uint i = 0; i < fileStream.Length - 6; i++)
{ {
SignatureAddress = ImageAddress + CodeSize; fileStream.Seek(i, SeekOrigin.Begin);
}
if (CertificatesAddress == 0xFFFFFFFF) ushort offset0 = reader.ReadUInt16();
short offset1 = (short)((reader.ReadByte() << 8) | reader.ReadByte());
ushort offset2 = reader.ReadUInt16();
if (offset0 == 0x8230 && offset1 >= 0 && offset2 == 0x8230)
{ {
CertificatesAddress = SignatureAddress + SignatureSize; uint CertificateSize = (uint)offset1 + 4; // Header Size is 4
}
// Headers newer than version 5 need more padding here bool IsCertificatePartOfExistingChain = LastOffset == 0 || LastOffset == i;
if (Version > 5) if (!IsCertificatePartOfExistingChain)
{ {
ImageOffset += 0x80;
}
SignatureOffset = ImageOffset + CodeSize;
CertificatesOffset = ImageOffset + CodeSize + SignatureSize;
// Keeping just in case
// SignatureOffset = SignatureAddress - ImageAddress + ImageOffset;
// CertificatesOffset = ImageSize - CertificatesSize + ImageOffset;
uint CurrentCertificateOffset = CertificatesOffset;
uint CertificateSize = 0;
while (CurrentCertificateOffset < (CertificatesOffset + CertificatesSize))
{
if ((Binary[CurrentCertificateOffset] == 0x30) && (Binary[CurrentCertificateOffset + 1] == 0x82))
{
CertificateSize = (uint)(Binary[CurrentCertificateOffset + 2] * 0x100) + Binary[CurrentCertificateOffset + 3] + 4; // Big endian!
if ((CurrentCertificateOffset + CertificateSize) == (CertificatesOffset + CertificatesSize))
{
// This is the last certificate. So this is the root key.
RootKeyHash = SHA256.HashData(Binary.AsSpan((int)CurrentCertificateOffset, (int)CertificateSize));
#if DEBUG
System.Diagnostics.Debug.Print("RKH: " + Converter.ConvertHexToString(RootKeyHash, ""));
#endif
}
#if DEBUG
else
{
System.Diagnostics.Debug.Print("Cert: " + Converter.ConvertHexToString(SHA256.HashData(Binary.AsSpan((int)CurrentCertificateOffset, (int)CertificateSize)), ""));
}
#endif
CurrentCertificateOffset += CertificateSize;
}
else
{
if ((RootKeyHash == null) && (CurrentCertificateOffset > CertificatesOffset))
{
CurrentCertificateOffset -= CertificateSize;
// This is the last certificate. So this is the root key.
RootKeyHash = SHA256.HashData(Binary.AsSpan((int)CurrentCertificateOffset, (int)CertificateSize));
#if DEBUG
System.Diagnostics.Debug.Print("RKH: " + Converter.ConvertHexToString(RootKeyHash, ""));
#endif
}
break; break;
} }
LastOffset = i + CertificateSize;
fileStream.Seek(i, SeekOrigin.Begin);
Signatures.Add(reader.ReadBytes((int)CertificateSize));
}
}
if (Signatures.Count > 0)
{
byte[] RootCertificate = Signatures[^1];
for (int i = 0; i < Signatures.Count; i++)
{
if (i + 1 != Signatures.Count)
{
#if DEBUG
System.Diagnostics.Debug.Print("Cert: " + Converter.ConvertHexToString(SHA256.HashData(Signatures[i]), ""));
#endif
}
else
{
// This is the last certificate. So this is the root key.
RootKeyHash = SHA256.HashData(Signatures[i]);
#if DEBUG
System.Diagnostics.Debug.Print("RKH: " + Converter.ConvertHexToString(RootKeyHash, ""));
#endif
}
}
} }
} }
} }
+8 -2
View File
@@ -58,7 +58,10 @@ namespace WPinternals
{ {
this.USBDevice = new USBDevice(DevicePath); this.USBDevice = new USBDevice(DevicePath);
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
} }
} }
@@ -146,7 +149,10 @@ namespace WPinternals
{ {
IsIncomplete = true; IsIncomplete = true;
} }
catch { } // Will be rethrown as BadConnectionException catch (Exception ex) // Will be rethrown as BadConnectionException
{
LogFile.LogException(ex, LogType.FileOnly);
}
} }
while (IsIncomplete); while (IsIncomplete);
+4 -1
View File
@@ -45,7 +45,10 @@ namespace WPinternals
Binary = FFUFile.GetPartition("SBL3"); Binary = FFUFile.GetPartition("SBL3");
} }
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
// If not succeeded, then try to parse it as raw image // If not succeeded, then try to parse it as raw image
if (Binary == null) if (Binary == null)
@@ -0,0 +1,399 @@
// 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
{
internal readonly LumiaBootManagerPhoneInfo BootManagerInfo = 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 LumiaBootManagerPhoneInfo 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 = BootManagerInfo.State != PhoneInfoState.Empty;
ReadPhoneInfoBootManager();
LumiaBootManagerPhoneInfo Result = BootManagerInfo;
if (!PhoneInfoLogged)
{
Result.Log(LogType.FileOnly);
}
return Result;
}
internal LumiaBootManagerPhoneInfo ReadPhoneInfoBootManager()
{
// NOKH = Get Phone Info (IMEI and info from Product.dat) - Not available on some phones, like Lumia 640.
// NOKV = Info Query
LumiaBootManagerPhoneInfo Result = BootManagerInfo;
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;
}
byte SubblockCount = Response[10];
int SubblockOffset = 11;
for (int i = 0; i < SubblockCount; i++)
{
byte SubblockID = Response[SubblockOffset + 0x00];
LogFile.Log($"{Result.App} SubblockID: 0x{SubblockID:X}");
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 0x04:
Result.FlashAppProtocolVersionMajor = Response[SubblockPayloadOffset + 0x00];
Result.FlashAppProtocolVersionMinor = Response[SubblockPayloadOffset + 0x01];
Result.FlashAppVersionMajor = Response[SubblockPayloadOffset + 0x02];
Result.FlashAppVersionMinor = Response[SubblockPayloadOffset + 0x03];
break;
case 0x1F:
Result.MmosOverUsbSupported = Response[SubblockPayloadOffset] == 1;
break;
case 0x20:
// CRC header info
break;
}
SubblockOffset += SubblockLength + 3;
}
}
Result.State = PhoneInfoState.Basic;
}
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()
{
LumiaBootManagerPhoneInfo info = ReadPhoneInfoBootManager();
bool ModernFlashApp = info.BootManagerVersionMajor >= 2;
// 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);
if (ModernFlashApp)
{
DisableRebootTimeOut();
info.App = FlashAppType.FlashApp;
RaiseInterfaceChanged(PhoneInterfaces.Lumia_Flash);
}
}
internal void SwitchToPhoneInfoAppContextLegacy()
{
LumiaBootManagerPhoneInfo info = ReadPhoneInfoBootManager();
bool ModernFlashApp = info.BootManagerVersionMajor >= 2;
byte[] Request = new byte[4];
ByteOperations.WriteAsciiString(Request, 0, RebootToPhoneInfoAppSignature);
ExecuteRawVoidMethod(Request);
if (ModernFlashApp)
{
DisableRebootTimeOut();
info.App = FlashAppType.PhoneInfoApp;
RaiseInterfaceChanged(PhoneInterfaces.Lumia_PhoneInfo);
}
}
internal void RebootToFlashApp()
{
LumiaBootManagerPhoneInfo info = ReadPhoneInfoBootManager();
bool ModernFlashApp = info.BootManagerVersionMajor >= 2;
byte[] Request = new byte[4];
ByteOperations.WriteAsciiString(Request, 0, RebootToFlashAppSignature); // This will let the phone charge
ExecuteRawVoidMethod(Request); // On phone with bootloader Spec A this triggers a reboot, so DisableRebootTimeOut() cannot be called immediately.
if (ModernFlashApp)
{
DisableRebootTimeOut();
info.App = FlashAppType.FlashApp;
RaiseInterfaceChanged(PhoneInterfaces.Lumia_Flash);
}
}
}
}
@@ -0,0 +1,239 @@
// 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.Collections.Generic;
using System.IO;
using System.Linq;
namespace WPinternals
{
internal class LumiaPhoneInfoAppModel : NokiaFlashModel
{
internal readonly LumiaPhoneInfoAppPhoneInfo PhoneInfoAppInfo = 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 (PhoneInfoAppInfo.PhoneInfoAppVersionMajor >= 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 LumiaPhoneInfoAppPhoneInfo 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 = PhoneInfoAppInfo.State != PhoneInfoState.Empty;
ReadPhoneInfoPhoneInfoApp();
LumiaPhoneInfoAppPhoneInfo Result = PhoneInfoAppInfo;
if (ExtendedInfo && (Result.State == PhoneInfoState.Basic))
{
try
{
if (Result.PhoneInfoAppProtocolVersionMajor >= 2)
{
Result.Type = ReadPhoneInfoVariable("TYPE");
Result.ProductCode = ReadPhoneInfoVariable("CTR");
Result.Imei = ReadPhoneInfoVariable("IMEI");
}
else
{
/*
* Version: 1.1.1.3
* TYPE: RM-885
* BTR: 059R0M0
* LPSN: ...
* HWID: 1000
* CTR: 059S4B1
* MC: 0205354
* IMEI: ...
*/
string PhoneInfoData = GetPhoneInfo();
if (!string.IsNullOrEmpty(PhoneInfoData))
{
string[] Variables = PhoneInfoData.Split("\n");
Dictionary<string, string> FormattedVariables = [];
foreach (string Variable in Variables)
{
if (!Variable.Contains(":"))
{
continue;
}
FormattedVariables.Add(Variable.Split(":")[0].Trim(), Variable.Split(":")[1].Trim());
}
Result.Type = FormattedVariables["TYPE"];
Result.ProductCode = FormattedVariables["CTR"];
Result.Imei = FormattedVariables["IMEI"];
}
}
}
catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
Result.State = PhoneInfoState.Extended;
}
if (!PhoneInfoLogged)
{
Result.Log(LogType.FileOnly);
}
return Result;
}
internal LumiaPhoneInfoAppPhoneInfo ReadPhoneInfoPhoneInfoApp()
{
// NOKH = Get Phone Info (IMEI and info from Product.dat) - Not available on some phones, like Lumia 640.
// NOKV = Info Query
LumiaPhoneInfoAppPhoneInfo Result = PhoneInfoAppInfo;
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.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];
LogFile.Log($"{Result.App} SubblockID: 0x{SubblockID:X}");
UInt16 SubblockLength = BigEndian.ToUInt16(Response, SubblockOffset + 0x01);
int SubblockPayloadOffset = SubblockOffset + 3;
byte SubblockVersion;
switch (SubblockID)
{
case 0x20:
// CRC header info
break;
}
SubblockOffset += SubblockLength + 3;
}
}
Result.State = PhoneInfoState.Basic;
}
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");
return Result;
}
}
}
@@ -0,0 +1,241 @@
// 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 delegate void InterfaceChangedHandler(PhoneInterfaces NewInterface, string DevicePath);
internal class NokiaFlashModel : NokiaPhoneModel
{
private string _devicePath;
private readonly CommonPhoneInfo CommonInfo = new();
internal event InterfaceChangedHandler InterfaceChanged = delegate { };
//
// Not valid commands
//
/* NOK */
private const string Signature = "NOK";
/* NOKX */
private const string ExtendedMessageSignature = $"{Signature}X";
/* NOKXC */
private const string CommonExtendedMessageSignature = $"{ExtendedMessageSignature}C";
//
// Common extended commands
//
/* NOKXCB */
private const string SwitchModeSignature = $"{CommonExtendedMessageSignature}B";
/* NOKXCE */
private const string EchoSignature = $"{CommonExtendedMessageSignature}E";
public NokiaFlashModel(string DevicePath) : base(DevicePath)
{
_devicePath = DevicePath;
}
internal void SwitchToBootManagerContext(bool DisableTimeOut = true)
{
CommonPhoneInfo info = ReadPhoneInfoCommon();
bool ModernFlashApp = info.VersionMajor >= 2;
byte[] Request = new byte[7];
ByteOperations.WriteAsciiString(Request, 0, $"{SwitchModeSignature}B");
byte[] Response = ExecuteRawMethod(Request);
if (ByteOperations.ReadAsciiString(Response, 0, 4) == "NOKU")
{
throw new NotSupportedException();
}
UInt16 Error = (UInt16)((Response[6] << 8) + Response[7]);
if (Error > 0)
{
throw new NotSupportedException("SwitchToBootManagerContext: Error 0x" + Error.ToString("X4"));
}
if (ModernFlashApp)
{
DisableRebootTimeOut();
InterfaceChanged(PhoneInterfaces.Lumia_Bootloader, _devicePath);
}
}
internal void SwitchToPhoneInfoAppContext()
{
CommonPhoneInfo info = ReadPhoneInfoCommon();
bool ModernFlashApp = info.VersionMajor >= 2;
byte[] Request = new byte[7];
ByteOperations.WriteAsciiString(Request, 0, SwitchModeSignature + "P");
byte[] Response = ExecuteRawMethod(Request);
if (ByteOperations.ReadAsciiString(Response, 0, 4) == "NOKU")
{
throw new NotSupportedException();
}
UInt16 Error = (UInt16)((Response[6] << 8) + Response[7]);
if (Error > 0)
{
throw new NotSupportedException("SwitchToPhoneInfoAppContext: Error 0x" + Error.ToString("X4"));
}
if (ModernFlashApp)
{
DisableRebootTimeOut();
CommonInfo.App = FlashAppType.PhoneInfoApp;
InterfaceChanged(PhoneInterfaces.Lumia_PhoneInfo, _devicePath);
}
}
internal void SwitchToMmosContext()
{
byte[] Request = new byte[7];
ByteOperations.WriteAsciiString(Request, 0, $"{SwitchModeSignature}A");
byte[] Response = ExecuteRawMethod(Request);
if (ByteOperations.ReadAsciiString(Response, 0, 4) == "NOKU")
{
throw new NotSupportedException();
}
UInt16 Error = (UInt16)((Response[6] << 8) + Response[7]);
if (Error > 0)
{
throw new NotSupportedException("SwitchToPhoneInfoAppContext: Error 0x" + Error.ToString("X4"));
}
}
internal void SwitchToFlashAppContext()
{
CommonPhoneInfo info = ReadPhoneInfoCommon();
bool ModernFlashApp = info.VersionMajor >= 2;
byte[] Request = new byte[7];
ByteOperations.WriteAsciiString(Request, 0, $"{SwitchModeSignature}F"); // This will stop charging the phone
byte[] Response = ExecuteRawMethod(Request);
if (ByteOperations.ReadAsciiString(Response, 0, 4) == "NOKU")
{
throw new NotSupportedException();
}
UInt16 Error = (UInt16)((Response[6] << 8) + Response[7]);
if (Error > 0)
{
throw new NotSupportedException("SwitchToFlashAppContext: Error 0x" + Error.ToString("X4"));
}
if (ModernFlashApp)
{
DisableRebootTimeOut();
InterfaceChanged(PhoneInterfaces.Lumia_Flash, _devicePath);
}
}
//
// Normal commands
//
/* NOKD */
private const string DisableTimeoutsSignature = $"{Signature}D";
/* NOKI */
private const string HelloSignature = $"{Signature}I";
/* NOKV */
private const string InfoQuerySignature = $"{Signature}V";
internal FlashAppType GetFlashAppType()
{
byte[] Request = new byte[4];
ByteOperations.WriteAsciiString(Request, 0, InfoQuerySignature);
byte[] Response = ExecuteRawMethod(Request);
if ((Response == null) || (ByteOperations.ReadAsciiString(Response, 0, 4) == "NOKU"))
{
throw new NotSupportedException();
}
return (FlashAppType)Response[5];
}
internal CommonPhoneInfo ReadPhoneInfoCommon()
{
// NOKH = Get Phone Info (IMEI and info from Product.dat) - Not available on some phones, like Lumia 640.
// NOKV = Info Query
CommonPhoneInfo Result = CommonInfo;
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];
Result.ProtocolVersionMajor = Response[6];
Result.ProtocolVersionMinor = Response[7];
Result.VersionMajor = Response[8];
Result.VersionMinor = Response[9];
}
Result.State = PhoneInfoState.Basic;
}
return Result;
}
public void DisableRebootTimeOut()
{
byte[] Request = new byte[4];
const string Header = DisableTimeoutsSignature;
Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
ExecuteRawMethod(Request);
}
internal void Hello()
{
byte[] Request = new byte[4];
ByteOperations.WriteAsciiString(Request, 0, HelloSignature);
byte[] Response = ExecuteRawMethod(Request);
if (Response == null)
{
throw new BadConnectionException();
}
if (ByteOperations.ReadAsciiString(Response, 0, 4) != HelloSignature)
{
throw new WPinternalsException("Bad response from phone!", "The phone did not answer properly to the Hello message sent.");
}
}
internal void RaiseInterfaceChanged(PhoneInterfaces NewInterface)
{
InterfaceChanged(NewInterface, _devicePath);
}
}
}
@@ -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;
}
}
+1 -1
View File
@@ -258,7 +258,7 @@ namespace WPinternals
{ {
LogFile.Log("Phone needs to be switched to emergency mode.", LogType.FileAndConsole); LogFile.Log("Phone needs to be switched to emergency mode.", LogType.FileAndConsole);
await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash); await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
PhoneInfo Info = ((NokiaFlashModel)Notifier.CurrentModel).ReadPhoneInfo(); LumiaFlashAppPhoneInfo Info = ((LumiaFlashAppModel)Notifier.CurrentModel).ReadPhoneInfo();
Info.Log(LogType.ConsoleOnly); Info.Log(LogType.ConsoleOnly);
await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Qualcomm_Download); await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Qualcomm_Download);
if (Notifier.CurrentInterface != PhoneInterfaces.Qualcomm_Download) if (Notifier.CurrentInterface != PhoneInterfaces.Qualcomm_Download)
+8 -2
View File
@@ -360,7 +360,10 @@ namespace WPinternals
} }
} }
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
finally finally
{ {
Phone.CloseVolume(); Phone.CloseVolume();
@@ -463,7 +466,10 @@ namespace WPinternals
} }
} }
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
finally finally
{ {
Phone.CloseVolume(); Phone.CloseVolume();
+267 -16
View File
@@ -20,7 +20,6 @@
using Microsoft.Win32; using Microsoft.Win32;
using System; using System;
using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
using System.Globalization; using System.Globalization;
@@ -73,15 +72,15 @@ namespace WPinternals
{ {
App.Config.AddFfuToRepository(FFUPath); App.Config.AddFfuToRepository(FFUPath);
App.Config.WriteConfig(); App.Config.WriteConfig();
LastStatusText = "File \"" + FFUFile + "\" was added to the repository."; LastStatusText = $"File \"{FFUFile}\" was added to the repository.";
} }
catch (WPinternalsException Ex) catch (WPinternalsException Ex)
{ {
LastStatusText = "Error: " + Ex.Message + ". File \"" + FFUFile + "\" was not added."; LastStatusText = $"Error: {Ex.Message}. File \"{FFUFile}\" was not added.";
} }
catch catch
{ {
LastStatusText = "Error: File \"" + FFUFile + "\" was not added."; LastStatusText = $"Error: File \"{FFUFile}\" was not added.";
} }
} }
else else
@@ -136,7 +135,11 @@ namespace WPinternals
internal static long GetFileLengthFromURL(string URL) internal static long GetFileLengthFromURL(string URL)
{ {
long Length = 0; long Length = 0;
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(URL);
WebRequest webReq = WebRequest.Create(URL);
if (webReq is HttpWebRequest req)
{
req.Method = "HEAD"; req.Method = "HEAD";
req.ServicePoint.ConnectionLimit = 10; req.ServicePoint.ConnectionLimit = 10;
using (WebResponse resp = req.GetResponse()) using (WebResponse resp = req.GetResponse())
@@ -145,6 +148,18 @@ namespace WPinternals
} }
return Length; return Length;
} }
else if (webReq is FileWebRequest filereq)
{
webReq.Method = "HEAD";
using (WebResponse resp = webReq.GetResponse())
{
long.TryParse(resp.Headers.Get("Content-Length"), out Length);
}
return Length;
}
return 0;
}
internal static string GetFileNameFromURL(string URL) internal static string GetFileNameFromURL(string URL)
{ {
@@ -174,6 +189,8 @@ namespace WPinternals
{ {
string FFUURL = null; string FFUURL = null;
string[] EmergencyURLs = null; string[] EmergencyURLs = null;
string SecureWIMURL = null;
try try
{ {
string TempProductType = ProductType.ToUpper(); string TempProductType = ProductType.ToUpper();
@@ -183,7 +200,17 @@ namespace WPinternals
} }
ProductType = TempProductType; ProductType = TempProductType;
try
{
FFUURL = LumiaDownloadModel.SearchFFU(ProductType, ProductCode, OperatorCode, out TempProductType); FFUURL = LumiaDownloadModel.SearchFFU(ProductType, ProductCode, OperatorCode, out TempProductType);
}
catch (WPinternalsException ex)
{
LogFile.LogException(ex, LogType.FileOnly);
FFUURL = LumiaDownloadModel.SearchFFU(ProductType, null, OperatorCode, out TempProductType);
}
if (TempProductType != null) if (TempProductType != null)
{ {
ProductType = TempProductType; ProductType = TempProductType;
@@ -193,8 +220,16 @@ namespace WPinternals
{ {
EmergencyURLs = LumiaDownloadModel.SearchEmergencyFiles(ProductType); EmergencyURLs = LumiaDownloadModel.SearchEmergencyFiles(ProductType);
} }
if (ProductType != null && FirmwareVersion != null)
{
(SecureWIMURL, string _) = LumiaDownloadModel.SearchENOSW(ProductType, FirmwareVersion);
}
}
catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
} }
catch { }
UIContext.Post(s => UIContext.Post(s =>
{ {
@@ -205,7 +240,12 @@ namespace WPinternals
if (EmergencyURLs != null) if (EmergencyURLs != null)
{ {
SearchResultList.Add(new SearchResult(ProductType + " emergency-files", EmergencyURLs, ProductType, EmergencyDownloaded, ProductType)); SearchResultList.Add(new SearchResult($"{ProductType} emergency-files", EmergencyURLs, ProductType, EmergencyDownloaded, ProductType));
}
if (SecureWIMURL != null)
{
SearchResultList.Add(new SearchResult($"{ProductType} ENOSW-files", SecureWIMURL, ProductType, ENOSWDownloaded, FirmwareVersion));
} }
}, null); }, null);
@@ -236,6 +276,7 @@ namespace WPinternals
{ {
string FFUURL = null; string FFUURL = null;
string[] EmergencyURLs = null; string[] EmergencyURLs = null;
string SecureWIMURL = null;
try try
{ {
string TempProductType = ProductType.ToUpper(); string TempProductType = ProductType.ToUpper();
@@ -255,8 +296,16 @@ namespace WPinternals
{ {
EmergencyURLs = LumiaDownloadModel.SearchEmergencyFiles(ProductType); EmergencyURLs = LumiaDownloadModel.SearchEmergencyFiles(ProductType);
} }
if (ProductType != null && FirmwareVersion != null)
{
(SecureWIMURL, string _) = LumiaDownloadModel.SearchENOSW(ProductType, FirmwareVersion);
}
}
catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
} }
catch { }
UIContext.Post(s => UIContext.Post(s =>
{ {
@@ -269,6 +318,11 @@ namespace WPinternals
{ {
Download(EmergencyURLs, ProductType, EmergencyDownloaded, ProductType); Download(EmergencyURLs, ProductType, EmergencyDownloaded, ProductType);
} }
if (SecureWIMURL != null)
{
Download(SecureWIMURL, ProductType, ENOSWDownloaded, FirmwareVersion);
}
}, null); }, null);
}).Start(); }).Start();
} }
@@ -322,6 +376,12 @@ namespace WPinternals
App.Config.AddEmergencyToRepository(Type, ProgrammerPath, PayloadPath); App.Config.AddEmergencyToRepository(Type, ProgrammerPath, PayloadPath);
} }
} }
private void ENOSWDownloaded(string[] Files, object State)
{
App.Config.AddSecWimToRepository(Files[0], (string)State);
}
public ObservableCollection<DownloadEntry> DownloadList { get; } = new(); public ObservableCollection<DownloadEntry> DownloadList { get; } = new();
public ObservableCollection<SearchResult> SearchResultList { get; } = new(); public ObservableCollection<SearchResult> SearchResultList { get; } = new();
@@ -369,7 +429,10 @@ namespace WPinternals
{ {
Directory.CreateDirectory(_DownloadFolder); Directory.CreateDirectory(_DownloadFolder);
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
if (!Directory.Exists(_DownloadFolder)) if (!Directory.Exists(_DownloadFolder))
{ {
_DownloadFolder = @"C:\ProgramData\WPinternals\Repository"; _DownloadFolder = @"C:\ProgramData\WPinternals\Repository";
@@ -433,6 +496,24 @@ namespace WPinternals
} }
} }
private string _FirmwareVersion = null;
public string FirmwareVersion
{
get
{
return _FirmwareVersion;
}
set
{
if (_FirmwareVersion != value)
{
_FirmwareVersion = value;
OnPropertyChanged(nameof(FirmwareVersion));
}
}
}
private string _OperatorCode = null; private string _OperatorCode = null;
public string OperatorCode public string OperatorCode
{ {
@@ -451,8 +532,13 @@ namespace WPinternals
} }
} }
internal override void EvaluateViewState() internal override async void EvaluateViewState()
{ {
if (IsSwitchingInterface)
{
return;
}
if (!IsActive) if (!IsActive)
{ {
return; return;
@@ -460,11 +546,120 @@ namespace WPinternals
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Flash) if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Flash)
{ {
NokiaFlashModel LumiaFlashModel = (NokiaFlashModel)Notifier.CurrentModel; LumiaFlashAppPhoneInfo FlashAppInfo = ((LumiaFlashAppModel)Notifier.CurrentModel).ReadPhoneInfo(ExtendedInfo: true);
PhoneInfo Info = LumiaFlashModel.ReadPhoneInfo(); FirmwareVersion = FlashAppInfo.Firmware;
IsSwitchingInterface = true;
try
{
bool ModernFlashApp = ((LumiaFlashAppModel)Notifier.CurrentModel).ReadPhoneInfo().FlashAppProtocolVersionMajor >= 2;
if (ModernFlashApp)
{
((LumiaFlashAppModel)Notifier.CurrentModel).SwitchToPhoneInfoAppContext();
}
else
{
((LumiaFlashAppModel)Notifier.CurrentModel).SwitchToPhoneInfoAppContextLegacy();
}
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_PhoneInfo)
{
await Notifier.WaitForArrival();
}
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_PhoneInfo)
{
throw new WPinternalsException("Unexpected Mode");
}
LumiaPhoneInfoAppModel LumiaPhoneInfoModel = (LumiaPhoneInfoAppModel)Notifier.CurrentModel;
LumiaPhoneInfoAppPhoneInfo Info = LumiaPhoneInfoModel.ReadPhoneInfo();
ProductType = Info.Type; ProductType = Info.Type;
OperatorCode = ""; OperatorCode = "";
ProductCode = Info.ProductCode; ProductCode = Info.ProductCode;
ModernFlashApp = Info.PhoneInfoAppVersionMajor >= 2;
if (ModernFlashApp)
{
LumiaPhoneInfoModel.SwitchToFlashAppContext();
}
else
{
LumiaPhoneInfoModel.ContinueBoot();
}
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)
{
await Notifier.WaitForArrival();
}
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)
{
throw new WPinternalsException("Unexpected Mode");
}
}
catch (Exception ex)
{
LogFile.LogException(ex);
}
IsSwitchingInterface = false;
}
else if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_PhoneInfo)
{
LumiaPhoneInfoAppModel LumiaPhoneInfoModel = (LumiaPhoneInfoAppModel)Notifier.CurrentModel;
LumiaPhoneInfoAppPhoneInfo Info = LumiaPhoneInfoModel.ReadPhoneInfo();
ProductType = Info.Type;
OperatorCode = "";
ProductCode = Info.ProductCode;
IsSwitchingInterface = true;
bool ModernFlashApp = Info.PhoneInfoAppVersionMajor >= 2;
if (ModernFlashApp)
{
LumiaPhoneInfoModel.SwitchToFlashAppContext();
}
else
{
LumiaPhoneInfoModel.ContinueBoot();
}
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)
{
await Notifier.WaitForArrival();
}
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)
{
throw new WPinternalsException("Unexpected Mode");
}
LumiaFlashAppPhoneInfo FlashAppInfo = ((LumiaFlashAppModel)Notifier.CurrentModel).ReadPhoneInfo(ExtendedInfo: true);
FirmwareVersion = FlashAppInfo.Firmware;
ModernFlashApp = FlashAppInfo.FlashAppProtocolVersionMajor >= 2;
if (ModernFlashApp)
{
((LumiaFlashAppModel)Notifier.CurrentModel).SwitchToPhoneInfoAppContext();
}
else
{
((LumiaFlashAppModel)Notifier.CurrentModel).SwitchToPhoneInfoAppContextLegacy();
}
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_PhoneInfo)
{
await Notifier.WaitForArrival();
}
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_PhoneInfo)
{
throw new WPinternalsException("Unexpected Mode");
}
IsSwitchingInterface = false;
} }
else if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Normal) else if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Normal)
{ {
@@ -478,6 +673,8 @@ namespace WPinternals
ProductType = TempProductType; ProductType = TempProductType;
ProductCode = LumiaNormalModel.ExecuteJsonMethodAsString("ReadProductCode", "ProductCode"); // 059Q9D7 ProductCode = LumiaNormalModel.ExecuteJsonMethodAsString("ReadProductCode", "ProductCode"); // 059Q9D7
FirmwareVersion = LumiaNormalModel.ExecuteJsonMethodAsString("ReadSwVersion", "SwVersion");
} }
} }
public DelegateCommand AddFFUCommand { get; } = null; public DelegateCommand AddFFUCommand { get; } = null;
@@ -490,7 +687,7 @@ namespace WPinternals
Failed Failed
}; };
internal class DownloadEntry : INotifyPropertyChanged internal class DownloadEntry : INotifyPropertyChanged, IProgress<GeneralDownloadProgress>
{ {
private readonly SynchronizationContext UIContext; private readonly SynchronizationContext UIContext;
public event PropertyChangedEventHandler PropertyChanged = delegate { }; public event PropertyChangedEventHandler PropertyChanged = delegate { };
@@ -499,7 +696,8 @@ namespace WPinternals
internal string URL; internal string URL;
internal string[] URLCollection; internal string[] URLCollection;
internal string Folder; internal string Folder;
internal HttpClient Client; //internal HttpClient Client;
internal HttpDownloader Client;
internal long SpeedIndex = -1; internal long SpeedIndex = -1;
internal long[] Speeds = new long[10]; internal long[] Speeds = new long[10];
internal long LastBytesReceived; internal long LastBytesReceived;
@@ -521,11 +719,42 @@ namespace WPinternals
{ {
Size = DownloadsViewModel.GetFileLengthFromURL(URL); Size = DownloadsViewModel.GetFileLengthFromURL(URL);
Client = new HttpClient(); //Client = new HttpClient();
_ = Client.DownloadFileAsync(Uri, Path.Combine(Folder, DownloadsViewModel.GetFileNameFromURL(Uri.LocalPath)), Client_DownloadProgressChanged, Client_DownloadFileCompleted);
//_ = Client.DownloadFileAsync(Uri, Path.Combine(Folder, DownloadsViewModel.GetFileNameFromURL(Uri.LocalPath)), Client_DownloadProgressChanged, Client_DownloadFileCompleted);
Client = new(Folder, 4, false);
_ = Client.DownloadAsync([new FileDownloadInformation(URL, DownloadsViewModel.GetFileNameFromURL(Uri.LocalPath), Size, null, null)], this);
}).Start(); }).Start();
} }
public void Report(GeneralDownloadProgress e)
{
foreach (FileDownloadStatus status in e.DownloadedStatus)
{
if (status == null)
{
continue;
}
if (status.FileStatus == FileStatus.Failed || status.FileStatus == FileStatus.Failed)
{
Client_DownloadFileCompleted(true);
}
if (status.FileStatus == FileStatus.Completed)
{
Client_DownloadFileCompleted(false);
}
if (status.FileStatus == FileStatus.Downloading)
{
Client_DownloadProgressChanged(new HttpClientDownloadProgress(status.DownloadedBytes, status.File.FileSize));
}
}
}
private void Client_DownloadFileCompleted(bool Error) private void Client_DownloadFileCompleted(bool Error)
{ {
void Finish() void Finish()
@@ -536,6 +765,9 @@ namespace WPinternals
{ {
if (URLCollection?.Any(c => App.DownloadManager.DownloadList.Any(d => d.URL == c)) != true) // if there are no files left to download from this collection, then call the callback-function. if (URLCollection?.Any(c => App.DownloadManager.DownloadList.Any(d => d.URL == c)) != true) // if there are no files left to download from this collection, then call the callback-function.
{ {
Client.Dispose();
Client = null;
string[] Files; string[] Files;
if (URLCollection == null) if (URLCollection == null)
{ {
@@ -556,8 +788,15 @@ namespace WPinternals
} }
} }
if (UIContext == null)
{
Finish();
}
else
{
UIContext?.Post(d => Finish(), null); UIContext?.Post(d => Finish(), null);
} }
}
private void Client_DownloadProgressChanged(HttpClientDownloadProgress e) private void Client_DownloadProgressChanged(HttpClientDownloadProgress e)
{ {
@@ -715,6 +954,18 @@ namespace WPinternals
GetSize(); GetSize();
} }
internal SearchResult(string Name, string URL, string Category, Action<string[], object> Callback, object State)
{
UIContext = SynchronizationContext.Current;
URLs = new string[1];
URLs[0] = URL;
this.Name = Name;
this.Callback = Callback;
this.State = State;
this.Category = Category;
GetSize();
}
private void GetSize() private void GetSize()
{ {
new Thread(() => new Thread(() =>
+642
View File
@@ -0,0 +1,642 @@
/*
* Copyright (c) Gustave Monce and Contributors
* Copyright (c) ADeltaX and Contributors
*
* 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.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
namespace WPinternals
{
public class GeneralDownloadProgress
{
public long EstimatedTotalBytes;
public long DownloadedTotalBytes;
public int NumFilesDownloadedSuccessfully;
public int NumFilesDownloadedUnsuccessfully;
public int NumFiles;
public FileDownloadStatus[] DownloadedStatus;
}
public enum FileStatus
{
Downloading,
Verifying,
Completed,
Expired,
Failed
}
public class FileDownloadStatus
{
public FileStatus FileStatus;
public long DownloadedBytes;
public long HashedBytes;
public FileDownloadInformation File;
public FileDownloadStatus(FileDownloadInformation file)
{
File = file;
}
}
public class FileDownloadInformation
{
public string DownloadUrl
{
get; set;
}
public string FileName
{
get; set;
}
public long FileSize
{
get; set;
}
public string Hash
{
get; set;
}
public string HashAlgorithm
{
get; set;
}
public FileDownloadInformation(string DownloadUrl, string FileName, long FileSize, string Hash, string HashAlgorithm)
{
this.DownloadUrl = DownloadUrl;
this.FileName = FileName;
this.FileSize = FileSize;
this.Hash = Hash;
this.HashAlgorithm = HashAlgorithm;
}
}
public class HttpDownloader : IDisposable
{
private const long CHUNK_SIZE = 8_388_608 + 65_536; //Slice 8MB+64KB
private const string TEMP_DOWNLOAD_EXTENSION = ".dlTmp";
private readonly HttpClient _hc;
public string DownloadFolderPath
{
get; set;
}
public int DownloadThreads
{
get; set;
}
public int DownloadRetries
{
get; set;
}
public bool VerifyFiles
{
get; set;
}
public HttpDownloader(string downloadFolderPath, int downloadThreads = 4, bool verifyFiles = true, IWebProxy proxy = null, bool useSystemProxy = true)
{
HttpClientHandler filter = new()
{
AutomaticDecompression = DecompressionMethods.All,
MaxConnectionsPerServer = 512,
};
if (proxy != null || !useSystemProxy)
{
filter.Proxy = proxy;
}
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
filter.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator; //For Linux, MS cert isn't trusted lol ¯\_(ツ)_/¯
}
_hc = new HttpClient(filter)
{
Timeout = TimeSpan.FromSeconds(10)
};
_hc.DefaultRequestHeaders.Connection.Add("keep-alive");
DownloadThreads = downloadThreads;
DownloadFolderPath = downloadFolderPath;
VerifyFiles = verifyFiles;
}
public async Task<bool> DownloadAsync(List<FileDownloadInformation> Files, IProgress<GeneralDownloadProgress> generalDownloadProgress, CancellationToken cancellationToken = default)
{
return await ParallelQueue(Files, DownloadFile, generalDownloadProgress, DownloadThreads, cancellationToken);
}
public async Task<bool> DownloadAsync(FileDownloadInformation File, IProgress<FileDownloadStatus> downloadProgress = null, CancellationToken cancellationToken = default)
{
return await DownloadFile(File, downloadProgress, cancellationToken);
}
private static async ValueTask<bool> ParallelQueue(List<FileDownloadInformation> items, Func<FileDownloadInformation, IProgress<FileDownloadStatus>, CancellationToken, ValueTask<bool>> func,
IProgress<GeneralDownloadProgress> generalProgress, int threads, CancellationToken cancellationToken)
{
Queue<FileDownloadInformation> pending = new(items);
Task<bool>[] workingSlots = new Task<bool>[threads];
int workingThreadsCount = 0;
GeneralDownloadProgress generalDownloadProgress = new()
{
DownloadedStatus = new FileDownloadStatus[threads],
NumFiles = items.Count
};
bool result = true;
while (pending.Count + workingThreadsCount != 0)
{
if (workingThreadsCount < threads && pending.Count != 0)
{
FileDownloadInformation item = pending.Dequeue();
FileDownloadStatus fileStatus = new(item);
Progress<FileDownloadStatus> progress = new();
workingThreadsCount++;
GetFreeSlotIndex(workingSlots, out int freeSlotIndex);
generalDownloadProgress.DownloadedStatus[freeSlotIndex] = fileStatus;
progress.ProgressChanged += (s, e) =>
{
generalDownloadProgress.DownloadedTotalBytes += e.DownloadedBytes - generalDownloadProgress.DownloadedStatus[freeSlotIndex].DownloadedBytes;
generalDownloadProgress.DownloadedStatus[freeSlotIndex].DownloadedBytes = e.DownloadedBytes;
generalDownloadProgress.DownloadedStatus[freeSlotIndex].HashedBytes = e.HashedBytes;
generalDownloadProgress.DownloadedStatus[freeSlotIndex].FileStatus = e.FileStatus;
generalProgress?.Report(generalDownloadProgress);
};
workingSlots[freeSlotIndex] = Task.Run(async () => await func(item, progress, cancellationToken));
}
else
{
_ = await Task.WhenAny(workingSlots.Where(t => t != null));
for (int i = 0; i < workingSlots.Length; i++)
{
if (workingSlots[i]?.IsCompleted == true)
{
if (workingSlots[i].Result)
{
generalDownloadProgress.NumFilesDownloadedSuccessfully++;
}
else
{
generalDownloadProgress.NumFilesDownloadedUnsuccessfully++;
result = false;
}
workingThreadsCount--;
workingSlots[i].Dispose();
workingSlots[i] = null;
}
}
}
cancellationToken.ThrowIfCancellationRequested();
}
return result;
}
private async ValueTask<bool> DownloadFile(FileDownloadInformation downloadFile, IProgress<FileDownloadStatus> progress, CancellationToken cancellationToken)
{
return await HttpDownload(DownloadFolderPath, downloadFile, _hc, VerifyFiles, progress, cancellationToken: cancellationToken);
}
private static async ValueTask<bool> HttpDownload(string basePath, FileDownloadInformation downloadFile, HttpClient httpClient, bool verifyFiles,
IProgress<FileDownloadStatus> downloadProgress = null, int bufferSize = 65_536, CancellationToken cancellationToken = default)
{
long currRange = 0;
long chunk = CHUNK_SIZE;
long totalBytesRead = 0;
long hashedBytes = 0;
int blockBufferSize = bufferSize;
try
{
//This path will be used for downloaded and validated files, moved/renamed
string filePath = Path.Combine(basePath, downloadFile.FileName);
//This path will be used for downloading files
string tempFilePath = filePath + TEMP_DOWNLOAD_EXTENSION;
//If we have an already completed file, prefer this under certain conditions.
if (File.Exists(tempFilePath) && File.Exists(filePath))
{
FileInfo tmpFileInfo = new(tempFilePath);
FileInfo fileInfo = new(filePath);
if (tmpFileInfo.Length == downloadFile.FileSize)
{
File.Delete(filePath);
}
else if (fileInfo.Length == downloadFile.FileSize)
{
File.Delete(tempFilePath);
}
else
{
File.Delete(filePath);
}
}
if (File.Exists(tempFilePath))
{
FileInfo tmpFileInfo = new(tempFilePath);
if (tmpFileInfo.Length == downloadFile.FileSize)
{
//Decrypted file should match estimated bytes.
//Imagine if it crashed during hashing, the file may be valid.
//So... lets rename this file so it can be verified.
File.Move(tempFilePath, filePath);
totalBytesRead = tmpFileInfo.Length;
}
else if (tmpFileInfo.Length < downloadFile.FileSize)
{
//Download the remaining part
currRange = tmpFileInfo.Length;
totalBytesRead = tmpFileInfo.Length;
}
else
{
//If it's bigger then we have a problem.
//Just... delete the file.
File.Delete(tempFilePath);
}
}
if (File.Exists(filePath))
{
//If the filename was renamed then the download must have been completed successfully,
//we just hash to be sure that the file hasn't been tampered
if (verifyFiles)
{
FileStream fileStreamToHash = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
totalBytesRead = fileStreamToHash.Length;
bool hashResult = await HashWithProgress(fileStreamToHash);
fileStreamToHash.Dispose();
if (hashResult)
{
//Nice, the file is ok, return success.
return true;
}
else
{
//The file is not ok.
//It's better to delete this file and redownload from scratch
//instead of partially downloading the missing parts and found later that the entire file was corrupted.
File.Delete(filePath);
//This range may have been changed before (e.g. when assuming for temp. file), so let's set it to 0
currRange = 0;
totalBytesRead = 0;
hashedBytes = 0;
}
}
else
{
//At your own risk lol
FileInfo fileInfo = new(filePath);
downloadProgress?.Report(new FileDownloadStatus(downloadFile)
{
DownloadedBytes = fileInfo.Length,
FileStatus = FileStatus.Completed
});
return true;
}
}
//Before we need to create a directory.
_ = Directory.CreateDirectory(Path.GetDirectoryName(filePath));
//Open the file as stream.
using FileStream streamToWriteTo = File.Open(tempFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);
//Set the seek position to current range position (via totalBytesRead or currRange). This is needed.
_ = streamToWriteTo.Seek(totalBytesRead, SeekOrigin.Begin);
using HttpRequestMessage httpRequestMessageHead = new(HttpMethod.Head, new Uri(downloadFile.DownloadUrl));
using HttpResponseMessage response = await httpClient.SendAsync(httpRequestMessageHead, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
//Technically the server reports both content-length and Accept-Ranges.
long? contentLength = response.Content.Headers.ContentLength;
bool hasAcceptRanges = response.Headers.AcceptRanges.Contains("bytes");
//This is just a fallback in case the file delivery server goes nuts.
if (!hasAcceptRanges)
{
//We don't have a way to download from a specific range, hence we set the position to 0
//and download everything from scratch... Sadly.
//TODO
_ = streamToWriteTo.Seek(0, SeekOrigin.Begin);
downloadProgress?.Report(new FileDownloadStatus(downloadFile)
{
DownloadedBytes = 0,
FileStatus = FileStatus.Downloading
});
//TODO: add download reporting for this
//TODO: may throw an exception if the server suddently closes the connection (e.g. file expired.)
using HttpResponseMessage fullFileResp = await httpClient.GetAsync(downloadFile.DownloadUrl, cancellationToken);
using Stream streamToReadFrom = await fullFileResp.Content.ReadAsStreamAsync();
await streamToReadFrom.CopyToAsync(streamToWriteTo);
downloadProgress?.Report(new FileDownloadStatus(downloadFile)
{
DownloadedBytes = contentLength.Value,
FileStatus = FileStatus.Downloading
});
//just an assumption
if (verifyFiles)
{
_ = streamToWriteTo.Seek(0, SeekOrigin.Begin);
bool hashResult = await HashWithProgress(streamToWriteTo);
if (hashResult)
{
streamToWriteTo.Close();
File.Move(tempFilePath, filePath);
}
return hashResult;
}
else
{
streamToWriteTo.Close();
File.Move(tempFilePath, filePath);
downloadProgress?.Report(new FileDownloadStatus(downloadFile)
{
DownloadedBytes = totalBytesRead,
FileStatus = FileStatus.Completed
});
return true;
}
}
while (currRange < contentLength.Value)
{
//Calculate range values
if (currRange + chunk >= contentLength.Value)
{
chunk = contentLength.Value - currRange - 1;
}
//Create request for range and send it, return asap (we just need the header to see if the status code is ok)
using HttpRequestMessage requestMessageRange = CreateRequestHeaderForRange(HttpMethod.Get, downloadFile.DownloadUrl, currRange, currRange + chunk);
using HttpResponseMessage filePartResp = await httpClient.SendAsync(requestMessageRange, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
//increment to the next range
currRange += chunk + 1;
//If the server has replied with 200 ok/206 partial content
if (filePartResp.IsSuccessStatusCode)
{
//get the underlying stream
using Stream streamToReadFrom = await filePartResp.Content.ReadAsStreamAsync();
int bytesRead;
byte[] buffer = new byte[blockBufferSize];
//read the content
//TODO: it may throw an exception (stream closed because file expired?)
//In that case we would wrap into another try catch and try to read the reason behind this
while ((bytesRead = await streamToReadFrom.ReadAsync(buffer, 0, buffer.Length, cancellationToken)) > 0)
{
totalBytesRead += bytesRead;
//simply write to the file
await streamToWriteTo.WriteAsync(buffer, 0, bytesRead, cancellationToken);
//report progress
downloadProgress?.Report(new FileDownloadStatus(downloadFile)
{
DownloadedBytes = totalBytesRead,
FileStatus = FileStatus.Downloading
});
}
}
else
{
if (filePartResp.StatusCode is HttpStatusCode.Forbidden or
HttpStatusCode.NotFound or
HttpStatusCode.Unauthorized)
{
//The url is expired.
//Report that is expired and return false
//We need to keep the file, because it's just incomplete, not corrupted.
downloadProgress?.Report(new FileDownloadStatus(downloadFile)
{
DownloadedBytes = totalBytesRead,
FileStatus = FileStatus.Expired
});
return false;
}
else
{
throw new Exception(filePartResp.ReasonPhrase);
}
}
}
//last left block if any
if (verifyFiles)
{
_ = streamToWriteTo.Seek(0, SeekOrigin.Begin);
bool hashResult = await HashWithProgress(streamToWriteTo);
if (hashResult)
{
streamToWriteTo.Close();
File.Move(tempFilePath, filePath);
}
return hashResult;
}
else
{
streamToWriteTo.Close();
File.Move(tempFilePath, filePath);
downloadProgress?.Report(new FileDownloadStatus(downloadFile)
{
DownloadedBytes = totalBytesRead,
FileStatus = FileStatus.Completed
});
return true;
}
}
catch //(Exception ex)
{
downloadProgress?.Report(new FileDownloadStatus(downloadFile)
{
DownloadedBytes = totalBytesRead,
FileStatus = FileStatus.Failed
});
return false;
}
//C# 7 - Local Functions
async ValueTask<bool> HashWithProgress(Stream strm)
{
Progress<long> progressHashedBytes = new();
progressHashedBytes.ProgressChanged += (s, e) =>
{
hashedBytes = e;
downloadProgress?.Report(new FileDownloadStatus(downloadFile)
{
DownloadedBytes = totalBytesRead,
HashedBytes = hashedBytes,
FileStatus = FileStatus.Verifying
});
};
bool hashMatches = true;
switch (downloadFile.HashAlgorithm?.ToLower())
{
case "sha1":
hashMatches = await IsDownloadedFileValidSHA1(strm, downloadFile.Hash,
progressHashedBytes, cancellationToken);
break;
case "sha256":
hashMatches = await IsDownloadedFileValidSHA256(strm, downloadFile.Hash,
progressHashedBytes, cancellationToken);
break;
}
if (hashMatches)
{
downloadProgress?.Report(new FileDownloadStatus(downloadFile)
{
DownloadedBytes = totalBytesRead,
HashedBytes = hashedBytes,
FileStatus = FileStatus.Completed
});
return true;
}
else
{
downloadProgress?.Report(new FileDownloadStatus(downloadFile)
{
DownloadedBytes = totalBytesRead,
HashedBytes = hashedBytes,
FileStatus = FileStatus.Failed
});
return false;
}
}
}
#region Helpers
private static async ValueTask<bool> IsDownloadedFileValidSHA256(Stream fileStream, string base64Hash, IProgress<long> progress = null, CancellationToken cancellationToken = default)
{
using SHA256 hashAlgo = SHA256.Create();
byte[] hashByte = await ComputeHashAsyncT(hashAlgo, fileStream, progress, cancellationToken: cancellationToken);
return ByteArraySpanCompare(Convert.FromBase64String(base64Hash), hashByte);
}
private static async ValueTask<bool> IsDownloadedFileValidSHA1(Stream fileStream, string base64Hash, IProgress<long> progress = null, CancellationToken cancellationToken = default)
{
using SHA1 hashAlgo = SHA1.Create();
byte[] hashByte = await ComputeHashAsyncT(hashAlgo, fileStream, progress, cancellationToken: cancellationToken);
return ByteArraySpanCompare(Convert.FromBase64String(base64Hash), hashByte);
}
public static async ValueTask<byte[]> ComputeHashAsyncT(HashAlgorithm hashAlgorithm, Stream fileStream, IProgress<long> progress = null,
int bufferSize = 1_048_576, CancellationToken cancellationToken = default)
{
int readBytes;
long totalBytesRead = 0;
long bufSizeEffective = Math.Min(bufferSize, fileStream.Length);
byte[] buffer = new byte[bufSizeEffective];
using MemoryStream ms = new(buffer);
using CryptoStream cs = new(ms, hashAlgorithm, CryptoStreamMode.Write);
while ((readBytes = await fileStream.ReadAsync(buffer, 0, buffer.Length, cancellationToken)) > 0)
{
await cs.WriteAsync(buffer, 0, readBytes, cancellationToken);
ms.Position = 0;
totalBytesRead += readBytes;
progress?.Report(totalBytesRead);
cancellationToken.ThrowIfCancellationRequested();
}
cs.FlushFinalBlock();
return hashAlgorithm.Hash;
}
private static bool ByteArraySpanCompare(ReadOnlySpan<byte> a1, ReadOnlySpan<byte> a2)
{
return a1.SequenceEqual(a2);
}
private static void GetFreeSlotIndex<T>(T[] array, out int firstFreeTaskIndex)
{
firstFreeTaskIndex = -1;
for (int i = 0; i < array.Length; i++)
{
if (array[i] == null)
{
firstFreeTaskIndex = i;
break;
}
}
}
private static HttpRequestMessage CreateRequestHeaderForRange(HttpMethod method, string url, long from, long to)
{
HttpRequestMessage request = new(method, new Uri(url));
request.Headers.Range = new System.Net.Http.Headers.RangeHeaderValue(from, to);
return request;
}
#endregion
public void Dispose()
{
//Release all resources that have been instanced and used
_hc.Dispose();
GC.SuppressFinalize(this);
}
}
}
@@ -256,7 +256,10 @@ namespace WPinternals
{ {
EvaluateViewState(); EvaluateViewState();
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
}).Start(); }).Start();
} }
@@ -73,7 +73,7 @@ namespace WPinternals
await SwitchModeViewModel.SwitchToWithProgress(PhoneNotifier, PhoneInterfaces.Lumia_Flash, await SwitchModeViewModel.SwitchToWithProgress(PhoneNotifier, PhoneInterfaces.Lumia_Flash,
(msg, sub) => (msg, sub) =>
ActivateSubContext(new BusyViewModel(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); FlashPartitionsTask(EFIESPPath, MainOSPath, DataPath);
} }
@@ -96,7 +96,7 @@ namespace WPinternals
ActivateSubContext(new BusyViewModel("Initializing flash...")); ActivateSubContext(new BusyViewModel("Initializing flash..."));
NokiaFlashModel Phone = (NokiaFlashModel)PhoneNotifier.CurrentModel; LumiaFlashAppModel Phone = (LumiaFlashAppModel)PhoneNotifier.CurrentModel;
GPT GPT = Phone.ReadGPT(); GPT GPT = Phone.ReadGPT();
@@ -268,7 +268,7 @@ namespace WPinternals
await SwitchModeViewModel.SwitchToWithProgress(PhoneNotifier, PhoneInterfaces.Lumia_Flash, await SwitchModeViewModel.SwitchToWithProgress(PhoneNotifier, PhoneInterfaces.Lumia_Flash,
(msg, sub) => (msg, sub) =>
ActivateSubContext(new BusyViewModel(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); FlashArchiveTask(ArchivePath);
} }
@@ -289,7 +289,7 @@ namespace WPinternals
{ {
ActivateSubContext(new BusyViewModel("Initializing flash...")); ActivateSubContext(new BusyViewModel("Initializing flash..."));
NokiaFlashModel Phone = (NokiaFlashModel)PhoneNotifier.CurrentModel; LumiaFlashAppModel Phone = (LumiaFlashAppModel)PhoneNotifier.CurrentModel;
ulong TotalSizeSectors = 0; ulong TotalSizeSectors = 0;
int PartitionCount = 0; int PartitionCount = 0;
@@ -343,7 +343,10 @@ namespace WPinternals
{ {
StreamLengthInSectors = (ulong)DecompressedStream.Length / 0x200; StreamLengthInSectors = (ulong)DecompressedStream.Length / 0x200;
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
TotalSizeSectors += StreamLengthInSectors; TotalSizeSectors += StreamLengthInSectors;
PartitionCount++; PartitionCount++;
@@ -438,7 +441,10 @@ namespace WPinternals
{ {
StreamLengthInSectors = (ulong)DecompressedStream.Length / 0x200; StreamLengthInSectors = (ulong)DecompressedStream.Length / 0x200;
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
if (StreamLengthInSectors <= Partition.SizeInSectors) if (StreamLengthInSectors <= Partition.SizeInSectors)
{ {
@@ -495,12 +501,12 @@ namespace WPinternals
internal void FlashFFUTask(string FFUPath) internal void FlashFFUTask(string FFUPath)
{ {
new Thread(() => new Thread(async () =>
{ {
bool Result = true; bool Result = true;
NokiaFlashModel Phone = (NokiaFlashModel)PhoneNotifier.CurrentModel; LumiaFlashAppModel Phone = (LumiaFlashAppModel)PhoneNotifier.CurrentModel;
PhoneInfo Info = Phone.ReadPhoneInfo(false); LumiaFlashAppPhoneInfo Info = Phone.ReadPhoneInfo(false);
#region Remove bootloader changes #region Remove bootloader changes
@@ -513,8 +519,35 @@ namespace WPinternals
if (Info.FlashAppProtocolVersionMajor >= 2) if (Info.FlashAppProtocolVersionMajor >= 2)
{ {
byte[] GPTChunk = LumiaUnlockBootloaderViewModel.GetGptChunk(Phone, 0x20000); // TODO: Get proper profile FFU and get ChunkSizeInBytes Phone.SwitchToBootManagerContext();
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_Bootloader)
{
await PhoneNotifier.WaitForArrival();
}
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_Bootloader)
{
throw new WPinternalsException("Unexpected Mode");
}
byte[] GPTChunk = ((LumiaBootManagerAppModel)PhoneNotifier.CurrentModel).GetGptChunk(0x20000); // TODO: Get proper profile FFU and get ChunkSizeInBytes
GPT GPT = new(GPTChunk); GPT GPT = new(GPTChunk);
((LumiaBootManagerAppModel)PhoneNotifier.CurrentModel).SwitchToFlashAppContext();
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)
{
await PhoneNotifier.WaitForArrival();
}
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)
{
throw new WPinternalsException("Unexpected Mode");
}
Phone = (LumiaFlashAppModel)PhoneNotifier.CurrentModel;
FlashPart Part; FlashPart Part;
List<FlashPart> FlashParts = new(); List<FlashPart> FlashParts = new();
@@ -592,14 +625,14 @@ namespace WPinternals
if (PhoneNotifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) if (PhoneNotifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
{ {
((NokiaFlashModel)PhoneNotifier.CurrentModel).SwitchToFlashAppContext(); ((LumiaBootManagerAppModel)PhoneNotifier.CurrentModel).SwitchToFlashAppContext();
} }
} }
} }
#endregion #endregion
Phone = (NokiaFlashModel)PhoneNotifier.CurrentModel; Phone = (LumiaFlashAppModel)PhoneNotifier.CurrentModel;
ActivateSubContext(new BusyViewModel("Initializing flash...")); ActivateSubContext(new BusyViewModel("Initializing flash..."));
@@ -658,12 +691,13 @@ namespace WPinternals
internal void FlashMMOSTask(string MMOSPath) internal void FlashMMOSTask(string MMOSPath)
{ {
NokiaFlashModel Phone = (NokiaFlashModel)PhoneNotifier.CurrentModel;
if (PhoneNotifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) if (PhoneNotifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
{ {
Phone.SwitchToFlashAppContext(); ((LumiaBootManagerAppModel)PhoneNotifier.CurrentModel).SwitchToFlashAppContext();
} }
LumiaFlashAppModel Phone = (LumiaFlashAppModel)PhoneNotifier.CurrentModel;
new Thread(() => new Thread(() =>
{ {
bool Result = true; bool Result = true;
+7 -3
View File
@@ -66,15 +66,19 @@ namespace WPinternals
switch (CurrentInterface) switch (CurrentInterface)
{ {
case null: case null:
case PhoneInterfaces.Lumia_Bootloader:
ActivateSubContext(null); 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((LumiaPhoneInfoAppModel)CurrentModel, ModeSwitchRequestCallback, SwitchToGettingStarted));
break; break;
case PhoneInterfaces.Lumia_Normal: case PhoneInterfaces.Lumia_Normal:
ActivateSubContext(new NokiaNormalViewModel((NokiaPhoneModel)CurrentModel, ModeSwitchRequestCallback)); ActivateSubContext(new NokiaNormalViewModel((NokiaPhoneModel)CurrentModel, ModeSwitchRequestCallback));
break; break;
case PhoneInterfaces.Lumia_Flash: case PhoneInterfaces.Lumia_Flash:
ActivateSubContext(new NokiaFlashViewModel((NokiaFlashModel)CurrentModel, ModeSwitchRequestCallback, SwitchToGettingStarted)); ActivateSubContext(new NokiaFlashViewModel((LumiaFlashAppModel)CurrentModel, ModeSwitchRequestCallback, SwitchToGettingStarted));
break; break;
case PhoneInterfaces.Lumia_Label: case PhoneInterfaces.Lumia_Label:
ActivateSubContext(new NokiaLabelViewModel((NokiaPhoneModel)CurrentModel, ModeSwitchRequestCallback)); ActivateSubContext(new NokiaLabelViewModel((NokiaPhoneModel)CurrentModel, ModeSwitchRequestCallback));
+5 -3
View File
@@ -87,14 +87,16 @@ namespace WPinternals
ActivateSubContext(null); ActivateSubContext(null);
break; break;
case PhoneInterfaces.Lumia_Bootloader: case PhoneInterfaces.Lumia_Bootloader:
ActivateSubContext(null); ActivateSubContext(new NokiaModeBootloaderViewModel((LumiaBootManagerAppModel)CurrentModel, OnModeSwitchRequested));
//ActivateSubContext(new NokiaModeBootloaderViewModel((NokiaFlashModel)CurrentModel, OnModeSwitchRequested)); break;
case PhoneInterfaces.Lumia_PhoneInfo:
ActivateSubContext(new NokiaModePhoneInfoViewModel((LumiaPhoneInfoAppModel)CurrentModel, OnModeSwitchRequested));
break; break;
case PhoneInterfaces.Lumia_Normal: case PhoneInterfaces.Lumia_Normal:
ActivateSubContext(new NokiaModeNormalViewModel((NokiaPhoneModel)CurrentModel, OnModeSwitchRequested)); ActivateSubContext(new NokiaModeNormalViewModel((NokiaPhoneModel)CurrentModel, OnModeSwitchRequested));
break; break;
case PhoneInterfaces.Lumia_Flash: case PhoneInterfaces.Lumia_Flash:
ActivateSubContext(new NokiaModeFlashViewModel((NokiaFlashModel)CurrentModel, OnModeSwitchRequested)); ActivateSubContext(new NokiaModeFlashViewModel((LumiaFlashAppModel)CurrentModel, OnModeSwitchRequested));
break; break;
case PhoneInterfaces.Lumia_Label: case PhoneInterfaces.Lumia_Label:
ActivateSubContext(new NokiaModeLabelViewModel((NokiaPhoneModel)CurrentModel, OnModeSwitchRequested)); ActivateSubContext(new NokiaModeLabelViewModel((NokiaPhoneModel)CurrentModel, OnModeSwitchRequested));
@@ -95,6 +95,11 @@ namespace WPinternals
return; return;
} }
if (IsSwitchingInterface)
{
return;
}
lock (EvaluateViewStateLockObject) lock (EvaluateViewStateLockObject)
{ {
switch (PhoneNotifier.CurrentInterface) switch (PhoneNotifier.CurrentInterface)
@@ -133,11 +138,11 @@ namespace WPinternals
{ {
// Some phones, like Lumia 928 verizon, do not support the Terminal interface! // Some phones, like Lumia 928 verizon, do not support the Terminal interface!
// To read the RootKeyHash we use ReadParam("RRKH"), instead of GetTerminalResponse().RootKeyHash. // 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; TestPos = 1;
UefiSecurityStatusResponse SecurityStatus = ((NokiaFlashModel)PhoneNotifier.CurrentModel).ReadSecurityStatus(); UefiSecurityStatusResponse SecurityStatus = ((LumiaFlashAppModel)PhoneNotifier.CurrentModel).ReadSecurityStatus();
if (SecurityStatus != null) if (SecurityStatus != null)
{ {
IsBootLoaderUnlocked = SecurityStatus.AuthenticationStatus || SecurityStatus.RdcStatus || !SecurityStatus.SecureFfuEfuseStatus; IsBootLoaderUnlocked = SecurityStatus.AuthenticationStatus || SecurityStatus.RdcStatus || !SecurityStatus.SecureFfuEfuseStatus;
@@ -145,20 +150,21 @@ namespace WPinternals
TestPos = 2; TestPos = 2;
PhoneInfo Info = ((NokiaFlashModel)PhoneNotifier.CurrentModel).ReadPhoneInfo(); LumiaFlashAppPhoneInfo FlashInfo = ((LumiaFlashAppModel)PhoneNotifier.CurrentModel).ReadPhoneInfo();
if (SecurityStatus == null) if (SecurityStatus == null)
{ {
IsBootLoaderUnlocked = !Info.IsBootloaderSecure; IsBootLoaderUnlocked = !FlashInfo.IsBootloaderSecure;
} }
if (RootKeyHash == null) if (RootKeyHash == null)
{ {
RootKeyHash = Info.RKH ?? (new byte[32]); RootKeyHash = FlashInfo.RKH ?? (new byte[32]);
} }
TestPos = 3; TestPos = 3;
if (Info.FlashAppProtocolVersionMajor < 2) if (FlashInfo.FlashAppProtocolVersionMajor < 2)
{ {
// This action is executed after the resources are selected by the user. // This action is executed after the resources are selected by the user.
void ReturnFunction(string FFUPath, string LoadersPath, string SBL3Path, string ProfileFFUPath, string EDEPath, string SupportedFFUPath, bool DoFixBoot) void ReturnFunction(string FFUPath, string LoadersPath, string SBL3Path, string ProfileFFUPath, string EDEPath, string SupportedFFUPath, bool DoFixBoot)
@@ -213,7 +219,7 @@ namespace WPinternals
bool AlreadyUnlocked = false; bool AlreadyUnlocked = false;
if (DoUnlock) if (DoUnlock)
{ {
NokiaFlashModel FlashModel = (NokiaFlashModel)PhoneNotifier.CurrentModel; LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)PhoneNotifier.CurrentModel;
GPT GPT = FlashModel.ReadGPT(); GPT GPT = FlashModel.ReadGPT();
if ((GPT.GetPartition("IS_UNLOCKED") != null) || (GPT.GetPartition("BACKUP_EFIESP") != null)) if ((GPT.GetPartition("IS_UNLOCKED") != null) || (GPT.GetPartition("BACKUP_EFIESP") != null))
{ {
@@ -281,7 +287,7 @@ namespace WPinternals
{ {
FFU ProfileFFU = null; FFU ProfileFFU = null;
List<FFUEntry> FFUs = App.Config.FFURepository.Where(e => Info.PlatformID.StartsWith(e.PlatformID, StringComparison.OrdinalIgnoreCase) && e.Exists()).ToList(); List<FFUEntry> FFUs = App.Config.FFURepository.Where(e => FlashInfo.PlatformID.StartsWith(e.PlatformID, StringComparison.OrdinalIgnoreCase) && e.Exists()).ToList();
ProfileFFU = FFUs.Count > 0 ProfileFFU = FFUs.Count > 0
? new FFU(FFUs[0].Path) ? new FFU(FFUs[0].Path)
: throw new WPinternalsException("Profile FFU missing", "No profile FFU has been found in the repository for your device. You can add a profile FFU within the download section of the tool or by using the command line."); : throw new WPinternalsException("Profile FFU missing", "No profile FFU has been found in the repository for your device. You can add a profile FFU within the download section of the tool or by using the command line.");
@@ -295,14 +301,64 @@ namespace WPinternals
TestPos = 5; TestPos = 5;
if (DoUnlock) IsSwitchingInterface = true;
Task.Run(async () =>
{ {
ActivateSubContext(new BootUnlockResourcesViewModel("Lumia Flash mode", RootKeyHash, SwitchToFlashRom, SwitchToUndoRoot, SwitchToDownload, ReturnFunction, Abort, IsBootLoaderUnlocked, true, Info.PlatformID, Info.Type)); bool ModernFlashApp = ((LumiaFlashAppModel)PhoneNotifier.CurrentModel).ReadPhoneInfo().FlashAppProtocolVersionMajor >= 2;
if (ModernFlashApp)
{
((LumiaFlashAppModel)PhoneNotifier.CurrentModel).SwitchToPhoneInfoAppContext();
} }
else else
{ {
ActivateSubContext(new BootRestoreResourcesViewModel("Lumia Flash mode", RootKeyHash, SwitchToFlashRom, SwitchToUndoRoot, SwitchToDownload, ReturnFunction, Abort, IsBootLoaderUnlocked, true, Info.PlatformID, Info.Type)); ((LumiaFlashAppModel)PhoneNotifier.CurrentModel).SwitchToPhoneInfoAppContextLegacy();
} }
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_PhoneInfo)
{
await PhoneNotifier.WaitForArrival();
}
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_PhoneInfo)
{
throw new WPinternalsException("Unexpected Mode");
}
LumiaPhoneInfoAppModel LumiaPhoneInfoModel = (LumiaPhoneInfoAppModel)PhoneNotifier.CurrentModel;
LumiaPhoneInfoAppPhoneInfo PhoneInfo = LumiaPhoneInfoModel.ReadPhoneInfo();
IsSwitchingInterface = true;
ModernFlashApp = PhoneInfo.PhoneInfoAppVersionMajor >= 2;
if (ModernFlashApp)
{
LumiaPhoneInfoModel.SwitchToFlashAppContext();
}
else
{
LumiaPhoneInfoModel.ContinueBoot();
}
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)
{
await PhoneNotifier.WaitForArrival();
}
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)
{
throw new WPinternalsException("Unexpected Mode");
}
if (DoUnlock)
{
ActivateSubContext(new BootUnlockResourcesViewModel("Lumia Flash mode", RootKeyHash, SwitchToFlashRom, SwitchToUndoRoot, SwitchToDownload, ReturnFunction, Abort, IsBootLoaderUnlocked, true, FlashInfo.PlatformID, PhoneInfo.Type));
}
else
{
ActivateSubContext(new BootRestoreResourcesViewModel("Lumia Flash mode", RootKeyHash, SwitchToFlashRom, SwitchToUndoRoot, SwitchToDownload, ReturnFunction, Abort, IsBootLoaderUnlocked, true, FlashInfo.PlatformID, PhoneInfo.Type));
}
});
} }
} }
catch (Exception Ex) catch (Exception Ex)
@@ -451,7 +507,7 @@ namespace WPinternals
}, null); }, null);
} }
private void StorePaths() private async void StorePaths()
{ {
RegistryKey Key = Registry.CurrentUser.OpenSubKey(@"Software\WPInternals", true) ?? Registry.CurrentUser.CreateSubKey(@"Software\WPInternals"); RegistryKey Key = Registry.CurrentUser.OpenSubKey(@"Software\WPInternals", true) ?? Registry.CurrentUser.CreateSubKey(@"Software\WPInternals");
@@ -510,8 +566,56 @@ namespace WPinternals
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Qualcomm_Download && PhoneNotifier.CurrentInterface != PhoneInterfaces.Qualcomm_Flash) 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(); LumiaFlashAppPhoneInfo FlashInfo = Model.ReadPhoneInfo();
bool OriginalIsSwitchingInterface = IsSwitchingInterface;
IsSwitchingInterface = true;
bool ModernFlashApp = ((LumiaFlashAppModel)PhoneNotifier.CurrentModel).ReadPhoneInfo().FlashAppProtocolVersionMajor >= 2;
if (ModernFlashApp)
{
((LumiaFlashAppModel)PhoneNotifier.CurrentModel).SwitchToPhoneInfoAppContext();
}
else
{
((LumiaFlashAppModel)PhoneNotifier.CurrentModel).SwitchToPhoneInfoAppContextLegacy();
}
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_PhoneInfo)
{
await PhoneNotifier.WaitForArrival();
}
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_PhoneInfo)
{
throw new WPinternalsException("Unexpected Mode");
}
LumiaPhoneInfoAppModel LumiaPhoneInfoModel = (LumiaPhoneInfoAppModel)PhoneNotifier.CurrentModel;
LumiaPhoneInfoAppPhoneInfo PhoneInfo = LumiaPhoneInfoModel.ReadPhoneInfo();
ModernFlashApp = PhoneInfo.PhoneInfoAppVersionMajor >= 2;
if (ModernFlashApp)
{
LumiaPhoneInfoModel.SwitchToFlashAppContext();
}
else
{
LumiaPhoneInfoModel.ContinueBoot();
}
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)
{
await PhoneNotifier.WaitForArrival();
}
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)
{
throw new WPinternalsException("Unexpected Mode");
}
IsSwitchingInterface = OriginalIsSwitchingInterface;
if (EDEPath == null) if (EDEPath == null)
{ {
@@ -524,7 +628,7 @@ namespace WPinternals
{ {
Key.SetValue("EDEPath", EDEPath); Key.SetValue("EDEPath", EDEPath);
App.Config.AddEmergencyToRepository(Info.Type, EDEPath, null); App.Config.AddEmergencyToRepository(PhoneInfo.Type, EDEPath, null);
} }
} }
@@ -642,7 +746,10 @@ namespace WPinternals
} }
} }
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
try try
{ {
@@ -658,7 +765,10 @@ namespace WPinternals
} }
} }
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
List<FFUEntry> FFUs = App.Config.FFURepository.Where(e => PlatformID.StartsWith(e.PlatformID, StringComparison.OrdinalIgnoreCase) && e.Exists()).ToList(); List<FFUEntry> FFUs = App.Config.FFURepository.Where(e => PlatformID.StartsWith(e.PlatformID, StringComparison.OrdinalIgnoreCase) && e.Exists()).ToList();
if (FFUs.Count > 0) if (FFUs.Count > 0)
@@ -688,7 +798,10 @@ namespace WPinternals
} }
} }
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
try try
{ {
@@ -703,7 +816,10 @@ namespace WPinternals
} }
} }
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
TempEDEPath = LumiaV2UnlockBootViewModel.GetProgrammerPath(RootKeyHash, ProductType); TempEDEPath = LumiaV2UnlockBootViewModel.GetProgrammerPath(RootKeyHash, ProductType);
if (TempEDEPath != null) if (TempEDEPath != null)
@@ -753,7 +869,10 @@ namespace WPinternals
} }
} }
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
try try
{ {
@@ -770,7 +889,10 @@ namespace WPinternals
} }
} }
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
List<FFUEntry> FFUs = App.Config.FFURepository.Where(e => App.PatchEngine.PatchDefinitions.First(p => p.Name == "SecureBootHack-V1.1-EFIESP").TargetVersions.Any(v => v.Description == e.OSVersion)).ToList(); List<FFUEntry> FFUs = App.Config.FFURepository.Where(e => App.PatchEngine.PatchDefinitions.First(p => p.Name == "SecureBootHack-V1.1-EFIESP").TargetVersions.Any(v => v.Description == e.OSVersion)).ToList();
if (FFUs.Count > 0) if (FFUs.Count > 0)
@@ -815,7 +937,10 @@ namespace WPinternals
} }
} }
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
try try
{ {
@@ -832,7 +957,10 @@ namespace WPinternals
} }
} }
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
List<FFUEntry> FFUs = App.Config.FFURepository.Where(e => App.PatchEngine.PatchDefinitions.First(p => p.Name == "SecureBootHack-V2-EFIESP").TargetVersions.Any(v => v.Description == e.OSVersion)).ToList(); List<FFUEntry> FFUs = App.Config.FFURepository.Where(e => App.PatchEngine.PatchDefinitions.First(p => p.Name == "SecureBootHack-V2-EFIESP").TargetVersions.Any(v => v.Description == e.OSVersion)).ToList();
if (FFUs.Count > 0) if (FFUs.Count > 0)
@@ -1025,6 +1153,8 @@ namespace WPinternals
{ {
ValidateSupportedFfuPath(); ValidateSupportedFfuPath();
} }
OkCommand.RaiseCanExecuteChanged();
} }
} }
} }
@@ -34,7 +34,7 @@ namespace WPinternals
// TODO: Add logging // TODO: Add logging
private static void PerformSoftBrick(PhoneNotifierViewModel Notifier, FFU FFU) private static void PerformSoftBrick(PhoneNotifierViewModel Notifier, FFU FFU)
{ {
NokiaFlashModel FlashModel = (NokiaFlashModel)Notifier.CurrentModel; LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)Notifier.CurrentModel;
// Send FFU headers // Send FFU headers
UInt64 CombinedFFUHeaderSize = FFU.HeaderSize; UInt64 CombinedFFUHeaderSize = FFU.HeaderSize;
@@ -82,7 +82,10 @@ namespace WPinternals
Result = true; Result = true;
LogFile.Log("Loader sent successfully"); LogFile.Log("Loader sent successfully");
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
if (Result) if (Result)
{ {
@@ -136,7 +139,7 @@ namespace WPinternals
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
{ {
((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot(); ((LumiaBootManagerAppModel)Notifier.CurrentModel).ContinueBoot();
} }
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal) if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal)
@@ -146,7 +149,7 @@ namespace WPinternals
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
{ {
((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot(); ((LumiaBootManagerAppModel)Notifier.CurrentModel).ContinueBoot();
} }
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal) if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal)
@@ -156,7 +159,7 @@ namespace WPinternals
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
{ {
((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot(); ((LumiaBootManagerAppModel)Notifier.CurrentModel).ContinueBoot();
} }
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal) if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal)
@@ -202,7 +205,7 @@ namespace WPinternals
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
{ {
((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot(); ((LumiaBootManagerAppModel)Notifier.CurrentModel).ContinueBoot();
} }
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal) if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal)
@@ -212,7 +215,7 @@ namespace WPinternals
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
{ {
((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot(); ((LumiaBootManagerAppModel)Notifier.CurrentModel).ContinueBoot();
} }
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal) if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal)
@@ -222,7 +225,7 @@ namespace WPinternals
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
{ {
((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot(); ((LumiaBootManagerAppModel)Notifier.CurrentModel).ContinueBoot();
} }
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal) if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal)
@@ -270,7 +273,7 @@ namespace WPinternals
try try
{ {
if (Notifier.CurrentModel is NokiaFlashModel) if (Notifier.CurrentModel is LumiaFlashAppModel)
{ {
await LumiaRelockUEFI(Notifier, FFUPath, true, SetWorkingStatus, UpdateWorkingStatus, null, (string Message, string SubMessage) => await LumiaRelockUEFI(Notifier, FFUPath, true, SetWorkingStatus, UpdateWorkingStatus, null, (string Message, string SubMessage) =>
{ {
@@ -317,9 +320,9 @@ namespace WPinternals
throw new Exception("Error: Parsing FFU-file failed."); 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) if (FlashVersion == null)
{ {
throw new Exception("Error: The version of the Flash Application on the phone could not be determined."); throw new Exception("Error: The version of the Flash Application on the phone could not be determined.");
@@ -330,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."); 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; IsBootLoaderUnlocked = SecurityStatus.AuthenticationStatus || SecurityStatus.RdcStatus || !SecurityStatus.SecureFfuEfuseStatus;
} }
@@ -347,9 +350,9 @@ namespace WPinternals
#endif #endif
GPT NewGPT = null; 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) if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Bootloader)
{ {
@@ -361,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."); 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); await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
@@ -445,7 +448,7 @@ namespace WPinternals
} }
else if (Notifier.CurrentInterface != PhoneInterfaces.Qualcomm_Flash) 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) if (Notifier.CurrentInterface != PhoneInterfaces.Qualcomm_Flash)
@@ -570,7 +573,7 @@ namespace WPinternals
if (IsBootLoaderUnlocked) if (IsBootLoaderUnlocked)
// Flash phone in Flash app // Flash phone in Flash app
{ {
NokiaFlashModel CurrentModel = (NokiaFlashModel)Notifier.CurrentModel; LumiaFlashAppModel CurrentModel = (LumiaFlashAppModel)Notifier.CurrentModel;
LogFile.Log("Start flashing in Custom Flash mode"); LogFile.Log("Start flashing in Custom Flash mode");
UInt64 TotalSectorCount = (UInt64)0x21 + 1 + UInt64 TotalSectorCount = (UInt64)0x21 + 1 +
@@ -729,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."); 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) 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."); ExitSuccess("Bootloader is restored", "NOTE: You need to flash a stock ROM because you recovered a phone from a bootloader unlock failure.");
@@ -740,7 +743,7 @@ namespace WPinternals
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
{ {
((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot(); ((LumiaBootManagerAppModel)Notifier.CurrentModel).ContinueBoot();
} }
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal) if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal)
@@ -750,7 +753,7 @@ namespace WPinternals
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
{ {
((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot(); ((LumiaBootManagerAppModel)Notifier.CurrentModel).ContinueBoot();
} }
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal) if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal)
@@ -760,7 +763,7 @@ namespace WPinternals
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
{ {
((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot(); ((LumiaBootManagerAppModel)Notifier.CurrentModel).ContinueBoot();
} }
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal) if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal)
@@ -840,9 +843,9 @@ namespace WPinternals
throw new Exception("Error: Parsing FFU-file failed."); 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) if (FlashVersion == null)
{ {
throw new Exception("Error: The version of the Flash Application on the phone could not be determined."); throw new Exception("Error: The version of the Flash Application on the phone could not be determined.");
@@ -853,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."); 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; IsBootLoaderUnlocked = SecurityStatus.AuthenticationStatus || SecurityStatus.RdcStatus || !SecurityStatus.SecureFfuEfuseStatus;
} }
@@ -901,9 +904,9 @@ namespace WPinternals
#endif #endif
GPT NewGPT = null; 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) if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Bootloader)
{ {
@@ -915,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."); 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); await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
@@ -1010,7 +1013,7 @@ namespace WPinternals
} }
else if (Notifier.CurrentInterface != PhoneInterfaces.Qualcomm_Flash) 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) if (Notifier.CurrentInterface != PhoneInterfaces.Qualcomm_Flash)
@@ -1249,7 +1252,7 @@ namespace WPinternals
if (IsBootLoaderUnlocked) if (IsBootLoaderUnlocked)
// Flash phone in Flash app // Flash phone in Flash app
{ {
NokiaFlashModel CurrentModel = (NokiaFlashModel)Notifier.CurrentModel; LumiaFlashAppModel CurrentModel = (LumiaFlashAppModel)Notifier.CurrentModel;
LogFile.Log("Start flashing in Custom Flash mode"); LogFile.Log("Start flashing in Custom Flash mode");
UInt64 TotalSectorCount = (UInt64)0x21 + 1 + UInt64 TotalSectorCount = (UInt64)0x21 + 1 +
@@ -1420,7 +1423,7 @@ namespace WPinternals
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
{ {
((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot(); ((LumiaBootManagerAppModel)Notifier.CurrentModel).ContinueBoot();
} }
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal) if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal)
@@ -1430,7 +1433,7 @@ namespace WPinternals
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
{ {
((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot(); ((LumiaBootManagerAppModel)Notifier.CurrentModel).ContinueBoot();
} }
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal) if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal)
@@ -1440,7 +1443,7 @@ namespace WPinternals
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
{ {
((NokiaFlashModel)Notifier.CurrentModel).ContinueBoot(); ((LumiaBootManagerAppModel)Notifier.CurrentModel).ContinueBoot();
} }
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal) if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Normal)
@@ -1464,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! // Magic!
// UEFI Secure Boot Hack for Spec A and Spec B devices // UEFI Secure Boot Hack for Spec A and Spec B devices
// //
@@ -1544,7 +1499,7 @@ namespace WPinternals
{ {
GPT GPT = null; GPT GPT = null;
Partition Target = null; Partition Target = null;
NokiaFlashModel FlashModel = null; LumiaFlashAppModel FlashModel = null;
LogFile.Log("Command: Relock phone", LogType.FileAndConsole); LogFile.Log("Command: Relock phone", LogType.FileAndConsole);
@@ -1555,13 +1510,18 @@ namespace WPinternals
byte[] EFIESPBackup = null; byte[] EFIESPBackup = null;
PhoneInfo Info = ((NokiaFlashModel)Notifier.CurrentModel).ReadPhoneInfo(); LumiaFlashAppPhoneInfo Info = ((LumiaFlashAppModel)Notifier.CurrentModel).ReadPhoneInfo();
bool IsSpecB = Info.FlashAppProtocolVersionMajor >= 2; bool IsSpecB = Info.FlashAppProtocolVersionMajor >= 2;
bool UndoEFIESPPadding = false; bool UndoEFIESPPadding = false;
byte[] GPTChunk;
if (!IsSpecB) if (!IsSpecB)
{ {
((NokiaFlashModel)Notifier.CurrentModel).ResetPhone(); if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)
{
((LumiaFlashAppModel)Notifier.CurrentModel).ResetPhone();
}
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Bootloader) if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Bootloader)
{ {
@@ -1572,9 +1532,14 @@ 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."); 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.");
} }
GPTChunk = ((LumiaBootManagerAppModel)Notifier.CurrentModel).GetGptChunk(0x20000);
}
else
{
GPTChunk = ((LumiaFlashAppModel)Notifier.CurrentModel).GetGptChunk(0x20000);
} }
byte[] GPTChunk = GetGptChunk((NokiaFlashModel)Notifier.CurrentModel, 0x20000);
GPT = new GPT(GPTChunk); GPT = new GPT(GPTChunk);
bool GPTChanged = false; bool GPTChanged = false;
Partition IsUnlockedPartitionSBL3 = GPT.GetPartition("IS_UNLOCKED_SBL3"); Partition IsUnlockedPartitionSBL3 = GPT.GetPartition("IS_UNLOCKED_SBL3");
@@ -1716,7 +1681,7 @@ namespace WPinternals
SetWorkingStatus("Flashing...", "The phone may reboot a couple of times. Just wait for it.", null, Status: WPinternalsStatus.Initializing); 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(); List<FlashPart> FlashParts = new();
@@ -1727,7 +1692,7 @@ namespace WPinternals
FlashPart Part; FlashPart Part;
FlashModel = (NokiaFlashModel)Notifier.CurrentModel; FlashModel = (LumiaFlashAppModel)Notifier.CurrentModel;
// Remove IS_UNLOCKED flag in GPT // Remove IS_UNLOCKED flag in GPT
Partition IsUnlockedPartition = GPT.GetPartition("IS_UNLOCKED"); Partition IsUnlockedPartition = GPT.GetPartition("IS_UNLOCKED");
@@ -1785,7 +1750,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. // 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; bool NvCleared = false;
Info = ((NokiaFlashModel)Notifier.CurrentModel).ReadPhoneInfo(); Info = ((LumiaFlashAppModel)Notifier.CurrentModel).ReadPhoneInfo();
if ((NvBackupPartition == null) && !Info.UefiSecureBootEnabled) if ((NvBackupPartition == null) && !Info.UefiSecureBootEnabled)
{ {
// ClearNV // ClearNV
@@ -1854,7 +1819,7 @@ namespace WPinternals
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
{ {
((NokiaFlashModel)Notifier.CurrentModel).SwitchToFlashAppContext(); ((LumiaBootManagerAppModel)Notifier.CurrentModel).SwitchToFlashAppContext();
} }
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Flash) if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Flash)
@@ -1883,7 +1848,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) 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"); LogFile.BeginAction("UnlockBootloader");
NokiaFlashModel FlashModel = (NokiaFlashModel)Notifier.CurrentModel; LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)Notifier.CurrentModel;
if (SetWorkingStatus == null) if (SetWorkingStatus == null)
{ {
@@ -1907,7 +1872,7 @@ namespace WPinternals
try try
{ {
PhoneInfo Info = FlashModel.ReadPhoneInfo(); LumiaFlashAppPhoneInfo Info = FlashModel.ReadPhoneInfo();
bool IsSpecB = Info.FlashAppProtocolVersionMajor >= 2; bool IsSpecB = Info.FlashAppProtocolVersionMajor >= 2;
if (ProfileFFUPath == null) if (ProfileFFUPath == null)
@@ -1954,7 +1919,7 @@ namespace WPinternals
LumiaPatchEFIESP(SupportedFFU, UnlockedEFIESP, IsSpecB); LumiaPatchEFIESP(SupportedFFU, UnlockedEFIESP, IsSpecB);
byte[] GPTChunk = GetGptChunk(FlashModel, (UInt32)ProfileFFU.ChunkSize); byte[] GPTChunk = FlashModel.GetGptChunk((UInt32)ProfileFFU.ChunkSize);
byte[] GPTChunkBackup = new byte[GPTChunk.Length]; byte[] GPTChunkBackup = new byte[GPTChunk.Length];
Buffer.BlockCopy(GPTChunk, 0, GPTChunkBackup, 0, GPTChunk.Length); Buffer.BlockCopy(GPTChunk, 0, GPTChunkBackup, 0, GPTChunk.Length);
GPT GPT = new(GPTChunk); GPT GPT = new(GPTChunk);
@@ -2039,8 +2004,8 @@ namespace WPinternals
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
{ {
FlashModel = (NokiaFlashModel)Notifier.CurrentModel; ((LumiaBootManagerAppModel)Notifier.CurrentModel).SwitchToFlashAppContext();
FlashModel.SwitchToFlashAppContext(); FlashModel = ((LumiaFlashAppModel)Notifier.CurrentModel);
} }
GPTChanged = false; GPTChanged = false;
@@ -2205,7 +2170,7 @@ namespace WPinternals
if (!IsSpecB && !SBL3Eng) if (!IsSpecB && !SBL3Eng)
{ {
((NokiaFlashModel)Notifier.CurrentModel).ResetPhone(); ((LumiaFlashAppModel)Notifier.CurrentModel).ResetPhone();
LogFile.Log("Bootloader unlocked!", LogType.FileAndConsole); LogFile.Log("Bootloader unlocked!", LogType.FileAndConsole);
ExitSuccess("Bootloader unlocked successfully!", null); ExitSuccess("Bootloader unlocked successfully!", null);
@@ -2341,7 +2306,7 @@ namespace WPinternals
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Bootloader) 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."); 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; UInt32 OriginalEfiespFirstSector;
if (!ReUnlockDevice) if (!ReUnlockDevice)
@@ -2501,7 +2466,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."); 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); Parts = LumiaGenerateEFIESPFlashPayload(UnlockedEFIESP, GPT, ProfileFFU, IsSpecB);
@@ -2514,7 +2479,7 @@ namespace WPinternals
if (!IsSpecB) if (!IsSpecB)
{ {
((NokiaFlashModel)Notifier.CurrentModel).ResetPhone(); ((LumiaFlashAppModel)Notifier.CurrentModel).ResetPhone();
} }
} }
@@ -2634,7 +2599,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) 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(); LumiaFlashAppPhoneInfo Info = ((LumiaFlashAppModel)Notifier.CurrentModel).ReadPhoneInfo();
bool IsSpecA = Info.FlashAppProtocolVersionMajor < 2; bool IsSpecA = Info.FlashAppProtocolVersionMajor < 2;
if (IsSpecA) if (IsSpecA)
@@ -2651,12 +2616,14 @@ namespace WPinternals
{ {
SetWorkingStatus("Initializing flash...", null, 100, Status: WPinternalsStatus.Initializing); SetWorkingStatus("Initializing flash...", null, 100, Status: WPinternalsStatus.Initializing);
NokiaFlashModel FlashModel = (NokiaFlashModel)Notifier.CurrentModel; LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)Notifier.CurrentModel;
UInt64 InputStreamLength = 0; UInt64 InputStreamLength = 0;
UInt64 totalwritten = 0; UInt64 totalwritten = 0;
int ProgressPercentage = 0; int ProgressPercentage = 0;
if (FlashParts != null)
{
foreach (FlashPart Part in FlashParts) foreach (FlashPart Part in FlashParts)
{ {
InputStreamLength += (ulong)Part.Stream.Length; InputStreamLength += (ulong)Part.Stream.Length;
@@ -2704,6 +2671,7 @@ namespace WPinternals
} }
} }
} }
}
UpdateWorkingStatus(null, null, 100, WPinternalsStatus.Flashing); UpdateWorkingStatus(null, null, 100, WPinternalsStatus.Flashing);
} }
@@ -57,9 +57,9 @@ namespace WPinternals
{ {
LogFile.Log("Find Flashing Profile", LogType.FileAndConsole); 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; LumiaFlashAppPhoneInfo Info;
if (DoResetFirst) if (DoResetFirst)
{ {
// The phone will be reset before flashing, so we have the opportunity to get some more info from the phone // The phone will be reset before flashing, so we have the opportunity to get some more info from the phone
@@ -125,14 +125,14 @@ namespace WPinternals
LogFile.Log("Command: Enable testsigning", LogType.FileAndConsole); LogFile.Log("Command: Enable testsigning", LogType.FileAndConsole);
PhoneNotifierViewModel Notifier = new(); PhoneNotifierViewModel Notifier = new();
UIContext.Send(s => Notifier.Start(), null); 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(); List<FlashPart> Parts = new();
FlashPart Part; FlashPart Part;
// Use GetGptChunk() here instead of ReadGPT(), because ReadGPT() skips the first sector. // 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. // 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); GPT GPT = new(GPTChunk);
bool GPTChanged = false; bool GPTChanged = false;
@@ -228,11 +228,11 @@ namespace WPinternals
return ((MassStorage)Notifier.CurrentModel).Drive; 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) if (DoResetFirst)
{ {
// The phone will be reset before flashing, so we have the opportunity to get some more info from the phone // The phone will be reset before flashing, so we have the opportunity to get some more info from the phone
PhoneInfo Info = FlashModel.ReadPhoneInfo(); LumiaFlashAppPhoneInfo Info = FlashModel.ReadPhoneInfo();
Info.Log(LogType.ConsoleOnly); Info.Log(LogType.ConsoleOnly);
} }
@@ -260,12 +260,12 @@ namespace WPinternals
LogFile.Log("Command: Clear NV", LogType.FileAndConsole); LogFile.Log("Command: Clear NV", LogType.FileAndConsole);
PhoneNotifierViewModel Notifier = new(); PhoneNotifierViewModel Notifier = new();
UIContext.Send(s => Notifier.Start(), null); 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(); List<FlashPart> Parts = new();
// Use GetGptChunk() here instead of ReadGPT(), because ReadGPT() skips the first sector. // 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. // 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); GPT GPT = new(GPTChunk);
bool GPTChanged = false; bool GPTChanged = false;
Partition BACKUP_BS_NV = GPT.GetPartition("BACKUP_BS_NV"); Partition BACKUP_BS_NV = GPT.GetPartition("BACKUP_BS_NV");
@@ -336,13 +336,13 @@ namespace WPinternals
PhoneNotifierViewModel Notifier = new(); PhoneNotifierViewModel Notifier = new();
UIContext.Send(s => Notifier.Start(), null); 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(); LumiaFlashAppPhoneInfo Info = FlashModel.ReadPhoneInfo();
// Use GetGptChunk() here instead of ReadGPT(), because ReadGPT() skips the first sector. // 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. // 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); GPT GPT = new(GPTChunk);
Partition TargetPartition = GPT.GetPartition(PartitionName); Partition TargetPartition = GPT.GetPartition(PartitionName);
@@ -445,9 +445,9 @@ namespace WPinternals
PhoneNotifierViewModel Notifier = new(); PhoneNotifierViewModel Notifier = new();
UIContext.Send(s => Notifier.Start(), null); 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(); LumiaFlashAppPhoneInfo Info = FlashModel.ReadPhoneInfo();
byte[] Data = File.ReadAllBytes(DataPath); byte[] Data = File.ReadAllBytes(DataPath);
@@ -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) 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(); LumiaFlashAppPhoneInfo Info = Model.ReadPhoneInfo();
byte[] GPTChunk = LumiaUnlockBootloaderViewModel.GetGptChunk(Model, 131072u); byte[] GPTChunk = Model.GetGptChunk(131072u);
GPT GPT = new(GPTChunk); GPT GPT = new(GPTChunk);
@@ -554,13 +554,55 @@ namespace WPinternals
ExitFailure = (m, s) => { }; ExitFailure = (m, s) => { };
} }
NokiaFlashModel Model = (NokiaFlashModel)Notifier.CurrentModel; LumiaFlashAppPhoneInfo FlashInfo = ((LumiaFlashAppModel)Notifier.CurrentModel).ReadPhoneInfo();
PhoneInfo Info = Model.ReadPhoneInfo();
string Type = Info.Type; bool ModernFlashApp = ((LumiaFlashAppModel)Notifier.CurrentModel).ReadPhoneInfo().FlashAppProtocolVersionMajor >= 2;
if (ModernFlashApp)
{
((LumiaFlashAppModel)Notifier.CurrentModel).SwitchToPhoneInfoAppContext();
}
else
{
((LumiaFlashAppModel)Notifier.CurrentModel).SwitchToPhoneInfoAppContextLegacy();
}
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_PhoneInfo)
{
await Notifier.WaitForArrival();
}
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_PhoneInfo)
{
throw new WPinternalsException("Unexpected Mode");
}
LumiaPhoneInfoAppModel LumiaPhoneInfoModel = (LumiaPhoneInfoAppModel)Notifier.CurrentModel;
LumiaPhoneInfoAppPhoneInfo PhoneInfo = LumiaPhoneInfoModel.ReadPhoneInfo();
ModernFlashApp = PhoneInfo.PhoneInfoAppVersionMajor >= 2;
if (ModernFlashApp)
{
LumiaPhoneInfoModel.SwitchToFlashAppContext();
}
else
{
LumiaPhoneInfoModel.ContinueBoot();
}
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)
{
await Notifier.WaitForArrival();
}
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)
{
throw new WPinternalsException("Unexpected Mode");
}
string Type = PhoneInfo.Type;
if (ProgrammerPath == null) if (ProgrammerPath == null)
{ {
ProgrammerPath = GetProgrammerPath(Info.RKH, Type); ProgrammerPath = GetProgrammerPath(FlashInfo.RKH, Type);
if (ProgrammerPath == null) if (ProgrammerPath == null)
{ {
LogFile.Log("WARNING: No emergency programmer file found. Finding flash profile and rebooting phone may take a long time!", LogType.FileAndConsole); LogFile.Log("WARNING: No emergency programmer file found. Finding flash profile and rebooting phone may take a long time!", LogType.FileAndConsole);
@@ -571,10 +613,10 @@ namespace WPinternals
if (FFUPath == null) if (FFUPath == null)
{ {
// Try to find an FFU from the repository for which there is also a known flashing profile // Try to find an FFU from the repository for which there is also a known flashing profile
FFUs = App.Config.FFURepository.Where(e => Info.PlatformID.StartsWith(e.PlatformID, StringComparison.OrdinalIgnoreCase) && e.Exists()).ToList(); FFUs = App.Config.FFURepository.Where(e => FlashInfo.PlatformID.StartsWith(e.PlatformID, StringComparison.OrdinalIgnoreCase) && e.Exists()).ToList();
foreach (FFUEntry CurrentEntry in FFUs) foreach (FFUEntry CurrentEntry in FFUs)
{ {
Profile = App.Config.GetProfile(Info.PlatformID, Info.Firmware, CurrentEntry.FirmwareVersion); Profile = App.Config.GetProfile(FlashInfo.PlatformID, FlashInfo.Firmware, CurrentEntry.FirmwareVersion);
if (Profile != null) if (Profile != null)
{ {
FFUPath = CurrentEntry.Path; FFUPath = CurrentEntry.Path;
@@ -630,14 +672,14 @@ namespace WPinternals
} }
} }
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. if ((FlashInfo.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.
{ {
throw new WPinternalsException("Flash failed!", "Protocols not supported. The phone reports that it does not support the Protocol Sync V2."); throw new WPinternalsException("Flash failed!", "Protocols not supported. The phone reports that it does not support the Protocol Sync V2.");
} }
if (Info.FlashAppProtocolVersionMajor < 2) // Old phones do not support the hack. These phones have Flash protocol 1.x. if (FlashInfo.FlashAppProtocolVersionMajor < 2) // Old phones do not support the hack. These phones have Flash protocol 1.x.
{ {
throw new WPinternalsException("Flash failed!", "Protocols not supported. The phone reports that Flash App communication protocol is lower than 2. Reported version by the phone: " + Info.FlashAppProtocolVersionMajor + "."); throw new WPinternalsException("Flash failed!", "Protocols not supported. The phone reports that Flash App communication protocol is lower than 2. Reported version by the phone: " + FlashInfo.FlashAppProtocolVersionMajor + ".");
} }
UEFI UEFI = new(FFU.GetPartition("UEFI")); UEFI UEFI = new(FFU.GetPartition("UEFI"));
@@ -649,7 +691,7 @@ namespace WPinternals
Options = (byte)FlashOptions.SkipWrite; Options = (byte)FlashOptions.SkipWrite;
} }
if (!Info.IsBootloaderSecure) if (!FlashInfo.IsBootloaderSecure)
{ {
Options = (byte)((FlashOptions)Options | FlashOptions.SkipSignatureCheck); Options = (byte)((FlashOptions)Options | FlashOptions.SkipSignatureCheck);
} }
@@ -673,7 +715,7 @@ namespace WPinternals
MaximumAttempts = (int)(((MaximumGapFill / FFU.ChunkSize) + 1) * 8); MaximumAttempts = (int)(((MaximumGapFill / FFU.ChunkSize) + 1) * 8);
} }
byte[] GPTChunk = LumiaUnlockBootloaderViewModel.GetGptChunk(Model, (UInt32)FFU.ChunkSize); byte[] GPTChunk = ((LumiaFlashAppModel)Notifier.CurrentModel).GetGptChunk((UInt32)FFU.ChunkSize);
// Start with a reset // Start with a reset
if (DoResetFirst) if (DoResetFirst)
@@ -682,7 +724,7 @@ namespace WPinternals
// When in flash mode, it is not possible to reboot straight to flash. // When in flash mode, it is not possible to reboot straight to flash.
// Reboot and catch the phone in bootloader mode and then switch to flash context // Reboot and catch the phone in bootloader mode and then switch to flash context
Model.ResetPhone(); ((LumiaFlashAppModel)Notifier.CurrentModel).ResetPhone();
#region Properly recover from reset - many phones respond differently #region Properly recover from reset - many phones respond differently
@@ -818,22 +860,22 @@ 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."); 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); UpdateWorkingStatus("Initializing flash...", null, null);
} }
try if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
{ {
// This will succeed on new models ((LumiaBootManagerAppModel)Notifier.CurrentModel).ResetPhoneToFlashMode();
Model.SwitchToFlashAppContext();
Model.DisableRebootTimeOut();
} }
catch
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)
{ {
// This will succeed on old models
Model.ResetPhoneToFlashMode();
await Notifier.WaitForArrival(); await Notifier.WaitForArrival();
Model = (NokiaFlashModel)Notifier.CurrentModel; }
if (Notifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)
{
throw new WPinternalsException("Unexpected Mode");
} }
// The payloads must be ordered by the number of locations // The payloads must be ordered by the number of locations
@@ -849,7 +891,7 @@ namespace WPinternals
{ {
payloads = payloads =
[ [
.. GetNonOptimizedPayloads(FlashParts, FFU.ChunkSize, (uint)(Info.WriteBufferSize / FFU.ChunkSize), SetWorkingStatus, UpdateWorkingStatus).OrderBy(x => x.TargetLocations.Length), .. GetNonOptimizedPayloads(FlashParts, FFU.ChunkSize, (uint)(FlashInfo.WriteBufferSize / FFU.ChunkSize), SetWorkingStatus, UpdateWorkingStatus).OrderBy(x => x.TargetLocations.Length),
]; ];
} }
@@ -876,7 +918,7 @@ namespace WPinternals
bool Scanning = false; bool Scanning = false;
bool ResetScanning = false; bool ResetScanning = false;
Profile = App.Config.GetProfile(Info.PlatformID, Info.Firmware, FFU.GetFirmwareVersion()); Profile = App.Config.GetProfile(FlashInfo.PlatformID, FlashInfo.Firmware, FFU.GetFirmwareVersion());
if (Profile == null) if (Profile == null)
{ {
LogFile.Log("No flashing profile found", LogType.FileAndConsole); LogFile.Log("No flashing profile found", LogType.FileAndConsole);
@@ -926,17 +968,17 @@ namespace WPinternals
// //
if (AllocateAsyncBuffersOnPhone) if (AllocateAsyncBuffersOnPhone)
{ {
Model.StartAsyncFlash(); ((LumiaFlashAppModel)Notifier.CurrentModel).StartAsyncFlash();
Model.EndAsyncFlash(); // Ending Async flashing is not necessary for Lumia 950, but it is necessary for Lumia 640! ((LumiaFlashAppModel)Notifier.CurrentModel).EndAsyncFlash(); // Ending Async flashing is not necessary for Lumia 950, but it is necessary for Lumia 640!
} }
if (AllocateBackupBuffersOnPhone) if (AllocateBackupBuffersOnPhone)
{ {
Model.BackupPartitionToRam("MODEM_FSG"); ((LumiaFlashAppModel)Notifier.CurrentModel).BackupPartitionToRam("MODEM_FSG");
Model.BackupPartitionToRam("MODEM_FS1"); ((LumiaFlashAppModel)Notifier.CurrentModel).BackupPartitionToRam("MODEM_FS1");
Model.BackupPartitionToRam("MODEM_FS2"); ((LumiaFlashAppModel)Notifier.CurrentModel).BackupPartitionToRam("MODEM_FS2");
Model.BackupPartitionToRam("SSD"); ((LumiaFlashAppModel)Notifier.CurrentModel).BackupPartitionToRam("SSD");
Model.BackupPartitionToRam("DPP"); ((LumiaFlashAppModel)Notifier.CurrentModel).BackupPartitionToRam("DPP");
} }
HeaderOffset = 0; HeaderOffset = 0;
@@ -986,20 +1028,20 @@ namespace WPinternals
// Previous data + new data must fit in new headersize. // Previous data + new data must fit in new headersize.
// We can send an extra byte, because last memory buffer was sent including the tail. // We can send an extra byte, because last memory buffer was sent including the tail.
// And there is always extra space in the memoryspace after the tail. // And there is always extra space in the memoryspace after the tail.
Model.SendFfuHeaderV2(LastHeaderV2Size + 1, 0, new byte[1], Options); ((LumiaFlashAppModel)Notifier.CurrentModel).SendFfuHeaderV2(LastHeaderV2Size + 1, 0, new byte[1], Options);
} }
// CurrentGapFill is the amount of data we want to be allocated on the phone // CurrentGapFill is the amount of data we want to be allocated on the phone
// But we send less data, so the header won't be processed yet. // But we send less data, so the header won't be processed yet.
PartialHeader = new byte[UefiMemorySim.PageSize]; PartialHeader = new byte[UefiMemorySim.PageSize];
Model.SendFfuHeaderV2(CurrentGapFill, 0, PartialHeader, Options); // Fill memory gap -> This will fail on phones with Flash Protocol v1.x !! On Lumia 640 this will hang on receiving the response when EndAsyncFlash was not called. ((LumiaFlashAppModel)Notifier.CurrentModel).SendFfuHeaderV2(CurrentGapFill, 0, PartialHeader, Options); // Fill memory gap -> This will fail on phones with Flash Protocol v1.x !! On Lumia 640 this will hang on receiving the response when EndAsyncFlash was not called.
} }
using (FileStream FfuFile = new(FFU.Path, FileMode.Open, FileAccess.Read)) using (FileStream FfuFile = new(FFU.Path, FileMode.Open, FileAccess.Read))
{ {
// On every flashing phase we need to send the full header again to reset all the counters. // On every flashing phase we need to send the full header again to reset all the counters.
FfuFile.Read(FfuHeader, 0, (int)CombinedFFUHeaderSize); FfuFile.Read(FfuHeader, 0, (int)CombinedFFUHeaderSize);
Model.SendFfuHeaderV1(FfuHeader, Options); ((LumiaFlashAppModel)Notifier.CurrentModel).SendFfuHeaderV1(FfuHeader, Options);
if (PerformFullFlashFirst && (FlashingPhase == 0)) if (PerformFullFlashFirst && (FlashingPhase == 0))
{ {
@@ -1016,11 +1058,11 @@ namespace WPinternals
UInt32 TotalChunkCount = (UInt32)FFU.TotalChunkCount; UInt32 TotalChunkCount = (UInt32)FFU.TotalChunkCount;
// Protocol v2 // Protocol v2
FlashPayload = new byte[Info.WriteBufferSize]; FlashPayload = new byte[FlashInfo.WriteBufferSize];
while (Position < (UInt64)FfuFile.Length) while (Position < (UInt64)FfuFile.Length)
{ {
UInt32 CommonFlashPayloadSize = Info.WriteBufferSize; UInt32 CommonFlashPayloadSize = FlashInfo.WriteBufferSize;
if (((UInt64)FfuFile.Length - Position) < CommonFlashPayloadSize) if (((UInt64)FfuFile.Length - Position) < CommonFlashPayloadSize)
{ {
CommonFlashPayloadSize = (UInt32)((UInt64)FfuFile.Length - Position); CommonFlashPayloadSize = (UInt32)((UInt64)FfuFile.Length - Position);
@@ -1029,7 +1071,7 @@ namespace WPinternals
FfuFile.Read(FlashPayload, 0, (int)CommonFlashPayloadSize); FfuFile.Read(FlashPayload, 0, (int)CommonFlashPayloadSize);
ChunkIndex += (int)(CommonFlashPayloadSize / FFU.ChunkSize); ChunkIndex += (int)(CommonFlashPayloadSize / FFU.ChunkSize);
Model.SendFfuPayloadV2(FlashPayload, ShowProgress ? (int)((double)(ChunkIndex + 1) * 100 / TotalChunkCount) : 0, 0); ((LumiaFlashAppModel)Notifier.CurrentModel).SendFfuPayloadV2(FlashPayload, ShowProgress ? (int)((double)(ChunkIndex + 1) * 100 / TotalChunkCount) : 0, 0);
Position += CommonFlashPayloadSize; Position += CommonFlashPayloadSize;
} }
} }
@@ -1151,7 +1193,7 @@ namespace WPinternals
// This will allocate new memory at the bottom of the memory-pool, but it will not reset the previously imported ffu header. // This will allocate new memory at the bottom of the memory-pool, but it will not reset the previously imported ffu header.
Step = 1; Step = 1;
PartialHeader = new byte[UefiMemorySim.PageSize]; PartialHeader = new byte[UefiMemorySim.PageSize];
Model.SendFfuHeaderV2(ExploitHeaderAllocationSize, 0, PartialHeader, Options); // SkipWrite = 1 (only works on engineering phones) ((LumiaFlashAppModel)Notifier.CurrentModel).SendFfuHeaderV2(ExploitHeaderAllocationSize, 0, PartialHeader, Options); // SkipWrite = 1 (only works on engineering phones)
// Now we will send the rest of the exploit header, but we will increase the total size even higher, so that it still won't start processing the headers. // Now we will send the rest of the exploit header, but we will increase the total size even higher, so that it still won't start processing the headers.
// We've send only a small first part of the header. The allocated header was bigger: ExploitHeaderAllocationSize. // We've send only a small first part of the header. The allocated header was bigger: ExploitHeaderAllocationSize.
@@ -1162,14 +1204,14 @@ namespace WPinternals
while (ExploitHeaderRemaining > 0) while (ExploitHeaderRemaining > 0)
{ {
UInt32 CurrentFill = ExploitHeaderRemaining; UInt32 CurrentFill = ExploitHeaderRemaining;
if (CurrentFill > Info.WriteBufferSize) if (CurrentFill > FlashInfo.WriteBufferSize)
{ {
CurrentFill = Info.WriteBufferSize; CurrentFill = FlashInfo.WriteBufferSize;
} }
PartialHeader = new byte[CurrentFill]; PartialHeader = new byte[CurrentFill];
PartialHeaderAllocation.CopyFromThisAllocation(HeaderOffset, CurrentFill, PartialHeader, 0); PartialHeaderAllocation.CopyFromThisAllocation(HeaderOffset, CurrentFill, PartialHeader, 0);
Model.SendFfuHeaderV2(HeaderOffset + CurrentFill + 1, HeaderOffset, PartialHeader, Options); // Phone may crash here. USB write is done. USB read might fail due to crash. Happens on my own Lumia 650. ((LumiaFlashAppModel)Notifier.CurrentModel).SendFfuHeaderV2(HeaderOffset + CurrentFill + 1, HeaderOffset, PartialHeader, Options); // Phone may crash here. USB write is done. USB read might fail due to crash. Happens on my own Lumia 650.
LastHeaderV2Size = HeaderOffset + CurrentFill + 1; LastHeaderV2Size = HeaderOffset + CurrentFill + 1;
ExploitHeaderRemaining -= CurrentFill; ExploitHeaderRemaining -= CurrentFill;
HeaderOffset += CurrentFill; HeaderOffset += CurrentFill;
@@ -1178,7 +1220,7 @@ namespace WPinternals
// Send custom payload // Send custom payload
Step = 3; Step = 3;
Int32 payloadCount = 0; Int32 payloadCount = 0;
byte[] payloadBuffer = new byte[Info.WriteBufferSize]; byte[] payloadBuffer = new byte[FlashInfo.WriteBufferSize];
bool sendPayload = false; bool sendPayload = false;
for (Int32 i = FlashInProgress ? 0 : -1; i < FlashingPhasePayloadCount; i++) for (Int32 i = FlashInProgress ? 0 : -1; i < FlashingPhasePayloadCount; i++)
{ {
@@ -1192,7 +1234,7 @@ namespace WPinternals
Step = 8; Step = 8;
// This may fail. Normally with WPinternalsException for Invalid Hash or Data not aligned. // This may fail. Normally with WPinternalsException for Invalid Hash or Data not aligned.
// Or it may fail with a BadConnectionException when the phone crashes and drops the connection. // Or it may fail with a BadConnectionException when the phone crashes and drops the connection.
Model.SendFfuPayloadV1(Buffer, 0); ((LumiaFlashAppModel)Notifier.CurrentModel).SendFfuPayloadV1(Buffer, 0);
if (!FlashInProgress) if (!FlashInProgress)
{ {
Step = 9; Step = 9;
@@ -1212,7 +1254,7 @@ namespace WPinternals
FlashingPayload payload = payloads[FlashingPhaseStartPayloadIndex + i]; FlashingPayload payload = payloads[FlashingPhaseStartPayloadIndex + i];
if (payloadCount == ((Info.WriteBufferSize / FFU.ChunkSize) - 1)) if (payloadCount == ((FlashInfo.WriteBufferSize / FFU.ChunkSize) - 1))
{ {
sendPayload = true; sendPayload = true;
} }
@@ -1288,10 +1330,10 @@ namespace WPinternals
if (i != -1 && sendPayload) if (i != -1 && sendPayload)
{ {
// This fails when sending multiple chunks per payload with 0x1003: Hash mismatch // This fails when sending multiple chunks per payload with 0x1003: Hash mismatch
Model.SendFfuPayloadV2(payloadBuffer, ShowProgress ? (Int32)((FlashingPhaseStartPayloadIndex + i + 1) * 100 / payloads.Length) : 0); ((LumiaFlashAppModel)Notifier.CurrentModel).SendFfuPayloadV2(payloadBuffer, ShowProgress ? (Int32)((FlashingPhaseStartPayloadIndex + i + 1) * 100 / payloads.Length) : 0);
sendPayload = false; sendPayload = false;
payloadCount = 0; payloadCount = 0;
payloadBuffer = new byte[Info.WriteBufferSize]; payloadBuffer = new byte[FlashInfo.WriteBufferSize];
} }
DestinationChunkIndex++; DestinationChunkIndex++;
@@ -1304,7 +1346,7 @@ namespace WPinternals
if (!HeadersFull) if (!HeadersFull)
{ {
Step = 12; Step = 12;
App.Config.SetProfile(Info.Type, Info.PlatformID, Info.ProductCode, Info.Firmware, FFU.GetFirmwareVersion(), CurrentGapFill, ExploitHeaderAllocationSize, AssumeImageHeaderFallsInGap, AllocateAsyncBuffersOnPhone); App.Config.SetProfile(PhoneInfo.Type, FlashInfo.PlatformID, PhoneInfo.ProductCode, FlashInfo.Firmware, FFU.GetFirmwareVersion(), CurrentGapFill, ExploitHeaderAllocationSize, AssumeImageHeaderFallsInGap, AllocateAsyncBuffersOnPhone);
if (ShowProgress) if (ShowProgress)
{ {
LogFile.Log("Custom flash succeeded!", LogType.FileAndConsole); LogFile.Log("Custom flash succeeded!", LogType.FileAndConsole);
@@ -1381,7 +1423,7 @@ namespace WPinternals
if (PhoneNeedsReset) if (PhoneNeedsReset)
{ {
Model.ResetPhone(); ((LumiaFlashAppModel)Notifier.CurrentModel).ResetPhone();
WaitForReset = true; WaitForReset = true;
} }
@@ -1516,11 +1558,9 @@ namespace WPinternals
break; break;
} }
Model = (NokiaFlashModel)Notifier.CurrentModel;
// In case we are on an Engineering phone which isn't stuck in flashmode and booted to BootMgrApp // 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.DisableRebootTimeOut(); ((LumiaFlashAppModel)Notifier.CurrentModel).DisableRebootTimeOut();
} }
PhoneNeedsReset = false; PhoneNeedsReset = false;
@@ -1613,38 +1653,38 @@ namespace WPinternals
ByteOperations.WriteUInt32(UefiMemorySim.Buffer, StoreHeaderAllocation.HeadStart + 4, 0); // Set allocation size to 0 in allocationhead ByteOperations.WriteUInt32(UefiMemorySim.Buffer, StoreHeaderAllocation.HeadStart + 4, 0); // Set allocation size to 0 in allocationhead
if (CurrentGapFill > UefiMemorySim.PageSize) if (CurrentGapFill > UefiMemorySim.PageSize)
{ {
Model.SendFfuHeaderV2(LastHeaderV2Size + 1, 0, new byte[1], Options); ((LumiaFlashAppModel)Notifier.CurrentModel).SendFfuHeaderV2(LastHeaderV2Size + 1, 0, new byte[1], Options);
PartialHeader = new byte[UefiMemorySim.PageSize]; PartialHeader = new byte[UefiMemorySim.PageSize];
Model.SendFfuHeaderV2(CurrentGapFill, 0, PartialHeader, Options); // Fill memory gap ((LumiaFlashAppModel)Notifier.CurrentModel).SendFfuHeaderV2(CurrentGapFill, 0, PartialHeader, Options); // Fill memory gap
} }
using (FileStream FfuFile = new(FFU.Path, FileMode.Open, FileAccess.Read)) using (FileStream FfuFile = new(FFU.Path, FileMode.Open, FileAccess.Read))
{ {
// On every flashing phase we need to send the full header again, because this triggers ffu_import_invalidate(), which is necessary to reset all the counters. // On every flashing phase we need to send the full header again, because this triggers ffu_import_invalidate(), which is necessary to reset all the counters.
FfuFile.Read(FfuHeader, 0, (int)CombinedFFUHeaderSize); FfuFile.Read(FfuHeader, 0, (int)CombinedFFUHeaderSize);
Model.SendFfuHeaderV1(FfuHeader, Options); ((LumiaFlashAppModel)Notifier.CurrentModel).SendFfuHeaderV1(FfuHeader, Options);
} }
PartialHeader = new byte[UefiMemorySim.PageSize]; PartialHeader = new byte[UefiMemorySim.PageSize];
Model.SendFfuHeaderV2(ExploitHeaderAllocationSize, 0, PartialHeader, Options); // SkipWrite = 1 (only works on engineering phones) ((LumiaFlashAppModel)Notifier.CurrentModel).SendFfuHeaderV2(ExploitHeaderAllocationSize, 0, PartialHeader, Options); // SkipWrite = 1 (only works on engineering phones)
UInt32 ExploitHeaderRemaining = SecurityHeaderAllocation.TailEnd + 1 - PartialHeaderAllocation.ContentStart - (UInt32)PartialHeader.Length; UInt32 ExploitHeaderRemaining = SecurityHeaderAllocation.TailEnd + 1 - PartialHeaderAllocation.ContentStart - (UInt32)PartialHeader.Length;
HeaderOffset = (UInt32)PartialHeader.Length; HeaderOffset = (UInt32)PartialHeader.Length;
while (ExploitHeaderRemaining > 0) while (ExploitHeaderRemaining > 0)
{ {
UInt32 CurrentFill = ExploitHeaderRemaining; UInt32 CurrentFill = ExploitHeaderRemaining;
if (CurrentFill > Info.WriteBufferSize) if (CurrentFill > FlashInfo.WriteBufferSize)
{ {
CurrentFill = Info.WriteBufferSize; CurrentFill = FlashInfo.WriteBufferSize;
} }
PartialHeader = new byte[CurrentFill]; PartialHeader = new byte[CurrentFill];
PartialHeaderAllocation.CopyFromThisAllocation(HeaderOffset, CurrentFill, PartialHeader, 0); PartialHeaderAllocation.CopyFromThisAllocation(HeaderOffset, CurrentFill, PartialHeader, 0);
Model.SendFfuHeaderV2(HeaderOffset + CurrentFill + 1, HeaderOffset, PartialHeader, Options); ((LumiaFlashAppModel)Notifier.CurrentModel).SendFfuHeaderV2(HeaderOffset + CurrentFill + 1, HeaderOffset, PartialHeader, Options);
LastHeaderV2Size = HeaderOffset + CurrentFill + 1; LastHeaderV2Size = HeaderOffset + CurrentFill + 1;
ExploitHeaderRemaining -= CurrentFill; ExploitHeaderRemaining -= CurrentFill;
HeaderOffset += CurrentFill; HeaderOffset += CurrentFill;
} }
// Do the actual reset, which will result in a crash while cleaning up memory // 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); LogFile.Log("Phone performs hard exit", LogType.FileAndConsole);
@@ -1782,7 +1822,7 @@ namespace WPinternals
else else
{ {
// If we didn't do a hard exit, we need to do a normal reboot // 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) if (Success)
@@ -1964,11 +2004,11 @@ namespace WPinternals
{ {
LogFile.BeginAction("FlashCustomROM"); 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. // 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. // 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); GPT GPT = new(GPTChunk);
Partition Target; Partition Target;
@@ -2049,7 +2089,10 @@ namespace WPinternals
{ {
StreamLengthInSectors = (ulong)DecompressedStream.Length / 0x200; StreamLengthInSectors = (ulong)DecompressedStream.Length / 0x200;
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
TotalSizeSectors += StreamLengthInSectors; TotalSizeSectors += StreamLengthInSectors;
PartitionCount++; PartitionCount++;
@@ -2170,7 +2213,7 @@ namespace WPinternals
GPTChanged = true; GPTChanged = true;
} }
PhoneInfo Info = FlashModel.ReadPhoneInfo(false); LumiaFlashAppPhoneInfo Info = FlashModel.ReadPhoneInfo(false);
// We should only clear NV if there was no backup NV to be restored and the current NV contains the SB unlock. // We should only clear NV if there was no backup NV to be restored and the current NV contains the SB unlock.
if ((NvBackupPartition == null) && !Info.UefiSecureBootEnabled) if ((NvBackupPartition == null) && !Info.UefiSecureBootEnabled)
@@ -2354,11 +2397,11 @@ namespace WPinternals
// Assumes phone is in flash mode // 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) 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. // 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. // 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); GPT GPT = new(GPTChunk);
Partition Target; Partition Target;
@@ -2529,7 +2572,7 @@ namespace WPinternals
GPTChanged = true; GPTChanged = true;
} }
PhoneInfo Info = FlashModel.ReadPhoneInfo(false); LumiaFlashAppPhoneInfo Info = FlashModel.ReadPhoneInfo(false);
// We should only clear NV if there was no backup NV to be restored and the current NV contains the SB unlock. // We should only clear NV if there was no backup NV to be restored and the current NV contains the SB unlock.
if ((NvBackupPartition == null) && !Info.UefiSecureBootEnabled) if ((NvBackupPartition == null) && !Info.UefiSecureBootEnabled)
@@ -192,8 +192,8 @@ namespace WPinternals
try try
{ {
NokiaFlashModel Model = (NokiaFlashModel)Notifier.CurrentModel; LumiaFlashAppModel Model = (LumiaFlashAppModel)Notifier.CurrentModel;
PhoneInfo Info = Model.ReadPhoneInfo(); LumiaFlashAppPhoneInfo 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. 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(); store.WriteDescriptorLength += payload.GetStoreHeaderSize();
} }
byte[] GPTChunk = LumiaUnlockBootloaderViewModel.GetGptChunk(Model, 0x20000); byte[] GPTChunk = Model.GetGptChunk(0x20000);
GPT GPT = new(GPTChunk); GPT GPT = new(GPTChunk);
UInt64 PlatEnd = 0; UInt64 PlatEnd = 0;
if (GPT.Partitions.Any(x => x.Name == "PLAT")) if (GPT.Partitions.Any(x => x.Name == "PLAT"))
+2 -1
View File
@@ -45,7 +45,8 @@ namespace WPinternals
Lumia_Bootloader, Lumia_Bootloader,
Qualcomm_Download, Qualcomm_Download,
Qualcomm_Flash, Qualcomm_Flash,
Lumia_BadMassStorage Lumia_BadMassStorage,
Lumia_PhoneInfo
}; };
// Create this class on the UI thread, after the main-window of the application is initialized. // Create this class on the UI thread, after the main-window of the application is initialized.
@@ -30,7 +30,7 @@ namespace WPinternals
internal class NokiaBootloaderViewModel : ContextViewModel internal class NokiaBootloaderViewModel : ContextViewModel
{ {
private readonly NokiaFlashModel CurrentModel; private readonly LumiaBootManagerAppModel CurrentModel;
private readonly Action<PhoneInterfaces> RequestModeSwitch; private readonly Action<PhoneInterfaces> RequestModeSwitch;
internal Action SwitchToGettingStarted; internal Action SwitchToGettingStarted;
private readonly object LockDeviceInfo = new(); private readonly object LockDeviceInfo = new();
@@ -38,7 +38,7 @@ namespace WPinternals
internal NokiaBootloaderViewModel(NokiaPhoneModel CurrentModel, Action<PhoneInterfaces> RequestModeSwitch, Action SwitchToGettingStarted) internal NokiaBootloaderViewModel(NokiaPhoneModel CurrentModel, Action<PhoneInterfaces> RequestModeSwitch, Action SwitchToGettingStarted)
: base() : base()
{ {
this.CurrentModel = (NokiaFlashModel)CurrentModel; this.CurrentModel = (LumiaBootManagerAppModel)CurrentModel;
this.RequestModeSwitch = RequestModeSwitch; this.RequestModeSwitch = RequestModeSwitch;
this.SwitchToGettingStarted = SwitchToGettingStarted; this.SwitchToGettingStarted = SwitchToGettingStarted;
} }
@@ -63,6 +63,9 @@ namespace WPinternals
case "Normal": case "Normal":
RequestModeSwitch(PhoneInterfaces.Lumia_Normal); RequestModeSwitch(PhoneInterfaces.Lumia_Normal);
break; break;
case "PhoneInfo":
RequestModeSwitch(PhoneInterfaces.Lumia_PhoneInfo);
break;
case "Label": case "Label":
RequestModeSwitch(PhoneInterfaces.Lumia_Label); RequestModeSwitch(PhoneInterfaces.Lumia_Label);
break; break;
+23 -20
View File
@@ -30,7 +30,7 @@ namespace WPinternals
internal class NokiaFlashViewModel : ContextViewModel internal class NokiaFlashViewModel : ContextViewModel
{ {
private readonly NokiaFlashModel CurrentModel; private readonly LumiaFlashAppModel CurrentModel;
private readonly Action<PhoneInterfaces> RequestModeSwitch; private readonly Action<PhoneInterfaces> RequestModeSwitch;
internal Action SwitchToGettingStarted; internal Action SwitchToGettingStarted;
private readonly object LockDeviceInfo = new(); private readonly object LockDeviceInfo = new();
@@ -39,7 +39,7 @@ namespace WPinternals
internal NokiaFlashViewModel(NokiaPhoneModel CurrentModel, Action<PhoneInterfaces> RequestModeSwitch, Action SwitchToGettingStarted) internal NokiaFlashViewModel(NokiaPhoneModel CurrentModel, Action<PhoneInterfaces> RequestModeSwitch, Action SwitchToGettingStarted)
: base() : base()
{ {
this.CurrentModel = (NokiaFlashModel)CurrentModel; this.CurrentModel = (LumiaFlashAppModel)CurrentModel;
this.RequestModeSwitch = RequestModeSwitch; this.RequestModeSwitch = RequestModeSwitch;
this.SwitchToGettingStarted = SwitchToGettingStarted; this.SwitchToGettingStarted = SwitchToGettingStarted;
} }
@@ -95,21 +95,21 @@ namespace WPinternals
SecurityFlags = (UInt32)CurrentModel.ReadSecurityFlags(); SecurityFlags = (UInt32)CurrentModel.ReadSecurityFlags();
LogFile.Log("Security flags: 0x" + SecurityFlags.ToString("X8")); LogFile.Log("Security flags: 0x" + SecurityFlags.ToString("X8"));
FinalConfigDakStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.Dak); FinalConfigDakStatus = CurrentModel.ReadFuseStatus(Fuse.Dak);
FinalConfigFastBootStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.FastBoot); FinalConfigFastBootStatus = CurrentModel.ReadFuseStatus(Fuse.FastBoot);
FinalConfigFfuVerifyStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.FfuVerify); FinalConfigFfuVerifyStatus = CurrentModel.ReadFuseStatus(Fuse.FfuVerify);
FinalConfigJtagStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.Jtag); FinalConfigJtagStatus = CurrentModel.ReadFuseStatus(Fuse.Jtag);
FinalConfigOemIdStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.OemId); FinalConfigOemIdStatus = CurrentModel.ReadFuseStatus(Fuse.OemId);
FinalConfigProductionDoneStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.ProductionDone); FinalConfigProductionDoneStatus = CurrentModel.ReadFuseStatus(Fuse.ProductionDone);
FinalConfigPublicIdStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.PublicId); FinalConfigPublicIdStatus = CurrentModel.ReadFuseStatus(Fuse.PublicId);
FinalConfigRkhStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.Rkh); FinalConfigRkhStatus = CurrentModel.ReadFuseStatus(Fuse.Rkh);
FinalConfigRpmWdogStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.RpmWdog); FinalConfigRpmWdogStatus = CurrentModel.ReadFuseStatus(Fuse.RpmWdog);
FinalConfigSecGenStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.SecGen); FinalConfigSecGenStatus = CurrentModel.ReadFuseStatus(Fuse.SecGen);
FinalConfigSecureBootStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.SecureBoot); FinalConfigSecureBootStatus = CurrentModel.ReadFuseStatus(Fuse.SecureBoot);
FinalConfigShkStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.Shk); FinalConfigShkStatus = CurrentModel.ReadFuseStatus(Fuse.Shk);
FinalConfigSimlockStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.Simlock); FinalConfigSimlockStatus = CurrentModel.ReadFuseStatus(Fuse.Simlock);
FinalConfigSpdmSecModeStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.SpdmSecMode); FinalConfigSpdmSecModeStatus = CurrentModel.ReadFuseStatus(Fuse.SpdmSecMode);
FinalConfigSsmStatus = CurrentModel.ReadFuseStatus(NokiaFlashModel.Fuse.Ssm); FinalConfigSsmStatus = CurrentModel.ReadFuseStatus(Fuse.Ssm);
} }
else else
{ {
@@ -222,15 +222,15 @@ namespace WPinternals
LogFile.Log("Charging status: " + ChargingStatus); LogFile.Log("Charging status: " + ChargingStatus);
} }
PhoneInfo Info = CurrentModel.ReadPhoneInfo(true); LumiaFlashAppPhoneInfo Info = CurrentModel.ReadPhoneInfo(true);
BootloaderDescription = Info.FlashAppProtocolVersionMajor < 2 ? "Lumia Bootloader Spec A" : "Lumia Bootloader Spec B"; BootloaderDescription = Info.FlashAppProtocolVersionMajor < 2 ? "Lumia Bootloader Spec A" : "Lumia Bootloader Spec B";
LogFile.Log("Bootloader: " + BootloaderDescription); LogFile.Log("Bootloader: " + BootloaderDescription);
ProductCode = Info.ProductCode; ProductCode = "";//TODO: FIXME: Info.ProductCode;
LogFile.Log("ProductCode: " + ProductCode); LogFile.Log("ProductCode: " + ProductCode);
ProductType = Info.Type; ProductType = "";//TODO: FIXME: Info.Type;
LogFile.Log("ProductType: " + ProductType); LogFile.Log("ProductType: " + ProductType);
if (RootKeyHash == null) if (RootKeyHash == null)
@@ -748,6 +748,9 @@ namespace WPinternals
case "Normal": case "Normal":
RequestModeSwitch(PhoneInterfaces.Lumia_Normal); RequestModeSwitch(PhoneInterfaces.Lumia_Normal);
break; break;
case "PhoneInfo":
RequestModeSwitch(PhoneInterfaces.Lumia_PhoneInfo);
break;
case "Label": case "Label":
RequestModeSwitch(PhoneInterfaces.Lumia_Label); RequestModeSwitch(PhoneInterfaces.Lumia_Label);
break; break;
+16 -4
View File
@@ -101,11 +101,20 @@ namespace WPinternals
IMEI = CurrentModel.ExecuteJsonMethodAsString("ReadSerialNumber", "SerialNumber"); // IMEI IMEI = CurrentModel.ExecuteJsonMethodAsString("ReadSerialNumber", "SerialNumber"); // IMEI
LogFile.Log("IMEI: " + IMEI); LogFile.Log("IMEI: " + IMEI);
BluetoothMac = CurrentModel.ExecuteJsonMethodAsBytes("ReadBtId", "BtId"); // 6 bytes: bc c6 ... BluetoothMac = CurrentModel.ExecuteJsonMethodAsBytes("ReadBtId", "BtId"); // 6 bytes: bc c6 ...
LogFile.Log("Bluetooth MAC: " + Converter.ConvertHexToString(BluetoothMac, " "));
WlanMac = CurrentModel.ExecuteJsonMethodAsBytes("ReadWlanMacAddress", "WlanMacAddress1"); // 6 bytes
LogFile.Log("WLAN MAC: " + Converter.ConvertHexToString(WlanMac, " "));
IsBootloaderSecurityEnabled = (bool)CurrentModel.ExecuteJsonMethodAsBoolean("ReadProductionDoneState", "ProductionDone"); if (BluetoothMac != null)
{
LogFile.Log("Bluetooth MAC: " + Converter.ConvertHexToString(BluetoothMac, " "));
}
WlanMac = CurrentModel.ExecuteJsonMethodAsBytes("ReadWlanMacAddress", "WlanMacAddress1"); // 6 bytes
if (WlanMac != null)
{
LogFile.Log("WLAN MAC: " + Converter.ConvertHexToString(WlanMac, " "));
}
IsBootloaderSecurityEnabled = CurrentModel.ExecuteJsonMethodAsBoolean("ReadProductionDoneState", "ProductionDone") ?? false;
LogFile.Log("Bootloader Security: " + ((bool)IsBootloaderSecurityEnabled ? "Enabled" : "Disabled")); LogFile.Log("Bootloader Security: " + ((bool)IsBootloaderSecurityEnabled ? "Enabled" : "Disabled"));
Params = new Dictionary<string, object> Params = new Dictionary<string, object>
@@ -283,6 +292,9 @@ namespace WPinternals
case "Flash": case "Flash":
RequestModeSwitch(PhoneInterfaces.Lumia_Flash); RequestModeSwitch(PhoneInterfaces.Lumia_Flash);
break; break;
case "PhoneInfo":
RequestModeSwitch(PhoneInterfaces.Lumia_PhoneInfo);
break;
case "Label": case "Label":
RequestModeSwitch(PhoneInterfaces.Lumia_Label); RequestModeSwitch(PhoneInterfaces.Lumia_Label);
break; break;
@@ -25,7 +25,7 @@ namespace WPinternals
{ {
internal class NokiaModeBootloaderViewModel : ContextViewModel internal class NokiaModeBootloaderViewModel : ContextViewModel
{ {
private readonly NokiaFlashModel CurrentModel; private readonly LumiaBootManagerAppModel CurrentModel;
private readonly Action<PhoneInterfaces?> RequestModeSwitch; private readonly Action<PhoneInterfaces?> RequestModeSwitch;
private readonly object LockDeviceInfo = new(); private readonly object LockDeviceInfo = new();
private bool DeviceInfoLoaded = false; private bool DeviceInfoLoaded = false;
@@ -33,7 +33,7 @@ namespace WPinternals
internal NokiaModeBootloaderViewModel(NokiaPhoneModel CurrentModel, Action<PhoneInterfaces?> RequestModeSwitch) internal NokiaModeBootloaderViewModel(NokiaPhoneModel CurrentModel, Action<PhoneInterfaces?> RequestModeSwitch)
: base() : base()
{ {
this.CurrentModel = (NokiaFlashModel)CurrentModel; this.CurrentModel = (LumiaBootManagerAppModel)CurrentModel;
this.RequestModeSwitch = RequestModeSwitch; this.RequestModeSwitch = RequestModeSwitch;
} }
@@ -67,21 +67,9 @@ namespace WPinternals
{ {
try try
{ {
PhoneInfo Info = CurrentModel.ReadPhoneInfo(); LumiaBootManagerPhoneInfo Info = CurrentModel.ReadPhoneInfo();
if (Info.FlashAppProtocolVersionMajor < 2) //EffectiveBootloaderSecurityStatus = Info.UefiSecureBootEnabled; // FIXME
{
UefiSecurityStatusResponse SecurityStatus = CurrentModel.ReadSecurityStatus();
if (SecurityStatus != null)
{
EffectiveBootloaderSecurityStatus = SecurityStatus.SecureFfuEfuseStatus && !SecurityStatus.AuthenticationStatus && !SecurityStatus.RdcStatus;
}
}
else
{
EffectiveBootloaderSecurityStatus = Info.UefiSecureBootEnabled;
}
LogFile.Log("Effective Bootloader Security Status: " + EffectiveBootloaderSecurityStatus.ToString()); LogFile.Log("Effective Bootloader Security Status: " + EffectiveBootloaderSecurityStatus.ToString());
} }
@@ -101,6 +89,9 @@ namespace WPinternals
case "Normal": case "Normal":
RequestModeSwitch(PhoneInterfaces.Lumia_Normal); RequestModeSwitch(PhoneInterfaces.Lumia_Normal);
break; break;
case "PhoneInfo":
RequestModeSwitch(PhoneInterfaces.Lumia_PhoneInfo);
break;
case "Flash": case "Flash":
RequestModeSwitch(PhoneInterfaces.Lumia_Flash); RequestModeSwitch(PhoneInterfaces.Lumia_Flash);
break; break;
@@ -25,7 +25,7 @@ namespace WPinternals
{ {
internal class NokiaModeFlashViewModel : ContextViewModel internal class NokiaModeFlashViewModel : ContextViewModel
{ {
private readonly NokiaFlashModel CurrentModel; private readonly LumiaFlashAppModel CurrentModel;
private readonly Action<PhoneInterfaces?> RequestModeSwitch; private readonly Action<PhoneInterfaces?> RequestModeSwitch;
private readonly object LockDeviceInfo = new(); private readonly object LockDeviceInfo = new();
private bool DeviceInfoLoaded = false; private bool DeviceInfoLoaded = false;
@@ -33,7 +33,7 @@ namespace WPinternals
internal NokiaModeFlashViewModel(NokiaPhoneModel CurrentModel, Action<PhoneInterfaces?> RequestModeSwitch) internal NokiaModeFlashViewModel(NokiaPhoneModel CurrentModel, Action<PhoneInterfaces?> RequestModeSwitch)
: base() : base()
{ {
this.CurrentModel = (NokiaFlashModel)CurrentModel; this.CurrentModel = (LumiaFlashAppModel)CurrentModel;
this.RequestModeSwitch = RequestModeSwitch; this.RequestModeSwitch = RequestModeSwitch;
} }
@@ -67,7 +67,7 @@ namespace WPinternals
{ {
try try
{ {
PhoneInfo Info = CurrentModel.ReadPhoneInfo(); LumiaFlashAppPhoneInfo Info = CurrentModel.ReadPhoneInfo();
if (Info.FlashAppProtocolVersionMajor < 2) if (Info.FlashAppProtocolVersionMajor < 2)
{ {
@@ -103,6 +103,12 @@ namespace WPinternals
case "Flash": case "Flash":
RequestModeSwitch(PhoneInterfaces.Lumia_Flash); RequestModeSwitch(PhoneInterfaces.Lumia_Flash);
break; break;
case "PhoneInfo":
RequestModeSwitch(PhoneInterfaces.Lumia_PhoneInfo);
break;
case "BootMgr":
RequestModeSwitch(PhoneInterfaces.Lumia_Bootloader);
break;
case "Label": case "Label":
RequestModeSwitch(PhoneInterfaces.Lumia_Label); RequestModeSwitch(PhoneInterfaces.Lumia_Label);
break; break;
@@ -41,6 +41,12 @@ namespace WPinternals
case "Normal": case "Normal":
RequestModeSwitch(PhoneInterfaces.Lumia_Normal); RequestModeSwitch(PhoneInterfaces.Lumia_Normal);
break; break;
case "PhoneInfo":
RequestModeSwitch(PhoneInterfaces.Lumia_PhoneInfo);
break;
case "BootMgr":
RequestModeSwitch(PhoneInterfaces.Lumia_Bootloader);
break;
case "Flash": case "Flash":
RequestModeSwitch(PhoneInterfaces.Lumia_Flash); RequestModeSwitch(PhoneInterfaces.Lumia_Flash);
break; break;
@@ -63,6 +63,12 @@ namespace WPinternals
case "Normal": case "Normal":
RequestModeSwitch(PhoneInterfaces.Lumia_Normal); RequestModeSwitch(PhoneInterfaces.Lumia_Normal);
break; break;
case "PhoneInfo":
RequestModeSwitch(PhoneInterfaces.Lumia_PhoneInfo);
break;
case "BootMgr":
RequestModeSwitch(PhoneInterfaces.Lumia_Bootloader);
break;
case "Label": case "Label":
RequestModeSwitch(PhoneInterfaces.Lumia_Label); RequestModeSwitch(PhoneInterfaces.Lumia_Label);
break; break;
@@ -41,6 +41,12 @@ namespace WPinternals
case "Flash": case "Flash":
RequestModeSwitch(PhoneInterfaces.Lumia_Flash); RequestModeSwitch(PhoneInterfaces.Lumia_Flash);
break; break;
case "PhoneInfo":
RequestModeSwitch(PhoneInterfaces.Lumia_PhoneInfo);
break;
case "BootMgr":
RequestModeSwitch(PhoneInterfaces.Lumia_Bootloader);
break;
case "Label": case "Label":
RequestModeSwitch(PhoneInterfaces.Lumia_Label); RequestModeSwitch(PhoneInterfaces.Lumia_Label);
break; break;
@@ -0,0 +1,112 @@
// 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.Threading;
namespace WPinternals
{
internal class NokiaModePhoneInfoViewModel : ContextViewModel
{
private readonly LumiaPhoneInfoAppModel CurrentModel;
private readonly Action<PhoneInterfaces?> RequestModeSwitch;
private readonly object LockDeviceInfo = new();
private bool DeviceInfoLoaded = false;
internal NokiaModePhoneInfoViewModel(NokiaPhoneModel CurrentModel, Action<PhoneInterfaces?> RequestModeSwitch)
: base()
{
this.CurrentModel = (LumiaPhoneInfoAppModel)CurrentModel;
this.RequestModeSwitch = RequestModeSwitch;
}
internal override void EvaluateViewState()
{
if (IsActive)
{
new Thread(() => StartLoadDeviceInfo()).Start();
}
}
private bool? _EffectivePhoneInfoSecurityStatus = null;
public bool? EffectivePhoneInfoSecurityStatus
{
get
{
return _EffectivePhoneInfoSecurityStatus;
}
set
{
_EffectivePhoneInfoSecurityStatus = value;
OnPropertyChanged(nameof(EffectivePhoneInfoSecurityStatus));
}
}
internal void StartLoadDeviceInfo()
{
lock (LockDeviceInfo)
{
if (!DeviceInfoLoaded)
{
try
{
LumiaPhoneInfoAppPhoneInfo Info = CurrentModel.ReadPhoneInfo();
//EffectivePhoneInfoSecurityStatus = Info.UefiSecureBootEnabled; // FIXME
LogFile.Log("Effective Bootloader Security Status: " + EffectivePhoneInfoSecurityStatus.ToString());
}
catch
{
LogFile.Log("Reading status from Flash interface was aborted.");
}
DeviceInfoLoaded = true;
}
}
}
internal void RebootTo(string Mode)
{
switch (Mode)
{
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;
case "MassStorage":
RequestModeSwitch(PhoneInterfaces.Lumia_MassStorage);
break;
case "Shutdown":
RequestModeSwitch(null);
break;
default:
return;
}
}
}
}
+28 -1
View File
@@ -67,17 +67,35 @@ namespace WPinternals
LogFile.Log("IMEI: " + IMEI); LogFile.Log("IMEI: " + IMEI);
PublicID = CurrentModel.ExecuteJsonMethodAsBytes("ReadPublicId", "PublicId"); // 0x14 bytes: a5 e5 ... PublicID = CurrentModel.ExecuteJsonMethodAsBytes("ReadPublicId", "PublicId"); // 0x14 bytes: a5 e5 ...
if (PublicID != null)
{
LogFile.Log("Public ID: " + Converter.ConvertHexToString(PublicID, " ")); LogFile.Log("Public ID: " + Converter.ConvertHexToString(PublicID, " "));
}
BluetoothMac = CurrentModel.ExecuteJsonMethodAsBytes("ReadBtId", "BtId"); // 6 bytes: bc c6 ... BluetoothMac = CurrentModel.ExecuteJsonMethodAsBytes("ReadBtId", "BtId"); // 6 bytes: bc c6 ...
if (BluetoothMac != null)
{
LogFile.Log("Bluetooth MAC: " + Converter.ConvertHexToString(BluetoothMac, " ")); LogFile.Log("Bluetooth MAC: " + Converter.ConvertHexToString(BluetoothMac, " "));
}
WlanMac1 = CurrentModel.ExecuteJsonMethodAsBytes("ReadWlanMacAddress", "WlanMacAddress1"); // 6 bytes WlanMac1 = CurrentModel.ExecuteJsonMethodAsBytes("ReadWlanMacAddress", "WlanMacAddress1"); // 6 bytes
if (WlanMac1 != null)
{
LogFile.Log("WLAN MAC 1: " + Converter.ConvertHexToString(WlanMac1, " ")); LogFile.Log("WLAN MAC 1: " + Converter.ConvertHexToString(WlanMac1, " "));
}
WlanMac2 = CurrentModel.ExecuteJsonMethodAsBytes("ReadWlanMacAddress", "WlanMacAddress2"); // 6 bytes WlanMac2 = CurrentModel.ExecuteJsonMethodAsBytes("ReadWlanMacAddress", "WlanMacAddress2"); // 6 bytes
if (WlanMac2 != null)
{
LogFile.Log("WLAN MAC 2: " + Converter.ConvertHexToString(WlanMac2, " ")); LogFile.Log("WLAN MAC 2: " + Converter.ConvertHexToString(WlanMac2, " "));
}
WlanMac3 = CurrentModel.ExecuteJsonMethodAsBytes("ReadWlanMacAddress", "WlanMacAddress3"); // 6 bytes WlanMac3 = CurrentModel.ExecuteJsonMethodAsBytes("ReadWlanMacAddress", "WlanMacAddress3"); // 6 bytes
if (WlanMac3 != null)
{
LogFile.Log("WLAN MAC 3: " + Converter.ConvertHexToString(WlanMac3, " ")); LogFile.Log("WLAN MAC 3: " + Converter.ConvertHexToString(WlanMac3, " "));
}
WlanMac4 = CurrentModel.ExecuteJsonMethodAsBytes("ReadWlanMacAddress", "WlanMacAddress4"); // 6 bytes WlanMac4 = CurrentModel.ExecuteJsonMethodAsBytes("ReadWlanMacAddress", "WlanMacAddress4"); // 6 bytes
if (WlanMac4 != null)
{
LogFile.Log("WLAN MAC 4: " + Converter.ConvertHexToString(WlanMac4, " ")); LogFile.Log("WLAN MAC 4: " + Converter.ConvertHexToString(WlanMac4, " "));
}
bool? ProductionDone = CurrentModel.ExecuteJsonMethodAsBoolean("ReadProductionDoneState", "ProductionDone"); bool? ProductionDone = CurrentModel.ExecuteJsonMethodAsBoolean("ReadProductionDoneState", "ProductionDone");
IsBootloaderSecurityEnabled = ProductionDone == null IsBootloaderSecurityEnabled = ProductionDone == null
@@ -105,7 +123,10 @@ namespace WPinternals
this.Pk = Pk; this.Pk = Pk;
LogFile.Log("PK: " + Pk); LogFile.Log("PK: " + Pk);
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
} }
private string _ProductCode = null; private string _ProductCode = null;
@@ -381,6 +402,12 @@ namespace WPinternals
case "Flash": case "Flash":
RequestModeSwitch(PhoneInterfaces.Lumia_Flash); RequestModeSwitch(PhoneInterfaces.Lumia_Flash);
break; break;
case "PhoneInfo":
RequestModeSwitch(PhoneInterfaces.Lumia_PhoneInfo);
break;
case "BootMgr":
RequestModeSwitch(PhoneInterfaces.Lumia_Bootloader);
break;
case "Label": case "Label":
RequestModeSwitch(PhoneInterfaces.Lumia_Label); RequestModeSwitch(PhoneInterfaces.Lumia_Label);
break; break;
@@ -0,0 +1,212 @@
// 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.Collections.Generic;
using System.Linq;
using System.Threading;
namespace WPinternals
{
// Create this class on the UI thread, after the main-window of the application is initialized.
// It is necessary to create the object on the UI thread, because notification events to the View need to be fired on that thread.
// The Model for this ViewModel communicates over USB and for that it uses the hWnd of the main window.
// Therefore the main window must be created before the ViewModel is created.
internal class NokiaPhoneInfoViewModel : ContextViewModel
{
private readonly LumiaPhoneInfoAppModel CurrentModel;
private readonly Action<PhoneInterfaces> RequestModeSwitch;
internal Action SwitchToGettingStarted;
private readonly object LockDeviceInfo = new();
private bool DeviceInfoLoaded = false;
internal NokiaPhoneInfoViewModel(NokiaPhoneModel CurrentModel, Action<PhoneInterfaces> RequestModeSwitch, Action SwitchToGettingStarted)
: base()
{
this.CurrentModel = (LumiaPhoneInfoAppModel)CurrentModel;
this.RequestModeSwitch = RequestModeSwitch;
this.SwitchToGettingStarted = SwitchToGettingStarted;
}
// Device info should be loaded only one time and only when the ViewModel is active
internal override void EvaluateViewState()
{
if (IsActive)
{
new Thread(() => StartLoadDeviceInfo()).Start();
}
}
private void StartLoadDeviceInfo()
{
lock (LockDeviceInfo)
{
if (!DeviceInfoLoaded)
{
try
{
/*
* Version: 1.1.1.3
* TYPE: RM-885
* BTR: 059R0M0
* LPSN: ...
* HWID: 1000
* CTR: 059S4B1
* MC: 0205354
* IMEI: ...
*/
string PhoneInfoData = CurrentModel.GetPhoneInfo();
if (!string.IsNullOrEmpty(PhoneInfoData))
{
string[] Variables = PhoneInfoData.Split("\n");
Dictionary<string, string> FormattedVariables = [];
foreach (string Variable in Variables)
{
if (!Variable.Contains(":"))
{
continue;
}
FormattedVariables.Add(Variable.Split(":")[0].Trim(), Variable.Split(":")[1].Trim());
}
HWID = FormattedVariables["HWID"];
LogFile.Log("HWID: " + HWID);
}
LumiaPhoneInfoAppPhoneInfo Info = CurrentModel.ReadPhoneInfo(true);
BootloaderDescription = Info.PhoneInfoAppVersionMajor < 2 ? "Lumia Bootloader Spec A" : "Lumia Bootloader Spec B";
LogFile.Log("Bootloader: " + BootloaderDescription);
ProductCode = Info.ProductCode;
LogFile.Log("ProductCode: " + ProductCode);
ProductType = Info.Type;
LogFile.Log("ProductType: " + ProductType);
IMEI = Info.Imei;
LogFile.Log("IMEI: " + ProductType);
}
catch
{
LogFile.Log("Reading status from Flash interface was aborted.");
}
DeviceInfoLoaded = true;
}
}
}
private string _ProductType = null;
public string ProductType
{
get
{
return _ProductType;
}
set
{
_ProductType = value;
OnPropertyChanged(nameof(ProductType));
}
}
private string _ProductCode = null;
public string ProductCode
{
get
{
return _ProductCode;
}
set
{
_ProductCode = value;
OnPropertyChanged(nameof(ProductCode));
}
}
private string _BootloaderDescription = null;
public string BootloaderDescription
{
get
{
return _BootloaderDescription;
}
set
{
_BootloaderDescription = value;
OnPropertyChanged(nameof(BootloaderDescription));
}
}
private string _HWID = null;
public string HWID
{
get
{
return _HWID;
}
set
{
_HWID = value;
OnPropertyChanged(nameof(HWID));
}
}
private string _IMEI = null;
public string IMEI
{
get
{
return _IMEI;
}
set
{
_IMEI = value;
OnPropertyChanged(nameof(IMEI));
}
}
internal void RebootTo(string Mode)
{
switch (Mode)
{
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;
case "MassStorage":
RequestModeSwitch(PhoneInterfaces.Lumia_MassStorage);
break;
default:
return;
}
}
}
}
@@ -115,7 +115,10 @@ namespace WPinternals
LogWatcher.Enabled = true; LogWatcher.Enabled = true;
App.IsPnPEventLogMissing = false; App.IsPnPEventLogMissing = false;
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
} }
private void PnPEventWritten(Object obj, EventRecordWrittenEventArgs arg) private void PnPEventWritten(Object obj, EventRecordWrittenEventArgs arg)
@@ -234,13 +237,12 @@ namespace WPinternals
e.DevicePath.Contains("&PID_0A02", StringComparison.OrdinalIgnoreCase) || // VID_045E&PID_0A02 is for Lumia 950 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 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; FlashAppType type = FlashAppType.FlashApp;
try 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); LogFile.Log("Flash App Type: " + type.ToString(), LogType.FileOnly);
} }
catch catch
@@ -252,6 +254,9 @@ namespace WPinternals
{ {
case FlashAppType.BootManager: case FlashAppType.BootManager:
{ {
CurrentModel = new LumiaBootManagerAppModel(e.DevicePath);
((NokiaFlashModel)CurrentModel).InterfaceChanged += InterfaceChanged;
CurrentInterface = PhoneInterfaces.Lumia_Bootloader; CurrentInterface = PhoneInterfaces.Lumia_Bootloader;
LogFile.Log("Found device on interface: " + ((USBNotifier)sender).Guid.ToString(), LogType.FileOnly); LogFile.Log("Found device on interface: " + ((USBNotifier)sender).Guid.ToString(), LogType.FileOnly);
LogFile.Log("Device path: " + e.DevicePath, LogType.FileOnly); LogFile.Log("Device path: " + e.DevicePath, LogType.FileOnly);
@@ -262,6 +267,9 @@ namespace WPinternals
} }
case FlashAppType.FlashApp: case FlashAppType.FlashApp:
{ {
CurrentModel = new LumiaFlashAppModel(e.DevicePath);
((NokiaFlashModel)CurrentModel).InterfaceChanged += InterfaceChanged;
((NokiaFlashModel)CurrentModel).DisableRebootTimeOut(); ((NokiaFlashModel)CurrentModel).DisableRebootTimeOut();
CurrentInterface = PhoneInterfaces.Lumia_Flash; CurrentInterface = PhoneInterfaces.Lumia_Flash;
LogFile.Log("Found device on interface: " + ((USBNotifier)sender).Guid.ToString(), LogType.FileOnly); LogFile.Log("Found device on interface: " + ((USBNotifier)sender).Guid.ToString(), LogType.FileOnly);
@@ -273,7 +281,11 @@ namespace WPinternals
} }
case FlashAppType.PhoneInfoApp: case FlashAppType.PhoneInfoApp:
{ {
CurrentInterface = PhoneInterfaces.Lumia_Bootloader; 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); LogFile.Log("Found device on interface: " + ((USBNotifier)sender).Guid.ToString(), LogType.FileOnly);
LogFile.Log("Device path: " + e.DevicePath, LogType.FileOnly); LogFile.Log("Device path: " + e.DevicePath, LogType.FileOnly);
LogFile.Log("Connected device: Lumia", LogType.FileAndConsole); LogFile.Log("Connected device: Lumia", LogType.FileAndConsole);
@@ -411,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) private void LumiaNotifier_Removal(object sender, USBEvent e)
+1 -1
View File
@@ -113,7 +113,7 @@ namespace WPinternals
Result = false; Result = false;
} }
NokiaFlashModel Phone = (NokiaFlashModel)PhoneNotifier.CurrentModel; LumiaFlashAppModel Phone = (LumiaFlashAppModel)PhoneNotifier.CurrentModel;
BusyViewModel Busy = new("Restoring...", MaxProgressValue: TotalSizeSectors, UIContext: UIContext); BusyViewModel Busy = new("Restoring...", MaxProgressValue: TotalSizeSectors, UIContext: UIContext);
ProgressUpdater Updater = Busy.ProgressUpdater; ProgressUpdater Updater = Busy.ProgressUpdater;
+625 -74
View File
@@ -21,6 +21,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Security.Policy;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -82,7 +83,7 @@ namespace WPinternals
{ {
if ((PhoneNotifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) && (TargetMode == PhoneInterfaces.Lumia_Flash)) if ((PhoneNotifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) && (TargetMode == PhoneInterfaces.Lumia_Flash))
{ {
PhoneInfo Info = ((NokiaFlashModel)PhoneNotifier.CurrentModel).ReadPhoneInfo(false); LumiaBootManagerPhoneInfo Info = ((LumiaBootManagerAppModel)PhoneNotifier.CurrentModel).ReadPhoneInfo(false);
if (Info.BootManagerProtocolVersionMajor >= 2) if (Info.BootManagerProtocolVersionMajor >= 2)
{ {
try try
@@ -95,13 +96,16 @@ namespace WPinternals
// It does not disconnect / reconnect anymore and the apptype is changed immediately // It does not disconnect / reconnect anymore and the apptype is changed immediately
// NOKS still doesnt return a status // NOKS still doesnt return a status
// BootMgr v1 uses normal NOKS and waits for arrival of FlashApp // 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. // But this was called as a real switch, so we will raise an arrival event.
PhoneNotifier.CurrentInterface = PhoneInterfaces.Lumia_Flash; PhoneNotifier.CurrentInterface = PhoneInterfaces.Lumia_Flash;
PhoneNotifier.NotifyArrival(); PhoneNotifier.NotifyArrival();
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
} }
} }
@@ -230,6 +234,12 @@ namespace WPinternals
{ {
IsSwitching = true; 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 // Make switch and set message or navigate to error
switch (CurrentMode) switch (CurrentMode)
{ {
@@ -284,7 +294,7 @@ namespace WPinternals
Params.Add("ResetMethod", "HwReset"); Params.Add("ResetMethod", "HwReset");
try try
{ {
((NokiaPhoneModel)CurrentModel).ExecuteJsonMethodAsync("SetDeviceMode", Params); ((NokiaPhoneModel)PhoneNotifier.CurrentModel).ExecuteJsonMethodAsync("SetDeviceMode", Params);
PhoneNotifier.NewDeviceArrived += NewDeviceArrived; PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
} }
catch (Exception Ex) catch (Exception Ex)
@@ -295,15 +305,11 @@ namespace WPinternals
} }
break; break;
case PhoneInterfaces.Lumia_Flash: 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; IsSwitchingInterface = true;
switch (TargetMode) switch (TargetMode)
{ {
case null: case null:
((NokiaFlashModel)CurrentModel).Shutdown(); ((LumiaFlashAppModel)PhoneNotifier.CurrentModel).Shutdown();
ModeSwitchProgressWrapper("Please disconnect your device. Waiting...", null); ModeSwitchProgressWrapper("Please disconnect your device. Waiting...", null);
LogFile.Log("Please disconnect your device. Waiting...", LogType.FileAndConsole); LogFile.Log("Please disconnect your device. Waiting...", LogType.FileAndConsole);
new Thread(() => new Thread(() =>
@@ -313,24 +319,38 @@ namespace WPinternals
}).Start(); }).Start();
break; break;
case PhoneInterfaces.Lumia_Normal: case PhoneInterfaces.Lumia_Normal:
((NokiaPhoneModel)CurrentModel).ExecuteRawVoidMethod(RebootCommand);
PhoneNotifier.NewDeviceArrived += NewDeviceArrived; PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
((LumiaFlashAppModel)PhoneNotifier.CurrentModel).ExecuteRawVoidMethod(RebootCommand);
ModeSwitchProgressWrapper("Rebooting phone to Normal mode...", null); ModeSwitchProgressWrapper("Rebooting phone to Normal mode...", null);
LogFile.Log("Rebooting phone to Normal mode", LogType.FileAndConsole); LogFile.Log("Rebooting phone to Normal mode", LogType.FileAndConsole);
break; break;
case PhoneInterfaces.Lumia_Bootloader: case PhoneInterfaces.Lumia_Bootloader:
((NokiaPhoneModel)CurrentModel).ExecuteRawVoidMethod(RebootCommand);
PhoneNotifier.NewDeviceArrived += NewDeviceArrived; PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
((LumiaFlashAppModel)PhoneNotifier.CurrentModel).ExecuteRawVoidMethod(RebootCommand);
ModeSwitchProgressWrapper("Rebooting phone to Bootloader mode...", null); ModeSwitchProgressWrapper("Rebooting phone to Bootloader mode...", null);
LogFile.Log("Rebooting phone to Bootloader mode", LogType.FileAndConsole); LogFile.Log("Rebooting phone to Bootloader mode", LogType.FileAndConsole);
break; break;
case PhoneInterfaces.Lumia_PhoneInfo:
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
ModernFlashApp = ((LumiaFlashAppModel)PhoneNotifier.CurrentModel).ReadPhoneInfo().FlashAppProtocolVersionMajor >= 2;
if (ModernFlashApp)
{
((LumiaFlashAppModel)PhoneNotifier.CurrentModel).SwitchToPhoneInfoAppContext();
}
else
{
((LumiaFlashAppModel)PhoneNotifier.CurrentModel).SwitchToPhoneInfoAppContextLegacy();
}
ModeSwitchProgressWrapper("Rebooting phone to Phone Info mode...", null);
LogFile.Log("Rebooting phone to Phone Info mode", LogType.FileAndConsole);
break;
case PhoneInterfaces.Lumia_Label: case PhoneInterfaces.Lumia_Label:
SwitchFromFlashToLabelMode(); SwitchFromFlashToLabelMode();
break; break;
case PhoneInterfaces.Lumia_Flash: // attempt to boot from limited flash to full flash case PhoneInterfaces.Lumia_Flash: // attempt to boot from limited flash to full flash
byte[] RebootToFlashCommand = [0x4E, 0x4F, 0x4B, 0x53]; // NOKS
((NokiaPhoneModel)CurrentModel).ExecuteRawVoidMethod(RebootToFlashCommand);
PhoneNotifier.NewDeviceArrived += NewDeviceArrived; PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
byte[] RebootToFlashCommand = [0x4E, 0x4F, 0x4B, 0x53]; // NOKS
((LumiaFlashAppModel)PhoneNotifier.CurrentModel).ExecuteRawVoidMethod(RebootToFlashCommand);
ModeSwitchProgressWrapper("Rebooting phone to Flash mode...", null); ModeSwitchProgressWrapper("Rebooting phone to Flash mode...", null);
LogFile.Log("Rebooting phone to Flash mode", LogType.FileAndConsole); LogFile.Log("Rebooting phone to Flash mode", LogType.FileAndConsole);
break; break;
@@ -338,8 +358,9 @@ namespace WPinternals
SwitchFromFlashToMassStorageMode(); SwitchFromFlashToMassStorageMode();
break; break;
case PhoneInterfaces.Qualcomm_Download: case PhoneInterfaces.Qualcomm_Download:
byte[] RebootToQualcommDownloadCommand = [0x4E, 0x4F, 0x4B, 0x58, 0x43, 0x42, 0x45]; // NOKXCBE PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
RebootCommandResult = ((NokiaPhoneModel)CurrentModel).ExecuteRawMethod(RebootToQualcommDownloadCommand); byte[] RebootToQualcommDownloadCommand = [0x4E, 0x4F, 0x4B, 0x58, 0x43, 0x42, 0x45]; // NOKXCBE // TODO
RebootCommandResult = ((LumiaFlashAppModel)PhoneNotifier.CurrentModel).ExecuteRawMethod(RebootToQualcommDownloadCommand);
if (RebootCommandResult?.Length == 4) // This means fail: NOKU (unknow command) if (RebootCommandResult?.Length == 4) // This means fail: NOKU (unknow command)
{ {
IsSwitchingInterface = false; IsSwitchingInterface = false;
@@ -347,7 +368,133 @@ namespace WPinternals
} }
else else
{ {
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:
PhoneNotifier.NewDeviceArrived += NewDeviceArrived; PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
((LumiaPhoneInfoAppModel)PhoneNotifier.CurrentModel).ExecuteRawVoidMethod(RebootCommand);
ModeSwitchProgressWrapper("Rebooting phone to Normal mode...", null);
LogFile.Log("Rebooting phone to Normal mode", LogType.FileAndConsole);
break;
case PhoneInterfaces.Lumia_Bootloader:
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
ModernFlashApp = ((LumiaPhoneInfoAppModel)PhoneNotifier.CurrentModel).ReadPhoneInfo().PhoneInfoAppVersionMajor >= 2;
if (ModernFlashApp)
{
((LumiaPhoneInfoAppModel)PhoneNotifier.CurrentModel).SwitchToBootManagerContext();
}
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
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
ModernFlashApp = ((LumiaPhoneInfoAppModel)PhoneNotifier.CurrentModel).ReadPhoneInfo().PhoneInfoAppVersionMajor >= 2;
if (ModernFlashApp)
{
((LumiaPhoneInfoAppModel)PhoneNotifier.CurrentModel).SwitchToPhoneInfoAppContext();
}
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:
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
ModernFlashApp = ((LumiaPhoneInfoAppModel)PhoneNotifier.CurrentModel).ReadPhoneInfo().PhoneInfoAppVersionMajor >= 2;
if (ModernFlashApp)
{
((LumiaPhoneInfoAppModel)PhoneNotifier.CurrentModel).SwitchToFlashAppContext();
}
else
{
((LumiaPhoneInfoAppModel)PhoneNotifier.CurrentModel).ContinueBoot();
}
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:
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
byte[] RebootToQualcommDownloadCommand = [0x4E, 0x4F, 0x4B, 0x58, 0x43, 0x42, 0x45]; // NOKXCBE // TODO
RebootCommandResult = ((LumiaPhoneInfoAppModel)PhoneNotifier.CurrentModel).ExecuteRawMethod(RebootToQualcommDownloadCommand);
if (RebootCommandResult?.Length == 4) // This means fail: NOKU (unknow command)
{
IsSwitchingInterface = false;
ModeSwitchErrorWrapper("Failed to switch to Qualcomm Download mode");
}
else
{
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)PhoneNotifier.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:
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
((LumiaBootManagerAppModel)PhoneNotifier.CurrentModel).ExecuteRawVoidMethod(RebootCommand);
ModeSwitchProgressWrapper("Rebooting phone to Normal mode...", null);
LogFile.Log("Rebooting phone to Normal mode", LogType.FileAndConsole);
break;
case PhoneInterfaces.Lumia_Bootloader:
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
((LumiaBootManagerAppModel)PhoneNotifier.CurrentModel).ExecuteRawVoidMethod(RebootCommand);
ModeSwitchProgressWrapper("Rebooting phone to Bootloader mode...", null);
LogFile.Log("Rebooting phone to Bootloader mode", LogType.FileAndConsole);
break;
case PhoneInterfaces.Lumia_Label:
SwitchFromFlashToLabelMode();
break;
case PhoneInterfaces.Lumia_Flash: // attempt to boot from limited flash to full flash
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
byte[] RebootToFlashCommand = [0x4E, 0x4F, 0x4B, 0x53]; // NOKS
((LumiaBootManagerAppModel)PhoneNotifier.CurrentModel).ExecuteRawVoidMethod(RebootToFlashCommand);
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:
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
byte[] RebootToQualcommDownloadCommand = [0x4E, 0x4F, 0x4B, 0x58, 0x43, 0x42, 0x45]; // NOKXCBE // TODO
RebootCommandResult = ((LumiaBootManagerAppModel)PhoneNotifier.CurrentModel).ExecuteRawMethod(RebootToQualcommDownloadCommand);
if (RebootCommandResult?.Length == 4) // This means fail: NOKU (unknow command)
{
IsSwitchingInterface = false;
ModeSwitchErrorWrapper("Failed to switch to Qualcomm Download mode");
}
else
{
ModeSwitchProgressWrapper("Rebooting phone to Qualcomm Download mode...", null); ModeSwitchProgressWrapper("Rebooting phone to Qualcomm Download mode...", null);
LogFile.Log("Rebooting phone to Qualcomm Download mode", LogType.FileAndConsole); LogFile.Log("Rebooting phone to Qualcomm Download mode", LogType.FileAndConsole);
} }
@@ -361,26 +508,26 @@ namespace WPinternals
switch (TargetMode) switch (TargetMode)
{ {
case PhoneInterfaces.Lumia_Normal: case PhoneInterfaces.Lumia_Normal:
((MassStorage)CurrentModel).Reboot();
PhoneNotifier.NewDeviceArrived += NewDeviceArrived; PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
((MassStorage)PhoneNotifier.CurrentModel).Reboot();
ModeSwitchProgressWrapper("Rebooting phone to Normal mode...", null); ModeSwitchProgressWrapper("Rebooting phone to Normal mode...", null);
LogFile.Log("Rebooting phone to Normal mode", LogType.FileAndConsole); LogFile.Log("Rebooting phone to Normal mode", LogType.FileAndConsole);
break; break;
case PhoneInterfaces.Lumia_Label: case PhoneInterfaces.Lumia_Label:
((MassStorage)CurrentModel).Reboot();
PhoneNotifier.NewDeviceArrived += NewDeviceArrivedFromMassStorageMode; PhoneNotifier.NewDeviceArrived += NewDeviceArrivedFromMassStorageMode;
((MassStorage)PhoneNotifier.CurrentModel).Reboot();
ModeSwitchProgressWrapper("Rebooting phone to Label mode...", null); ModeSwitchProgressWrapper("Rebooting phone to Label mode...", null);
LogFile.Log("Rebooting phone to Label mode...", LogType.FileAndConsole); LogFile.Log("Rebooting phone to Label mode...", LogType.FileAndConsole);
break; break;
case PhoneInterfaces.Lumia_Flash: case PhoneInterfaces.Lumia_Flash:
((MassStorage)CurrentModel).Reboot();
PhoneNotifier.NewDeviceArrived += NewDeviceArrivedFromMassStorageMode; PhoneNotifier.NewDeviceArrived += NewDeviceArrivedFromMassStorageMode;
((MassStorage)PhoneNotifier.CurrentModel).Reboot();
ModeSwitchProgressWrapper("Rebooting phone to Flash mode...", null); ModeSwitchProgressWrapper("Rebooting phone to Flash mode...", null);
LogFile.Log("Rebooting phone to Flash mode...", LogType.FileAndConsole); LogFile.Log("Rebooting phone to Flash mode...", LogType.FileAndConsole);
break; break;
case null: case null:
((MassStorage)CurrentModel).Reboot();
PhoneNotifier.NewDeviceArrived += NewDeviceArrivedFromMassStorageMode; PhoneNotifier.NewDeviceArrived += NewDeviceArrivedFromMassStorageMode;
((MassStorage)PhoneNotifier.CurrentModel).Reboot();
ModeSwitchProgressWrapper("First rebooting phone to Flash mode...", null); ModeSwitchProgressWrapper("First rebooting phone to Flash mode...", null);
LogFile.Log("First rebooting phone to Bootloader mode...", LogType.FileAndConsole); LogFile.Log("First rebooting phone to Bootloader mode...", LogType.FileAndConsole);
break; break;
@@ -420,6 +567,12 @@ namespace WPinternals
case PhoneInterfaces.Lumia_Flash: case PhoneInterfaces.Lumia_Flash:
ModeSwitchErrorWrapper("Failed to switch to Flash mode"); ModeSwitchErrorWrapper("Failed to switch to Flash mode");
break; 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: case PhoneInterfaces.Lumia_Label:
ModeSwitchErrorWrapper("Failed to switch to Label mode"); ModeSwitchErrorWrapper("Failed to switch to Label mode");
break; break;
@@ -440,6 +593,12 @@ namespace WPinternals
case PhoneInterfaces.Lumia_Flash: case PhoneInterfaces.Lumia_Flash:
ModeSwitchErrorWrapper("Failed to switch to Flash mode"); ModeSwitchErrorWrapper("Failed to switch to Flash mode");
break; 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: case PhoneInterfaces.Lumia_Label:
ModeSwitchErrorWrapper("Failed to switch to Label mode"); ModeSwitchErrorWrapper("Failed to switch to Label mode");
break; break;
@@ -468,18 +627,21 @@ namespace WPinternals
// SwitchToFlashAppContext() will only switch context. Phone will not charge. // 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. // ResetPhoneToFlashMode() reboots to real flash app. Phone will charge. Works when in BootMgrApp, not when already in FlashApp.
((NokiaFlashModel)CurrentModel).ResetPhoneToFlashMode(); ((LumiaBootManagerAppModel)PhoneNotifier.CurrentModel).ResetPhoneToFlashMode();
CurrentMode = PhoneInterfaces.Lumia_Flash; CurrentMode = PhoneInterfaces.Lumia_Flash;
PhoneNotifier.NotifyArrival(); PhoneNotifier.NotifyArrival();
} }
catch { } catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
} }
if (CurrentMode == TargetMode) if (CurrentMode == TargetMode)
{ {
if (TargetMode == PhoneInterfaces.Lumia_Bootloader) if (TargetMode == PhoneInterfaces.Lumia_Bootloader)
{ {
((NokiaFlashModel)CurrentModel).DisableRebootTimeOut(); ((NokiaFlashModel)PhoneNotifier.CurrentModel).DisableRebootTimeOut();
} }
ModeSwitchSuccessWrapper(); ModeSwitchSuccessWrapper();
@@ -505,10 +667,10 @@ namespace WPinternals
else if ((CurrentMode == PhoneInterfaces.Lumia_Flash) && (TargetMode == PhoneInterfaces.Qualcomm_Download)) else if ((CurrentMode == PhoneInterfaces.Lumia_Flash) && (TargetMode == PhoneInterfaces.Qualcomm_Download))
{ {
byte[] RebootCommand = [0x4E, 0x4F, 0x4B, 0x52]; 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; IsSwitchingInterface = true;
LogFile.Log("Sending command for rebooting to Emergency Download mode"); LogFile.Log("Sending command for rebooting to Emergency Download mode");
byte[] RebootCommandResult = ((NokiaPhoneModel)CurrentModel).ExecuteRawMethod(RebootToQualcommDownloadCommand); byte[] RebootCommandResult = ((NokiaPhoneModel)PhoneNotifier.CurrentModel).ExecuteRawMethod(RebootToQualcommDownloadCommand);
if (RebootCommandResult?.Length >= 8) if (RebootCommandResult?.Length >= 8)
{ {
int ResultCode = (RebootCommandResult[6] << 8) + RebootCommandResult[7]; int ResultCode = (RebootCommandResult[6] << 8) + RebootCommandResult[7];
@@ -536,6 +698,12 @@ namespace WPinternals
case PhoneInterfaces.Lumia_Flash: case PhoneInterfaces.Lumia_Flash:
ModeSwitchErrorWrapper("Failed to switch to Flash mode"); ModeSwitchErrorWrapper("Failed to switch to Flash mode");
break; 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: case PhoneInterfaces.Lumia_Label:
ModeSwitchErrorWrapper("Failed to switch to Label mode"); ModeSwitchErrorWrapper("Failed to switch to Label mode");
break; break;
@@ -546,37 +714,64 @@ namespace WPinternals
} }
} }
private void SwitchFromFlashToLabelMode(bool Continuation = false) private void SwitchFromPhoneInfoToLabelMode(bool Continuation = false)
{ {
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_PhoneInfo)
{
throw new WPinternalsException("Unexpected Mode");
}
string ProgressText = Continuation ? "And now preparing to boot the phone to Label mode..." : "Preparing to boot the phone to Label mode..."; 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) LumiaPhoneInfoAppPhoneInfo PhoneInfoAppInfo = ((LumiaPhoneInfoAppModel)PhoneNotifier.CurrentModel).ReadPhoneInfo(ExtendedInfo: true);
bool ModernFlashApp = ((LumiaPhoneInfoAppModel)PhoneNotifier.CurrentModel).ReadPhoneInfo().PhoneInfoAppVersionMajor >= 2;
if (ModernFlashApp)
{ {
try ((LumiaPhoneInfoAppModel)PhoneNotifier.CurrentModel).SwitchToFlashAppContext();
}
else
{ {
FlashModel.SwitchToFlashAppContext(); ((LumiaPhoneInfoAppModel)PhoneNotifier.CurrentModel).ContinueBoot();
} }
catch { }
Task.Run(async () =>
{
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)
{
await PhoneNotifier.WaitForArrival();
} }
PhoneInfo Info = FlashModel.ReadPhoneInfo(ExtendedInfo: true);
void Finish()
{
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)
{
throw new WPinternalsException("Unexpected Mode");
}
LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)PhoneNotifier.CurrentModel;
LumiaFlashAppPhoneInfo Info = FlashModel.ReadPhoneInfo(ExtendedInfo: true);
if (Info.MmosOverUsbSupported) if (Info.MmosOverUsbSupported)
{
new Thread(() =>
{ {
LogFile.BeginAction("SwitchToLabelMode"); LogFile.BeginAction("SwitchToLabelMode");
try try
{ {
ModeSwitchProgressWrapper(ProgressText, null); ModeSwitchProgressWrapper(ProgressText, null);
string TempFolder = Environment.GetEnvironmentVariable("TEMP") + @"\WPInternals";
if (Info.Type == "RM-1152") string TempFolder = $@"{Environment.GetEnvironmentVariable("TEMP")}\WPInternals";
if (PhoneInfoAppInfo.Type == "RM-1152")
{ {
Info.Type = "RM-1151"; PhoneInfoAppInfo.Type = "RM-1151";
} }
string ENOSWPackage = LumiaDownloadModel.SearchENOSW(Info.Type, Info.Firmware);
SetWorkingStatus("Downloading " + Info.Type + " Test Mode package...", MaxProgressValue: 100); (string ENOSWFileUrl, string DPLFileUrl) = LumiaDownloadModel.SearchENOSW(PhoneInfoAppInfo.Type, Info.Firmware);
DownloadEntry downloadEntry = new(ENOSWPackage, TempFolder, null, null, null);
UIContext?.Post(d => SetWorkingStatus($"Downloading {PhoneInfoAppInfo.Type} Test Mode package...", MaxProgressValue: 100), null);
DownloadEntry downloadEntry = new(ENOSWFileUrl, TempFolder, [ENOSWFileUrl], ENOSWDownloadCompleted, Info.Firmware);
downloadEntry.PropertyChanged += (object sender, System.ComponentModel.PropertyChangedEventArgs e) => downloadEntry.PropertyChanged += (object sender, System.ComponentModel.PropertyChangedEventArgs e) =>
{ {
@@ -584,27 +779,7 @@ namespace WPinternals
{ {
int progress = (sender as DownloadEntry)?.Progress ?? 0; int progress = (sender as DownloadEntry)?.Progress ?? 0;
ulong.TryParse(progress.ToString(), out ulong progressret); ulong.TryParse(progress.ToString(), out ulong progressret);
UpdateWorkingStatus(null, CurrentProgressValue: progressret); UIContext?.Post(d => UpdateWorkingStatus(null, CurrentProgressValue: progressret), null);
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.");
}
} }
}; };
} }
@@ -615,35 +790,200 @@ namespace WPinternals
} }
LogFile.EndAction("SwitchToLabelMode"); LogFile.EndAction("SwitchToLabelMode");
}).Start();
} }
else else
{ {
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
byte[] BootModeFlagCommand = [0x4E, 0x4F, 0x4B, 0x58, 0x46, 0x57, 0x00, 0x55, 0x42, 0x46, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00]; // NOKFW UBF 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[] RebootCommand = [0x4E, 0x4F, 0x4B, 0x52]; // NOKR
BootModeFlagCommand[0x0F] = 0x59; BootModeFlagCommand[0x0F] = 0x59;
((NokiaPhoneModel)CurrentModel).ExecuteRawMethod(BootModeFlagCommand); ((LumiaFlashAppModel)PhoneNotifier.CurrentModel).ExecuteRawMethod(BootModeFlagCommand);
((NokiaPhoneModel)CurrentModel).ExecuteRawVoidMethod(RebootCommand); ((LumiaFlashAppModel)PhoneNotifier.CurrentModel).ExecuteRawVoidMethod(RebootCommand);
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
ModeSwitchProgressWrapper("Rebooting phone to Label mode", null); ModeSwitchProgressWrapper("Rebooting phone to Label mode", null);
LogFile.Log("Rebooting phone to Label mode", LogType.FileAndConsole); LogFile.Log("Rebooting phone to Label mode", LogType.FileAndConsole);
} }
} }
private void SwitchFromFlashToMassStorageMode(bool Continuation = false) UIContext?.Post(d => Finish(), null);
});
}
private void SwitchFromFlashToLabelMode(bool Continuation = false)
{ {
string ProgressText = Continuation ? "And now rebooting phone to Mass Storage mode..." : "Rebooting phone to Mass Storage mode..."; 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) if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)
{ {
throw new WPinternalsException("Unexpected Mode");
}
LumiaFlashAppPhoneInfo Info = ((LumiaFlashAppModel)PhoneNotifier.CurrentModel).ReadPhoneInfo(ExtendedInfo: true);
bool ModernFlashApp = ((LumiaFlashAppModel)PhoneNotifier.CurrentModel).ReadPhoneInfo().FlashAppProtocolVersionMajor >= 2;
if (ModernFlashApp)
{
((LumiaFlashAppModel)PhoneNotifier.CurrentModel).SwitchToPhoneInfoAppContext();
}
else
{
((LumiaFlashAppModel)PhoneNotifier.CurrentModel).SwitchToPhoneInfoAppContextLegacy();
}
Task.Run(async () =>
{
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_PhoneInfo)
{
await PhoneNotifier.WaitForArrival();
}
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_PhoneInfo)
{
throw new WPinternalsException("Unexpected Mode");
}
LumiaPhoneInfoAppModel LumiaPhoneInfoAppModel = (LumiaPhoneInfoAppModel)PhoneNotifier.CurrentModel;
LumiaPhoneInfoAppPhoneInfo PhoneInfoAppInfo = LumiaPhoneInfoAppModel.ReadPhoneInfo(ExtendedInfo: true);
ModernFlashApp = PhoneInfoAppInfo.PhoneInfoAppVersionMajor >= 2;
if (ModernFlashApp)
{
LumiaPhoneInfoAppModel.SwitchToFlashAppContext();
}
else
{
LumiaPhoneInfoAppModel.ContinueBoot();
}
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)
{
await PhoneNotifier.WaitForArrival();
}
void Finish()
{
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)
{
throw new WPinternalsException("Unexpected Mode");
}
LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)PhoneNotifier.CurrentModel;
if (Info.MmosOverUsbSupported)
{
LogFile.BeginAction("SwitchToLabelMode");
try try
{ {
FlashModel.SwitchToFlashAppContext(); ModeSwitchProgressWrapper(ProgressText, null);
string TempFolder = $@"{Environment.GetEnvironmentVariable("TEMP")}\WPInternals";
if (PhoneInfoAppInfo.Type == "RM-1152")
{
PhoneInfoAppInfo.Type = "RM-1151";
} }
catch { }
(string ENOSWFileUrl, string DPLFileUrl) = LumiaDownloadModel.SearchENOSW(PhoneInfoAppInfo.Type, Info.Firmware);
UIContext?.Post(d => SetWorkingStatus($"Downloading {PhoneInfoAppInfo.Type} Test Mode package...", MaxProgressValue: 100), null);
DownloadEntry downloadEntry = new(ENOSWFileUrl, TempFolder, [ENOSWFileUrl], ENOSWDownloadCompleted, Info.Firmware);
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);
UIContext?.Post(d => UpdateWorkingStatus(null, CurrentProgressValue: progressret), null);
} }
PhoneInfo Info = FlashModel.ReadPhoneInfo(ExtendedInfo: false); };
}
catch (Exception Ex)
{
LogFile.LogException(Ex);
ModeSwitchErrorWrapper(Ex.Message);
}
LogFile.EndAction("SwitchToLabelMode");
}
else
{
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
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)PhoneNotifier.CurrentModel).ExecuteRawMethod(BootModeFlagCommand);
((LumiaFlashAppModel)PhoneNotifier.CurrentModel).ExecuteRawVoidMethod(RebootCommand);
ModeSwitchProgressWrapper("Rebooting phone to Label mode", null);
LogFile.Log("Rebooting phone to Label mode", LogType.FileAndConsole);
}
}
UIContext?.Post(d => Finish(), null);
});
}
private void ENOSWDownloadCompleted(string[] URLs, object State)
{
string Firmware = (string)State;
string ENOSWFileUrl = URLs[0];
string Name = DownloadsViewModel.GetFileNameFromURL(ENOSWFileUrl);
string TempFolder = $@"{Environment.GetEnvironmentVariable("TEMP")}\WPInternals";
LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)PhoneNotifier.CurrentModel;
Task.Run(() =>
{
ModeSwitchProgressWrapper("Initializing Flash...", null);
string MMOSPath = Path.Combine(TempFolder, Name);
App.Config.AddSecWimToRepository(MMOSPath, Firmware);
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
LumiaFlashAppPhoneInfo Info = FlashModel.ReadPhoneInfo();
FileInfo info = new(MMOSPath);
uint length = uint.Parse(info.Length.ToString());
int maximumBufferSize = (int)Info.WriteBufferSize;
uint chunkCount = (uint)Math.Truncate((decimal)length / maximumBufferSize);
UIContext?.Post(d => SetWorkingStatus("Flashing Test Mode package...", MaxProgressValue: 100), null);
ProgressUpdater progressUpdater = new(chunkCount + 1, (int i, TimeSpan? time) => UpdateWorkingStatus(null, CurrentProgressValue: (ulong)i));
FlashModel.FlashMMOS(MMOSPath, progressUpdater);
ModeSwitchProgressWrapper("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.");
});
}
private void SwitchFromPhoneInfoToMassStorageMode(bool Continuation = false)
{
string ProgressText = Continuation ? "And now rebooting phone to Mass Storage mode..." : "Rebooting phone to Mass Storage mode...";
new Thread(async () =>
{
bool ModernFlashApp = ((LumiaPhoneInfoAppModel)PhoneNotifier.CurrentModel).ReadPhoneInfo().PhoneInfoAppVersionMajor >= 2;
if (ModernFlashApp)
{
((LumiaPhoneInfoAppModel)PhoneNotifier.CurrentModel).SwitchToFlashAppContext();
}
else
{
((LumiaPhoneInfoAppModel)PhoneNotifier.CurrentModel).ContinueBoot();
}
await PhoneNotifier.WaitForArrival();
LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)PhoneNotifier.CurrentModel;
LumiaFlashAppPhoneInfo Info = FlashModel.ReadPhoneInfo(ExtendedInfo: false);
MassStorageWarning = null; MassStorageWarning = null;
if (Info.FlashAppProtocolVersionMajor < 2) if (Info.FlashAppProtocolVersionMajor < 2)
@@ -675,16 +1015,17 @@ namespace WPinternals
byte[] RebootCommand = [0x4E, 0x4F, 0x4B, 0x52]; byte[] RebootCommand = [0x4E, 0x4F, 0x4B, 0x52];
byte[] RebootToMassStorageCommand = [0x4E, 0x4F, 0x4B, 0x4D]; // NOKM byte[] RebootToMassStorageCommand = [0x4E, 0x4F, 0x4B, 0x4D]; // NOKM
IsSwitchingInterface = true; IsSwitchingInterface = true;
byte[] RebootCommandResult = ((NokiaPhoneModel)CurrentModel).ExecuteRawMethod(RebootToMassStorageCommand); byte[] RebootCommandResult = ((NokiaPhoneModel)PhoneNotifier.CurrentModel).ExecuteRawMethod(RebootToMassStorageCommand);
if (RebootCommandResult?.Length == 4) // This means fail: NOKU (unknown command) if (RebootCommandResult?.Length == 4) // This means fail: NOKU (unknown command)
{ {
BootModeFlagCommand[0x0F] = 0x4D; BootModeFlagCommand[0x0F] = 0x4D;
byte[] BootFlagResult = ((NokiaPhoneModel)CurrentModel).ExecuteRawMethod(BootModeFlagCommand); byte[] BootFlagResult = ((NokiaPhoneModel)PhoneNotifier.CurrentModel).ExecuteRawMethod(BootModeFlagCommand);
UInt16 ResultCode = BitConverter.ToUInt16(BootFlagResult, 6); UInt16 ResultCode = BitConverter.ToUInt16(BootFlagResult, 6);
if (ResultCode == 0) if (ResultCode == 0)
{ {
PhoneNotifier.NewDeviceArrived += NewDeviceArrived; PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
((NokiaPhoneModel)CurrentModel).ExecuteRawVoidMethod(RebootCommand);
((NokiaPhoneModel)PhoneNotifier.CurrentModel).ExecuteRawVoidMethod(RebootCommand);
ModeSwitchProgressWrapper(ProgressText, MassStorageWarning); ModeSwitchProgressWrapper(ProgressText, MassStorageWarning);
LogFile.Log("Rebooting phone to Mass Storage mode"); LogFile.Log("Rebooting phone to Mass Storage mode");
} }
@@ -697,6 +1038,216 @@ namespace WPinternals
else else
{ {
PhoneNotifier.NewDeviceArrived += NewDeviceArrived; 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.");
}
}).Start();
}
private void SwitchFromFlashToMassStorageMode(bool Continuation = false)
{
string ProgressText = Continuation ? "And now rebooting phone to Mass Storage mode..." : "Rebooting phone to Mass Storage mode...";
if (CurrentMode == PhoneInterfaces.Lumia_Bootloader)
{
try
{
((LumiaBootManagerAppModel)PhoneNotifier.CurrentModel).SwitchToFlashAppContext();
}
catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
}
LumiaFlashAppModel FlashModel = (LumiaFlashAppModel)PhoneNotifier.CurrentModel;
LumiaFlashAppPhoneInfo 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)PhoneNotifier.CurrentModel).ExecuteRawMethod(RebootToMassStorageCommand);
if (RebootCommandResult?.Length == 4) // This means fail: NOKU (unknown command)
{
BootModeFlagCommand[0x0F] = 0x4D;
byte[] BootFlagResult = ((NokiaPhoneModel)PhoneNotifier.CurrentModel).ExecuteRawMethod(BootModeFlagCommand);
UInt16 ResultCode = BitConverter.ToUInt16(BootFlagResult, 6);
if (ResultCode == 0)
{
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
((NokiaPhoneModel)PhoneNotifier.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); ModeSwitchProgressWrapper(ProgressText, MassStorageWarning);
LogFile.Log("Rebooting phone to Mass Storage mode"); LogFile.Log("Rebooting phone to Mass Storage mode");
} }
+4 -1
View File
@@ -159,13 +159,16 @@ DEALINGS IN THE SOFTWARE.
<RowDefinition /> <RowDefinition />
<RowDefinition /> <RowDefinition />
<RowDefinition /> <RowDefinition />
<RowDefinition />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0">Producttype</TextBlock> <TextBlock Grid.Column="0" Grid.Row="0">Producttype</TextBlock>
<TextBlock Grid.Column="0" Grid.Row="1">Productcode</TextBlock> <TextBlock Grid.Column="0" Grid.Row="1">Productcode</TextBlock>
<TextBlock Grid.Column="0" Grid.Row="2">Operatorcode</TextBlock> <TextBlock Grid.Column="0" Grid.Row="2">Operatorcode</TextBlock>
<TextBlock Grid.Column="0" Grid.Row="3">Firmwareversion</TextBlock>
<TextBox Grid.Column="1" Grid.Row="0" Width="Auto" Margin="0,0,0,8" Text="{Binding ProductType, Mode=TwoWay}"/> <TextBox Grid.Column="1" Grid.Row="0" Width="Auto" Margin="0,0,0,8" Text="{Binding ProductType, Mode=TwoWay}"/>
<TextBox Grid.Column="1" Grid.Row="1" Width="Auto" Margin="0,0,0,8" Text="{Binding ProductCode, Mode=TwoWay}"/> <TextBox Grid.Column="1" Grid.Row="1" Width="Auto" Margin="0,0,0,8" Text="{Binding ProductCode, Mode=TwoWay}"/>
<TextBox Grid.Column="1" Grid.Row="2" Width="Auto" Text="{Binding OperatorCode, Mode=TwoWay}"/> <TextBox Grid.Column="1" Grid.Row="2" Width="Auto" Margin="0,0,0,8" Text="{Binding OperatorCode, Mode=TwoWay}"/>
<TextBox Grid.Column="1" Grid.Row="3" Width="Auto" Text="{Binding FirmwareVersion, Mode=TwoWay}"/>
</Grid> </Grid>
<StackPanel Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Bottom" Orientation="Horizontal"> <StackPanel Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Bottom" Orientation="Horizontal">
<Button Content="Search" Padding="0,5" Width="120" Margin="0,0,20,0" Command="{Binding Path=SearchCommand, Mode=OneWay}" IsDefault="True"/> <Button Content="Search" Padding="0,5" Width="120" Margin="0,0,20,0" Command="{Binding Path=SearchCommand, Mode=OneWay}" IsDefault="True"/>
+6
View File
@@ -37,6 +37,9 @@ DEALINGS IN THE SOFTWARE.
<DataTemplate DataType="{x:Type local:NokiaBootloaderViewModel}"> <DataTemplate DataType="{x:Type local:NokiaBootloaderViewModel}">
<local:NokiaBootloaderView /> <local:NokiaBootloaderView />
</DataTemplate> </DataTemplate>
<DataTemplate DataType="{x:Type local:NokiaPhoneInfoViewModel}">
<local:NokiaPhoneInfoView />
</DataTemplate>
<DataTemplate DataType="{x:Type local:NokiaFlashViewModel}"> <DataTemplate DataType="{x:Type local:NokiaFlashViewModel}">
<local:NokiaFlashView /> <local:NokiaFlashView />
</DataTemplate> </DataTemplate>
@@ -58,6 +61,9 @@ DEALINGS IN THE SOFTWARE.
<DataTemplate DataType="{x:Type local:NokiaModeBootloaderViewModel}"> <DataTemplate DataType="{x:Type local:NokiaModeBootloaderViewModel}">
<local:NokiaModeBootloaderView /> <local:NokiaModeBootloaderView />
</DataTemplate> </DataTemplate>
<DataTemplate DataType="{x:Type local:NokiaModePhoneInfoViewModel}">
<local:NokiaModePhoneInfoView />
</DataTemplate>
<DataTemplate DataType="{x:Type local:NokiaModeLabelViewModel}"> <DataTemplate DataType="{x:Type local:NokiaModeLabelViewModel}">
<local:NokiaModeLabelView /> <local:NokiaModeLabelView />
</DataTemplate> </DataTemplate>
@@ -99,10 +99,39 @@ DEALINGS IN THE SOFTWARE.
</StackPanel> </StackPanel>
</Border> </Border>
<Border BorderThickness="1" BorderBrush="#FFD4D4D4" HorizontalAlignment="Stretch" VerticalAlignment="Center" Padding="25" Margin="0,0,0,20"> <Border BorderThickness="1" BorderBrush="#FFD4D4D4" HorizontalAlignment="Stretch" VerticalAlignment="Center" Padding="25" Margin="0,0,0,20">
<StackPanel>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal"> <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
<local:GifImage x:Name="GifImage" Stretch="None"/> <local:GifImage x:Name="GifImage" Stretch="None"/>
<Label Content="Phone is booting..." FontSize="20" Margin="10,0,0,0" VerticalContentAlignment="Center"/> <Label Content="Phone is booting..." FontSize="20" Margin="10,0,0,0" VerticalContentAlignment="Center"/>
</StackPanel> </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>
<Border BorderThickness="1" BorderBrush="#FFD4D4D4" HorizontalAlignment="Stretch" VerticalAlignment="Center" Padding="25"> <Border BorderThickness="1" BorderBrush="#FFD4D4D4" HorizontalAlignment="Stretch" VerticalAlignment="Center" Padding="25">
<Expander Header="Phone identity" HorizontalContentAlignment="Stretch" Template="{DynamicResource TopicExpanderTemplate}" Margin="20,0"> <Expander Header="Phone identity" HorizontalContentAlignment="Stretch" Template="{DynamicResource TopicExpanderTemplate}" Margin="20,0">
+85 -3
View File
@@ -18,9 +18,13 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System.Threading.Tasks;
using System.Threading;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Documents; using System.Windows.Documents;
using System.Windows.Media;
using System;
namespace WPinternals namespace WPinternals
{ {
@@ -29,13 +33,41 @@ namespace WPinternals
/// </summary> /// </summary>
public partial class NokiaBootloaderView : UserControl public partial class NokiaBootloaderView : UserControl
{ {
private static PhoneNotifierViewModel PhoneNotifier;
private static SynchronizationContext UIContext;
public NokiaBootloaderView() public NokiaBootloaderView()
{ {
InitializeComponent(); InitializeComponent();
InterruptBoot = App.InterruptBoot;
UIContext = SynchronizationContext.Current;
// Setting these properties in XAML results in an error. Why? // Setting these properties in XAML results in an error. Why?
GifImage.GifSource = "/aerobusy.gif"; GifImage.GifSource = "/aerobusy.gif";
GifImage.AutoStart = true; 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) private void HandleHyperlinkClick(object sender, RoutedEventArgs args)
@@ -43,10 +75,24 @@ namespace WPinternals
Hyperlink link = args.Source as Hyperlink; Hyperlink link = args.Source as Hyperlink;
if (link?.NavigateUri != null) if (link?.NavigateUri != null)
{ {
if (link.NavigateUri.ToString() == "GettingStarted") if (link.NavigateUri.ToString() == "Getting started")
{ {
(this.DataContext as NokiaBootloaderViewModel)?.SwitchToGettingStarted(); App.NavigateToGettingStarted();
} (this.DataContext as NokiaBootloaderViewModel)?.RebootTo(link.NavigateUri.ToString()); }
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)); (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));
}
}
} }
} }
+10
View File
@@ -58,6 +58,16 @@ DEALINGS IN THE SOFTWARE.
<Run Text="This will switch back to Windows Phone OS." /> <Run Text="This will switch back to Windows Phone OS." />
<LineBreak /> <LineBreak />
<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> <Hyperlink NavigateUri="Label">Switch to Label-mode</Hyperlink>
<LineBreak /> <LineBreak />
<Run Text="This interface is meant for querying and provisioning the phone. This is normally used for configuring the phone during manufacturing." /> <Run Text="This interface is meant for querying and provisioning the phone. This is normally used for configuring the phone during manufacturing." />
@@ -0,0 +1,102 @@
<!--
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.
-->
<UserControl x:Class="WPinternals.NokiaModePhoneInfoView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WPinternals"
mc:Ignorable="d"
d:DesignWidth="700">
<UserControl.Resources>
<local:BooleanConverter x:Key="VisibilityConverter" OnTrue="Visible" OnFalse="Collapsed" />
<local:BooleanConverter x:Key="InvisibilityConverter" OnTrue="Collapsed" OnFalse="Visible" />
<local:BooleanConverter x:Key="InverseConverter" OnTrue="False" OnFalse="True" />
</UserControl.Resources>
<Border BorderThickness="1" BorderBrush="#FFD4D4D4" HorizontalAlignment="Stretch" VerticalAlignment="Center" Padding="25">
<local:FlowDocumentScrollViewerNoMouseWheel Grid.Column="1" Margin="20,0,0,0" VerticalScrollBarVisibility="Auto" >
<FlowDocument x:Name="Document" FontFamily="Segoe UI" FontSize="12" Loaded="Document_Loaded" TextAlignment="Left">
<FlowDocument.Resources>
<!-- This style is used to set the margins for all paragraphs in the FlowDocument to 0. -->
<Style TargetType="{x:Type Paragraph}">
<Setter Property="Margin" Value="0"/>
</Style>
<Style TargetType="{x:Type Section}">
<Setter Property="Margin" Value="0"/>
</Style>
</FlowDocument.Resources>
<local:Paragraph>
<Run Text="Nokia Lumia - Switch mode" FontSize="18" FontWeight="Bold" Foreground="#FF3753A6" />
<LineBreak />
<LineBreak />
<Run Text="Current mode: " />
<Run Text="Bootloader (Phone Info)" Foreground="#FF3753A6" FontWeight="Bold" />
<LineBreak />
<LineBreak />
<Hyperlink NavigateUri="Normal">Switch to Normal-mode</Hyperlink>
<LineBreak />
<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." />
<LineBreak />
<LineBreak />
<Hyperlink NavigateUri="MassStorage">Switch to Mass-Storage-mode</Hyperlink>
<LineBreak />
<Run Text="This mode allows you to access the complete file-system of the phone. " />
<local:CollapsibleRun IsVisible="{Binding EffectiveBootloaderSecurityStatus, Mode=OneWay}" Text="Your security flags indicate that this mode is prohibited on this phone."/>
<local:CollapsibleRun IsVisible="{Binding EffectiveBootloaderSecurityStatus, Converter={StaticResource InverseConverter}, Mode=OneWay}" Text="Your security flags indicate the this mode can be accessed. But this switch will only succeed if you took all measures to unlock Mass Storage mode." />
<LineBreak />
<LineBreak />
<Hyperlink NavigateUri="Shutdown">Shutdown the phone</Hyperlink>
<LineBreak />
<Run Text="This will shutdown your phone. After selecting this option, you'll need to unplug your phone from your computer." />
<LineBreak />
<LineBreak />
<Run Text="Warning 1: " Foreground="Red" FontWeight="Bold"/>
<Run Text="Once you've entered Mass Storage mode, be very careful with altering files. You can easily brick your phone, when you make invalid changes to the file-system of the phone." />
<LineBreak />
<LineBreak />
<Run Text="Warning 2: " Foreground="Red" FontWeight="Bold"/>
<Run Text="Before switching to Mass Storage Mode, verify that you do not have any other Windows Phone disks or partitions mounted. The partitions may have equal identifiers, which will result in a conflict. The phone partitions will be mounted &quot;offline&quot; and if you try to switch them &quot;online&quot; in the Disk Manager, it will corrupt the partitions on the phone. Unmount any Windows Phone partitions before you continue." />
<LineBreak />
<LineBreak />
<Run Text="Warning 3: " Foreground="Red" FontWeight="Bold"/>
<Run Text="Switching to Mass Storage mode should take about 10 seconds. Phones with Bootloader Spec A 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." />
</local:Paragraph>
</FlowDocument>
</local:FlowDocumentScrollViewerNoMouseWheel>
</Border>
</UserControl>
@@ -0,0 +1,50 @@
// 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.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
namespace WPinternals
{
/// <summary>
/// Interaction logic for NokiaModePhoneInfoView.xaml
/// </summary>
public partial class NokiaModePhoneInfoView : UserControl
{
public NokiaModePhoneInfoView()
{
InitializeComponent();
}
private void HandleHyperlinkClick(object sender, RoutedEventArgs args)
{
if (args.Source is Hyperlink link)
{
(this.DataContext as NokiaModePhoneInfoViewModel)?.RebootTo(link.NavigateUri.ToString());
}
}
private void Document_Loaded(object sender, RoutedEventArgs e)
{
(sender as FlowDocument)?.AddHandler(Hyperlink.ClickEvent, new RoutedEventHandler(HandleHyperlinkClick));
}
}
}
+108
View File
@@ -0,0 +1,108 @@
<!--
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.
-->
<UserControl x:Class="WPinternals.NokiaPhoneInfoView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WPinternals"
mc:Ignorable="d"
d:DesignWidth="700">
<UserControl.Resources>
<BitmapImage x:Key="Busy" UriSource="..\aerobusy.gif" />
<local:HexConverter x:Key="HexConverter" />
<local:BooleanConverter x:Key="VisibilityConverter" OnTrue="Visible" OnFalse="Collapsed" OnNull="Collapsed"/>
<local:BooleanConverter x:Key="InverseVisibilityConverter" OnTrue="Collapsed" OnFalse="Visible" OnNull="Collapsed" />
<local:ObjectToVisibilityConverter x:Key="ObjectToVisibilityConverter" />
</UserControl.Resources>
<StackPanel VerticalAlignment="Center">
<Border BorderThickness="1" BorderBrush="#FFD4D4D4" HorizontalAlignment="Stretch" VerticalAlignment="Center" Padding="25" Margin="0,0,0,20">
<StackPanel Orientation="Vertical">
<local:FlowDocumentScrollViewerNoMouseWheel Grid.Column="1" Margin="20,0" VerticalScrollBarVisibility="Auto">
<FlowDocument FontFamily="Segoe UI" FontSize="12" Loaded="Document_Loaded" PagePadding="1">
<local:Paragraph>
<Run Text="General info" FontSize="18" FontWeight="Bold" Foreground="#FF3753A6" />
<LineBreak />
<LineBreak />
<Grid IsHitTestVisible="False">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Operating mode" />
<TextBlock Grid.Row="0" Grid.Column="1" Text="Bootloader (Phone Info)" FontWeight="Bold" Foreground="#FF3753A6" TextWrapping="Wrap" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="Product Type" Visibility="{Binding Path=ProductType, Converter={StaticResource ObjectToVisibilityConverter}}"/>
<TextBlock Grid.Row="1" Grid.Column="1" FontWeight="Bold" Foreground="#FF3753A6" TextWrapping="Wrap" Text="{Binding ProductType}" Visibility="{Binding Path=ProductType, Converter={StaticResource ObjectToVisibilityConverter}}"/>
<TextBlock Grid.Row="2" Grid.Column="0" Text="Product Code" Visibility="{Binding Path=ProductCode, Converter={StaticResource ObjectToVisibilityConverter}}"/>
<TextBlock Grid.Row="2" Grid.Column="1" FontWeight="Bold" Foreground="#FF3753A6" TextWrapping="Wrap" Text="{Binding ProductCode}" Visibility="{Binding Path=ProductCode, Converter={StaticResource ObjectToVisibilityConverter}}"/>
<TextBlock Grid.Row="3" Grid.Column="0" Text="Hardware version" Visibility="{Binding Path=HWID, Converter={StaticResource ObjectToVisibilityConverter}}"/>
<TextBlock Grid.Row="3" Grid.Column="1" FontWeight="Bold" Foreground="#FF3753A6" TextWrapping="Wrap" Text="{Binding Path=HWID}" Visibility="{Binding Path=HWID, Converter={StaticResource ObjectToVisibilityConverter}}" />
<TextBlock Grid.Row="4" Grid.Column="0" Text="Bootloader" />
<TextBlock Grid.Row="4" Grid.Column="1" FontWeight="Bold" Foreground="#FF3753A6" TextWrapping="Wrap" Text="{Binding BootloaderDescription}"/>
</Grid>
</local:Paragraph>
</FlowDocument>
</local:FlowDocumentScrollViewerNoMouseWheel>
<local:FlowDocumentScrollViewerNoMouseWheel Grid.Column="1" Margin="20,0" VerticalScrollBarVisibility="Auto">
<FlowDocument FontFamily="Segoe UI" FontSize="12" Loaded="Document_Loaded" PagePadding="1">
<local:Paragraph>
<LineBreak />
<Run Text="To let the phone go back to Windows, boot to " />
<Hyperlink NavigateUri="Normal">Normal</Hyperlink>
<Run Text=" mode." />
</local:Paragraph>
</FlowDocument>
</local:FlowDocumentScrollViewerNoMouseWheel>
</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" >
<FlowDocument x:Name="Document" FontFamily="Segoe UI" FontSize="12" Loaded="Document_Loaded" PagePadding="1">
<local:Paragraph>
<LineBreak />
<Grid IsHitTestVisible="False">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="IMEI" />
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Path=IMEI}" TextWrapping="Wrap" />
</Grid>
</local:Paragraph>
</FlowDocument>
</local:FlowDocumentScrollViewerNoMouseWheel>
</Expander>
</Border>
</StackPanel>
</UserControl>
@@ -0,0 +1,54 @@
// 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.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
namespace WPinternals
{
/// <summary>
/// Interaction logic for NokiaPhoneInfoView.xaml
/// </summary>
public partial class NokiaPhoneInfoView : UserControl
{
public NokiaPhoneInfoView()
{
InitializeComponent();
}
private void HandleHyperlinkClick(object sender, RoutedEventArgs args)
{
Hyperlink link = args.Source as Hyperlink;
if (link?.NavigateUri != null)
{
if (link.NavigateUri.ToString() == "GettingStarted")
{
(this.DataContext as NokiaPhoneInfoViewModel)?.SwitchToGettingStarted();
} (this.DataContext as NokiaPhoneInfoViewModel)?.RebootTo(link.NavigateUri.ToString());
}
}
private void Document_Loaded(object sender, RoutedEventArgs e)
{
(sender as FlowDocument)?.AddHandler(Hyperlink.ClickEvent, new RoutedEventHandler(HandleHyperlinkClick));
}
}
}
+1 -1
View File
@@ -337,7 +337,7 @@
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" /> <PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="System.IO.Ports" Version="8.0.0" /> <PackageReference Include="System.IO.Ports" Version="8.0.0" />
<PackageReference Include="System.Management" Version="8.0.0" /> <PackageReference Include="System.Management" Version="8.0.0" />
<PackageReference Include="System.Text.Json" Version="8.0.0" /> <PackageReference Include="System.Text.Json" Version="8.0.4" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="DiscUtils\DiscUtils.Core\CoreCompat\" /> <Folder Include="DiscUtils\DiscUtils.Core\CoreCompat\" />
+5
View File
@@ -114,4 +114,9 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Preview-Test|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Preview-Test|AnyCPU'">
<StartArguments>/Test</StartArguments> <StartArguments>/Test</StartArguments>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Page Update="Views\NokiaModePhoneInfoView.xaml">
<SubType>Designer</SubType>
</Page>
</ItemGroup>
</Project> </Project>
+58 -1
View File
@@ -36,7 +36,7 @@ namespace WPinternals
internal const bool IsPrerelease = false; internal const bool IsPrerelease = false;
#endif #endif
internal static readonly DateTime ExpirationDate = new(2023, 12, 21); internal static readonly DateTime ExpirationDate = new(2024, 12, 21);
internal static void CheckExpiration() internal static void CheckExpiration()
{ {
@@ -220,6 +220,52 @@ namespace WPinternals
public List<FFUEntry> FFURepository = new(); public List<FFUEntry> FFURepository = new();
internal void AddSecWimToRepository(string SecWimPath, string FirmwareVersion)
{
SecWimEntry Entry = SecWimRepository.Find(e => (e.FirmwareVersion == FirmwareVersion) && string.Equals(e.Path, SecWimPath, StringComparison.CurrentCultureIgnoreCase));
if (Entry == null)
{
LogFile.Log("Adding Secure WIM to repository: " + SecWimPath, LogType.FileAndConsole);
if (FirmwareVersion != null)
{
LogFile.Log("Firmware version: " + FirmwareVersion, LogType.FileAndConsole);
}
Entry = new SecWimEntry
{
Path = SecWimPath,
FirmwareVersion = FirmwareVersion
};
SecWimRepository.Add(Entry);
WriteConfig();
}
else
{
LogFile.Log("Secure WIM not added, because it was already present in the repository.", LogType.FileAndConsole);
}
}
internal void RemoveSecWimFromRepository(string SecWimPath)
{
int Count = 0;
SecWimRepository.Where(e => string.Equals(e.Path, SecWimPath, StringComparison.CurrentCultureIgnoreCase)).ToList().ForEach(e =>
{
Count++;
SecWimRepository.Remove(e);
});
if (Count == 0)
{
LogFile.Log("Secure WIM was not removed from repository because it was not present.", LogType.FileAndConsole);
}
else
{
LogFile.Log("Removed Secure WIM from repository: " + SecWimPath, LogType.FileAndConsole);
WriteConfig();
}
}
public List<SecWimEntry> SecWimRepository = new();
public List<EmergencyFileEntry> EmergencyRepository = new(); public List<EmergencyFileEntry> EmergencyRepository = new();
internal void AddEmergencyToRepository(string Type, string ProgrammerPath, string PayloadPath) internal void AddEmergencyToRepository(string Type, string ProgrammerPath, string PayloadPath)
@@ -344,6 +390,17 @@ namespace WPinternals
} }
} }
public class SecWimEntry
{
public string FirmwareVersion;
public string Path;
internal bool Exists()
{
return File.Exists(Path);
}
}
public class EmergencyFileEntry public class EmergencyFileEntry
{ {
public string Type; public string Type;