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
|
||||
{
|
||||
internal static class EncodingHelper
|
||||
public static class EncodingHelper
|
||||
{
|
||||
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
|
||||
{
|
||||
internal static class Utilities
|
||||
public static class Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// 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
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
|
||||
@@ -1,26 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0-windows</TargetFramework>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RootNamespace>Patcher</RootNamespace>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
</PropertyGroup>
|
||||
<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>
|
||||
<Platforms>x86</Platforms>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\Patcher\ArmCompiler.cs">
|
||||
@@ -50,7 +35,5 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<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>
|
||||
</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
|
||||
//
|
||||
@@ -81,7 +81,7 @@ PatchDefinition Name="RootAccess-MainOS" VersionFrom="EFIESP\Windows\System32\Bo
|
||||
|
||||
PatchFile Path="Windows\System32\ntoskrnl.exe"
|
||||
|
||||
// Fase 1: find all kernel-functions
|
||||
// Phase 1: find all kernel-functions
|
||||
|
||||
JumpToExport "SeAccessCheckWithHint"
|
||||
CreateLabel "SeAccessCheckWithHint"
|
||||
@@ -150,7 +150,7 @@ PatchDefinition Name="RootAccess-MainOS" VersionFrom="EFIESP\Windows\System32\Bo
|
||||
JumpToExport "ObReferenceObjectByHandleWithTag"
|
||||
CreateLabel "ObReferenceObjectByHandleWithTag"
|
||||
|
||||
// Fase 2: patches
|
||||
// Phase 2: patches
|
||||
|
||||
JumpToLabel "SeAccessCheckByType"
|
||||
|
||||
|
||||
@@ -183,7 +183,7 @@
|
||||
this.label4.Name = "label4";
|
||||
this.label4.Size = new System.Drawing.Size(117, 13);
|
||||
this.label4.TabIndex = 3;
|
||||
this.label4.Text = "Patch defintions xml-file";
|
||||
this.label4.Text = "Patch definitions xml-file";
|
||||
//
|
||||
// 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
|
||||
// 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
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("AutoPatcher")]
|
||||
[assembly: AssemblyTitle("ARM Auto-patcher")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("AutoPatcher")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||
[assembly: AssemblyCompany("WPinternals.net")]
|
||||
[assembly: AssemblyProduct("ARM Auto-patcher")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2018 by Rene Lergner")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[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
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
@@ -617,7 +617,7 @@ namespace Patcher
|
||||
// Patch bytes in buffer
|
||||
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);
|
||||
if (CurrentPatch == null)
|
||||
{
|
||||
@@ -1487,13 +1487,16 @@ namespace Patcher
|
||||
|
||||
if (FindSuccess)
|
||||
{
|
||||
FunctionDescriptor FoundLabel = Labels.Find(l => string.Equals(l.Name, Label, StringComparison.CurrentCultureIgnoreCase));
|
||||
if (FoundLabel == null)
|
||||
throw new ScriptExecutionException("Label not found: " + Label);
|
||||
|
||||
WriteLog("Condition was found, jumping to label: " + Label);
|
||||
WriteLog("New virtual address: 0x" + FoundLabel.VirtualAddress.ToString("X8"));
|
||||
CurrentVirtualAddressTarget = FoundLabel.VirtualAddress;
|
||||
CodeLine NewLine = ScriptCode.Find(l => string.Equals(l.Label, Label, StringComparison.CurrentCultureIgnoreCase));
|
||||
if (NewLine == null)
|
||||
{
|
||||
throw new ScriptExecutionException("Label " + Label + " not found");
|
||||
}
|
||||
else
|
||||
{
|
||||
Pointer = ScriptCode.IndexOf(NewLine);
|
||||
WriteLog("Go to label: " + Label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1504,13 +1507,16 @@ namespace Patcher
|
||||
|
||||
if (!FindSuccess)
|
||||
{
|
||||
FunctionDescriptor FoundLabel = Labels.Find(l => string.Equals(l.Name, Label, StringComparison.CurrentCultureIgnoreCase));
|
||||
if (FoundLabel == null)
|
||||
throw new ScriptExecutionException("Label not found: " + Label);
|
||||
|
||||
WriteLog("Condition was not found, jumping to label: " + Label);
|
||||
WriteLog("New virtual address: 0x" + FoundLabel.VirtualAddress.ToString("X8"));
|
||||
CurrentVirtualAddressTarget = FoundLabel.VirtualAddress;
|
||||
CodeLine NewLine = ScriptCode.Find(l => string.Equals(l.Label, Label, StringComparison.CurrentCultureIgnoreCase));
|
||||
if (NewLine == null)
|
||||
{
|
||||
throw new ScriptExecutionException("Label " + Label + " not found");
|
||||
}
|
||||
else
|
||||
{
|
||||
Pointer = ScriptCode.IndexOf(NewLine);
|
||||
WriteLog("Go to label: " + Label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.28010.2041
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.12.35323.107
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Patcher", "Patcher\Patcher.csproj", "{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}"
|
||||
EndProject
|
||||
@@ -9,66 +9,26 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoPatcher", "AutoPatcher\
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
.NET45Debug|Any CPU = .NET45Debug|Any CPU
|
||||
.NET45Debug|x64 = .NET45Debug|x64
|
||||
.NET45Debug|x86 = .NET45Debug|x86
|
||||
.NET45Release|Any CPU = .NET45Release|Any CPU
|
||||
.NET45Release|x64 = .NET45Release|x64
|
||||
.NET45Release|x86 = .NET45Release|x86
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
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.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.Build.0 = Release|x86
|
||||
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{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}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Debug|x86.Build.0 = Debug|x86
|
||||
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Release|x86.ActiveCfg = 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.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.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.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.Build.0 = Release|x86
|
||||
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
|
||||
// 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
|
||||
// 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
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
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
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -184,7 +184,7 @@
|
||||
this.label4.Name = "label4";
|
||||
this.label4.Size = new System.Drawing.Size(117, 13);
|
||||
this.label4.TabIndex = 3;
|
||||
this.label4.Text = "Patch defintions xml-file";
|
||||
this.label4.Text = "Patch definitions xml-file";
|
||||
//
|
||||
// label5
|
||||
//
|
||||
@@ -193,7 +193,7 @@
|
||||
this.label5.Name = "label5";
|
||||
this.label5.Size = new System.Drawing.Size(107, 13);
|
||||
this.label5.TabIndex = 6;
|
||||
this.label5.Text = "Patch defintion name";
|
||||
this.label5.Text = "Patch definition name";
|
||||
//
|
||||
// cmbPatchDefinitionName
|
||||
//
|
||||
@@ -239,7 +239,7 @@
|
||||
this.label7.Name = "label7";
|
||||
this.label7.Size = new System.Drawing.Size(269, 13);
|
||||
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
|
||||
//
|
||||
|
||||
@@ -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
|
||||
// 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
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
@@ -41,8 +41,8 @@ namespace Patcher
|
||||
/// <param name="VirtualAddress"></param>
|
||||
/// <param name="CodeType"></param>
|
||||
/// <param name="ArmCodeFragment"></param>
|
||||
/// <param name="PatchDefintionsXmlPath"></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)
|
||||
/// <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 PatchDefinitionsXmlPath)
|
||||
{
|
||||
SHA1Managed SHA = new();
|
||||
|
||||
@@ -65,8 +65,8 @@ namespace Patcher
|
||||
RawOffset = PeFile.ConvertVirtualAddressToRawOffset(VirtualAddress);
|
||||
|
||||
// Add or replace patch
|
||||
string PatchDefintionsXml = File.ReadAllText(PatchDefintionsXmlPath);
|
||||
PatchEngine PatchEngine = new(PatchDefintionsXml);
|
||||
string PatchDefinitionsXml = File.ReadAllText(PatchDefinitionsXmlPath);
|
||||
PatchEngine PatchEngine = new(PatchDefinitionsXml);
|
||||
PatchDefinition PatchDefinition = PatchEngine.PatchDefinitions.Find(d => string.Equals(d.Name, PatchDefinitionName, StringComparison.CurrentCultureIgnoreCase));
|
||||
if (PatchDefinition == null)
|
||||
{
|
||||
@@ -143,8 +143,8 @@ namespace Patcher
|
||||
if (OutputFilePath != null)
|
||||
File.WriteAllBytes(OutputFilePath, Binary);
|
||||
|
||||
// Write PatchDefintions
|
||||
PatchEngine.WriteDefinitions(PatchDefintionsXmlPath);
|
||||
// Write PatchDefinitions
|
||||
PatchEngine.WriteDefinitions(PatchDefinitionsXmlPath);
|
||||
}
|
||||
|
||||
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
|
||||
// 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
|
||||
// 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("");
|
||||
FileWriter.WriteLine("<!--");
|
||||
FileWriter.WriteLine("Copyright(c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda");
|
||||
FileWriter.WriteLine("Copyright(c) 2018, Rene Lergner - @Heathcliff74xda");
|
||||
FileWriter.WriteLine("");
|
||||
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\"),");
|
||||
|
||||
@@ -1,28 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0-windows</TargetFramework>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
</PropertyGroup>
|
||||
<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>
|
||||
<Platforms>x86</Platforms>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
|
||||
<ProjectReference Include="..\AutoPatcher\AutoPatcher.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
|
||||
// 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
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
|
||||
@@ -77,14 +77,14 @@ namespace WPinternals
|
||||
Registration.CheckExpiration();
|
||||
|
||||
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))
|
||||
{
|
||||
PatchDefintionsXml = File.ReadAllText(PatchDefintionsPath);
|
||||
}
|
||||
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);
|
||||
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 WPinternals.Config;
|
||||
using WPinternals.HelperClasses;
|
||||
using WPinternals.Models.Lumia.MSR;
|
||||
using WPinternals.Models.Lumia.NCSd;
|
||||
using WPinternals.Models.UEFIApps.BootMgr;
|
||||
using WPinternals.Models.UEFIApps.Flash;
|
||||
@@ -1268,262 +1267,6 @@ namespace WPinternals
|
||||
|
||||
LogFile.Log("Root access enabled on image", LogType.FileAndConsole);
|
||||
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":
|
||||
if (args.Length < 2)
|
||||
{
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace WPinternals.Config
|
||||
internal const bool IsPrerelease = false;
|
||||
#endif
|
||||
|
||||
internal static readonly DateTime ExpirationDate = new(2024, 12, 21);
|
||||
internal static readonly DateTime ExpirationDate = new(2027, 4, 1);
|
||||
|
||||
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)
|
||||
{
|
||||
// Mass Storage device is not WinUSB
|
||||
try
|
||||
{
|
||||
Device = new USBDevice(DevicePath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogFile.LogException(ex, LogType.FileOnly);
|
||||
}
|
||||
Device = new USBDevice(DevicePath);
|
||||
}
|
||||
|
||||
public void ResetDevice()
|
||||
@@ -93,7 +85,7 @@ namespace WPinternals.Models.Lumia
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
Device?.Dispose();
|
||||
Device.Dispose();
|
||||
}
|
||||
|
||||
// Clean unmanaged resources here.
|
||||
|
||||
@@ -28,8 +28,9 @@ using WPinternals.Models.Lumia;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class MassStorage : NokiaPhoneModel
|
||||
internal class MassStorage : IDisposable
|
||||
{
|
||||
protected bool Disposed = false;
|
||||
internal string Drive = null;
|
||||
internal string PhysicalDrive = null;
|
||||
internal string VolumeLabel = null;
|
||||
@@ -39,7 +40,7 @@ namespace WPinternals
|
||||
|
||||
private string Serial;
|
||||
|
||||
internal MassStorage(string DevicePath) : base(DevicePath)
|
||||
internal MassStorage(string DevicePath)
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -141,8 +162,6 @@ namespace WPinternals
|
||||
if (disposing)
|
||||
{
|
||||
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 System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
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.Models.Lumia.MSR;
|
||||
using WPinternals.Models.Lumia.NCSd;
|
||||
using WPinternals.Models.UEFIApps.Flash;
|
||||
using WPinternals.Models.UEFIApps.PhoneInfo;
|
||||
@@ -41,7 +31,6 @@ namespace WPinternals
|
||||
internal class DownloadsViewModel : ContextViewModel
|
||||
{
|
||||
private readonly PhoneNotifierViewModel Notifier;
|
||||
private bool IsSearching = false;
|
||||
|
||||
internal DownloadsViewModel(PhoneNotifierViewModel Notifier)
|
||||
{
|
||||
@@ -50,11 +39,6 @@ namespace WPinternals
|
||||
this.Notifier = Notifier;
|
||||
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(() =>
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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()
|
||||
{
|
||||
if (IsSwitchingInterface)
|
||||
@@ -574,9 +220,6 @@ namespace WPinternals
|
||||
|
||||
LumiaPhoneInfoAppModel LumiaPhoneInfoModel = (LumiaPhoneInfoAppModel)Notifier.CurrentModel;
|
||||
LumiaPhoneInfoAppPhoneInfo Info = LumiaPhoneInfoModel.ReadPhoneInfo();
|
||||
ProductType = Info.Type;
|
||||
OperatorCode = "";
|
||||
ProductCode = Info.ProductCode;
|
||||
|
||||
ModernFlashApp = Info.PhoneInfoAppVersionMajor >= 2;
|
||||
if (ModernFlashApp)
|
||||
@@ -609,9 +252,6 @@ namespace WPinternals
|
||||
{
|
||||
LumiaPhoneInfoAppModel LumiaPhoneInfoModel = (LumiaPhoneInfoAppModel)Notifier.CurrentModel;
|
||||
LumiaPhoneInfoAppPhoneInfo Info = LumiaPhoneInfoModel.ReadPhoneInfo();
|
||||
ProductType = Info.Type;
|
||||
OperatorCode = "";
|
||||
ProductCode = Info.ProductCode;
|
||||
|
||||
IsSwitchingInterface = true;
|
||||
|
||||
@@ -663,556 +303,10 @@ namespace WPinternals
|
||||
else if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Normal)
|
||||
{
|
||||
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");
|
||||
}
|
||||
}
|
||||
public DelegateCommand AddFFUCommand { 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.
|
||||
|
||||
using System;
|
||||
using UnifiedFlashingPlatform;
|
||||
using WPinternals.HelperClasses;
|
||||
using WPinternals.Models.Lumia.NCSd;
|
||||
using WPinternals.Models.SimpleIO;
|
||||
using WPinternals.Models.UEFIApps.BootMgr;
|
||||
using WPinternals.Models.UEFIApps.Flash;
|
||||
using WPinternals.Models.UEFIApps.PhoneInfo;
|
||||
@@ -91,6 +93,12 @@ namespace WPinternals
|
||||
case PhoneInterfaces.Lumia_MassStorage:
|
||||
ActivateSubContext(new NokiaMassStorageViewModel((MassStorage)CurrentModel));
|
||||
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.
|
||||
|
||||
using System;
|
||||
using UnifiedFlashingPlatform;
|
||||
using WPinternals.HelperClasses;
|
||||
using WPinternals.Models.Lumia.NCSd;
|
||||
using WPinternals.Models.SimpleIO;
|
||||
using WPinternals.Models.UEFIApps.BootMgr;
|
||||
using WPinternals.Models.UEFIApps.Flash;
|
||||
using WPinternals.Models.UEFIApps.PhoneInfo;
|
||||
@@ -109,6 +111,12 @@ namespace WPinternals
|
||||
case PhoneInterfaces.Lumia_MassStorage:
|
||||
ActivateSubContext(new NokiaModeMassStorageViewModel((MassStorage)CurrentModel, OnModeSwitchRequested));
|
||||
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();
|
||||
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.
|
||||
string SBRes = IsSpecB ? "WPinternals.SB" : "WPinternals.SBA";
|
||||
string SBRes = IsSpecB ? "WPinternals.Assets.SB" : "WPinternals.Assets.SBA";
|
||||
Part.Stream = new SeekableStream(() =>
|
||||
{
|
||||
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.
|
||||
// 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.
|
||||
Stream stream = assembly.GetManifestResourceStream("WPinternals.SB");
|
||||
Stream stream = assembly.GetManifestResourceStream("WPinternals.Assets.SB");
|
||||
|
||||
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.
|
||||
// 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.
|
||||
Stream stream = assembly.GetManifestResourceStream("WPinternals.SB");
|
||||
Stream stream = assembly.GetManifestResourceStream("WPinternals.Assets.SB");
|
||||
|
||||
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.
|
||||
// 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.
|
||||
Stream stream = assembly.GetManifestResourceStream("WPinternals.SB");
|
||||
Stream stream = assembly.GetManifestResourceStream("WPinternals.Assets.SB");
|
||||
|
||||
return new DecompressedStream(stream);
|
||||
});
|
||||
|
||||
@@ -49,7 +49,9 @@ namespace WPinternals
|
||||
Qualcomm_Download,
|
||||
Qualcomm_Flash,
|
||||
Lumia_BadMassStorage,
|
||||
Lumia_PhoneInfo
|
||||
Lumia_PhoneInfo,
|
||||
SimpleIO,
|
||||
UFP
|
||||
};
|
||||
|
||||
// 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 Action<PhoneInterfaces?> RequestModeSwitch;
|
||||
|
||||
internal NokiaModeMassStorageViewModel(NokiaPhoneModel CurrentModel, Action<PhoneInterfaces?> RequestModeSwitch)
|
||||
internal NokiaModeMassStorageViewModel(MassStorage CurrentModel, Action<PhoneInterfaces?> RequestModeSwitch)
|
||||
: base()
|
||||
{
|
||||
this.CurrentModel = (MassStorage)CurrentModel;
|
||||
this.CurrentModel = CurrentModel;
|
||||
this.RequestModeSwitch = RequestModeSwitch;
|
||||
}
|
||||
|
||||
|
||||