Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d270cace79 | ||
|
|
af61c9ad29 | ||
|
|
de4d5e577a | ||
|
|
df02025a31 | ||
|
|
ad92ecdab3 | ||
|
|
b3b037a3c8 | ||
|
|
be15155c39 | ||
|
|
a17dae3931 | ||
|
|
7646e3fc76 | ||
|
|
933e9e53b6 | ||
|
|
e838168127 | ||
|
|
058cde0d91 | ||
|
|
1cc7a5cee4 | ||
|
|
132e21e58a | ||
|
|
1e5da5452b | ||
|
|
6992ed3f70 | ||
|
|
bb9702a3c3 |
@@ -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,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,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"
|
||||||
|
|
||||||
|
|||||||
@@ -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,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,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("")]
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,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,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,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,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
|
||||||
|
|||||||
@@ -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,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,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,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,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\"),");
|
||||||
|
|||||||
@@ -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,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,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"),
|
||||||
|
|||||||
@@ -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 |
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -32,15 +32,7 @@ namespace WPinternals.Models.Lumia
|
|||||||
|
|
||||||
public NokiaPhoneModel(string DevicePath)
|
public NokiaPhoneModel(string DevicePath)
|
||||||
{
|
{
|
||||||
// Mass Storage device is not WinUSB
|
Device = new USBDevice(DevicePath);
|
||||||
try
|
|
||||||
{
|
|
||||||
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.
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
namespace UnifiedFlashingPlatform
|
||||||
|
{
|
||||||
|
internal enum FfuProtocol
|
||||||
|
{
|
||||||
|
ProtocolSyncV1 = 1,
|
||||||
|
ProtocolAsyncV1 = 2,
|
||||||
|
ProtocolSyncV2 = 4,
|
||||||
|
ProtocolAsyncV2 = 8,
|
||||||
|
ProtocolAsyncV3 = 16
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||