17 Commits
Author SHA1 Message Date
Gustave Monce d270cace79 Fix: device being null 2026-04-22 18:36:50 +02:00
Gustave Monce af61c9ad29 Preliminary support for UFP 2026-04-16 18:46:00 +02:00
Gustave Monce de4d5e577a Add preliminary SimpleIO support 2026-04-16 18:11:13 +02:00
Gustave Monce df02025a31 Update timebomb 2026-01-03 23:26:37 +01:00
Gustave Monce ad92ecdab3 Restructure assets into their own dedicated folders 2025-11-01 11:06:33 +01:00
Gustave Monce b3b037a3c8 Remove deprecated download command line options 2025-11-01 11:06:17 +01:00
Gustave Monce be15155c39 Deprecate MSR download fully as the MSR and repair avoidance services are fully deprecated as of 2025 2025-11-01 11:06:02 +01:00
Gustave Monce a17dae3931 Update project structure 2025-11-01 09:44:23 +01:00
Gustave Monce 7646e3fc76 Bump timebomb date 2025-11-01 09:42:59 +01:00
Gustave Monce 933e9e53b6 Migrate DiscUtils fat code to a standalone project dependency 2025-11-01 09:42:52 +01:00
Gustave Monce e838168127 Migrate 7zip code to a standalone project dependency 2025-11-01 09:31:14 +01:00
Gustave Monce 058cde0d91 Migrate WinUSBNet code to a standalone project dependency 2025-11-01 09:28:08 +01:00
Gustave Monce 1cc7a5cee4 Update Timebomb 2024-12-23 15:14:30 +01:00
Gustave Monce 132e21e58a Patcher: fix: broken go to labels in script engine 2024-10-22 21:22:30 +02:00
Gustave Monce 1e5da5452b Small fixes 2024-10-21 23:52:08 +02:00
Gustave Monce 6992ed3f70 Remove references to dead website 2024-10-21 23:30:50 +02:00
Gustave Monce bb9702a3c3 Patcher: fix compilation with dotnet 8 2024-10-21 23:25:50 +02:00
149 changed files with 6335 additions and 1648 deletions
+10
View File
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>_7zip</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
@@ -4,7 +4,7 @@ using System.Text;
namespace DiscUtils.CoreCompat namespace DiscUtils.CoreCompat
{ {
internal static class EncodingHelper public static class EncodingHelper
{ {
private static bool _registered; private static bool _registered;
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DiscUtils.Core" Version="0.16.13" />
</ItemGroup>
</Project>
@@ -28,7 +28,7 @@ using System.Text.RegularExpressions;
namespace DiscUtils.Internal namespace DiscUtils.Internal
{ {
internal static class Utilities public static class Utilities
{ {
/// <summary> /// <summary>
/// Converts between two arrays. /// Converts between two arrays.
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\DiscUtils.Core\DiscUtils.Core.WPI.csproj" />
</ItemGroup>
</Project>
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda // Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
// //
// Permission is hereby granted, free of charge, to any person obtaining a // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
+2 -19
View File
@@ -1,26 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0-windows</TargetFramework> <TargetFramework>net8.0-windows</TargetFramework>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<RootNamespace>Patcher</RootNamespace> <RootNamespace>Patcher</RootNamespace>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
</PropertyGroup> <Platforms>x86</Platforms>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<OutputPath>bin\x86\Debug\</OutputPath>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<OutputPath>bin\x64\Debug\</OutputPath>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="..\Patcher\ArmCompiler.cs"> <Compile Include="..\Patcher\ArmCompiler.cs">
@@ -50,7 +35,5 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Gee.External.Capstone" Version="2.0.2" /> <PackageReference Include="Gee.External.Capstone" Version="2.0.2" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda // Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
// //
// Patch Definition Script for Boot Unlock and Root Access on Windows Mobile // Patch Definition Script for Boot Unlock and Root Access on Windows Mobile
// //
@@ -81,7 +81,7 @@ PatchDefinition Name="RootAccess-MainOS" VersionFrom="EFIESP\Windows\System32\Bo
PatchFile Path="Windows\System32\ntoskrnl.exe" PatchFile Path="Windows\System32\ntoskrnl.exe"
// Fase 1: find all kernel-functions // Phase 1: find all kernel-functions
JumpToExport "SeAccessCheckWithHint" JumpToExport "SeAccessCheckWithHint"
CreateLabel "SeAccessCheckWithHint" CreateLabel "SeAccessCheckWithHint"
@@ -150,7 +150,7 @@ PatchDefinition Name="RootAccess-MainOS" VersionFrom="EFIESP\Windows\System32\Bo
JumpToExport "ObReferenceObjectByHandleWithTag" JumpToExport "ObReferenceObjectByHandleWithTag"
CreateLabel "ObReferenceObjectByHandleWithTag" CreateLabel "ObReferenceObjectByHandleWithTag"
// Fase 2: patches // Phase 2: patches
JumpToLabel "SeAccessCheckByType" JumpToLabel "SeAccessCheckByType"
+1 -1
View File
@@ -183,7 +183,7 @@
this.label4.Name = "label4"; this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(117, 13); this.label4.Size = new System.Drawing.Size(117, 13);
this.label4.TabIndex = 3; this.label4.TabIndex = 3;
this.label4.Text = "Patch defintions xml-file"; this.label4.Text = "Patch definitions xml-file";
// //
// txtConsole // txtConsole
// //
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda // Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
// //
// Permission is hereby granted, free of charge, to any person obtaining a // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda // Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
// //
// Permission is hereby granted, free of charge, to any person obtaining a // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
@@ -1,16 +1,15 @@
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following // General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information // set of attributes. Change these attribute values to modify the information
// associated with an assembly. // associated with an assembly.
[assembly: AssemblyTitle("AutoPatcher")] [assembly: AssemblyTitle("ARM Auto-patcher")]
[assembly: AssemblyDescription("")] [assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")] [assembly: AssemblyCompany("WPinternals.net")]
[assembly: AssemblyProduct("AutoPatcher")] [assembly: AssemblyProduct("ARM Auto-patcher")]
[assembly: AssemblyCopyright("Copyright © 2018")] [assembly: AssemblyCopyright("Copyright © 2018 by Rene Lergner")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
+22 -16
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda // Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
// //
// Permission is hereby granted, free of charge, to any person obtaining a // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
@@ -617,7 +617,7 @@ namespace Patcher
// Patch bytes in buffer // Patch bytes in buffer
System.Buffer.BlockCopy(Bytes, 0, FileBuffer, (int)RawOffset, Bytes.Length); System.Buffer.BlockCopy(Bytes, 0, FileBuffer, (int)RawOffset, Bytes.Length);
// Add patch to defintions (original and patched bytes) // Add patch to definitions (original and patched bytes)
Patch CurrentPatch = FilePatchCollection.Patches.Find(p => p.Address == RawOffset); Patch CurrentPatch = FilePatchCollection.Patches.Find(p => p.Address == RawOffset);
if (CurrentPatch == null) if (CurrentPatch == null)
{ {
@@ -1487,13 +1487,16 @@ namespace Patcher
if (FindSuccess) if (FindSuccess)
{ {
FunctionDescriptor FoundLabel = Labels.Find(l => string.Equals(l.Name, Label, StringComparison.CurrentCultureIgnoreCase)); CodeLine NewLine = ScriptCode.Find(l => string.Equals(l.Label, Label, StringComparison.CurrentCultureIgnoreCase));
if (FoundLabel == null) if (NewLine == null)
throw new ScriptExecutionException("Label not found: " + Label); {
throw new ScriptExecutionException("Label " + Label + " not found");
WriteLog("Condition was found, jumping to label: " + Label); }
WriteLog("New virtual address: 0x" + FoundLabel.VirtualAddress.ToString("X8")); else
CurrentVirtualAddressTarget = FoundLabel.VirtualAddress; {
Pointer = ScriptCode.IndexOf(NewLine);
WriteLog("Go to label: " + Label);
}
} }
} }
@@ -1504,13 +1507,16 @@ namespace Patcher
if (!FindSuccess) if (!FindSuccess)
{ {
FunctionDescriptor FoundLabel = Labels.Find(l => string.Equals(l.Name, Label, StringComparison.CurrentCultureIgnoreCase)); CodeLine NewLine = ScriptCode.Find(l => string.Equals(l.Label, Label, StringComparison.CurrentCultureIgnoreCase));
if (FoundLabel == null) if (NewLine == null)
throw new ScriptExecutionException("Label not found: " + Label); {
throw new ScriptExecutionException("Label " + Label + " not found");
WriteLog("Condition was not found, jumping to label: " + Label); }
WriteLog("New virtual address: 0x" + FoundLabel.VirtualAddress.ToString("X8")); else
CurrentVirtualAddressTarget = FoundLabel.VirtualAddress; {
Pointer = ScriptCode.IndexOf(NewLine);
WriteLog("Go to label: " + Label);
}
} }
} }
+4 -44
View File
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio Version 17
VisualStudioVersion = 15.0.28010.2041 VisualStudioVersion = 17.12.35323.107
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Patcher", "Patcher\Patcher.csproj", "{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Patcher", "Patcher\Patcher.csproj", "{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}"
EndProject EndProject
@@ -9,66 +9,26 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoPatcher", "AutoPatcher\
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
.NET45Debug|Any CPU = .NET45Debug|Any CPU
.NET45Debug|x64 = .NET45Debug|x64
.NET45Debug|x86 = .NET45Debug|x86 .NET45Debug|x86 = .NET45Debug|x86
.NET45Release|Any CPU = .NET45Release|Any CPU
.NET45Release|x64 = .NET45Release|x64
.NET45Release|x86 = .NET45Release|x86 .NET45Release|x86 = .NET45Release|x86
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86 Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86 Release|x86 = Release|x86
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Debug|Any CPU.Build.0 = Debug|Any CPU
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Debug|x64.ActiveCfg = Debug|x64
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Debug|x64.Build.0 = Debug|x64
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Debug|x86.ActiveCfg = Debug|x86 {B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Debug|x86.ActiveCfg = Debug|x86
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Debug|x86.Build.0 = Debug|x86 {B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Debug|x86.Build.0 = Debug|x86
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Release|Any CPU.ActiveCfg = Release|Any CPU
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Release|Any CPU.Build.0 = Release|Any CPU
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Release|x64.ActiveCfg = Release|x64
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Release|x64.Build.0 = Release|x64
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Release|x86.ActiveCfg = Release|x86 {B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Release|x86.ActiveCfg = Release|x86
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Release|x86.Build.0 = Release|x86 {B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Release|x86.Build.0 = Release|x86
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Debug|x86.ActiveCfg = Debug|x86
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Debug|Any CPU.Build.0 = Debug|Any CPU {B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Debug|x86.Build.0 = Debug|x86
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Debug|x64.ActiveCfg = Debug|x64
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Debug|x64.Build.0 = Debug|x64
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Debug|x86.ActiveCfg = Debug|Any CPU
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Debug|x86.Build.0 = Debug|Any CPU
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Release|Any CPU.Build.0 = Release|Any CPU
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Release|x64.ActiveCfg = Release|x64
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Release|x64.Build.0 = Release|x64
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Release|x86.ActiveCfg = Release|Any CPU {B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Release|x86.ActiveCfg = Release|Any CPU
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Release|x86.Build.0 = Release|Any CPU {B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Release|x86.Build.0 = Release|Any CPU
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Debug|Any CPU.ActiveCfg = Debug|Any CPU
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Debug|Any CPU.Build.0 = Debug|Any CPU
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Debug|x64.ActiveCfg = Debug|x64
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Debug|x64.Build.0 = Debug|x64
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Debug|x86.ActiveCfg = Debug|x86 {95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Debug|x86.ActiveCfg = Debug|x86
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Debug|x86.Build.0 = Debug|x86 {95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Debug|x86.Build.0 = Debug|x86
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Release|Any CPU.ActiveCfg = Release|Any CPU
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Release|Any CPU.Build.0 = Release|Any CPU
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Release|x64.ActiveCfg = Release|x64
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Release|x64.Build.0 = Release|x64
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Release|x86.ActiveCfg = Release|x86 {95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Release|x86.ActiveCfg = Release|x86
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Release|x86.Build.0 = Release|x86 {95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Release|x86.Build.0 = Release|x86
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Debug|x64.ActiveCfg = Debug|x64
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Debug|x64.Build.0 = Debug|x64
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Debug|x86.ActiveCfg = Debug|x86 {95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Debug|x86.ActiveCfg = Debug|x86
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Debug|x86.Build.0 = Debug|x86 {95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Debug|x86.Build.0 = Debug|x86
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Release|Any CPU.Build.0 = Release|Any CPU
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Release|x64.ActiveCfg = Release|x64
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Release|x64.Build.0 = Release|x64
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Release|x86.ActiveCfg = Release|x86 {95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Release|x86.ActiveCfg = Release|x86
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Release|x86.Build.0 = Release|x86 {95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Release|x86.Build.0 = Release|x86
EndGlobalSection EndGlobalSection
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda // Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
// //
// Permission is hereby granted, free of charge, to any person obtaining a // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda // Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
// //
// Permission is hereby granted, free of charge, to any person obtaining a // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda // Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
// //
// Permission is hereby granted, free of charge, to any person obtaining a // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
+3 -3
View File
@@ -184,7 +184,7 @@
this.label4.Name = "label4"; this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(117, 13); this.label4.Size = new System.Drawing.Size(117, 13);
this.label4.TabIndex = 3; this.label4.TabIndex = 3;
this.label4.Text = "Patch defintions xml-file"; this.label4.Text = "Patch definitions xml-file";
// //
// label5 // label5
// //
@@ -193,7 +193,7 @@
this.label5.Name = "label5"; this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(107, 13); this.label5.Size = new System.Drawing.Size(107, 13);
this.label5.TabIndex = 6; this.label5.TabIndex = 6;
this.label5.Text = "Patch defintion name"; this.label5.Text = "Patch definition name";
// //
// cmbPatchDefinitionName // cmbPatchDefinitionName
// //
@@ -239,7 +239,7 @@
this.label7.Name = "label7"; this.label7.Name = "label7";
this.label7.Size = new System.Drawing.Size(269, 13); this.label7.Size = new System.Drawing.Size(269, 13);
this.label7.TabIndex = 10; this.label7.TabIndex = 10;
this.label7.Text = "Folder for target file relative to Patch Defintion rootfolder"; this.label7.Text = "Folder for target file relative to Patch Definition rootfolder";
// //
// label8 // label8
// //
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda // Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
// //
// Permission is hereby granted, free of charge, to any person obtaining a // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
+7 -7
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda // Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
// //
// Permission is hereby granted, free of charge, to any person obtaining a // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
@@ -41,8 +41,8 @@ namespace Patcher
/// <param name="VirtualAddress"></param> /// <param name="VirtualAddress"></param>
/// <param name="CodeType"></param> /// <param name="CodeType"></param>
/// <param name="ArmCodeFragment"></param> /// <param name="ArmCodeFragment"></param>
/// <param name="PatchDefintionsXmlPath"></param> /// <param name="PatchDefinitionsXmlPath"></param>
public static void AddPatch(string InputFilePath, string OutputFilePath, string PatchDefinitionName, string TargetVersionDescription, string TargetFilePath, string PathToVisualStudioWithWP8SDK, UInt32 VirtualAddress, CodeType CodeType, string ArmCodeFragment, string PatchDefintionsXmlPath) public static void AddPatch(string InputFilePath, string OutputFilePath, string PatchDefinitionName, string TargetVersionDescription, string TargetFilePath, string PathToVisualStudioWithWP8SDK, UInt32 VirtualAddress, CodeType CodeType, string ArmCodeFragment, string PatchDefinitionsXmlPath)
{ {
SHA1Managed SHA = new(); SHA1Managed SHA = new();
@@ -65,8 +65,8 @@ namespace Patcher
RawOffset = PeFile.ConvertVirtualAddressToRawOffset(VirtualAddress); RawOffset = PeFile.ConvertVirtualAddressToRawOffset(VirtualAddress);
// Add or replace patch // Add or replace patch
string PatchDefintionsXml = File.ReadAllText(PatchDefintionsXmlPath); string PatchDefinitionsXml = File.ReadAllText(PatchDefinitionsXmlPath);
PatchEngine PatchEngine = new(PatchDefintionsXml); PatchEngine PatchEngine = new(PatchDefinitionsXml);
PatchDefinition PatchDefinition = PatchEngine.PatchDefinitions.Find(d => string.Equals(d.Name, PatchDefinitionName, StringComparison.CurrentCultureIgnoreCase)); PatchDefinition PatchDefinition = PatchEngine.PatchDefinitions.Find(d => string.Equals(d.Name, PatchDefinitionName, StringComparison.CurrentCultureIgnoreCase));
if (PatchDefinition == null) if (PatchDefinition == null)
{ {
@@ -143,8 +143,8 @@ namespace Patcher
if (OutputFilePath != null) if (OutputFilePath != null)
File.WriteAllBytes(OutputFilePath, Binary); File.WriteAllBytes(OutputFilePath, Binary);
// Write PatchDefintions // Write PatchDefinitions
PatchEngine.WriteDefinitions(PatchDefintionsXmlPath); PatchEngine.WriteDefinitions(PatchDefinitionsXmlPath);
} }
private static UInt32 CalculateChecksum(byte[] PEFile) private static UInt32 CalculateChecksum(byte[] PEFile)
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda // Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
// //
// Permission is hereby granted, free of charge, to any person obtaining a // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
+2 -2
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda // Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
// //
// Permission is hereby granted, free of charge, to any person obtaining a // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
@@ -53,7 +53,7 @@ namespace WPinternals
FileWriter.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>"); FileWriter.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
FileWriter.WriteLine(""); FileWriter.WriteLine("");
FileWriter.WriteLine("<!--"); FileWriter.WriteLine("<!--");
FileWriter.WriteLine("Copyright(c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda"); FileWriter.WriteLine("Copyright(c) 2018, Rene Lergner - @Heathcliff74xda");
FileWriter.WriteLine(""); FileWriter.WriteLine("");
FileWriter.WriteLine("Permission is hereby granted, free of charge, to any person obtaining a"); FileWriter.WriteLine("Permission is hereby granted, free of charge, to any person obtaining a");
FileWriter.WriteLine("copy of this software and associated documentation files(the \"Software\"),"); FileWriter.WriteLine("copy of this software and associated documentation files(the \"Software\"),");
+3 -19
View File
@@ -1,28 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0-windows</TargetFramework> <TargetFramework>net8.0-windows</TargetFramework>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
</PropertyGroup> <Platforms>x86</Platforms>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<OutputPath>bin\x86\Debug\</OutputPath>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<OutputPath>bin\x64\Debug\</OutputPath>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" /> <ProjectReference Include="..\AutoPatcher\AutoPatcher.csproj" />
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda // Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
// //
// Permission is hereby granted, free of charge, to any person obtaining a // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda // Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
// //
// Permission is hereby granted, free of charge, to any person obtaining a // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
+1789 -3
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -77,14 +77,14 @@ namespace WPinternals
Registration.CheckExpiration(); Registration.CheckExpiration();
string PatchDefintionsXml; string PatchDefintionsXml;
string PatchDefintionsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "PatchDefintions.xml"); string PatchDefintionsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets", "PatchDefintions.xml");
if (File.Exists(PatchDefintionsPath)) if (File.Exists(PatchDefintionsPath))
{ {
PatchDefintionsXml = File.ReadAllText(PatchDefintionsPath); PatchDefintionsXml = File.ReadAllText(PatchDefintionsPath);
} }
else else
{ {
using Stream stream = System.Reflection.Assembly.GetEntryAssembly().GetManifestResourceStream("WPinternals.PatchDefinitions.xml"); using Stream stream = System.Reflection.Assembly.GetEntryAssembly().GetManifestResourceStream("WPinternals.Assets.PatchDefinitions.xml");
using StreamReader sr = new(stream); using StreamReader sr = new(stream);
PatchDefintionsXml = sr.ReadToEnd(); PatchDefintionsXml = sr.ReadToEnd();
} }

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

-257
View File
@@ -28,7 +28,6 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using WPinternals.Config; using WPinternals.Config;
using WPinternals.HelperClasses; using WPinternals.HelperClasses;
using WPinternals.Models.Lumia.MSR;
using WPinternals.Models.Lumia.NCSd; using WPinternals.Models.Lumia.NCSd;
using WPinternals.Models.UEFIApps.BootMgr; using WPinternals.Models.UEFIApps.BootMgr;
using WPinternals.Models.UEFIApps.Flash; using WPinternals.Models.UEFIApps.Flash;
@@ -1268,262 +1267,6 @@ namespace WPinternals
LogFile.Log("Root access enabled on image", LogType.FileAndConsole); LogFile.Log("Root access enabled on image", LogType.FileAndConsole);
break; break;
case "downloademergency":
LogFile.Log("Command: Download Emergency files", LogType.FileAndConsole);
Notifier = new PhoneNotifierViewModel();
UIContext.Send(s => Notifier.Start(), null);
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Normal)
{
NormalModel = (NokiaCareSuiteModel)Notifier.CurrentModel;
ProductType = NormalModel.ExecuteJsonMethodAsString("ReadManufacturerModelName", "ManufacturerModelName");
if (ProductType.Contains('_'))
{
ProductType = ProductType.Substring(0, ProductType.IndexOf('_'));
}
}
else if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
{
BootMgrModel = (LumiaBootManagerAppModel)Notifier.CurrentModel;
BootManagerInfo = BootMgrModel.ReadPhoneInfo();
//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
{
NormalModel = (NokiaCareSuiteModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Normal);
ProductType = NormalModel.ExecuteJsonMethodAsString("ReadManufacturerModelName", "ManufacturerModelName");
if (ProductType.Contains('_'))
{
ProductType = ProductType.Substring(0, ProductType.IndexOf('_'));
}
}
URLs = LumiaDownloadModel.SearchEmergencyFiles(ProductType);
if (URLs != null)
{
DownloadFolder = args.Length >= 3
? args[2]
: Environment.ExpandEnvironmentVariables("%ALLUSERSPROFILE%\\WPInternals\\Repository\\" + ProductType.ToUpper());
if (!Directory.Exists(DownloadFolder))
{
Directory.CreateDirectory(DownloadFolder);
}
LogFile.Log("Download folder: " + DownloadFolder, LogType.FileAndConsole);
for (int i = 0; i < URLs.Length; i++)
{
LogFile.Log("URL: " + URLs[i], LogType.FileAndConsole);
URI = new Uri(URLs[i]);
EmergencyFileName = Path.GetFileName(URI.LocalPath);
LogFile.Log("File: " + EmergencyFileName, LogType.FileAndConsole);
EmergencyFilePath = Path.Combine(DownloadFolder, EmergencyFileName);
if (i == 0)
{
ProgrammerPath = EmergencyFilePath;
}
else
{
PayloadPath = EmergencyFilePath;
}
LogFile.Log("Downloading...", LogType.FileAndConsole);
using (System.Net.WebClient myWebClient = new())
{
await myWebClient.DownloadFileTaskAsync(URLs[i], EmergencyFilePath);
}
LogFile.Log("Download finished", LogType.FileAndConsole);
}
App.Config.AddEmergencyToRepository(ProductType, ProgrammerPath, PayloadPath);
}
Notifier.Stop();
break;
case "downloademergencybyproducttype":
LogFile.Log("Command: Download Emergency files", LogType.FileAndConsole);
if (args.Length < 3)
{
throw new WPinternalsException("Wrong number of arguments. Usage: WPinternals.exe -DownloadEmergencyByProductType <Product type> <Optional: Download folder>");
}
ProductType = args[2];
URLs = LumiaDownloadModel.SearchEmergencyFiles(ProductType);
if (URLs != null)
{
DownloadFolder = args.Length >= 4
? args[3]
: Environment.ExpandEnvironmentVariables("%ALLUSERSPROFILE%\\WPInternals\\Repository\\" + ProductType.ToUpper());
if (!Directory.Exists(DownloadFolder))
{
Directory.CreateDirectory(DownloadFolder);
}
LogFile.Log("Download folder: " + DownloadFolder, LogType.FileAndConsole);
for (int i = 0; i < URLs.Length; i++)
{
LogFile.Log("URL: " + URLs[i], LogType.FileAndConsole);
URI = new Uri(URLs[i]);
EmergencyFileName = Path.GetFileName(URI.LocalPath);
LogFile.Log("File: " + EmergencyFileName, LogType.FileAndConsole);
EmergencyFilePath = Path.Combine(DownloadFolder, EmergencyFileName);
if (i == 0)
{
ProgrammerPath = EmergencyFilePath;
}
else
{
PayloadPath = EmergencyFilePath;
}
LogFile.Log("Downloading...", LogType.FileAndConsole);
using (System.Net.WebClient myWebClient = new())
{
await myWebClient.DownloadFileTaskAsync(URLs[i], EmergencyFilePath);
}
LogFile.Log("Download finished", LogType.FileAndConsole);
}
App.Config.AddEmergencyToRepository(ProductType, ProgrammerPath, PayloadPath);
}
break;
case "downloadall":
LogFile.Log("Command: Download all", LogType.FileAndConsole);
Notifier = new PhoneNotifierViewModel();
UIContext.Send(s => Notifier.Start(), null);
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Normal)
{
NormalModel = (NokiaCareSuiteModel)Notifier.CurrentModel;
ProductType = NormalModel.ExecuteJsonMethodAsString("ReadManufacturerModelName", "ManufacturerModelName");
if (ProductType.Contains('_'))
{
ProductType = ProductType.Substring(0, ProductType.IndexOf('_'));
}
}
else if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader)
{
BootMgrModel = (LumiaBootManagerAppModel)Notifier.CurrentModel;
BootManagerInfo = BootMgrModel.ReadPhoneInfo();
//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
{
NormalModel = (NokiaCareSuiteModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Normal);
ProductType = NormalModel.ExecuteJsonMethodAsString("ReadManufacturerModelName", "ManufacturerModelName");
if (ProductType.Contains('_'))
{
ProductType = ProductType.Substring(0, ProductType.IndexOf('_'));
}
}
DownloadFolder = args.Length >= 3
? args[2]
: Environment.ExpandEnvironmentVariables("%ALLUSERSPROFILE%\\WPInternals\\Repository\\" + ProductType.ToUpper());
if (!Directory.Exists(DownloadFolder))
{
Directory.CreateDirectory(DownloadFolder);
}
URLs = LumiaDownloadModel.SearchEmergencyFiles(ProductType);
if (URLs != null)
{
for (int i = 0; i < URLs.Length; i++)
{
LogFile.Log("URL: " + URLs[i], LogType.FileAndConsole);
URI = new Uri(URLs[i]);
EmergencyFileName = Path.GetFileName(URI.LocalPath);
LogFile.Log("File: " + EmergencyFileName, LogType.FileAndConsole);
EmergencyFilePath = Path.Combine(DownloadFolder, EmergencyFileName);
if (i == 0)
{
ProgrammerPath = EmergencyFilePath;
}
else
{
PayloadPath = EmergencyFilePath;
}
LogFile.Log("Downloading...", LogType.FileAndConsole);
using (System.Net.WebClient myWebClient = new())
{
await myWebClient.DownloadFileTaskAsync(URLs[i], EmergencyFilePath);
}
LogFile.Log("Download finished", LogType.FileAndConsole);
}
App.Config.AddEmergencyToRepository(ProductType, ProgrammerPath, PayloadPath);
}
if (!App.Config.FFURepository.Any(e => App.PatchEngine.PatchDefinitions.First(p => p.Name == "SecureBootHack-V2-EFIESP").TargetVersions.Any(v => v.Description == e.OSVersion)))
{
throw new WPinternalsException("Unable to find compatible FFU", "No donor-FFU has been found in the repository with a supported OS version. You can add a donor-FFU within the download section of the tool or by using the command line. A donor-FFU can be for a different device and a different CPU than your device. It is only used to gather Operating System specific binaries to be patched and used as part of the unlock process.");
}
Notifier.Stop();
break;
case "downloadallbyproducttype":
LogFile.Log("Command: Download all by Product Type", LogType.FileAndConsole);
if (args.Length < 3)
{
throw new ArgumentException("Wrong number of arguments. Usage: WPinternals.exe -DownloadAllByProductType <Product type> <Optional: Download folder>");
}
ProductType = args[2];
LogFile.Log("Product type: " + ProductType, LogType.FileAndConsole);
DownloadFolder = args.Length >= 4
? args[3]
: Environment.ExpandEnvironmentVariables("%ALLUSERSPROFILE%\\WPInternals\\Repository\\" + ProductType.ToUpper());
if (!Directory.Exists(DownloadFolder))
{
Directory.CreateDirectory(DownloadFolder);
}
URLs = LumiaDownloadModel.SearchEmergencyFiles(ProductType);
if (URLs != null)
{
for (int i = 0; i < URLs.Length; i++)
{
LogFile.Log("URL: " + URLs[i], LogType.FileAndConsole);
URI = new Uri(URLs[i]);
EmergencyFileName = Path.GetFileName(URI.LocalPath);
LogFile.Log("File: " + EmergencyFileName, LogType.FileAndConsole);
EmergencyFilePath = Path.Combine(DownloadFolder, EmergencyFileName);
if (i == 0)
{
ProgrammerPath = EmergencyFilePath;
}
else
{
PayloadPath = EmergencyFilePath;
}
LogFile.Log("Downloading...", LogType.FileAndConsole);
using (System.Net.WebClient myWebClient = new())
{
await myWebClient.DownloadFileTaskAsync(URLs[i], EmergencyFilePath);
}
LogFile.Log("Download finished", LogType.FileAndConsole);
}
App.Config.AddEmergencyToRepository(ProductType, ProgrammerPath, PayloadPath);
}
if (!App.Config.FFURepository.Any(e => App.PatchEngine.PatchDefinitions.First(p => p.Name == "SecureBootHack-V2-EFIESP").TargetVersions.Any(v => v.Description == e.OSVersion)))
{
throw new WPinternalsException("Unable to find compatible FFU", "No donor-FFU has been found in the repository with a supported OS version. You can add a donor-FFU within the download section of the tool or by using the command line. A donor-FFU can be for a different device and a different CPU than your device. It is only used to gather Operating System specific binaries to be patched and used as part of the unlock process.");
}
break;
case "rewritepartitionsfrommassstorage": case "rewritepartitionsfrommassstorage":
if (args.Length < 2) if (args.Length < 2)
{ {
+1 -1
View File
@@ -33,7 +33,7 @@ namespace WPinternals.Config
internal const bool IsPrerelease = false; internal const bool IsPrerelease = false;
#endif #endif
internal static readonly DateTime ExpirationDate = new(2024, 12, 21); internal static readonly DateTime ExpirationDate = new(2027, 4, 1);
internal static void CheckExpiration() internal static void CheckExpiration()
{ {
@@ -1,113 +0,0 @@
// 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.Net;
using System.Xml;
using WPinternals.HelperClasses;
namespace WPinternals.Models.Lumia.MSR
{
internal static class LumiaDownloadModel
{
internal static string[] SearchEmergencyFiles(string ProductType)
{
ProductType = ProductType.ToUpper();
if (ProductType.StartsWith("RM") && !ProductType.StartsWith("RM-"))
{
ProductType = "RM-" + ProductType[2..];
}
LogFile.Log("Getting Emergency files for: " + ProductType, LogType.FileAndConsole);
if (ProductType == "RM-1072" || ProductType == "RM-1073")
{
LogFile.Log("Due to mix-up in online-repository, redirecting to emergency files of RM-1113", LogType.FileAndConsole);
ProductType = "RM-1113";
}
List<string> Result = [];
WebClient Client = new();
string Src;
string FileName;
string Config = null;
try
{
Config = Client.DownloadString($"https://repairavoidance.blob.core.windows.net/packages/EmergencyFlash/{ProductType}/emergency_flash_config.xml");
}
catch (Exception ex)
{
LogFile.Log("An unexpected error happened", LogType.FileAndConsole);
LogFile.Log(ex.GetType().ToString(), LogType.FileAndConsole);
LogFile.Log(ex.Message, LogType.FileAndConsole);
LogFile.Log(ex.StackTrace, LogType.FileAndConsole);
LogFile.Log("Emergency files for " + ProductType + " not found", LogType.FileAndConsole);
return null;
}
Client.Dispose();
XmlDocument Doc = new();
Doc.LoadXml(Config);
// Hex
XmlNode Node = Doc.SelectSingleNode("//emergency_flash_config/hex_flasher");
if (Node != null)
{
FileName = Node.Attributes["image_path"].InnerText;
Src = $"https://repairavoidance.blob.core.windows.net/packages/EmergencyFlash/{ProductType}/{FileName}";
LogFile.Log("Hex-file: " + Src);
Result.Add(Src);
}
// Mbn
Node = Doc.SelectSingleNode("//emergency_flash_config/mbn_image");
if (Node != null)
{
FileName = Node.Attributes["image_path"].InnerText;
Src = $"https://repairavoidance.blob.core.windows.net/packages/EmergencyFlash/{ProductType}/{FileName}";
LogFile.Log("Mbn-file: " + Src);
Result.Add(Src);
}
// Ede
foreach (XmlNode SubNode in Doc.SelectNodes("//emergency_flash_config/first_boot_images/first_boot_image"))
{
FileName = SubNode.Attributes["image_path"].InnerText;
Src = $"https://repairavoidance.blob.core.windows.net/packages/EmergencyFlash/{ProductType}/{FileName}";
LogFile.Log("Firehose-programmer-file: " + Src);
Result.Add(Src);
}
// Edp
foreach (XmlNode SubNode in Doc.SelectNodes("//emergency_flash_config/second_boot_firehose_single_image/firehose_image"))
{
FileName = SubNode.Attributes["image_path"].InnerText;
Src = $"https://repairavoidance.blob.core.windows.net/packages/EmergencyFlash/{ProductType}/{FileName}";
LogFile.Log("Firehose-payload-file: " + Src);
Result.Add(Src);
}
return [.. Result];
}
}
}
+1 -9
View File
@@ -31,17 +31,9 @@ namespace WPinternals.Models.Lumia
internal readonly object UsbLock = new(); internal readonly object UsbLock = new();
public NokiaPhoneModel(string DevicePath) public NokiaPhoneModel(string DevicePath)
{
// Mass Storage device is not WinUSB
try
{ {
Device = new USBDevice(DevicePath); Device = new USBDevice(DevicePath);
} }
catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
}
public void ResetDevice() public void ResetDevice()
{ {
@@ -93,7 +85,7 @@ namespace WPinternals.Models.Lumia
if (disposing) if (disposing)
{ {
Device?.Dispose(); Device.Dispose();
} }
// Clean unmanaged resources here. // Clean unmanaged resources here.
+24 -5
View File
@@ -28,8 +28,9 @@ using WPinternals.Models.Lumia;
namespace WPinternals namespace WPinternals
{ {
internal class MassStorage : NokiaPhoneModel internal class MassStorage : IDisposable
{ {
protected bool Disposed = false;
internal string Drive = null; internal string Drive = null;
internal string PhysicalDrive = null; internal string PhysicalDrive = null;
internal string VolumeLabel = null; internal string VolumeLabel = null;
@@ -39,7 +40,7 @@ namespace WPinternals
private string Serial; private string Serial;
internal MassStorage(string DevicePath) : base(DevicePath) internal MassStorage(string DevicePath)
{ {
try try
{ {
@@ -131,7 +132,27 @@ namespace WPinternals
} }
} }
protected override void Dispose(bool disposing) /// <summary>
/// Disposes the UsbDevice including all unmanaged WinUSB handles. This function
/// should be called when the UsbDevice object is no longer in use, otherwise
/// unmanaged handles will remain open until the garbage collector finalizes the
/// object.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Finalizer for the UsbDevice. Disposes all unmanaged handles.
/// </summary>
~MassStorage()
{
Dispose(false);
}
protected void Dispose(bool disposing)
{ {
if (Disposed) if (Disposed)
{ {
@@ -141,8 +162,6 @@ namespace WPinternals
if (disposing) if (disposing)
{ {
CloseVolume(); CloseVolume();
base.Dispose(disposing);
} }
} }
@@ -0,0 +1,671 @@
/*
* MIT License
*
* Copyright (c) 2026 The DuoWOA authors
*
* 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 MadWizard.WinUSBNet;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Resources;
using System.Text;
namespace WPinternals.Models.SimpleIO
{
public partial class SimpleIOModel : IDisposable
{
// TODO: Use Locks!
// TODO: Timeouts!!
// TODO: Handle timeout
// TODO: Check functionality on true proto
// TODO: WIM Transfers!
// TODO: FFU Transfers!
// TODO: Missing command implementations nowhere to be found!
private bool Disposed = false;
private readonly USBDevice USBDevice;
private readonly USBPipe InputPipe;
private readonly USBPipe OutputPipe;
private readonly object UsbLock = new();
private bool HasCachedV2Results = false;
private (long curPosition, Guid guid, bool supportsFastFlash, bool supportsCompatFastFlash, int clientVersion, Guid DeviceUniqueID, string DeviceFriendlyName) CachedV2Results = (0, new Guid(), false, false, 0, new Guid(), "");
public SimpleIOModel(string DevicePath)
{
USBDevice = new USBDevice(DevicePath);
// LineSetState, 1
// Not sure why this is needed
byte LineSetState = 34;
USBDevice.ControlOut(33, LineSetState, 1, 0);
foreach (USBPipe Pipe in USBDevice.Pipes)
{
if (Pipe.IsIn)
{
InputPipe = Pipe;
}
if (Pipe.IsOut)
{
OutputPipe = Pipe;
}
}
if (InputPipe == null || OutputPipe == null)
{
throw new Exception("Invalid USB device!");
}
}
public byte[]? ExecuteRawMethod(byte[] RawMethod)
{
return ExecuteRawMethod(RawMethod, RawMethod.Length);
}
public byte[]? ExecuteRawMethod(byte[] RawMethod, int Length)
{
byte[] Buffer = new byte[0xF000]; // Should be at least 0x4408 for receiving the GPT packet.
byte[]? Result = null;
lock (UsbLock)
{
OutputPipe.Write(RawMethod, 0, Length);
try
{
int OutputLength = InputPipe.Read(Buffer);
Result = new byte[OutputLength];
System.Buffer.BlockCopy(Buffer, 0, Result, 0, OutputLength);
}
catch { } // Reboot command looses connection
}
return Result;
}
public void ExecuteRawVoidMethod(byte[] RawMethod)
{
ExecuteRawVoidMethod(RawMethod, RawMethod.Length);
}
public void ExecuteRawVoidMethod(byte[] RawMethod, int Length)
{
lock (UsbLock)
{
OutputPipe.Write(RawMethod, 0, Length);
}
}
public (long curPosition, Guid guid, bool supportsFastFlash, bool supportsCompatFastFlash, int clientVersion, Guid DeviceUniqueID, string DeviceFriendlyName) GetIdV2()
{
if (HasCachedV2Results)
{
return CachedV2Results;
}
int num = 0;
(long curPosition, Guid guid, bool supportsFastFlash, bool supportsCompatFastFlash, int clientVersion, Guid DeviceUniqueID, string DeviceFriendlyName) ID;
do
{
ID = GetId();
num++;
}
while (!ID.supportsFastFlash && !ID.supportsCompatFastFlash && ID.clientVersion < 2 && num < COMPATFLASH_MagicSequence);
CachedV2Results = ID;
HasCachedV2Results = true;
return ID;
}
private const int COMPATFLASH_MagicSequence = 1000;
private const byte INDEX_SUPPORTCOMPATFLASH = 15;
private const byte INDEX_SUPPORTV2CMDS = 14;
private const byte INDEX_SUPPORTFASTFLASH = 0;
// 1
public (long curPosition, Guid guid, bool supportsFastFlash, bool supportsCompatFastFlash, int clientVersion, Guid DeviceUniqueID, string DeviceFriendlyName) GetId()
{
bool supportsFastFlash = false;
bool supportsCompatFastFlash = false;
int clientVersion = 1;
byte[] buffer = ExecuteRawMethod([(byte)SioOpcode.SioId])!;
using MemoryStream stream = new(buffer);
using BinaryReader binaryReader = new(stream);
long curPosition = binaryReader.ReadInt64();
byte[] guidBuffer = binaryReader.ReadBytes(16);
Guid guid = new(guidBuffer);
if (guidBuffer[INDEX_SUPPORTFASTFLASH] >= 1)
{
supportsFastFlash = true;
}
else if (guidBuffer[INDEX_SUPPORTCOMPATFLASH] == 1)
{
supportsCompatFastFlash = true;
}
if (guidBuffer[INDEX_SUPPORTV2CMDS] >= 1)
{
clientVersion = guidBuffer[INDEX_SUPPORTV2CMDS] + 1;
}
Guid DeviceUniqueID = new(binaryReader.ReadBytes(16));
string DeviceFriendlyName = binaryReader.ReadString();
return (curPosition, guid, supportsFastFlash, supportsCompatFastFlash, clientVersion, DeviceUniqueID, DeviceFriendlyName);
}
// 7
public bool ContinueBoot()
{
byte[] buffer = ExecuteRawMethod([(byte)SioOpcode.SioSkip])!;
return buffer[0] == 3;
}
// 8
public bool EndTransfer()
{
HasCachedV2Results = false;
GetIdV2();
if (CachedV2Results.curPosition == 0L)
{
return true;
}
ExecuteRawVoidMethod([(byte)SioOpcode.SioSkip]);
byte[] array = new byte[16376];
do
{
InputPipe.Read(array, 0, array.Length);
}
while (array[0] == 5);
if (array[0] == 6)
{
HasCachedV2Results = false;
GetIdV2();
if (CachedV2Results.curPosition == 0L)
{
return true;
}
}
return false;
}
// 9
public void FlashDataFile(string path)
{
/*string fileName = Path.GetFileName(path);
this.InitFlashingStream();*/
ExecuteRawVoidMethod([(byte)SioOpcode.SioFile]);
/*this.packets.DataStream = this.GetStringStream(fileName);
this.TransferPackets(false);
this.WaitForEndResponse(false);
this.packets.DataStream = this.GetBufferedFileStream(path);
this.TransferPackets(false);
this.WaitForEndResponse(false);*/
}
// 10
public void Reboot()
{
ExecuteRawVoidMethod([(byte)SioOpcode.SioReboot]);
}
// 11
public bool EnterMassStorage()
{
byte[] buffer = ExecuteRawMethod([(byte)SioOpcode.SioMassStorage])!;
return buffer[0] == 3;
}
// 12
public void ReadDiskInfo(out int transferSize, out uint blockSize, out ulong lastBlock)
{
ExecuteRawVoidMethod([(byte)SioOpcode.SioGetDiskInfo]);
byte[] array = new byte[16];
lock (UsbLock)
{
InputPipe.Read(array, 0, array.Length);
}
int num = 0;
transferSize = BitConverter.ToInt32(array, num);
num += 4;
blockSize = BitConverter.ToUInt32(array, num);
num += 4;
lastBlock = BitConverter.ToUInt64(array, num);
num += 8;
}
// 13
public void ReadDataToBuffer(ulong diskOffset, byte[] buffer, int offset, int count, int diskTransferSize)
{
ExecuteRawVoidMethod([(byte)SioOpcode.SioReadDisk]);
byte[] buffer1 = new byte[16];
BitConverter.GetBytes(diskOffset).CopyTo(buffer1, 0);
BitConverter.GetBytes((ulong)count).CopyTo(buffer1, 8);
ExecuteRawVoidMethod(buffer1);
int offset1 = offset;
int count1;
for (int index = offset + count; offset1 < index; offset1 += count1)
{
count1 = diskTransferSize;
if (count1 > index - offset1)
{
count1 = index - offset1;
}
lock (UsbLock)
{
InputPipe.Read(buffer, offset1, count1);
}
byte[] singlebyte = new byte[1];
if (count1 % 512 == 0)
{
lock (UsbLock)
{
//InputPipe.Read(singlebyte, 0, singlebyte.Length);
}
}
}
}
// 14
public bool WriteDataFromBuffer(ulong diskOffset, byte[] buffer, int offset, int count, int diskTransferSize)
{
ExecuteRawVoidMethod([(byte)SioOpcode.SioWriteDisk]);
byte[] array = new byte[16];
BitConverter.GetBytes(diskOffset).CopyTo(array, 0);
BitConverter.GetBytes((ulong)((long)count)).CopyTo(array, 8);
ExecuteRawVoidMethod(array);
int i = offset;
int num2 = offset + count;
while (i < num2)
{
int num3 = diskTransferSize;
if (num3 > num2 - i)
{
num3 = num2 - i;
}
lock (UsbLock)
{
OutputPipe.Write(buffer, i, num3);
}
if (num3 % 512 == 0)
{
byte[] array2 = [];
lock (UsbLock)
{
OutputPipe.Write(array2, 0, array2.Length);
}
}
i += num3;
}
byte[] array3 = new byte[8];
lock (UsbLock)
{
InputPipe.Read(array3, 0, array3.Length);
}
if (count != (long)BitConverter.ToUInt64(array3, 0))
{
return false;
}
return true;
}
// 15
public bool ClearIdOverride()
{
byte[] buffer = ExecuteRawMethod([(byte)SioOpcode.SioClearIdOverride])!;
bool result = buffer[0] == 3;
// Refresh the ID
if (result)
{
HasCachedV2Results = false;
GetIdV2();
}
return result;
}
// 17
public Guid? GetSerialNumber()
{
byte[] buffer = ExecuteRawMethod([(byte)SioOpcode.SioSerialNumber])!;
return new Guid(buffer);
}
// 19
public uint SetBootMode(uint bootMode, string profileName)
{
uint num = 0x80000015U;
if (Encoding.Unicode.GetByteCount(profileName) >= 128)
{
num = 0x80000002U;
throw new Win32Exception(87);
}
uint num2 = 132U;
byte[] array = new byte[num2];
Array.Clear(array, 0, array.Length);
byte[] array2 = BitConverter.GetBytes(bootMode);
array2.CopyTo(array, 0);
array2 = Encoding.Unicode.GetBytes(profileName);
array2.CopyTo(array, 4);
ExecuteRawVoidMethod([(byte)SioOpcode.SioSetBootMode]);
OutputPipe.Write(array, 0, array.Length);
byte[] array3 = new byte[4];
InputPipe.Read(array3, 0, array3.Length);
num = BitConverter.ToUInt32(array3, 0);
return num;
}
// 22
public void GetDeviceVersion()
{
byte[] buffer = ExecuteRawMethod([(byte)SioOpcode.SioDeviceVersion])!;
Console.WriteLine(Convert.ToHexString(buffer));
}
// 23
public bool QueryForCommandAvailable(SioOpcode Cmd)
{
(_, Guid _, bool supportsFastFlash, bool _, int clientVersion, Guid _, string _) = GetIdV2();
if (clientVersion < 2)
{
return Cmd < SioOpcode.SioFastFlash || supportsFastFlash;
}
ExecuteRawVoidMethod([(byte)SioOpcode.SioQueryForCmd]);
byte[] buffer = ExecuteRawMethod([(byte)Cmd])!;
return buffer[0] != 0;
}
// 24
public string GetServicingLogs(string logFolderPath)
{
string? text = null;
if (!QueryForCommandAvailable(SioOpcode.SioGetUpdateLogs))
{
throw new Exception("Command not available");
}
if (string.IsNullOrEmpty(logFolderPath))
{
throw new ArgumentNullException(nameof(logFolderPath));
}
ExecuteRawVoidMethod([(byte)SioOpcode.SioGetUpdateLogs]);
byte[] array = new byte[262144];
int num = 0;
byte[] array2 = new byte[4];
int num2 = InputPipe.Read(array2, 0, array2.Length);
int num3 = BitConverter.ToInt32(array2, 0);
string text2 = Path.GetFullPath(logFolderPath);
Directory.CreateDirectory(text2);
text2 = Path.Combine(text2, Path.GetRandomFileName() + ".cab");
using (FileStream fileStream = File.Open(text2, FileMode.Create, FileAccess.Write))
{
do
{
Array.Clear(array, 0, array.Length);
num2 = InputPipe.Read(array, 0, array.Length);
num += num2;
fileStream.Write(array, 0, array.Length);
}
while (num != num3);
text = text2;
}
return text;
}
// 25
public void QueryDeviceUnlockId(out byte[] unlockId, out byte[] oemId, out byte[] platformId)
{
unlockId = new byte[32];
oemId = new byte[16];
platformId = new byte[16];
if (!QueryForCommandAvailable(SioOpcode.SioQueryDeviceUnlockId))
{
throw new Exception("Command not available");
}
ExecuteRawVoidMethod([(byte)SioOpcode.SioQueryDeviceUnlockId]);
byte[] numBuffer = new byte[4];
InputPipe.Read(numBuffer, 0, 4);
int num = BitConverter.ToInt32(numBuffer);
byte[] tmpBuffer = new byte[4];
InputPipe.Read(tmpBuffer, 0, 4);
InputPipe.Read(unlockId, 0, 32);
InputPipe.Read(oemId, 0, 16);
InputPipe.Read(platformId, 0, 16);
if (num != 0)
{
throw new Exception("Error while reading device unlock id, " + num);
}
}
// 26
public void RelockDeviceUnlockId()
{
if (!QueryForCommandAvailable(SioOpcode.SioRelockDeviceUnlockId))
{
throw new Exception("Command not available");
}
ExecuteRawVoidMethod([(byte)SioOpcode.SioRelockDeviceUnlockId]);
byte[] numBuffer = new byte[4];
InputPipe.Read(numBuffer, 0, 4);
int num = BitConverter.ToInt32(numBuffer);
if (num != 0)
{
throw new Exception("Error while relocking device unlock id, " + num);
}
}
// 27
public uint[] QueryUnlockTokenFiles()
{
byte[] array = new byte[16];
List<uint> list = [];
if (!QueryForCommandAvailable(SioOpcode.SioQueryUnlockTokenFiles))
{
throw new Exception("Command not available");
}
ExecuteRawVoidMethod([(byte)SioOpcode.SioQueryUnlockTokenFiles]);
byte[] numBuffer = new byte[4];
InputPipe.Read(numBuffer, 0, 4);
int num = BitConverter.ToInt32(numBuffer);
byte[] tmpBuffer = new byte[4];
InputPipe.Read(tmpBuffer, 0, 4);
InputPipe.Read(array, 0, 16);
BitArray bitArray = new BitArray(array);
uint num2 = 0U;
while (num2 < (ulong)((long)bitArray.Count))
{
if (bitArray.Get(Convert.ToInt32(num2)))
{
list.Add(num2);
}
num2 += 1U;
}
if (num != 0)
{
throw new Exception("Error while querying unlock token files, " + num);
}
return [.. list];
}
// 28
public void WriteUnlockTokenFile(uint unlockTokenId, byte[] fileData)
{
uint num = 0U;
uint num2 = (uint)fileData.Length;
if (1048576 < fileData.Length)
{
throw new ArgumentException("fileData");
}
if (127U < unlockTokenId)
{
throw new ArgumentException("unlockTokenId");
}
if (!QueryForCommandAvailable(SioOpcode.SioWriteUnlockTokenFile))
{
throw new Exception("Command not available");
}
ExecuteRawVoidMethod([(byte)SioOpcode.SioWriteUnlockTokenFile]);
OutputPipe.Write(BitConverter.GetBytes(num));
OutputPipe.Write(BitConverter.GetBytes(num2));
OutputPipe.Write(BitConverter.GetBytes(unlockTokenId));
OutputPipe.Write(fileData, 0, fileData.Length);
byte[] numBuffer = new byte[4];
InputPipe.Read(numBuffer, 0, 4);
int num3 = BitConverter.ToInt32(numBuffer);
if (num3 != 0)
{
throw new Exception("Error while writing unlock token files, " + num3);
}
}
// 29
public bool QueryBitlockerState()
{
if (!QueryForCommandAvailable(SioOpcode.SioQueryBitlockerState))
{
throw new Exception("Command not available");
}
ExecuteRawVoidMethod([(byte)SioOpcode.SioQueryBitlockerState]);
byte[] numBuffer = new byte[4];
InputPipe.Read(numBuffer, 0, 4);
int num = BitConverter.ToInt32(numBuffer);
byte[] flagBuffer = new byte[1];
InputPipe.Read(flagBuffer, 0, 1);
bool flag = flagBuffer[0] != 0;
if (num != 0)
{
throw new Exception("Error while reading bitlocker state, " + num);
}
return flag;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~SimpleIOModel()
{
Dispose(false);
}
public void Close()
{
USBDevice?.Dispose();
}
protected virtual void Dispose(bool disposing)
{
if (Disposed)
{
return;
}
if (disposing)
{
// Other disposables
}
// Clean unmanaged resources here.
Close();
Disposed = true;
}
}
}
+63
View File
@@ -0,0 +1,63 @@
/*
* MIT License
*
* Copyright (c) 2026 The DuoWOA authors
*
* 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.Text;
namespace WPinternals.Models.SimpleIO
{
public enum SioOpcode : byte
{
SioId = 1, //
SioFlash,
SioAck,
SioNack,
SioLog,
SioErr,
SioSkip, //
SioReset, //
SioFile, // WIP!
SioReboot, //
SioMassStorage, //
SioGetDiskInfo, //
SioReadDisk, //
SioWriteDisk, //
SioClearIdOverride, //
SioWim,
SioSerialNumber, //
SioExternalWim,
SioSetBootMode, //
SioFastFlash,
SioDeviceParams,
SioDeviceVersion,
SioQueryForCmd, //
SioGetUpdateLogs, //
SioQueryDeviceUnlockId, //
SioRelockDeviceUnlockId, //
SioQueryUnlockTokenFiles, //
SioWriteUnlockTokenFile, //
SioQueryBitlockerState, //
SioLast = 29
}
}
+33
View File
@@ -0,0 +1,33 @@
/*
* MIT License
*
* Copyright (c) 2024 The DuoWOA authors
*
* 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 UnifiedFlashingPlatform
{
public enum AppType : byte
{
Min,
UEFI,
BOOT,
Max
};
}
+33
View File
@@ -0,0 +1,33 @@
/*
* MIT License
*
* Copyright (c) 2024 The DuoWOA authors
*
* 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 UnifiedFlashingPlatform
{
public enum DeviceLogType
{
Min,
Flashing,
Servicing,
Max
}
}
@@ -0,0 +1,47 @@
/*
* MIT License
*
* Copyright (c) 2024 The DuoWOA authors
*
* 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 UnifiedFlashingPlatform
{
public struct DeviceTargetingInfo
{
public string Manufacturer;
public string Family;
public string ProductName;
public string ProductVersion;
public string SKUNumber;
public string BaseboardManufacturer;
public string BaseboardProduct;
public override readonly string ToString()
{
return "Manufacturer: " + Manufacturer +
" - Family: " + Family +
" - Product Name: " + ProductName +
" - Product Version: " + ProductVersion +
" - SKU Number: " + SKUNumber +
" - Baseboard Manufacturer: " + BaseboardManufacturer +
" - Baseboard Product: " + BaseboardProduct;
}
}
}
+11
View File
@@ -0,0 +1,11 @@
namespace UnifiedFlashingPlatform
{
internal enum FfuProtocol
{
ProtocolSyncV1 = 1,
ProtocolAsyncV1 = 2,
ProtocolSyncV2 = 4,
ProtocolAsyncV2 = 8,
ProtocolAsyncV3 = 16
}
}
+41
View File
@@ -0,0 +1,41 @@
/*
* MIT License
*
* Copyright (c) 2024 The DuoWOA authors
*
* 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 UnifiedFlashingPlatform
{
public struct FlashAppInfo
{
public byte ProtocolMajorVersion;
public byte ProtocolMinorVersion;
public byte ImplementationMajorVersion;
public byte ImplementationMinorVersion;
public override readonly string ToString()
{
return "ProtocolMajorVersion: " + ProtocolMajorVersion +
" - ProtocolMinorVersion: " + ProtocolMinorVersion +
" - ImplementationMajorVersion: " + ImplementationMajorVersion +
" - ImplementationMinorVersion: " + ImplementationMinorVersion;
}
}
}
+31
View File
@@ -0,0 +1,31 @@
/*
* MIT License
*
* Copyright (c) 2024 The DuoWOA authors
*
* 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 UnifiedFlashingPlatform
{
public enum Mode : byte
{
DiagnosticMode,
Max
}
}
@@ -0,0 +1,39 @@
/*
* MIT License
*
* Copyright (c) 2024 The DuoWOA authors
*
* 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 UnifiedFlashingPlatform
{
public struct ResetProtectionInfo
{
public bool IsResetProtectionEnabled;
public uint MajorVersion;
public uint MinorVersion;
public override readonly string ToString()
{
return "IsResetProtectionEnabled: " + IsResetProtectionEnabled +
" - MajorVersion: " + MajorVersion +
" - MinorVersion: " + MinorVersion;
}
}
}
@@ -0,0 +1,85 @@
using System;
using System.Drawing;
using System.Text;
using WPinternals.HelperClasses;
namespace UnifiedFlashingPlatform.UEFI
{
public struct BOOT_OPTION
{
public byte BootOrderIndex;
public ushort BootOption;
public LoadOptionAttribute Attributes;
public string Description;
public string DevicePath;
public string CommandLine;
public ushort DescriptionStringOffset;
public ushort DevicePathStringOffset;
public ushort CommandLineStringOffset;
public ushort TotalSize;
public static BOOT_OPTION ReadFromBuffer(byte[] Buffer, int offset)
{
byte BootOrderIndex = Buffer[offset];
var Attributes = (LoadOptionAttribute)BigEndian.ToUInt32(Buffer, offset + 1);
ushort BootOption = BigEndian.ToUInt16(Buffer, offset + 5);
// Latest
ushort DescriptionStringOffset = BigEndian.ToUInt16(Buffer, offset + 7);
ushort DevicePathStringOffset = BigEndian.ToUInt16(Buffer, offset + 9);
ushort CommandLineStringOffset = BigEndian.ToUInt16(Buffer, offset + 11);
ushort TotalSize = BigEndian.ToUInt16(Buffer, offset + 13);
string Description = Encoding.Unicode.GetString(Buffer, offset + DescriptionStringOffset, DevicePathStringOffset - DescriptionStringOffset);
string DevicePath;
string CommandLine = "";
if (CommandLineStringOffset == 0)
{
DevicePath = Encoding.Unicode.GetString(Buffer, offset + DevicePathStringOffset, TotalSize - DevicePathStringOffset);
}
else
{
DevicePath = Encoding.Unicode.GetString(Buffer, offset + DevicePathStringOffset, CommandLineStringOffset - DevicePathStringOffset);
CommandLine = Encoding.Unicode.GetString(Buffer, offset + CommandLineStringOffset, TotalSize - CommandLineStringOffset);
}
// Older
/*ushort DescriptionStringLength = BigEndian.ToUInt16(Buffer, offset + 7);
ushort DevicePathStringLength = BigEndian.ToUInt16(Buffer, offset + 9);
string Description = Encoding.Unicode.GetString(Buffer, offset + 11, DescriptionStringLength);
string DevicePath = Encoding.Unicode.GetString(Buffer, offset + 11 + DescriptionStringLength, DevicePathStringLength);
string CommandLine = "";
ushort DescriptionStringOffset = 11;
ushort DevicePathStringOffset = (ushort)(11 + DescriptionStringLength);
ushort CommandLineStringOffset = 0;
ushort TotalSize = (ushort)(11 + DescriptionStringLength + DevicePathStringLength);*/
return new BOOT_OPTION()
{
BootOrderIndex = BootOrderIndex,
Attributes = Attributes,
BootOption = BootOption,
Description = Description,
DevicePath = DevicePath,
CommandLine = CommandLine,
DescriptionStringOffset = DescriptionStringOffset,
DevicePathStringOffset = DevicePathStringOffset,
CommandLineStringOffset = CommandLineStringOffset,
TotalSize = TotalSize
};
}
public override readonly string ToString()
{
return "BootOrderIndex: " + BootOrderIndex +
" - Attributes: " + Attributes +
" - BootOption: " + BootOption +
" - Description: " + Description +
" - DevicePath: " + DevicePath +
" - CommandLine: " + CommandLine;
}
}
}
+53
View File
@@ -0,0 +1,53 @@
using System;
using System.Text;
namespace UnifiedFlashingPlatform.UEFI
{
public struct FILE_INFO
{
public ulong Size;
public ulong FileSize;
public ulong PhysicalSize;
public UefiDateTime CreateTime;
public UefiDateTime LastAccessTime;
public UefiDateTime ModificationTime;
public FileAttribute Attribute;
public string FileName;
public static FILE_INFO ReadFromBuffer(byte[] Buffer, int offset)
{
ulong size = BitConverter.ToUInt64(Buffer, offset);
ulong fileSize = BitConverter.ToUInt64(Buffer, offset + 8);
ulong physicalSize = BitConverter.ToUInt64(Buffer, offset + 16);
UefiDateTime createTime = UefiDateTime.ReadFromBuffer(Buffer, offset + 24);
UefiDateTime lastAccessTime = UefiDateTime.ReadFromBuffer(Buffer, offset + 40);
UefiDateTime modificationTime = UefiDateTime.ReadFromBuffer(Buffer, offset + 56);
ulong attribute = BitConverter.ToUInt64(Buffer, offset + 72);
string fileName = Encoding.Unicode.GetString(Buffer, offset + 80, (int)(size - 80));
return new FILE_INFO()
{
Size = size,
FileSize = fileSize,
PhysicalSize = physicalSize,
CreateTime = createTime,
LastAccessTime = lastAccessTime,
ModificationTime = modificationTime,
Attribute = (FileAttribute)attribute,
FileName = fileName
};
}
public override readonly string ToString()
{
return "Size: " + Size +
"- File Size: " + FileSize +
"- Physical Size: " + PhysicalSize +
"- Create Time: " + CreateTime.ToDateTime() +
"- Last Access Time: " + LastAccessTime.ToDateTime() +
"- Modification Time: " + ModificationTime.ToDateTime() +
"- Attribute: " + Attribute +
"- FileName: " + FileName;
}
}
}
@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace UnifiedFlashingPlatform.UEFI
{
[Flags]
public enum FileAttribute : ulong
{
EfiFileReadOnly = 1UL,
EfiFileHidden = 2UL,
EfiFileSystem = 4UL,
EfiFileReserved = 8UL,
EfiFileDirectory = 16UL,
EfiFileArchive = 32UL,
EfiFileValidAttr = 55UL
}
}
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace UnifiedFlashingPlatform.UEFI
{
[Flags]
public enum LoadOptionAttribute : uint
{
LoadOptionCategoryBoot = 0U,
LoadOptionActive = 1U,
LoadOptionForceReconnect = 2U,
LoadOptionHidden = 8U,
LoadOptionCategoryApp = 256U,
LoadOptionCategory = 7936U
}
}
@@ -0,0 +1,62 @@
using System;
namespace UnifiedFlashingPlatform.UEFI
{
public struct UefiDateTime
{
public ushort year;
public byte month;
public byte day;
public byte hour;
public byte minute;
public byte second;
public uint nanosecond;
public short timezone;
public byte daylight;
public static UefiDateTime ReadFromBuffer(byte[] Buffer, int offset)
{
ushort year = BitConverter.ToUInt16(Buffer, offset);
byte month = Buffer[offset + 2];
byte day = Buffer[offset + 3];
byte hour = Buffer[offset + 4];
byte minute = Buffer[offset + 5];
byte second = Buffer[offset + 6];
uint nanosecond = BitConverter.ToUInt32(Buffer, offset + 8);
short timezone = BitConverter.ToInt16(Buffer, offset + 12);
byte daylight = Buffer[offset + 14];
return new UefiDateTime()
{
year = year,
month = month,
day = day,
hour = hour,
minute = minute,
second = second,
nanosecond = nanosecond,
timezone = timezone,
daylight = daylight
};
}
public readonly DateTime ToDateTime()
{
DateTime dateTime;
byte month = this.month == 0 ? (byte)1 : this.month;
byte day = this.day == 0 ? (byte)1 : this.day;
if (timezone == 2047)
{
dateTime = new DateTime(year, month, day, hour, minute, second, Convert.ToInt32(nanosecond / 1000000U), DateTimeKind.Local);
}
else
{
dateTime = new DateTime(year, month, day, hour, minute, second, Convert.ToInt32(nanosecond / 1000000U), DateTimeKind.Utc);
}
return dateTime;
}
}
}
@@ -0,0 +1,41 @@
/*
* MIT License
*
* Copyright (c) 2024 The DuoWOA authors
*
* 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 UnifiedFlashingPlatform.UEFI
{
[Flags]
public enum UefiVariableAttributes : uint
{
EfiVariableNone,
EfiVariableNonVolatile,
EfiVariableBootServiceAccess,
EfiVariableRuntimeAccess = 4U,
EfiVariableHardwareErrorRecord = 8U,
EfiVariableAuthenticatedWriteAccess = 16U,
EfiVariableTimeBasedAuthenticatedWriteAccess = 32U,
EfiVariableAppendWrite = 64U,
EfiVariableEnhancedAuthenticatedAccess = 128U
}
}
+37
View File
@@ -0,0 +1,37 @@
/*
* MIT License
*
* Copyright (c) 2024 The DuoWOA authors
*
* 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 UnifiedFlashingPlatform
{
public struct USBSpeed
{
public byte CurrentUSBSpeed;
public byte MaxUSBSpeed;
public override readonly string ToString()
{
return "CurrentUSBSpeed: " + CurrentUSBSpeed +
" - MaxUSBSpeed: " + MaxUSBSpeed;
}
}
}
+42
View File
@@ -0,0 +1,42 @@
/*
* MIT License
*
* Copyright (c) 2024 The DuoWOA authors
*
* 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 UnifiedFlashingPlatform.UEFI;
namespace UnifiedFlashingPlatform
{
public struct UefiVariable
{
public UefiVariableAttributes Attributes;
public uint DataSize;
public byte[] Data;
public override readonly string ToString()
{
return "Attributes: " + Attributes +
" - DataSize: " + DataSize +
" - Data: " + BitConverter.ToString(Data);
}
}
}
@@ -0,0 +1,136 @@
namespace UnifiedFlashingPlatform
{
public partial class UnifiedFlashingPlatformModel
{
//
// Not valid commands
//
/* NOK */
private const string Signature = "NOK";
/* NOKX */
private const string ExtendedMessageSignature = $"{Signature}X";
/* NOKXC */
private const string CommonExtendedMessageSignature = $"{ExtendedMessageSignature}C";
/* NOKXF */
private const string UFPExtendedMessageSignature = $"{ExtendedMessageSignature}F";
//
// Normal commands
//
/* NOKF */
private const string FlashSignature = $"{Signature}F";
/* NOKI */
private const string HelloSignature = $"{Signature}I";
/* NOKM */
private const string MassStorageSignature = $"{Signature}M";
/* NOKN */
private const string TelemetryEndSignature = $"{Signature}N";
/* NOKR */
private const string RebootSignature = $"{Signature}R";
/* NOKS */
private const string TelemetryStartSignature = $"{Signature}S";
/* NOKT */
private const string GetGPTSignature = $"{Signature}T";
/* NOKV */
private const string InfoQuerySignature = $"{Signature}V";
/* NOKZ */
private const string ShutdownSignature = $"{Signature}Z";
//
// Common extended commands
//
/* NOKXCB */
private const string SwitchModeSignature = $"{CommonExtendedMessageSignature}B";
/* NOKXCC */
private const string ClearScreenSignature = $"{CommonExtendedMessageSignature}C";
/* NOKXCD */
private const string GetDirectoryEntriesSignature = $"{CommonExtendedMessageSignature}D";
/* NOKXCE */
private const string EchoSignature = $"{CommonExtendedMessageSignature}E";
/* NOKXCF */
private const string GetFileSignature = $"{CommonExtendedMessageSignature}F";
/* NOKXCM */
private const string DisplayCustomMessageSignature = $"{CommonExtendedMessageSignature}M";
/* NOKXCP */
private const string PutFileSignature = $"{CommonExtendedMessageSignature}P";
/* NOKXCT */
private const string BenchmarkTestsSignature = $"{CommonExtendedMessageSignature}T";
//
// UFP extended commands
//
/* NOKXFF */
private const string AsyncFlashModeSignature = $"{UFPExtendedMessageSignature}F";
/* NOKXFI */
private const string UnlockSignature = $"{UFPExtendedMessageSignature}I";
/* NOKXFO */
private const string RelockSignature = $"{UFPExtendedMessageSignature}O";
/* NOKXFR */
private const string ReadParamSignature = $"{UFPExtendedMessageSignature}R";
/* NOKXFS */
private const string SecureFlashSignature = $"{UFPExtendedMessageSignature}S";
/* NOKXFT */
private const string TelemetryReadSignature = $"{UFPExtendedMessageSignature}T";
/* NOKXFW */
private const string WriteParamSignature = $"{UFPExtendedMessageSignature}W";
/* NOKXFX */
private const string GetLogsSignature = $"{UFPExtendedMessageSignature}X";
//
// UFP Read Params
//
private const string AppTypeReadParamSignature = "APPT";
private const string ResetProtectionReadParamSignature = "ATRP";
private const string BitlockerStateReadParamSignature = "BITL";
private const string BuildInfoReadParamSignature = "BNFO";
private const string CurrentBootOptionReadParamSignature = "CUFO";
private const string AsyncProtocolSupportReadParamSignature = "DAS\0";
private const string DirectoryEntriesSizeReadParamSignature = "DES\0";
private const string DevicePlatformIDReadParamSignature = "DPI\0";
private const string DevicePropertiesReadParamSignature = "DPR\0";
private const string DeviceTargetInfoReadParamSignature = "DTI\0";
private const string DataVerifySpeedReadParamSignature = "DTSP";
private const string DeviceIDReadParamSignature = "DUI\0";
private const string EMMCTestResultReadParamSignature = "EMMT";
private const string EMMCSizeReadParamSignature = "EMS\0";
private const string EMMCWriteSpeedReadParamSignature = "EMWS";
private const string FlashAppInfoReadParamSignature = "FAI\0";
private const string FlashAppOptionsReadParamSignature = "FO\0\0";
private const string FlashingStatusReadParamSignature = "FS\0\0";
private const string FileSizeReadParamSignature = "FZ\0\0";
private const string SecureBootStatusReadParamSignature = "GSBS";
private const string GetUEFIVariableReadParamSignature = "GUFV";
private const string GetUEFIVariableSizeReadParamSignature = "GUVS";
private const string LargestMemoryRegionReadParamSignature = "LGMR";
private const string LogSizeReadParamSignature = "LZ\0\0";
private const string MACAddressReadParamSignature = "MAC\0";
private const string ModeDataReadParamSignature = "MODE";
private const string ProcessorManufacturerReadParamSignature = "pm\0\0";
private const string SDCardSizeReadParamSignature = "SDS\0";
private const string SupportedSecureFFUProtocolsReadParamSignature = "SFPI";
private const string SMBIOSDataReadParamSignature = "SMBD";
private const string SerialNumberReadParamSignature = "SN\0\0";
private const string SizeOfSystemMemoryReadParamSignature = "SOSM";
private const string SecurityStatusReadParamSignature = "SS\0\0";
private const string TelemetryLogSizeReadParamSignature = "TELS";
private const string TransferSizeReadParamSignature = "TS\0\0";
private const string UEFIBootFlagReadParamSignature = "UBF\0";
private const string UEFIBootOptionsReadParamSignature = "UEBO";
private const string UnlockIDReadParamSignature = "UKID";
private const string UnlockTokenFilesReadParamSignature = "UKTF";
private const string USBSpeedReadParamSignature = "USBS";
private const string WriteBufferSizeReadParamSignature = "WBS\0";
//
// UFP Write Params
//
private const string BootOptionOptionalDataWriteParamSignature = "BOCL";
private const string BootOptionAsFirstEntryWriteParamSignature = "BOF\0";
private const string BootOptionAsLastEntryWriteParamSignature = "BOL\0";
private const string FlashOptionsWriteParamSignature = "FO\0\0";
private const string LogInsertWriteParamSignature = "LI\0\0";
private const string ModeWriteParamSignature = "MODE";
private const string OneTimeBootSequenceWriteParamSignature = "OBU\0";
private const string SettingUEFIVariableWriteParamSignature = "SUFV";
}
}
@@ -0,0 +1,534 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnifiedFlashingPlatform.UEFI;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace UnifiedFlashingPlatform
{
public partial class UnifiedFlashingPlatformModel
{
public byte[]? ReadParam(string Param)
{
byte[] Request = new byte[0x0B];
const string Header = ReadParamSignature; // NOKXFR
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Param), 0, Request, 7, Param.Length);
byte[]? Response = ExecuteRawMethod(Request);
if ((Response == null) || (Response.Length < 0x10))
{
return null;
}
byte[] Result = new byte[Response[0x10]];
Buffer.BlockCopy(Response, 0x11, Result, 0, Response[0x10]);
return Result;
}
public string? ReadStringParam(string Param)
{
byte[]? Bytes = ReadParam(Param);
return Bytes == null ? null : Encoding.ASCII.GetString(Bytes).Trim('\0');
}
public AppType ReadAppType()
{
byte[]? Bytes = ReadParam(AppTypeReadParamSignature);
return Bytes == null ? AppType.Min : Bytes[0] == 1 ? AppType.UEFI : AppType.Min;
}
public ResetProtectionInfo? ReadResetProtection()
{
byte[]? Bytes = ReadParam(ResetProtectionReadParamSignature);
return Bytes == null
? null
: new ResetProtectionInfo()
{
IsResetProtectionEnabled = Bytes[0] == 1,
MajorVersion = BitConverter.ToUInt32(Bytes[1..5].Reverse().ToArray()),
MinorVersion = BitConverter.ToUInt32(Bytes[5..9].Reverse().ToArray())
};
}
public bool? ReadBitlocker()
{
byte[]? Bytes = ReadParam(BitlockerStateReadParamSignature);
return Bytes == null ? null : Bytes[0] == 1;
}
public string? ReadBuildInfo()
{
return ReadStringParam(BuildInfoReadParamSignature);
}
public ushort? ReadCurrentBootOption()
{
byte[]? Bytes = ReadParam(CurrentBootOptionReadParamSignature);
return Bytes == null || Bytes.Length != 2 ? null : BitConverter.ToUInt16(Bytes.Reverse().ToArray());
}
public bool? ReadDeviceAsyncSupport()
{
byte[]? Bytes = ReadParam(AsyncProtocolSupportReadParamSignature);
return Bytes == null || Bytes.Length != 2 ? null : BitConverter.ToUInt16(Bytes.Reverse().ToArray()) == 1;
}
public ulong? ReadDirectoryEntriesSize(string PartitionName, string DirectoryName)
{
if (PartitionName.Length > 35)
{
return null;
}
byte[] PartitionNameBuffer = Encoding.Unicode.GetBytes(PartitionName);
byte[] DirectoryNameBuffer = Encoding.Unicode.GetBytes(DirectoryName);
byte[] Request = new byte[87 + DirectoryNameBuffer.Length + 2];
const string Header = ReadParamSignature; // NOKXFR
const string Param = DirectoryEntriesSizeReadParamSignature;
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Param), 0, Request, 7, Param.Length);
Buffer.BlockCopy(PartitionNameBuffer, 0, Request, 15, PartitionNameBuffer.Length);
Buffer.BlockCopy(DirectoryNameBuffer, 0, Request, 87, DirectoryNameBuffer.Length);
byte[]? Response = ExecuteRawMethod(Request);
if ((Response == null) || (Response.Length < 0x10))
{
return null;
}
byte[] Result = new byte[Response[0x10]];
Buffer.BlockCopy(Response, 0x11, Result, 0, Response[0x10]);
return BitConverter.ToUInt64(Result.Reverse().ToArray());
}
public string? ReadDevicePlatformID()
{
return ReadStringParam(DevicePlatformIDReadParamSignature);
}
//
// Reads the device properties from the UEFI Variable "MSRuntimeDeviceProperties"
// in the g_guidMSRuntimeDeviceProperties namespace and returns it as a string.
//
public string? ReadDeviceProperties()
{
return ReadStringParam(DevicePropertiesReadParamSignature);
}
public DeviceTargetingInfo? ReadDeviceTargetInfo()
{
byte[]? Bytes = ReadParam(DeviceTargetInfoReadParamSignature);
if (Bytes == null)
{
return null;
}
ushort ManufacturerLength = BitConverter.ToUInt16(Bytes[0..2].Reverse().ToArray());
ushort FamilyLength = BitConverter.ToUInt16(Bytes[2..4].Reverse().ToArray());
ushort ProductNameLength = BitConverter.ToUInt16(Bytes[4..6].Reverse().ToArray());
ushort ProductVersionLength = BitConverter.ToUInt16(Bytes[6..8].Reverse().ToArray());
ushort SKUNumberLength = BitConverter.ToUInt16(Bytes[8..10].Reverse().ToArray());
ushort BaseboardManufacturerLength = BitConverter.ToUInt16(Bytes[10..12].Reverse().ToArray());
ushort BaseboardProductLength = BitConverter.ToUInt16(Bytes[12..14].Reverse().ToArray());
int CurrentOffset = 14;
string Manufacturer = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + ManufacturerLength)]);
CurrentOffset += ManufacturerLength;
string Family = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + FamilyLength)]);
CurrentOffset += FamilyLength;
string ProductName = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + ProductNameLength)]);
CurrentOffset += ProductNameLength;
string ProductVersion = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + ProductVersionLength)]);
CurrentOffset += ProductVersionLength;
string SKUNumber = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + SKUNumberLength)]);
CurrentOffset += SKUNumberLength;
string BaseboardManufacturer = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + BaseboardManufacturerLength)]);
CurrentOffset += BaseboardManufacturerLength;
string BaseboardProduct = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + BaseboardProductLength)]);
return new DeviceTargetingInfo()
{
Manufacturer = Manufacturer,
Family = Family,
ProductName = ProductName,
ProductVersion = ProductVersion,
SKUNumber = SKUNumber,
BaseboardManufacturer = BaseboardManufacturer,
BaseboardProduct = BaseboardProduct
};
}
//
// Gets the last FFU Flash Operation Data verify speed in KB/s
//
public uint? ReadDataVerifySpeed()
{
byte[]? Bytes = ReadParam(DataVerifySpeedReadParamSignature);
return Bytes == null || Bytes.Length != 4 ? null : BitConverter.ToUInt32(Bytes.Reverse().ToArray());
}
public Guid? ReadDeviceID()
{
byte[]? Bytes = ReadParam(DeviceIDReadParamSignature);
return Bytes == null || Bytes.Length != 16 ? null : new Guid(Bytes);
}
public uint? ReadEmmcTestResult()
{
byte[]? Bytes = ReadParam(EMMCTestResultReadParamSignature);
return Bytes == null || Bytes.Length != 4 ? null : BitConverter.ToUInt32(Bytes.Reverse().ToArray());
}
//
// Gets the eMMC Size in sectors, if present
//
public uint? ReadEmmcSize()
{
byte[]? Bytes = ReadParam(EMMCSizeReadParamSignature);
return Bytes == null || Bytes.Length != 4 ? null : BitConverter.ToUInt32(Bytes.Reverse().ToArray());
}
//
// Gets the eMMC Write speed in KB/s
//
public uint? ReadEmmcWriteSpeed()
{
byte[]? Bytes = ReadParam(EMMCWriteSpeedReadParamSignature);
return Bytes == null || Bytes.Length != 4 ? null : BitConverter.ToUInt32(Bytes.Reverse().ToArray());
}
public FlashAppInfo? ReadFlashAppInfo()
{
byte[]? Bytes = ReadParam(FlashAppInfoReadParamSignature);
return Bytes == null || Bytes.Length != 6 || Bytes[0] != 2
? null
: new FlashAppInfo()
{
ProtocolMajorVersion = Bytes[1],
ProtocolMinorVersion = Bytes[2],
ImplementationMajorVersion = Bytes[3],
ImplementationMinorVersion = Bytes[4]
};
}
//
// Reads the device properties from the UEFI Variable "FfuConfigurationOptions"
// in the g_guidLumiaGuid namespace and returns it as a string.
//
public string? ReadFlashOptions()
{
return ReadStringParam(FlashAppOptionsReadParamSignature);
}
public uint? ReadFlashingStatus()
{
byte[]? Bytes = ReadParam(FlashingStatusReadParamSignature);
return Bytes == null || Bytes.Length != 4 ? null : BitConverter.ToUInt32(Bytes.Reverse().ToArray());
}
public ulong? ReadFileSize(string PartitionName, string FileName)
{
if (PartitionName.Length > 35)
{
return null;
}
byte[] PartitionNameBuffer = Encoding.Unicode.GetBytes(PartitionName);
byte[] FileNameBuffer = Encoding.Unicode.GetBytes(FileName);
byte[] Request = new byte[87 + FileNameBuffer.Length + 2];
const string Header = ReadParamSignature; // NOKXFR
const string Param = FileSizeReadParamSignature;
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Param), 0, Request, 7, Param.Length);
Buffer.BlockCopy(PartitionNameBuffer, 0, Request, 15, PartitionNameBuffer.Length);
Buffer.BlockCopy(FileNameBuffer, 0, Request, 87, FileNameBuffer.Length);
byte[]? Response = ExecuteRawMethod(Request);
if ((Response == null) || (Response.Length < 0x10))
{
return null;
}
byte[] Result = new byte[Response[0x10]];
Buffer.BlockCopy(Response, 0x11, Result, 0, Response[0x10]);
return BitConverter.ToUInt64(Result.Reverse().ToArray());
}
public bool? ReadSecureBootStatus()
{
byte[]? Bytes = ReadParam(SecureBootStatusReadParamSignature);
return Bytes == null ? null : Bytes[0] == 1;
}
public UefiVariable? ReadUEFIVariable(Guid Guid, string Name, uint Size)
{
byte[] Request = new byte[39 + ((Name.Length + 1) * 2)];
const string Header = ReadParamSignature; // NOKXFR
string Param = GetUEFIVariableReadParamSignature;
byte[] VariableNameBuffer = Encoding.Unicode.GetBytes(Name);
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Param), 0, Request, 7, Param.Length);
Buffer.BlockCopy(Guid.ToByteArray(), 0, Request, 15, 16);
Buffer.BlockCopy(BitConverter.GetBytes(Size).Reverse().ToArray(), 0, Request, 31, 4);
Buffer.BlockCopy(BitConverter.GetBytes((Name.Length + 1) * 2).Reverse().ToArray(), 0, Request, 35, 4);
Buffer.BlockCopy(VariableNameBuffer, 0, Request, 39, VariableNameBuffer.Length);
byte[]? Response = ExecuteRawMethod(Request);
if ((Response == null) || (Response.Length < 0x10))
{
return null;
}
byte[] Result = new byte[Response[0x10]];
Buffer.BlockCopy(Response, 0x11, Result, 0, Response[0x10]);
return new UefiVariable()
{
Attributes = (UefiVariableAttributes)BitConverter.ToUInt32(Result[0..4].Reverse().ToArray()),
DataSize = BitConverter.ToUInt32(Result[4..8].Reverse().ToArray()),
Data = Result[8..^0]
};
}
public uint? ReadUEFIVariableSize(Guid Guid, string Name)
{
byte[] Request = new byte[39 + ((Name.Length + 1) * 2)];
const string Header = ReadParamSignature; // NOKXFR
string Param = GetUEFIVariableSizeReadParamSignature;
byte[] VariableNameBuffer = Encoding.Unicode.GetBytes(Name);
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Param), 0, Request, 7, Param.Length);
Buffer.BlockCopy(Guid.ToByteArray(), 0, Request, 15, 16);
Buffer.BlockCopy(BitConverter.GetBytes((Name.Length + 1) * 2).Reverse().ToArray(), 0, Request, 35, 4);
Buffer.BlockCopy(VariableNameBuffer, 0, Request, 39, VariableNameBuffer.Length);
byte[]? Response = ExecuteRawMethod(Request);
if ((Response == null) || (Response.Length < 0x10))
{
return null;
}
byte[] Result = new byte[Response[0x10]];
Buffer.BlockCopy(Response, 0x11, Result, 0, Response[0x10]);
return Result == null || Result.Length != 4 ? null : BitConverter.ToUInt32(Result.Reverse().ToArray());
}
//
// Returns the largest memory region in bytes available for use by UFP
//
public ulong? ReadLargestMemoryRegion()
{
byte[]? Bytes = ReadParam(LargestMemoryRegionReadParamSignature);
return Bytes == null || Bytes.Length != 8 ? null : BitConverter.ToUInt64(Bytes.Reverse().ToArray());
}
public ulong? ReadLogSize(DeviceLogType LogType)
{
byte[] Request = new byte[0x10];
const string Header = ReadParamSignature; // NOKXFR
const string Param = LogSizeReadParamSignature;
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Param), 0, Request, 7, Param.Length);
Request[15] = (byte)LogType;
byte[]? Response = ExecuteRawMethod(Request);
if ((Response == null) || (Response.Length < 0x10))
{
return 0;
}
byte[] Result = new byte[Response[0x10]];
Buffer.BlockCopy(Response, 0x11, Result, 0, Response[0x10]);
return BitConverter.ToUInt64([.. Result.Reverse()], 0);
}
//
// Reads the MAC Address in the following format: "%02x-%02x-%02x-%02x-%02x-%02x"
//
public string? ReadMacAddress()
{
return ReadStringParam(MACAddressReadParamSignature);
}
public uint? ReadModeData(Mode Mode)
{
byte[] Request = new byte[0x10];
const string Header = ReadParamSignature; // NOKXFR
string Param = ModeDataReadParamSignature;
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Param), 0, Request, 7, Param.Length);
Request[15] = (byte)Mode;
byte[]? Response = ExecuteRawMethod(Request);
if ((Response == null) || (Response.Length < 0x10))
{
return null;
}
byte[] Result = new byte[Response[0x10]];
Buffer.BlockCopy(Response, 0x11, Result, 0, Response[0x10]);
return Result == null || Result.Length != 4 ? null : BitConverter.ToUInt32(Result.Reverse().ToArray());
}
public string? ReadProcessorManufacturer()
{
return ReadStringParam(ProcessorManufacturerReadParamSignature);
}
//
// Gets the SD Card Size in sectors, if present
//
public uint? ReadSDCardSize()
{
byte[]? Bytes = ReadParam(SDCardSizeReadParamSignature);
return Bytes == null || Bytes.Length != 4 ? null : BitConverter.ToUInt32(Bytes.Reverse().ToArray());
}
public string? ReadSupportedFFUProtocolInfo()
{
// TODO
return ReadStringParam(SupportedSecureFFUProtocolsReadParamSignature);
}
public string? ReadSMBIOSData()
{
// TODO
return ReadStringParam(SMBIOSDataReadParamSignature);
}
public Guid? ReadSerialNumber()
{
byte[]? Bytes = ReadParam(SerialNumberReadParamSignature);
return Bytes == null || Bytes.Length != 16 ? null : new Guid(Bytes);
}
//
// Returns the size of system memory in kB
//
public ulong? ReadSizeOfSystemMemory()
{
byte[]? Bytes = ReadParam(SizeOfSystemMemoryReadParamSignature);
return Bytes == null || Bytes.Length != 8 ? null : BitConverter.ToUInt64(Bytes.Reverse().ToArray());
}
public string? ReadSecurityStatus()
{
// TODO
return ReadStringParam(SecurityStatusReadParamSignature);
}
public string? ReadTelemetryLogSize()
{
// TODO
return ReadStringParam(TelemetryLogSizeReadParamSignature);
}
public uint? ReadTransferSize()
{
byte[]? Bytes = ReadParam(TransferSizeReadParamSignature);
return Bytes == null || Bytes.Length != 4 ? null : BitConverter.ToUInt32(Bytes.Reverse().ToArray());
}
//
// Reads the UEFI Boot Flag variable content and returns it as a string.
//
public string? ReadUEFIBootFlag()
{
return ReadStringParam(UEFIBootFlagReadParamSignature);
}
public BOOT_OPTION[]? ReadUEFIBootOptions()
{
byte[] Request = new byte[0x0B];
const string Header = ReadParamSignature; // NOKXFR
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(Encoding.ASCII.GetBytes(UEFIBootOptionsReadParamSignature), 0, Request, 7, UEFIBootOptionsReadParamSignature.Length);
byte[]? Response = ExecuteRawMethod(Request);
if ((Response == null) || (Response.Length < 0x10))
{
return null;
}
byte[] ResponseBuffer = Response[0x19..];
List<BOOT_OPTION> bootOptions = [];
int j = 0;
while (j != ResponseBuffer.Length)
{
BOOT_OPTION bootOption = BOOT_OPTION.ReadFromBuffer(ResponseBuffer, j);
j += bootOption.TotalSize;
bootOptions.Add(bootOption);
}
return [.. bootOptions];
}
//
// Reads the device properties from the UEFI Variable "UnlockID"
// in the g_guidOfflineDUIdEfiNamespace namespace and returns it as a string.
//
public byte[] ReadUnlockID()
{
return ReadParam(UnlockIDReadParamSignature);
}
public string? ReadUnlockTokenFiles()
{
// TODO
return ReadStringParam(UnlockTokenFilesReadParamSignature);
}
public USBSpeed? ReadUSBSpeed()
{
byte[]? Bytes = ReadParam(USBSpeedReadParamSignature);
return Bytes == null || Bytes.Length != 2
? null
: new USBSpeed()
{
CurrentUSBSpeed = Bytes[0],
MaxUSBSpeed = Bytes[1]
};
}
public uint? ReadWriteBufferSize()
{
byte[]? Bytes = ReadParam(WriteBufferSizeReadParamSignature);
return Bytes == null || Bytes.Length != 4 ? null : BitConverter.ToUInt32(Bytes.Reverse().ToArray());
}
}
}
@@ -0,0 +1,543 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using WPinternals;
using WPinternals.HelperClasses;
namespace UnifiedFlashingPlatform
{
public partial class UnifiedFlashingPlatformModel
{
private readonly PhoneInfo Info = new();
public void FlashSectors(uint StartSector, byte[] Data, byte TargetDevice = 0, int Progress = 0)
{
// Start sector is in UInt32, so max size of eMMC is 2 TB.
byte[] Request = new byte[Data.Length + 0x40];
const string Header = FlashSignature; // NOKF
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Request[0x05] = TargetDevice; // Target device: 0: eMMC, 1: SDIO, 2: Other ???, 3: ???
Buffer.BlockCopy(BigEndian.GetBytes(StartSector, 4), 0, Request, 0x0B, 4); // Start sector
Buffer.BlockCopy(BigEndian.GetBytes(Data.Length / 0x200, 4), 0, Request, 0x0F, 4); // Sector count
Request[0x13] = (byte)Progress; // Progress (0 - 100)
Request[0x18] = 0; // Verify needed
Request[0x19] = 0; // Skip write
Buffer.BlockCopy(Data, 0, Request, 0x40, Data.Length);
_ = ExecuteRawMethod(Request);
}
public void Hello()
{
byte[] Request = new byte[4];
ByteOperations.WriteAsciiString(Request, 0, HelloSignature);
byte[] Response = ExecuteRawMethod(Request) ?? 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.");
}
}
public void ResetPhone()
{
Debug.WriteLine("Rebooting phone");
try
{
byte[] Request = new byte[4];
ByteOperations.WriteAsciiString(Request, 0, RebootSignature);
ExecuteRawVoidMethod(Request);
}
catch
{
Debug.WriteLine("Sending reset-request failed");
Debug.WriteLine("Assuming automatic reset already in progress");
}
}
public 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!!
/*PhoneInfo Info = ReadPhoneInfo(ExtendedInfo: false);
FlashAppType OriginalAppType = Info.App;
bool Switch = (Info.App != FlashAppType.BootManager) && Info.IsBootloaderSecure;
if (Switch)
{
SwitchToBootManagerContext();
}*/
byte[] Request = new byte[0x04];
const string Header = GetGPTSignature;
System.Buffer.BlockCopy(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!");
}
ushort Error = (ushort)((Buffer[6] << 8) + Buffer[7]);
if (Error > 0)
{
throw new NotSupportedException($"ReadGPT: Error 0x{Error:X4}");
}
// Length: 0x4400 for 512 (0x200) Sector Size (from sector 0 to sector 34)
// Length: 0x6000 for 4096 (0x1000) Sector Size (from sector 0 to sector 6)
uint ReturnedGPTBufferLength = (uint)Buffer.Length - 8;
uint SectorSize = Buffer.Length == 0x4408
? 512
: Buffer.Length == 0x6008
? (uint)4096
: throw new NotSupportedException($"ReadGPT: Unsupported output size! 0x{ReturnedGPTBufferLength:X4}");
byte[] GPTBuffer = new byte[ReturnedGPTBufferLength - SectorSize];
System.Buffer.BlockCopy(Buffer, 8 + (int)SectorSize, GPTBuffer, 0, (int)ReturnedGPTBufferLength - (int)SectorSize);
/*if (Switch)
{
if (OriginalAppType == FlashAppType.FlashApp)
{
SwitchToFlashAppContext();
}
else
{
SwitchToPhoneInfoAppContext();
}
}*/
return new GPT(GPTBuffer);//, SectorSize); // NOKT message header and MBR are ignored
}
private static 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!")
{
SubMessage = $"Error 0x{ErrorCode:X4}: {SubMessage}"
};
throw Ex;
}
public void SendFfuHeaderV1(byte[] FfuHeader, int Progress = 0, byte Options = 0)
{
byte[] Request = new byte[FfuHeader.Length + 0x20];
const string Header = SecureFlashSignature;
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(BigEndian.GetBytes(0x0001, 2), 0, Request, 0x06, 2); // Protocol version = 0x0001
Request[0x08] = (byte)Progress; // Progress = 0% (0 - 100)
Request[0x0B] = 1; // Subblock count = 1
Buffer.BlockCopy(BigEndian.GetBytes(0x0000000B, 4), 0, Request, 0x0C, 4); // Subblock type for header = 0x0B
Buffer.BlockCopy(BigEndian.GetBytes(FfuHeader.Length + 0x0C, 4), 0, Request, 0x10, 4); // Subblock length = length of header + 0x0C
Buffer.BlockCopy(BigEndian.GetBytes(0x00000000, 4), 0, Request, 0x14, 4); // Header type = 0
Buffer.BlockCopy(BigEndian.GetBytes(FfuHeader.Length, 4), 0, Request, 0x18, 4); // Payload length = length of header
Request[0x1C] = Options; // Header options = 0
Buffer.BlockCopy(FfuHeader, 0, Request, 0x20, FfuHeader.Length);
byte[] Response = ExecuteRawMethod(Request) ?? throw new BadConnectionException();
int ResultCode = (Response[6] << 8) + Response[7];
if (ResultCode != 0)
{
ThrowFlashError(ResultCode);
}
}
public void SendFfuHeaderV2(uint TotalHeaderLength, uint OffsetForThisPart, byte[] FfuHeader, int Progress = 0, byte Options = 0)
{
byte[] Request = new byte[FfuHeader.Length + 0x3C];
const string Header = SecureFlashSignature;
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(BigEndian.GetBytes(0x0002, 2), 0, Request, 0x06, 2); // Protocol version = 0x0002
Request[0x08] = (byte)Progress; // Progress = 0% (0 - 100)
Request[0x0B] = 1; // Subblock count = 1
Buffer.BlockCopy(BigEndian.GetBytes(0x00000021, 4), 0, Request, 0x0C, 4); // Subblock type for header v2 = 0x21
Buffer.BlockCopy(BigEndian.GetBytes(FfuHeader.Length + 0x28, 4), 0, Request, 0x10, 4); // Subblock starts at 0x14, payload starts at 0x3C.
Buffer.BlockCopy(BigEndian.GetBytes(0x00000000, 4), 0, Request, 0x14, 4); // Header type = 0
Buffer.BlockCopy(BigEndian.GetBytes(TotalHeaderLength, 4), 0, Request, 0x18, 4); // Payload length = length of header
Request[0x1C] = Options; // Header options = 0
Buffer.BlockCopy(BigEndian.GetBytes(OffsetForThisPart, 4), 0, Request, 0x1D, 4);
Buffer.BlockCopy(BigEndian.GetBytes(FfuHeader.Length, 4), 0, Request, 0x21, 4);
Request[0x25] = 0; // No Erase
Buffer.BlockCopy(FfuHeader, 0, Request, 0x3C, FfuHeader.Length);
byte[] Response = ExecuteRawMethod(Request) ?? throw new BadConnectionException();
if (Response.Length == 4)
{
throw new WPinternalsException("Flash protocol v2 not supported", "The device reported that the Flash protocol v2 was not supported while sending the FFU header.");
}
int ResultCode = (Response[6] << 8) + Response[7];
if (ResultCode != 0)
{
ThrowFlashError(ResultCode);
}
}
public void SendFfuPayloadV1(byte[] FfuChunk, int Progress = 0, byte Options = 0)
{
byte[] Request = new byte[FfuChunk.Length + 0x1C];
const string Header = SecureFlashSignature;
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(BigEndian.GetBytes((int)FfuProtocol.ProtocolSyncV1, 2), 0, Request, 0x06, 2); // Protocol version = 0x0001
Request[0x08] = (byte)Progress; // Progress = 0% (0 - 100)
Request[0x0B] = 1; // Subblock count = 1
Buffer.BlockCopy(BigEndian.GetBytes(0x0000000C, 4), 0, Request, 0x0C, 4); // Subblock type for ChunkData = 0x0C
Buffer.BlockCopy(BigEndian.GetBytes(FfuChunk.Length + 0x08, 4), 0, Request, 0x10, 4); // Subblock length = length of chunk + 0x08
Buffer.BlockCopy(BigEndian.GetBytes(FfuChunk.Length, 4), 0, Request, 0x14, 4); // Payload length = length of chunk
Request[0x18] = Options; // Data options = 0 (1 = verify)
Buffer.BlockCopy(FfuChunk, 0, Request, 0x1C, FfuChunk.Length);
byte[] Response = ExecuteRawMethod(Request) ?? throw new BadConnectionException();
int ResultCode = (Response[6] << 8) + Response[7];
if (ResultCode != 0)
{
ThrowFlashError(ResultCode);
}
}
public void SendFfuPayloadV2(byte[] FfuChunk, int Progress = 0, byte Options = 0)
{
byte[] Request = new byte[FfuChunk.Length + 0x20];
const string Header = SecureFlashSignature;
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(BigEndian.GetBytes((int)FfuProtocol.ProtocolSyncV2, 2), 0, Request, 0x06, 2); // Protocol
Request[0x08] = (byte)Progress; // Progress = 0% (0 - 100)
Request[0x0B] = 1; // Subblock count = 1
Buffer.BlockCopy(BigEndian.GetBytes(0x0000001B, 4), 0, Request, 0x0C, 4); // Subblock type for Payload v2 = 0x1B
Buffer.BlockCopy(BigEndian.GetBytes(FfuChunk.Length + 0x0C, 4), 0, Request, 0x10, 4); // Subblock length = length of chunk + 0x08
Buffer.BlockCopy(BigEndian.GetBytes(FfuChunk.Length, 4), 0, Request, 0x14, 4); // Payload length = length of chunk
Request[0x18] = Options; // Data options = 0 (1 = verify)
Buffer.BlockCopy(FfuChunk, 0, Request, 0x20, FfuChunk.Length);
byte[] Response = ExecuteRawMethod(Request) ?? throw new BadConnectionException();
int ResultCode = (Response[6] << 8) + Response[7];
if (ResultCode != 0)
{
ThrowFlashError(ResultCode);
}
}
public void SendFfuPayloadV3(byte[] FfuChunk, uint WriteDescriptorIndex, uint CRC, int Progress = 0, byte Options = 0)
{
byte[] Request = new byte[FfuChunk.Length + 0x20];
const string Header = SecureFlashSignature;
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(BigEndian.GetBytes((int)FfuProtocol.ProtocolAsyncV3, 2), 0, Request, 0x06, 2); // Protocol
Request[0x08] = (byte)Progress; // Progress = 0% (0 - 100)
Request[0x0B] = 1; // Subblock count = 1
Buffer.BlockCopy(BigEndian.GetBytes(0x0000001D, 4), 0, Request, 0x0C, 4); // Subblock type for Payload v2 = 0x1B
Buffer.BlockCopy(BigEndian.GetBytes(FfuChunk.Length + 0x2C, 4), 0, Request, 0x10, 4); // Subblock length = length of chunk + 0x08
Buffer.BlockCopy(BigEndian.GetBytes(FfuChunk.Length, 4), 0, Request, 0x14, 4); // Payload length = length of chunk
Request[0x18] = Options; // Data options = 0 (1 = verify)
Buffer.BlockCopy(BigEndian.GetBytes(WriteDescriptorIndex, 4), 0, Request, 0x19, 4); // Payload length = length of chunk
Buffer.BlockCopy(BigEndian.GetBytes(CRC, 4), 0, Request, 0x1D, 4); // Payload length = length of chunk
Buffer.BlockCopy(FfuChunk, 0, Request, 0x40, FfuChunk.Length);
byte[] Response = ExecuteRawMethod(Request) ?? throw new BadConnectionException();
int ResultCode = (Response[6] << 8) + Response[7];
if (ResultCode != 0)
{
ThrowFlashError(ResultCode);
}
}
public PhoneInfo ReadPhoneInfo()
{
// NOKV = Info Query
bool PhoneInfoLogged = Info.State != PhoneInfoState.Empty;
PhoneInfo Result = Info;
if (Result.State == PhoneInfoState.Empty)
{
byte[] Request = new byte[4];
ByteOperations.WriteAsciiString(Request, 0, InfoQuerySignature);
byte[]? Response = ExecuteRawMethod(Request);
if ((Response != null) && (ByteOperations.ReadAsciiString(Response, 0, 4) != "NOKU"))
{
Result.App = (FlashAppType)Response[5];
switch (Result.App)
{
case FlashAppType.FlashApp:
Result.FlashAppProtocolVersionMajor = Response[6];
Result.FlashAppProtocolVersionMinor = Response[7];
Result.FlashAppVersionMajor = Response[8];
Result.FlashAppVersionMinor = Response[9];
break;
}
byte SubblockCount = Response[10];
int SubblockOffset = 11;
for (int i = 0; i < SubblockCount; i++)
{
byte SubblockID = Response[SubblockOffset + 0x00];
ushort SubblockLength = BigEndian.ToUInt16(Response, SubblockOffset + 0x01);
int SubblockPayloadOffset = SubblockOffset + 3;
byte SubblockVersion;
switch (SubblockID)
{
case 0x01:
Result.TransferSize = BigEndian.ToUInt32(Response, SubblockPayloadOffset);
break;
case 0x02:
Result.WriteBufferSize = BigEndian.ToUInt32(Response, SubblockPayloadOffset);
break;
case 0x03:
Result.EmmcSizeInSectors = BigEndian.ToUInt32(Response, SubblockPayloadOffset);
break;
case 0x04:
if (Result.App == FlashAppType.FlashApp)
{
Result.SdCardSizeInSectors = BigEndian.ToUInt32(Response, SubblockPayloadOffset);
}
break;
case 0x05:
Result.PlatformID = ByteOperations.ReadAsciiString(Response, (uint)SubblockPayloadOffset, SubblockLength).Trim([' ', '\0']);
break;
case 0x0D:
Result.AsyncSupport = Response[SubblockPayloadOffset + 1] == 1;
break;
case 0x0F: // Supported but check parsing below pls
SubblockVersion = Response[SubblockPayloadOffset]; // 0x03
Result.PlatformSecureBootEnabled = Response[SubblockPayloadOffset + 0x01] == 0x01;
Result.SecureFfuEnabled = Response[SubblockPayloadOffset + 0x02] == 0x01;
Result.JtagDisabled = Response[SubblockPayloadOffset + 0x03] == 0x01;
Result.RdcPresent = Response[SubblockPayloadOffset + 0x04] == 0x01;
Result.Authenticated = (Response[SubblockPayloadOffset + 0x05] == 0x01) || (Response[SubblockPayloadOffset + 0x05] == 0x02);
Result.UefiSecureBootEnabled = Response[SubblockPayloadOffset + 0x06] == 0x01;
Result.SecondaryHardwareKeyPresent = Response[SubblockPayloadOffset + 0x07] == 0x01;
break;
case 0x10: // Also check to be sure
SubblockVersion = Response[SubblockPayloadOffset]; // 0x01
Result.SecureFfuSupportedProtocolMask = BigEndian.ToUInt16(Response, SubblockPayloadOffset + 0x01);
break;
case 0x1F: // Recheck too
Result.MmosOverUsbSupported = Response[SubblockPayloadOffset] == 1;
break;
case 0x20:
// CRC header info
break;
case 0x22:
uint SectorCount = BigEndian.ToUInt32(Response, SubblockPayloadOffset);
uint SectorSize = BigEndian.ToUInt32(Response, SubblockPayloadOffset + 4);
ushort FlashType = BigEndian.ToUInt16(Response, SubblockPayloadOffset + 8);
ushort FlashTypeIndex = BigEndian.ToUInt16(Response, SubblockPayloadOffset + 10);
uint Unknown = BigEndian.ToUInt32(Response, SubblockPayloadOffset + 12);
string DevicePath = ByteOperations.ReadUnicodeString(Response, (uint)SubblockPayloadOffset + 16, (uint)SubblockLength - 16).Trim([' ', '\0']);
Result.BootDevices.Add((SectorCount, SectorSize, FlashType, FlashTypeIndex, Unknown, DevicePath));
break;
case 0x23:
byte[] Bytes = Response[SubblockPayloadOffset..(SubblockPayloadOffset + SubblockLength)];
ushort ManufacturerLength = BitConverter.ToUInt16(Bytes[0..2].Reverse().ToArray());
ushort FamilyLength = BitConverter.ToUInt16(Bytes[2..4].Reverse().ToArray());
ushort ProductNameLength = BitConverter.ToUInt16(Bytes[4..6].Reverse().ToArray());
ushort ProductVersionLength = BitConverter.ToUInt16(Bytes[6..8].Reverse().ToArray());
ushort SKUNumberLength = BitConverter.ToUInt16(Bytes[8..10].Reverse().ToArray());
ushort BaseboardManufacturerLength = BitConverter.ToUInt16(Bytes[10..12].Reverse().ToArray());
ushort BaseboardProductLength = BitConverter.ToUInt16(Bytes[12..14].Reverse().ToArray());
int CurrentOffset = 14;
Result.Manufacturer = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + ManufacturerLength)]);
CurrentOffset += ManufacturerLength;
Result.Family = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + FamilyLength)]);
CurrentOffset += FamilyLength;
Result.ProductName = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + ProductNameLength)]);
CurrentOffset += ProductNameLength;
Result.ProductVersion = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + ProductVersionLength)]);
CurrentOffset += ProductVersionLength;
Result.SKUNumber = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + SKUNumberLength)]);
CurrentOffset += SKUNumberLength;
Result.BaseboardManufacturer = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + BaseboardManufacturerLength)]);
CurrentOffset += BaseboardManufacturerLength;
Result.BaseboardProduct = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + BaseboardProductLength)]);
break;
case 0x24:
Result.LargestMemoryRegion = BitConverter.ToUInt64(Response[SubblockPayloadOffset..(SubblockPayloadOffset + 8)].Reverse().ToArray());
break;
case 0x25:
Result.AppType = (AppType)Response[SubblockPayloadOffset];
break;
default:
Debug.WriteLine($"Unknown Subblock: ID: 0x{SubblockID:X2} Length: 0x{SubblockLength:X4}");
break;
}
SubblockOffset += SubblockLength + 3;
}
}
Result.State = PhoneInfoState.Basic;
}
Result.IsBootloaderSecure = !(Info.Authenticated || Info.RdcPresent || !Info.SecureFfuEnabled);
if (!PhoneInfoLogged)
{
Result.Log();
}
return Result;
}
public enum FlashAppType
{
FlashApp = 2
};
public enum PhoneInfoState
{
Empty,
Basic
};
public class PhoneInfo
{
public PhoneInfoState State = PhoneInfoState.Empty;
public FlashAppType App;
public byte FlashAppVersionMajor;
public byte FlashAppVersionMinor;
public byte FlashAppProtocolVersionMajor;
public byte FlashAppProtocolVersionMinor;
public uint TransferSize;
public bool MmosOverUsbSupported;
public uint SdCardSizeInSectors;
public uint WriteBufferSize;
public uint EmmcSizeInSectors;
public string? PlatformID;
public ushort 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 string? Manufacturer;
public string? Family;
public string? ProductName;
public string? ProductVersion;
public string? SKUNumber;
public string? BaseboardManufacturer;
public string? BaseboardProduct;
public ulong LargestMemoryRegion;
public AppType AppType;
public List<(uint SectorCount, uint SectorSize, ushort FlashType, ushort FlashIndex, uint Unknown, string DevicePath)> BootDevices = [];
public bool IsBootloaderSecure;
public void Log()
{
switch (App)
{
case FlashAppType.FlashApp:
Debug.WriteLine($"Flash app: {FlashAppVersionMajor}.{FlashAppVersionMinor}");
Debug.WriteLine($"Flash protocol: {FlashAppProtocolVersionMajor}.{FlashAppProtocolVersionMinor}");
break;
}
Debug.WriteLine($"SecureBoot: {((!PlatformSecureBootEnabled || !UefiSecureBootEnabled) ? "Disabled" : "Enabled")} (Platform Secure Boot: {(PlatformSecureBootEnabled ? "Enabled" : "Disabled")}, UEFI Secure Boot: {(UefiSecureBootEnabled ? "Enabled" : "Disabled")})");
Debug.WriteLine($"Flash app security: {(!IsBootloaderSecure ? "Disabled" : "Enabled")}");
Debug.WriteLine($"Flash app security: {(!IsBootloaderSecure ? "Disabled" : "Enabled")} (FFU security: {(SecureFfuEnabled ? "Enabled" : "Disabled")}, RDC: {(RdcPresent ? "Present" : "Not found")}, Authenticated: {(Authenticated ? "True" : "False")})");
Debug.WriteLine($"JTAG: {(JtagDisabled ? "Disabled" : "Enabled")}");
}
}
public void Shutdown()
{
byte[] Request = new byte[4];
const string Header = ShutdownSignature;
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
ExecuteRawVoidMethod(Request);
}
}
}
@@ -0,0 +1,61 @@
using System;
using System.Linq;
using System.Text;
using UnifiedFlashingPlatform.UEFI;
using WPinternals.HelperClasses;
namespace UnifiedFlashingPlatform
{
public partial class UnifiedFlashingPlatformModel
{
public void WriteParam(string Param, byte[] Data)
{
byte[] Request = new byte[0x0F + Data.Length];
const string Header = WriteParamSignature; // NOKXFW
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Param), 0, Request, 7, Param.Length);
// 4 empty bytes here
Buffer.BlockCopy(Data, 0, Request, 15, Data.Length);
ExecuteRawMethod(Request);
}
// TODO: Verify proper functionality
public void SetUEFIVariable(Guid Guid, string Name, UefiVariableAttributes Attributes, byte[] Data)
{
byte[] ParamBuffer = new byte[540 + Data.Length];
/* 15..30 */ Buffer.BlockCopy(Guid.ToByteArray(), 0, ParamBuffer, 0, 16);
/* 31..34 */ Buffer.BlockCopy(BigEndian.GetBytes(Math.Min(512, Name.Length * 2), 4), 0, ParamBuffer, 16, 4);
/* 35.. */ Buffer.BlockCopy(Encoding.Unicode.GetBytes(Name), 0, ParamBuffer, 20, Math.Min(512, Name.Length * 2)); // 256 Max Size for name (unicode)
/* 547..550 */ Buffer.BlockCopy(BigEndian.GetBytes(Attributes, 4), 0, ParamBuffer, 532, 4);
/* 551..554 */ Buffer.BlockCopy(BigEndian.GetBytes(Data.Length, 4), 0, ParamBuffer, 536, 4);
/* 555.. */ Buffer.BlockCopy(Data, 0, ParamBuffer, 540, Data.Length);
WriteParam(SettingUEFIVariableWriteParamSignature, ParamBuffer);
}
public void SetOneTimeBootSequence(ushort BootEntryID)
{
//WriteParam(OneTimeBootSequenceWriteParamSignature, BigEndian.GetBytes(BootEntryID, 2));
WriteParam("UOBU", [.. BigEndian.GetBytes(BootEntryID, 2).Reverse()]);
}
public void SetBootOptionAsFirstEntry(ushort BootEntryID)
{
//WriteParam(BootOptionAsFirstEntryWriteParamSignature, BigEndian.GetBytes(BootEntryID, 2));
WriteParam("UBOF", [.. BigEndian.GetBytes(BootEntryID, 2).Reverse()]);
}
public void SetBootOptionAsLastEntry(ushort BootEntryID)
{
WriteParam(BootOptionAsLastEntryWriteParamSignature, BigEndian.GetBytes(BootEntryID, 2));
}
public void SetProgressBar(uint Percentage)
{
WriteParam("PBI\0", BigEndian.GetBytes(Percentage, 1));
}
}
}
@@ -0,0 +1,359 @@
/*
* MIT License
*
* Copyright (c) 2024 The DuoWOA authors
*
* 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 MadWizard.WinUSBNet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnifiedFlashingPlatform.UEFI;
using WPinternals.HelperClasses;
namespace UnifiedFlashingPlatform
{
public partial class UnifiedFlashingPlatformModel : IDisposable
{
private bool Disposed = false;
private readonly USBDevice USBDevice;
private readonly USBPipe InputPipe;
private readonly USBPipe OutputPipe;
private readonly object UsbLock = new();
public UnifiedFlashingPlatformModel(string DevicePath)
{
USBDevice = new USBDevice(DevicePath);
foreach (USBPipe Pipe in USBDevice.Pipes)
{
if (Pipe.IsIn)
{
InputPipe = Pipe;
}
if (Pipe.IsOut)
{
OutputPipe = Pipe;
}
}
if (InputPipe == null || OutputPipe == null)
{
throw new Exception("Invalid USB device!");
}
}
public byte[]? ExecuteRawMethod(byte[] RawMethod)
{
return ExecuteRawMethod(RawMethod, RawMethod.Length);
}
public byte[]? ExecuteRawMethod(byte[] RawMethod, int Length)
{
byte[] Buffer = new byte[0xF000]; // Should be at least 0x4408 for receiving the GPT packet.
byte[]? Result = null;
lock (UsbLock)
{
OutputPipe.Write(RawMethod, 0, Length);
try
{
int OutputLength = InputPipe.Read(Buffer);
Result = new byte[OutputLength];
System.Buffer.BlockCopy(Buffer, 0, Result, 0, OutputLength);
}
catch { } // Reboot command looses connection
}
return Result;
}
public void ExecuteRawVoidMethod(byte[] RawMethod)
{
ExecuteRawVoidMethod(RawMethod, RawMethod.Length);
}
public void ExecuteRawVoidMethod(byte[] RawMethod, int Length)
{
lock (UsbLock)
{
OutputPipe.Write(RawMethod, 0, Length);
}
}
public void Relock()
{
byte[] Request = new byte[7];
const string Header = RelockSignature; // NOKXFO
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
_ = ExecuteRawMethod(Request);
}
public void MassStorage()
{
byte[] Request = new byte[7];
const string Header = MassStorageSignature; // NOKM
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
_ = ExecuteRawMethod(Request);
}
public void RebootPhone()
{
byte[] Request = new byte[7];
const string Header = $"{SwitchModeSignature}R"; // NOKXCBR
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
_ = ExecuteRawMethod(Request);
}
public void SwitchToUFP()
{
byte[] Request = new byte[7];
const string Header = $"{SwitchModeSignature}U"; // NOKXCBU
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
_ = ExecuteRawMethod(Request);
}
public void ContinueBoot()
{
byte[] Request = new byte[7];
const string Header = $"{SwitchModeSignature}W"; // NOKXCBW
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
_ = ExecuteRawMethod(Request);
}
public void PowerOff()
{
byte[] Request = new byte[7];
const string Header = $"{SwitchModeSignature}Z"; // NOKXCBZ
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
ExecuteRawVoidMethod(Request);
}
public void TransitionToUFPBootApp()
{
byte[] Request = new byte[7];
const string Header = $"{SwitchModeSignature}T"; // NOKXCBT
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
ExecuteRawVoidMethod(Request);
}
public void DisplayCustomMessage(string Message, ushort Row)
{
byte[] MessageBuffer = Encoding.Unicode.GetBytes(Message);
byte[] Request = new byte[8 + MessageBuffer.Length];
const string Header = DisplayCustomMessageSignature; // NOKXCM
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(BitConverter.GetBytes(Row).Reverse().ToArray(), 0, Request, 6, 2);
Buffer.BlockCopy(MessageBuffer, 0, Request, 8, MessageBuffer.Length);
_ = ExecuteRawMethod(Request);
}
public void ClearScreen()
{
byte[] Request = new byte[6];
const string Header = ClearScreenSignature; // NOKXCC
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
_ = ExecuteRawMethod(Request);
}
public byte[]? Echo(byte[] DataPayload)
{
byte[] Request = new byte[10 + DataPayload.Length];
const string Header = EchoSignature; // NOKXCE
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(BitConverter.GetBytes(DataPayload.Length).Reverse().ToArray(), 0, Request, 6, 4);
Buffer.BlockCopy(DataPayload, 0, Request, 10, DataPayload.Length);
byte[]? Response = ExecuteRawMethod(Request);
if ((Response == null) || (Response.Length < 6 + DataPayload.Length))
{
return null;
}
byte[] Result = new byte[DataPayload.Length];
Buffer.BlockCopy(Response, 6, Result, 0, DataPayload.Length);
return Result;
}
public FILE_INFO[]? GetDirectoryEntries(string PartitionName, string DirectoryName)
{
ulong? size = ReadDirectoryEntriesSize(PartitionName, DirectoryName);
if (size == null)
{
return null;
}
return GetDirectoryEntries(PartitionName, DirectoryName, size.Value);
}
private FILE_INFO[]? GetDirectoryEntries(string PartitionName, string DirectoryName, ulong DataStructSize)
{
if (PartitionName.Length > 35)
{
return null;
}
byte[] PartitionNameBuffer = Encoding.Unicode.GetBytes(PartitionName);
byte[] DirectoryNameBuffer = Encoding.Unicode.GetBytes(DirectoryName);
byte[] Request = new byte[1114];
const string Header = GetDirectoryEntriesSignature; // NOKXCD
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(PartitionNameBuffer, 0, Request, 6, PartitionNameBuffer.Length);
Buffer.BlockCopy(DirectoryNameBuffer, 0, Request, 78, DirectoryNameBuffer.Length); // 512 max size (1024 for unicode)
Buffer.BlockCopy(BigEndian.GetBytes((int)DataStructSize, 4), 0, Request, 1102, 4);
// TODO: Investigate data size
//Buffer.BlockCopy(BigEndian.GetBytes(360, 8), 0, Request, 1106, 8);
byte[]? Response = ExecuteRawMethod(Request);
if ((Response == null) || (Response.Length < 0x10))
{
return null;
}
int ResultCode = (Response[6] << 8) + Response[7];
if (ResultCode != 0)
{
ThrowFlashError(ResultCode);
}
int ResponseLength = BigEndian.ToInt32(Response, 8);
byte[] Result = new byte[ResponseLength];
Buffer.BlockCopy(Response, 12, Result, 0, ResponseLength);
List<FILE_INFO> directoryEntries = [];
int j = 0;
while (j != Result.Length)
{
FILE_INFO directoryEntry = FILE_INFO.ReadFromBuffer(Result, j);
j += (int)directoryEntry.Size;
directoryEntries.Add(directoryEntry);
}
return [.. directoryEntries];
}
public void TelemetryStart()
{
byte[] Request = new byte[4];
const string Header = TelemetryStartSignature; // NOKS
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
ExecuteRawVoidMethod(Request);
}
public void TelemetryEnd()
{
byte[] Request = new byte[4];
const string Header = TelemetryEndSignature; // NOKN
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
ExecuteRawVoidMethod(Request);
}
// WIP!
public string? ReadLog()
{
byte[] Request = new byte[0x13];
const string Header = GetLogsSignature;
ulong BufferSize = 0xE000 - 0xC;
ulong Length = ReadLogSize(DeviceLogType.Flashing)!.Value;
if (Length == 0)
{
return null;
}
string LogContent = "";
for (ulong i = 0; i < Length; i += BufferSize)
{
if (i + BufferSize > Length)
{
BufferSize = Length - i;
}
uint BufferSizeInt = (uint)BufferSize;
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Request[6] = 1;
Buffer.BlockCopy(BitConverter.GetBytes(BufferSizeInt).Reverse().ToArray(), 0, Request, 7, 4);
Buffer.BlockCopy(BitConverter.GetBytes(i).Reverse().ToArray(), 0, Request, 11, 8);
byte[]? Response = ExecuteRawMethod(Request);
if ((Response == null) || (Response.Length < 0xC))
{
return null;
}
int ResultLength = Response.Length - 0xC;
byte[] Result = new byte[ResultLength];
Buffer.BlockCopy(Response, 0xC, Result, 0, ResultLength);
string PartialLogContent = Encoding.ASCII.GetString(Result);
LogContent += PartialLogContent;
}
return LogContent;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~UnifiedFlashingPlatformModel()
{
Dispose(false);
}
public void Close()
{
USBDevice?.Dispose();
}
protected virtual void Dispose(bool disposing)
{
if (Disposed)
{
return;
}
if (disposing)
{
// Other disposables
}
// Clean unmanaged resources here.
Close();
Disposed = true;
}
}
}
@@ -20,18 +20,8 @@
using Microsoft.Win32; using Microsoft.Win32;
using System; using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.IO; using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Data;
using WPinternals.HelperClasses; using WPinternals.HelperClasses;
using WPinternals.Models.Lumia.MSR;
using WPinternals.Models.Lumia.NCSd; using WPinternals.Models.Lumia.NCSd;
using WPinternals.Models.UEFIApps.Flash; using WPinternals.Models.UEFIApps.Flash;
using WPinternals.Models.UEFIApps.PhoneInfo; using WPinternals.Models.UEFIApps.PhoneInfo;
@@ -41,7 +31,6 @@ namespace WPinternals
internal class DownloadsViewModel : ContextViewModel internal class DownloadsViewModel : ContextViewModel
{ {
private readonly PhoneNotifierViewModel Notifier; private readonly PhoneNotifierViewModel Notifier;
private bool IsSearching = false;
internal DownloadsViewModel(PhoneNotifierViewModel Notifier) internal DownloadsViewModel(PhoneNotifierViewModel Notifier)
{ {
@@ -50,11 +39,6 @@ namespace WPinternals
this.Notifier = Notifier; this.Notifier = Notifier;
Notifier.NewDeviceArrived += Notifier_NewDeviceArrived; Notifier.NewDeviceArrived += Notifier_NewDeviceArrived;
RegistryKey Key = Registry.CurrentUser.OpenSubKey(@"Software\WPInternals", true) ?? Registry.CurrentUser.CreateSubKey(@"Software\WPInternals");
DownloadFolder = (string)Key.GetValue("DownloadFolder", @"C:\ProgramData\WPinternals\Repository");
Key.Close();
AddFFUCommand = new DelegateCommand(() => AddFFUCommand = new DelegateCommand(() =>
{ {
string FFUPath = null; string FFUPath = null;
@@ -170,331 +154,11 @@ namespace WPinternals
} }
} }
internal static void TimerCallback(object State)
{
foreach (DownloadEntry Entry in App.DownloadManager.DownloadList)
{
if (Entry.SpeedIndex >= 0)
{
int ArrayIndex = (int)(Entry.SpeedIndex % 10);
Entry.Speeds[ArrayIndex] = Entry.BytesReceived - Entry.LastBytesReceived;
int Count = (int)((Entry.SpeedIndex + 1) > 10 ? 10 : (Entry.SpeedIndex + 1));
long Sum = 0;
for (int i = 0; i < Count; i++)
{
Sum += Entry.Speeds[i];
}
Entry.Speed = Sum / Count;
Entry.TimeLeft = Entry.Speed < 1000 ? Timeout.InfiniteTimeSpan : TimeSpan.FromSeconds((Entry.Size - Entry.BytesReceived) / Entry.Speed);
}
Entry.LastBytesReceived = Entry.BytesReceived;
Entry.SpeedIndex++;
}
}
private void Notifier_NewDeviceArrived(ArrivalEventArgs Args) private void Notifier_NewDeviceArrived(ArrivalEventArgs Args)
{ {
EvaluateViewState(); EvaluateViewState();
} }
internal static long GetFileLengthFromURL(string URL)
{
long Length = 0;
WebRequest webReq = WebRequest.Create(URL);
if (webReq is HttpWebRequest req)
{
req.Method = "HEAD";
req.ServicePoint.ConnectionLimit = 10;
using (WebResponse resp = req.GetResponse())
{
long.TryParse(resp.Headers.Get("Content-Length"), out 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)
{
string FileName = Path.GetFileName(URL);
int End = FileName.IndexOf('?');
if (End >= 0)
{
FileName = FileName.Substring(0, End);
}
return FileName;
}
private void Search()
{
if (IsSearching)
{
return;
}
IsSearching = true;
SynchronizationContext UIContext = SynchronizationContext.Current;
SearchResultList.Clear();
new Thread(() =>
{
string[] EmergencyURLs = null;
try
{
string TempProductType = ProductType.ToUpper();
if ((TempProductType?.StartsWith("RM") == true) && !TempProductType.StartsWith("RM-"))
{
TempProductType = "RM-" + TempProductType[2..];
}
ProductType = TempProductType;
if (TempProductType != null)
{
ProductType = TempProductType;
}
if (ProductType != null)
{
EmergencyURLs = LumiaDownloadModel.SearchEmergencyFiles(ProductType);
}
}
catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
UIContext.Post(s =>
{
if (EmergencyURLs != null)
{
SearchResultList.Add(new SearchResult($"{ProductType} emergency-files", EmergencyURLs, ProductType, EmergencyDownloaded, ProductType));
}
}, null);
IsSearching = false;
}).Start();
}
internal void Download(string URL, string Category, Action<string[], object> Callback, object State = null)
{
string Folder = Category == null ? DownloadFolder : Path.Combine(DownloadFolder, Category);
DownloadList.Add(new DownloadEntry(URL, Folder, null, Callback, State));
}
internal void Download(string[] URLs, string Category, Action<string[], object> Callback, object State = null)
{
string Folder = Category == null ? DownloadFolder : Path.Combine(DownloadFolder, Category);
foreach (string URL in URLs)
{
DownloadList.Add(new DownloadEntry(URL, Folder, URLs, Callback, State));
}
}
private void DownloadAll()
{
SynchronizationContext UIContext = SynchronizationContext.Current;
new Thread(() =>
{
string[] EmergencyURLs = null;
try
{
string TempProductType = ProductType.ToUpper();
if ((TempProductType?.StartsWith("RM") == true) && !TempProductType.StartsWith("RM-"))
{
TempProductType = "RM-" + TempProductType[2..];
}
ProductType = TempProductType;
if (TempProductType != null)
{
ProductType = TempProductType;
}
if (ProductType != null)
{
EmergencyURLs = LumiaDownloadModel.SearchEmergencyFiles(ProductType);
}
}
catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
UIContext.Post(s =>
{
if (EmergencyURLs != null)
{
Download(EmergencyURLs, ProductType, EmergencyDownloaded, ProductType);
}
}, null);
}).Start();
}
private void DownloadSelected()
{
foreach (SearchResult Result in SearchResultList.Where(r => r.IsSelected))
{
App.DownloadManager.Download(Result.URLs, Result.Category, Result.Callback, Result.State);
}
}
private void EmergencyDownloaded(string[] Files, object State)
{
string Type = (string)State;
string ProgrammerPath = null;
string PayloadPath = null;
for (int i = 0; i < Files.Length; i++)
{
if (Files[i].EndsWith(".ede", StringComparison.OrdinalIgnoreCase))
{
ProgrammerPath = Files[i];
}
if (Files[i].EndsWith(".edp", StringComparison.OrdinalIgnoreCase))
{
PayloadPath = Files[i];
}
}
if ((Type != null) && (ProgrammerPath != null) && (PayloadPath != null))
{
App.Config.AddEmergencyToRepository(Type, ProgrammerPath, PayloadPath);
}
}
public ObservableCollection<DownloadEntry> DownloadList { get; } = [];
public ObservableCollection<SearchResult> SearchResultList { get; } = [];
private DelegateCommand _DownloadSelectedCommand = null;
public DelegateCommand DownloadSelectedCommand
{
get
{
return _DownloadSelectedCommand ??= new DelegateCommand(() => DownloadSelected());
}
}
private DelegateCommand _SearchCommand = null;
public DelegateCommand SearchCommand
{
get
{
return _SearchCommand ??= new DelegateCommand(() => Search());
}
}
private DelegateCommand _DownloadAllCommand = null;
public DelegateCommand DownloadAllCommand
{
get
{
return _DownloadAllCommand ??= new DelegateCommand(() => DownloadAll());
}
}
private string _DownloadFolder = null;
public string DownloadFolder
{
get
{
return _DownloadFolder;
}
set
{
if (_DownloadFolder != value)
{
_DownloadFolder = value;
try
{
Directory.CreateDirectory(_DownloadFolder);
}
catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
if (!Directory.Exists(_DownloadFolder))
{
_DownloadFolder = @"C:\ProgramData\WPinternals\Repository";
Directory.CreateDirectory(_DownloadFolder);
}
RegistryKey Key = Registry.CurrentUser.OpenSubKey(@"Software\WPInternals", true);
if (_DownloadFolder == null)
{
if (Key.GetValue("DownloadFolder") != null)
{
Key.DeleteValue("DownloadFolder");
}
}
else
{
Key.SetValue("DownloadFolder", _DownloadFolder);
}
Key.Close();
OnPropertyChanged(nameof(DownloadFolder));
}
}
}
private string _ProductCode = null;
public string ProductCode
{
get
{
return _ProductCode;
}
set
{
if (_ProductCode != value)
{
_ProductCode = value;
OnPropertyChanged(nameof(ProductCode));
}
}
}
private string _ProductType = null;
public string ProductType
{
get
{
return _ProductType;
}
set
{
if (_ProductType != value)
{
_ProductType = value;
OnPropertyChanged(nameof(ProductType));
}
}
}
private string _FirmwareVersion = null; private string _FirmwareVersion = null;
public string FirmwareVersion public string FirmwareVersion
{ {
@@ -513,24 +177,6 @@ namespace WPinternals
} }
} }
private string _OperatorCode = null;
public string OperatorCode
{
get
{
return _OperatorCode;
}
set
{
if (_OperatorCode != value)
{
_OperatorCode = value;
OnPropertyChanged(nameof(OperatorCode));
}
}
}
internal override async void EvaluateViewState() internal override async void EvaluateViewState()
{ {
if (IsSwitchingInterface) if (IsSwitchingInterface)
@@ -574,9 +220,6 @@ namespace WPinternals
LumiaPhoneInfoAppModel LumiaPhoneInfoModel = (LumiaPhoneInfoAppModel)Notifier.CurrentModel; LumiaPhoneInfoAppModel LumiaPhoneInfoModel = (LumiaPhoneInfoAppModel)Notifier.CurrentModel;
LumiaPhoneInfoAppPhoneInfo Info = LumiaPhoneInfoModel.ReadPhoneInfo(); LumiaPhoneInfoAppPhoneInfo Info = LumiaPhoneInfoModel.ReadPhoneInfo();
ProductType = Info.Type;
OperatorCode = "";
ProductCode = Info.ProductCode;
ModernFlashApp = Info.PhoneInfoAppVersionMajor >= 2; ModernFlashApp = Info.PhoneInfoAppVersionMajor >= 2;
if (ModernFlashApp) if (ModernFlashApp)
@@ -609,9 +252,6 @@ namespace WPinternals
{ {
LumiaPhoneInfoAppModel LumiaPhoneInfoModel = (LumiaPhoneInfoAppModel)Notifier.CurrentModel; LumiaPhoneInfoAppModel LumiaPhoneInfoModel = (LumiaPhoneInfoAppModel)Notifier.CurrentModel;
LumiaPhoneInfoAppPhoneInfo Info = LumiaPhoneInfoModel.ReadPhoneInfo(); LumiaPhoneInfoAppPhoneInfo Info = LumiaPhoneInfoModel.ReadPhoneInfo();
ProductType = Info.Type;
OperatorCode = "";
ProductCode = Info.ProductCode;
IsSwitchingInterface = true; IsSwitchingInterface = true;
@@ -663,556 +303,10 @@ namespace WPinternals
else if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Normal) else if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Normal)
{ {
NokiaCareSuiteModel LumiaNormalModel = (NokiaCareSuiteModel)Notifier.CurrentModel; NokiaCareSuiteModel LumiaNormalModel = (NokiaCareSuiteModel)Notifier.CurrentModel;
OperatorCode = LumiaNormalModel.ExecuteJsonMethodAsString("ReadOperatorName", "OperatorName"); // Example: 000-NL
string TempProductType = LumiaNormalModel.ExecuteJsonMethodAsString("ReadManufacturerModelName", "ManufacturerModelName"); // RM-821_eu_denmark_251
if (TempProductType.Contains('_'))
{
TempProductType = TempProductType.Substring(0, TempProductType.IndexOf('_'));
}
ProductType = TempProductType;
ProductCode = LumiaNormalModel.ExecuteJsonMethodAsString("ReadProductCode", "ProductCode"); // 059Q9D7
FirmwareVersion = LumiaNormalModel.ExecuteJsonMethodAsString("ReadSwVersion", "SwVersion"); FirmwareVersion = LumiaNormalModel.ExecuteJsonMethodAsString("ReadSwVersion", "SwVersion");
} }
} }
public DelegateCommand AddFFUCommand { get; } = null; public DelegateCommand AddFFUCommand { get; } = null;
public DelegateCommand AddSecWIMCommand { get; } = null; public DelegateCommand AddSecWIMCommand { get; } = null;
} }
internal enum DownloadStatus
{
Downloading,
Ready,
Failed
};
internal class DownloadEntry : INotifyPropertyChanged, IProgress<GeneralDownloadProgress>
{
private readonly SynchronizationContext UIContext;
public event PropertyChangedEventHandler PropertyChanged = delegate { };
internal Action<string[], object> Callback;
internal object State;
internal string URL;
internal string[] URLCollection;
internal string Folder;
//internal HttpClient Client;
internal HttpDownloader Client;
internal long SpeedIndex = -1;
internal long[] Speeds = new long[10];
internal long LastBytesReceived;
internal long BytesReceived;
internal DownloadEntry(string URL, string Folder, string[] URLCollection, Action<string[], object> Callback, object State)
{
UIContext = SynchronizationContext.Current;
this.URL = URL;
this.Callback = Callback;
this.State = State;
this.URLCollection = URLCollection;
this.Folder = Folder;
Directory.CreateDirectory(Folder);
Name = DownloadsViewModel.GetFileNameFromURL(URL);
Uri Uri = new(URL);
Status = DownloadStatus.Downloading;
new Thread(() =>
{
Size = DownloadsViewModel.GetFileLengthFromURL(URL);
//Client = new HttpClient();
//_ = 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();
}
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)
{
void Finish()
{
Status = Error ? DownloadStatus.Failed : DownloadStatus.Ready;
App.DownloadManager.DownloadList.Remove(this);
if (Status == DownloadStatus.Ready)
{
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;
if (URLCollection == null)
{
Files = new string[1];
Files[0] = Path.Combine(Folder, DownloadsViewModel.GetFileNameFromURL(URL));
}
else
{
Files = new string[URLCollection.Length];
for (int i = 0; i < URLCollection.Length; i++)
{
Files[i] = Path.Combine(Folder, DownloadsViewModel.GetFileNameFromURL(URLCollection[i]));
}
}
Callback(Files, State);
}
}
}
if (UIContext == null)
{
Finish();
}
else
{
UIContext?.Post(d => Finish(), null);
}
}
private void Client_DownloadProgressChanged(HttpClientDownloadProgress e)
{
BytesReceived = e.BytesReceived;
Progress = e.ProgressPercentage;
}
protected void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
if (SynchronizationContext.Current == UIContext)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
else
{
UIContext.Post((s) => PropertyChanged(this, new PropertyChangedEventArgs(propertyName)), null);
}
}
}
private DownloadStatus _Status;
public DownloadStatus Status
{
get
{
return _Status;
}
set
{
if (_Status != value)
{
_Status = value;
OnPropertyChanged(nameof(Status));
}
}
}
private string _Name;
public string Name
{
get
{
return _Name;
}
set
{
if (_Name != value)
{
_Name = value;
OnPropertyChanged(nameof(Name));
}
}
}
private long _Size;
public long Size
{
get
{
return _Size;
}
set
{
if (_Size != value)
{
_Size = value;
OnPropertyChanged(nameof(Size));
}
}
}
private TimeSpan _TimeLeft;
public TimeSpan TimeLeft
{
get
{
return _TimeLeft;
}
set
{
if (_TimeLeft != value)
{
_TimeLeft = value;
OnPropertyChanged(nameof(TimeLeft));
}
}
}
private double _Speed;
public double Speed
{
get
{
return _Speed;
}
set
{
if (_Speed != value)
{
_Speed = value;
OnPropertyChanged(nameof(Speed));
}
}
}
private int _Progress;
public int Progress
{
get
{
return _Progress;
}
set
{
if (_Progress != value)
{
_Progress = value;
OnPropertyChanged(nameof(Progress));
}
}
}
}
internal class SearchResult : INotifyPropertyChanged
{
private readonly SynchronizationContext UIContext;
public event PropertyChangedEventHandler PropertyChanged;
internal string[] URLs;
internal Action<string[], object> Callback;
internal object State;
internal string Category;
internal SearchResult(string URL, string Category, Action<string[], object> Callback, object State)
{
UIContext = SynchronizationContext.Current;
URLs = new string[1];
URLs[0] = URL;
Name = DownloadsViewModel.GetFileNameFromURL(URL);
this.Callback = Callback;
this.State = State;
this.Category = Category;
GetSize();
}
internal SearchResult(string Name, string[] URLs, string Category, Action<string[], object> Callback, object State)
{
UIContext = SynchronizationContext.Current;
this.URLs = URLs;
this.Name = Name;
this.Callback = Callback;
this.State = State;
this.Category = Category;
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()
{
new Thread(() =>
{
long CalcSize = 0;
foreach (string URL in URLs)
{
CalcSize += DownloadsViewModel.GetFileLengthFromURL(URL);
}
Size = CalcSize;
}).Start();
}
protected void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
if (SynchronizationContext.Current == UIContext)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
else
{
UIContext.Post((s) => PropertyChanged(this, new PropertyChangedEventArgs(propertyName)), null);
}
}
}
private string _Name;
public string Name
{
get
{
return _Name;
}
set
{
if (_Name != value)
{
_Name = value;
OnPropertyChanged(nameof(Name));
}
}
}
private long _Size;
public long Size
{
get
{
return _Size;
}
set
{
if (_Size != value)
{
_Size = value;
OnPropertyChanged(nameof(Size));
}
}
}
private bool _IsSelected;
public bool IsSelected
{
get
{
return _IsSelected;
}
set
{
if (_IsSelected != value)
{
_IsSelected = value;
OnPropertyChanged(nameof(IsSelected));
}
}
}
}
public class HttpClientDownloadProgress
{
//
// Summary:
// Gets the asynchronous task progress percentage.
//
// Returns:
// A percentage value indicating the asynchronous task progress.
public int ProgressPercentage { get; }
//
// Summary:
// Gets the number of bytes received.
//
// Returns:
// An System.Int64 value that indicates the number of bytes received.
public long BytesReceived { get; }
//
// Summary:
// Gets the total number of bytes in a System.Net.WebClient data download operation.
//
// Returns:
// An System.Int64 value that indicates the number of bytes that will be received.
public long TotalBytesToReceive { get; }
internal HttpClientDownloadProgress(long BytesReceived, long TotalBytesToReceive)
{
this.TotalBytesToReceive = TotalBytesToReceive;
this.BytesReceived = BytesReceived;
ProgressPercentage = (int)Math.Round((float)BytesReceived / TotalBytesToReceive * 100f);
}
}
public static class HttpClientProgressExtensions
{
public static async Task DownloadFileAsync(this HttpClient client, Uri address, string fileName, Action<HttpClientDownloadProgress> progress = null, Action<bool> completed = null, CancellationToken cancellationToken = default)
{
try
{
using FileStream destination = File.Create(fileName);
using HttpResponseMessage response = await client.GetAsync(address, HttpCompletionOption.ResponseHeadersRead);
long? contentLength = response.Content.Headers.ContentLength;
using Stream download = await response.Content.ReadAsStreamAsync();
if (progress is null || !contentLength.HasValue)
{
await download.CopyToAsync(destination);
completed?.Invoke(true);
return;
}
Progress<long> progressWrapper = new(totalBytes => progress(new HttpClientDownloadProgress(totalBytes, contentLength.Value)));
await download.CopyToAsync(destination, 81920, progressWrapper, cancellationToken);
completed?.Invoke(true);
}
catch (Exception ex)
{
LogFile.Log("An unexpected error happened", LogType.FileAndConsole);
LogFile.Log(ex.GetType().ToString(), LogType.FileAndConsole);
LogFile.Log(ex.Message, LogType.FileAndConsole);
LogFile.Log(ex.StackTrace, LogType.FileAndConsole);
completed?.Invoke(false);
}
}
private static async Task CopyToAsync(this Stream source, Stream destination, int bufferSize, IProgress<long> progress = null, CancellationToken cancellationToken = default)
{
if (bufferSize < 0)
throw new ArgumentOutOfRangeException(nameof(bufferSize));
if (source is null)
throw new ArgumentNullException(nameof(source));
if (!source.CanRead)
throw new InvalidOperationException($"'{nameof(source)}' is not readable.");
if (destination == null)
throw new ArgumentNullException(nameof(destination));
if (!destination.CanWrite)
throw new InvalidOperationException($"'{nameof(destination)}' is not writable.");
byte[] buffer = new byte[bufferSize];
long totalBytesRead = 0;
int bytesRead;
while ((bytesRead = await source.ReadAsync(buffer, cancellationToken).ConfigureAwait(false)) != 0)
{
await destination.WriteAsync(buffer.AsMemory(0, bytesRead), cancellationToken).ConfigureAwait(false);
totalBytesRead += bytesRead;
progress?.Report(totalBytesRead);
}
}
}
public class DownloaderNameConvertor : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
return Path.GetFileNameWithoutExtension((string)value);
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
return Binding.DoNothing;
}
}
public class DownloaderSizeConvertor : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
long? Size = value as long?;
if (Size < 1024)
{
return Size + " B";
}
if (Size < (1024 * 1024))
{
return Math.Round((double)Size / 1024, 0) + " KB";
}
return Math.Round((double)Size / 1024 / 1024, 0) + " MB";
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
return Binding.DoNothing;
}
}
public class DownloaderSpeedConvertor : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
return ((int)((double)value / 1024)).ToString() + " KB/s";
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
return Binding.DoNothing;
}
}
public class DownloaderTimeRemainingConvertor : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
TimeSpan TimeLeft = (TimeSpan)value;
if (TimeLeft == Timeout.InfiniteTimeSpan)
{
return "";
}
return TimeLeft.ToString(@"h\:mm\:ss");
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
return Binding.DoNothing;
}
}
} }
@@ -19,8 +19,10 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using UnifiedFlashingPlatform;
using WPinternals.HelperClasses; using WPinternals.HelperClasses;
using WPinternals.Models.Lumia.NCSd; using WPinternals.Models.Lumia.NCSd;
using WPinternals.Models.SimpleIO;
using WPinternals.Models.UEFIApps.BootMgr; using WPinternals.Models.UEFIApps.BootMgr;
using WPinternals.Models.UEFIApps.Flash; using WPinternals.Models.UEFIApps.Flash;
using WPinternals.Models.UEFIApps.PhoneInfo; using WPinternals.Models.UEFIApps.PhoneInfo;
@@ -91,6 +93,12 @@ namespace WPinternals
case PhoneInterfaces.Lumia_MassStorage: case PhoneInterfaces.Lumia_MassStorage:
ActivateSubContext(new NokiaMassStorageViewModel((MassStorage)CurrentModel)); ActivateSubContext(new NokiaMassStorageViewModel((MassStorage)CurrentModel));
break; break;
case PhoneInterfaces.SimpleIO:
ActivateSubContext(new SimpleIOViewModel((SimpleIOModel)CurrentModel, ModeSwitchRequestCallback));
break;
case PhoneInterfaces.UFP:
ActivateSubContext(new UFPViewModel((UnifiedFlashingPlatformModel)CurrentModel, ModeSwitchRequestCallback));
break;
} }
} }
} }
@@ -19,8 +19,10 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using UnifiedFlashingPlatform;
using WPinternals.HelperClasses; using WPinternals.HelperClasses;
using WPinternals.Models.Lumia.NCSd; using WPinternals.Models.Lumia.NCSd;
using WPinternals.Models.SimpleIO;
using WPinternals.Models.UEFIApps.BootMgr; using WPinternals.Models.UEFIApps.BootMgr;
using WPinternals.Models.UEFIApps.Flash; using WPinternals.Models.UEFIApps.Flash;
using WPinternals.Models.UEFIApps.PhoneInfo; using WPinternals.Models.UEFIApps.PhoneInfo;
@@ -109,6 +111,12 @@ namespace WPinternals
case PhoneInterfaces.Lumia_MassStorage: case PhoneInterfaces.Lumia_MassStorage:
ActivateSubContext(new NokiaModeMassStorageViewModel((MassStorage)CurrentModel, OnModeSwitchRequested)); ActivateSubContext(new NokiaModeMassStorageViewModel((MassStorage)CurrentModel, OnModeSwitchRequested));
break; break;
case PhoneInterfaces.SimpleIO:
ActivateSubContext(new SimpleIOModeViewModel((SimpleIOModel)CurrentModel, OnModeSwitchRequested));
break;
case PhoneInterfaces.UFP:
ActivateSubContext(new UFPModeViewModel((UnifiedFlashingPlatformModel)CurrentModel, OnModeSwitchRequested));
break;
} }
} }
@@ -2108,7 +2108,7 @@ namespace WPinternals
Part = new FlashPart(); Part = new FlashPart();
Partition TargetPartition = GPT.GetPartition("UEFI_BS_NV"); Partition TargetPartition = GPT.GetPartition("UEFI_BS_NV");
Part.StartSector = (UInt32)TargetPartition.FirstSector; // GPT is prepared for 64-bit sector-offset, but flash app isn't. Part.StartSector = (UInt32)TargetPartition.FirstSector; // GPT is prepared for 64-bit sector-offset, but flash app isn't.
string SBRes = IsSpecB ? "WPinternals.SB" : "WPinternals.SBA"; string SBRes = IsSpecB ? "WPinternals.Assets.SB" : "WPinternals.Assets.SBA";
Part.Stream = new SeekableStream(() => Part.Stream = new SeekableStream(() =>
{ {
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly(); System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
@@ -197,7 +197,7 @@ namespace WPinternals
// It overwrites the variable in a different NV-partition than where this variable is stored usually. // 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. // 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. // But the partition contains an extra hack to break out the endless loops.
Stream stream = assembly.GetManifestResourceStream("WPinternals.SB"); Stream stream = assembly.GetManifestResourceStream("WPinternals.Assets.SB");
return new DecompressedStream(stream); return new DecompressedStream(stream);
}); });
@@ -2293,7 +2293,7 @@ namespace WPinternals
// It overwrites the variable in a different NV-partition than where this variable is stored usually. // 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. // 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. // But the partition contains an extra hack to break out the endless loops.
Stream stream = assembly.GetManifestResourceStream("WPinternals.SB"); Stream stream = assembly.GetManifestResourceStream("WPinternals.Assets.SB");
return new DecompressedStream(stream); return new DecompressedStream(stream);
}); });
@@ -2652,7 +2652,7 @@ namespace WPinternals
// It overwrites the variable in a different NV-partition than where this variable is stored usually. // 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. // 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. // But the partition contains an extra hack to break out the endless loops.
Stream stream = assembly.GetManifestResourceStream("WPinternals.SB"); Stream stream = assembly.GetManifestResourceStream("WPinternals.Assets.SB");
return new DecompressedStream(stream); return new DecompressedStream(stream);
}); });
+3 -1
View File
@@ -49,7 +49,9 @@ namespace WPinternals
Qualcomm_Download, Qualcomm_Download,
Qualcomm_Flash, Qualcomm_Flash,
Lumia_BadMassStorage, Lumia_BadMassStorage,
Lumia_PhoneInfo Lumia_PhoneInfo,
SimpleIO,
UFP
}; };
// 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.
@@ -28,10 +28,10 @@ namespace WPinternals
private readonly MassStorage CurrentModel; private readonly MassStorage CurrentModel;
private readonly Action<PhoneInterfaces?> RequestModeSwitch; private readonly Action<PhoneInterfaces?> RequestModeSwitch;
internal NokiaModeMassStorageViewModel(NokiaPhoneModel CurrentModel, Action<PhoneInterfaces?> RequestModeSwitch) internal NokiaModeMassStorageViewModel(MassStorage CurrentModel, Action<PhoneInterfaces?> RequestModeSwitch)
: base() : base()
{ {
this.CurrentModel = (MassStorage)CurrentModel; this.CurrentModel = CurrentModel;
this.RequestModeSwitch = RequestModeSwitch; this.RequestModeSwitch = RequestModeSwitch;
} }

Some files were not shown because too many files have changed in this diff Show More