17 Commits
Author SHA1 Message Date
Gustave Monce d270cace79 Fix: device being null 2026-04-22 18:36:50 +02:00
Gustave Monce af61c9ad29 Preliminary support for UFP 2026-04-16 18:46:00 +02:00
Gustave Monce de4d5e577a Add preliminary SimpleIO support 2026-04-16 18:11:13 +02:00
Gustave Monce df02025a31 Update timebomb 2026-01-03 23:26:37 +01:00
Gustave Monce ad92ecdab3 Restructure assets into their own dedicated folders 2025-11-01 11:06:33 +01:00
Gustave Monce b3b037a3c8 Remove deprecated download command line options 2025-11-01 11:06:17 +01:00
Gustave Monce be15155c39 Deprecate MSR download fully as the MSR and repair avoidance services are fully deprecated as of 2025 2025-11-01 11:06:02 +01:00
Gustave Monce a17dae3931 Update project structure 2025-11-01 09:44:23 +01:00
Gustave Monce 7646e3fc76 Bump timebomb date 2025-11-01 09:42:59 +01:00
Gustave Monce 933e9e53b6 Migrate DiscUtils fat code to a standalone project dependency 2025-11-01 09:42:52 +01:00
Gustave Monce e838168127 Migrate 7zip code to a standalone project dependency 2025-11-01 09:31:14 +01:00
Gustave Monce 058cde0d91 Migrate WinUSBNet code to a standalone project dependency 2025-11-01 09:28:08 +01:00
Gustave Monce 1cc7a5cee4 Update Timebomb 2024-12-23 15:14:30 +01:00
Gustave Monce 132e21e58a Patcher: fix: broken go to labels in script engine 2024-10-22 21:22:30 +02:00
Gustave Monce 1e5da5452b Small fixes 2024-10-21 23:52:08 +02:00
Gustave Monce 6992ed3f70 Remove references to dead website 2024-10-21 23:30:50 +02:00
Gustave Monce bb9702a3c3 Patcher: fix compilation with dotnet 8 2024-10-21 23:25:50 +02:00
149 changed files with 6335 additions and 1648 deletions
+10
View File
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>_7zip</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
@@ -4,7 +4,7 @@ using System.Text;
namespace DiscUtils.CoreCompat
{
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 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
+2 -19
View File
@@ -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"
+1 -1
View File
@@ -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 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
//
// Permission is hereby granted, free of charge, to any person obtaining a
// 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("")]
+22 -16
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
//
// Permission is hereby granted, free of charge, to any person obtaining a
// 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);
}
}
}
+4 -44
View File
@@ -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 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
+1 -1
View File
@@ -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
+3 -3
View File
@@ -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 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
+7 -7
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
//
// Permission is hereby granted, free of charge, to any person obtaining a
// 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 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
+2 -2
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
//
// Permission is hereby granted, free of charge, to any person obtaining a
// 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\"),");
+3 -19
View File
@@ -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 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
+1789 -3
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -77,14 +77,14 @@ namespace WPinternals
Registration.CheckExpiration();
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

-257
View File
@@ -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)
{
+1 -1
View File
@@ -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];
}
}
}
+2 -10
View File
@@ -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.
+24 -5
View File
@@ -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;
}
}
}
+63
View File
@@ -0,0 +1,63 @@
/*
* MIT License
*
* Copyright (c) 2026 The DuoWOA authors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace WPinternals.Models.SimpleIO
{
public enum SioOpcode : byte
{
SioId = 1, //
SioFlash,
SioAck,
SioNack,
SioLog,
SioErr,
SioSkip, //
SioReset, //
SioFile, // WIP!
SioReboot, //
SioMassStorage, //
SioGetDiskInfo, //
SioReadDisk, //
SioWriteDisk, //
SioClearIdOverride, //
SioWim,
SioSerialNumber, //
SioExternalWim,
SioSetBootMode, //
SioFastFlash,
SioDeviceParams,
SioDeviceVersion,
SioQueryForCmd, //
SioGetUpdateLogs, //
SioQueryDeviceUnlockId, //
SioRelockDeviceUnlockId, //
SioQueryUnlockTokenFiles, //
SioWriteUnlockTokenFile, //
SioQueryBitlockerState, //
SioLast = 29
}
}
+33
View File
@@ -0,0 +1,33 @@
/*
* MIT License
*
* Copyright (c) 2024 The DuoWOA authors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
namespace UnifiedFlashingPlatform
{
public enum AppType : byte
{
Min,
UEFI,
BOOT,
Max
};
}
+33
View File
@@ -0,0 +1,33 @@
/*
* MIT License
*
* Copyright (c) 2024 The DuoWOA authors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
namespace UnifiedFlashingPlatform
{
public enum DeviceLogType
{
Min,
Flashing,
Servicing,
Max
}
}
@@ -0,0 +1,47 @@
/*
* MIT License
*
* Copyright (c) 2024 The DuoWOA authors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
namespace UnifiedFlashingPlatform
{
public struct DeviceTargetingInfo
{
public string Manufacturer;
public string Family;
public string ProductName;
public string ProductVersion;
public string SKUNumber;
public string BaseboardManufacturer;
public string BaseboardProduct;
public override readonly string ToString()
{
return "Manufacturer: " + Manufacturer +
" - Family: " + Family +
" - Product Name: " + ProductName +
" - Product Version: " + ProductVersion +
" - SKU Number: " + SKUNumber +
" - Baseboard Manufacturer: " + BaseboardManufacturer +
" - Baseboard Product: " + BaseboardProduct;
}
}
}
+11
View File
@@ -0,0 +1,11 @@
namespace UnifiedFlashingPlatform
{
internal enum FfuProtocol
{
ProtocolSyncV1 = 1,
ProtocolAsyncV1 = 2,
ProtocolSyncV2 = 4,
ProtocolAsyncV2 = 8,
ProtocolAsyncV3 = 16
}
}
+41
View File
@@ -0,0 +1,41 @@
/*
* MIT License
*
* Copyright (c) 2024 The DuoWOA authors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
namespace UnifiedFlashingPlatform
{
public struct FlashAppInfo
{
public byte ProtocolMajorVersion;
public byte ProtocolMinorVersion;
public byte ImplementationMajorVersion;
public byte ImplementationMinorVersion;
public override readonly string ToString()
{
return "ProtocolMajorVersion: " + ProtocolMajorVersion +
" - ProtocolMinorVersion: " + ProtocolMinorVersion +
" - ImplementationMajorVersion: " + ImplementationMajorVersion +
" - ImplementationMinorVersion: " + ImplementationMinorVersion;
}
}
}
+31
View File
@@ -0,0 +1,31 @@
/*
* MIT License
*
* Copyright (c) 2024 The DuoWOA authors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
namespace UnifiedFlashingPlatform
{
public enum Mode : byte
{
DiagnosticMode,
Max
}
}
@@ -0,0 +1,39 @@
/*
* MIT License
*
* Copyright (c) 2024 The DuoWOA authors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
namespace UnifiedFlashingPlatform
{
public struct ResetProtectionInfo
{
public bool IsResetProtectionEnabled;
public uint MajorVersion;
public uint MinorVersion;
public override readonly string ToString()
{
return "IsResetProtectionEnabled: " + IsResetProtectionEnabled +
" - MajorVersion: " + MajorVersion +
" - MinorVersion: " + MinorVersion;
}
}
}
@@ -0,0 +1,85 @@
using System;
using System.Drawing;
using System.Text;
using WPinternals.HelperClasses;
namespace UnifiedFlashingPlatform.UEFI
{
public struct BOOT_OPTION
{
public byte BootOrderIndex;
public ushort BootOption;
public LoadOptionAttribute Attributes;
public string Description;
public string DevicePath;
public string CommandLine;
public ushort DescriptionStringOffset;
public ushort DevicePathStringOffset;
public ushort CommandLineStringOffset;
public ushort TotalSize;
public static BOOT_OPTION ReadFromBuffer(byte[] Buffer, int offset)
{
byte BootOrderIndex = Buffer[offset];
var Attributes = (LoadOptionAttribute)BigEndian.ToUInt32(Buffer, offset + 1);
ushort BootOption = BigEndian.ToUInt16(Buffer, offset + 5);
// Latest
ushort DescriptionStringOffset = BigEndian.ToUInt16(Buffer, offset + 7);
ushort DevicePathStringOffset = BigEndian.ToUInt16(Buffer, offset + 9);
ushort CommandLineStringOffset = BigEndian.ToUInt16(Buffer, offset + 11);
ushort TotalSize = BigEndian.ToUInt16(Buffer, offset + 13);
string Description = Encoding.Unicode.GetString(Buffer, offset + DescriptionStringOffset, DevicePathStringOffset - DescriptionStringOffset);
string DevicePath;
string CommandLine = "";
if (CommandLineStringOffset == 0)
{
DevicePath = Encoding.Unicode.GetString(Buffer, offset + DevicePathStringOffset, TotalSize - DevicePathStringOffset);
}
else
{
DevicePath = Encoding.Unicode.GetString(Buffer, offset + DevicePathStringOffset, CommandLineStringOffset - DevicePathStringOffset);
CommandLine = Encoding.Unicode.GetString(Buffer, offset + CommandLineStringOffset, TotalSize - CommandLineStringOffset);
}
// Older
/*ushort DescriptionStringLength = BigEndian.ToUInt16(Buffer, offset + 7);
ushort DevicePathStringLength = BigEndian.ToUInt16(Buffer, offset + 9);
string Description = Encoding.Unicode.GetString(Buffer, offset + 11, DescriptionStringLength);
string DevicePath = Encoding.Unicode.GetString(Buffer, offset + 11 + DescriptionStringLength, DevicePathStringLength);
string CommandLine = "";
ushort DescriptionStringOffset = 11;
ushort DevicePathStringOffset = (ushort)(11 + DescriptionStringLength);
ushort CommandLineStringOffset = 0;
ushort TotalSize = (ushort)(11 + DescriptionStringLength + DevicePathStringLength);*/
return new BOOT_OPTION()
{
BootOrderIndex = BootOrderIndex,
Attributes = Attributes,
BootOption = BootOption,
Description = Description,
DevicePath = DevicePath,
CommandLine = CommandLine,
DescriptionStringOffset = DescriptionStringOffset,
DevicePathStringOffset = DevicePathStringOffset,
CommandLineStringOffset = CommandLineStringOffset,
TotalSize = TotalSize
};
}
public override readonly string ToString()
{
return "BootOrderIndex: " + BootOrderIndex +
" - Attributes: " + Attributes +
" - BootOption: " + BootOption +
" - Description: " + Description +
" - DevicePath: " + DevicePath +
" - CommandLine: " + CommandLine;
}
}
}
+53
View File
@@ -0,0 +1,53 @@
using System;
using System.Text;
namespace UnifiedFlashingPlatform.UEFI
{
public struct FILE_INFO
{
public ulong Size;
public ulong FileSize;
public ulong PhysicalSize;
public UefiDateTime CreateTime;
public UefiDateTime LastAccessTime;
public UefiDateTime ModificationTime;
public FileAttribute Attribute;
public string FileName;
public static FILE_INFO ReadFromBuffer(byte[] Buffer, int offset)
{
ulong size = BitConverter.ToUInt64(Buffer, offset);
ulong fileSize = BitConverter.ToUInt64(Buffer, offset + 8);
ulong physicalSize = BitConverter.ToUInt64(Buffer, offset + 16);
UefiDateTime createTime = UefiDateTime.ReadFromBuffer(Buffer, offset + 24);
UefiDateTime lastAccessTime = UefiDateTime.ReadFromBuffer(Buffer, offset + 40);
UefiDateTime modificationTime = UefiDateTime.ReadFromBuffer(Buffer, offset + 56);
ulong attribute = BitConverter.ToUInt64(Buffer, offset + 72);
string fileName = Encoding.Unicode.GetString(Buffer, offset + 80, (int)(size - 80));
return new FILE_INFO()
{
Size = size,
FileSize = fileSize,
PhysicalSize = physicalSize,
CreateTime = createTime,
LastAccessTime = lastAccessTime,
ModificationTime = modificationTime,
Attribute = (FileAttribute)attribute,
FileName = fileName
};
}
public override readonly string ToString()
{
return "Size: " + Size +
"- File Size: " + FileSize +
"- Physical Size: " + PhysicalSize +
"- Create Time: " + CreateTime.ToDateTime() +
"- Last Access Time: " + LastAccessTime.ToDateTime() +
"- Modification Time: " + ModificationTime.ToDateTime() +
"- Attribute: " + Attribute +
"- FileName: " + FileName;
}
}
}
@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace UnifiedFlashingPlatform.UEFI
{
[Flags]
public enum FileAttribute : ulong
{
EfiFileReadOnly = 1UL,
EfiFileHidden = 2UL,
EfiFileSystem = 4UL,
EfiFileReserved = 8UL,
EfiFileDirectory = 16UL,
EfiFileArchive = 32UL,
EfiFileValidAttr = 55UL
}
}
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace UnifiedFlashingPlatform.UEFI
{
[Flags]
public enum LoadOptionAttribute : uint
{
LoadOptionCategoryBoot = 0U,
LoadOptionActive = 1U,
LoadOptionForceReconnect = 2U,
LoadOptionHidden = 8U,
LoadOptionCategoryApp = 256U,
LoadOptionCategory = 7936U
}
}
@@ -0,0 +1,62 @@
using System;
namespace UnifiedFlashingPlatform.UEFI
{
public struct UefiDateTime
{
public ushort year;
public byte month;
public byte day;
public byte hour;
public byte minute;
public byte second;
public uint nanosecond;
public short timezone;
public byte daylight;
public static UefiDateTime ReadFromBuffer(byte[] Buffer, int offset)
{
ushort year = BitConverter.ToUInt16(Buffer, offset);
byte month = Buffer[offset + 2];
byte day = Buffer[offset + 3];
byte hour = Buffer[offset + 4];
byte minute = Buffer[offset + 5];
byte second = Buffer[offset + 6];
uint nanosecond = BitConverter.ToUInt32(Buffer, offset + 8);
short timezone = BitConverter.ToInt16(Buffer, offset + 12);
byte daylight = Buffer[offset + 14];
return new UefiDateTime()
{
year = year,
month = month,
day = day,
hour = hour,
minute = minute,
second = second,
nanosecond = nanosecond,
timezone = timezone,
daylight = daylight
};
}
public readonly DateTime ToDateTime()
{
DateTime dateTime;
byte month = this.month == 0 ? (byte)1 : this.month;
byte day = this.day == 0 ? (byte)1 : this.day;
if (timezone == 2047)
{
dateTime = new DateTime(year, month, day, hour, minute, second, Convert.ToInt32(nanosecond / 1000000U), DateTimeKind.Local);
}
else
{
dateTime = new DateTime(year, month, day, hour, minute, second, Convert.ToInt32(nanosecond / 1000000U), DateTimeKind.Utc);
}
return dateTime;
}
}
}
@@ -0,0 +1,41 @@
/*
* MIT License
*
* Copyright (c) 2024 The DuoWOA authors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
namespace UnifiedFlashingPlatform.UEFI
{
[Flags]
public enum UefiVariableAttributes : uint
{
EfiVariableNone,
EfiVariableNonVolatile,
EfiVariableBootServiceAccess,
EfiVariableRuntimeAccess = 4U,
EfiVariableHardwareErrorRecord = 8U,
EfiVariableAuthenticatedWriteAccess = 16U,
EfiVariableTimeBasedAuthenticatedWriteAccess = 32U,
EfiVariableAppendWrite = 64U,
EfiVariableEnhancedAuthenticatedAccess = 128U
}
}
+37
View File
@@ -0,0 +1,37 @@
/*
* MIT License
*
* Copyright (c) 2024 The DuoWOA authors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
namespace UnifiedFlashingPlatform
{
public struct USBSpeed
{
public byte CurrentUSBSpeed;
public byte MaxUSBSpeed;
public override readonly string ToString()
{
return "CurrentUSBSpeed: " + CurrentUSBSpeed +
" - MaxUSBSpeed: " + MaxUSBSpeed;
}
}
}
+42
View File
@@ -0,0 +1,42 @@
/*
* MIT License
*
* Copyright (c) 2024 The DuoWOA authors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using UnifiedFlashingPlatform.UEFI;
namespace UnifiedFlashingPlatform
{
public struct UefiVariable
{
public UefiVariableAttributes Attributes;
public uint DataSize;
public byte[] Data;
public override readonly string ToString()
{
return "Attributes: " + Attributes +
" - DataSize: " + DataSize +
" - Data: " + BitConverter.ToString(Data);
}
}
}
@@ -0,0 +1,136 @@
namespace UnifiedFlashingPlatform
{
public partial class UnifiedFlashingPlatformModel
{
//
// Not valid commands
//
/* NOK */
private const string Signature = "NOK";
/* NOKX */
private const string ExtendedMessageSignature = $"{Signature}X";
/* NOKXC */
private const string CommonExtendedMessageSignature = $"{ExtendedMessageSignature}C";
/* NOKXF */
private const string UFPExtendedMessageSignature = $"{ExtendedMessageSignature}F";
//
// Normal commands
//
/* NOKF */
private const string FlashSignature = $"{Signature}F";
/* NOKI */
private const string HelloSignature = $"{Signature}I";
/* NOKM */
private const string MassStorageSignature = $"{Signature}M";
/* NOKN */
private const string TelemetryEndSignature = $"{Signature}N";
/* NOKR */
private const string RebootSignature = $"{Signature}R";
/* NOKS */
private const string TelemetryStartSignature = $"{Signature}S";
/* NOKT */
private const string GetGPTSignature = $"{Signature}T";
/* NOKV */
private const string InfoQuerySignature = $"{Signature}V";
/* NOKZ */
private const string ShutdownSignature = $"{Signature}Z";
//
// Common extended commands
//
/* NOKXCB */
private const string SwitchModeSignature = $"{CommonExtendedMessageSignature}B";
/* NOKXCC */
private const string ClearScreenSignature = $"{CommonExtendedMessageSignature}C";
/* NOKXCD */
private const string GetDirectoryEntriesSignature = $"{CommonExtendedMessageSignature}D";
/* NOKXCE */
private const string EchoSignature = $"{CommonExtendedMessageSignature}E";
/* NOKXCF */
private const string GetFileSignature = $"{CommonExtendedMessageSignature}F";
/* NOKXCM */
private const string DisplayCustomMessageSignature = $"{CommonExtendedMessageSignature}M";
/* NOKXCP */
private const string PutFileSignature = $"{CommonExtendedMessageSignature}P";
/* NOKXCT */
private const string BenchmarkTestsSignature = $"{CommonExtendedMessageSignature}T";
//
// UFP extended commands
//
/* NOKXFF */
private const string AsyncFlashModeSignature = $"{UFPExtendedMessageSignature}F";
/* NOKXFI */
private const string UnlockSignature = $"{UFPExtendedMessageSignature}I";
/* NOKXFO */
private const string RelockSignature = $"{UFPExtendedMessageSignature}O";
/* NOKXFR */
private const string ReadParamSignature = $"{UFPExtendedMessageSignature}R";
/* NOKXFS */
private const string SecureFlashSignature = $"{UFPExtendedMessageSignature}S";
/* NOKXFT */
private const string TelemetryReadSignature = $"{UFPExtendedMessageSignature}T";
/* NOKXFW */
private const string WriteParamSignature = $"{UFPExtendedMessageSignature}W";
/* NOKXFX */
private const string GetLogsSignature = $"{UFPExtendedMessageSignature}X";
//
// UFP Read Params
//
private const string AppTypeReadParamSignature = "APPT";
private const string ResetProtectionReadParamSignature = "ATRP";
private const string BitlockerStateReadParamSignature = "BITL";
private const string BuildInfoReadParamSignature = "BNFO";
private const string CurrentBootOptionReadParamSignature = "CUFO";
private const string AsyncProtocolSupportReadParamSignature = "DAS\0";
private const string DirectoryEntriesSizeReadParamSignature = "DES\0";
private const string DevicePlatformIDReadParamSignature = "DPI\0";
private const string DevicePropertiesReadParamSignature = "DPR\0";
private const string DeviceTargetInfoReadParamSignature = "DTI\0";
private const string DataVerifySpeedReadParamSignature = "DTSP";
private const string DeviceIDReadParamSignature = "DUI\0";
private const string EMMCTestResultReadParamSignature = "EMMT";
private const string EMMCSizeReadParamSignature = "EMS\0";
private const string EMMCWriteSpeedReadParamSignature = "EMWS";
private const string FlashAppInfoReadParamSignature = "FAI\0";
private const string FlashAppOptionsReadParamSignature = "FO\0\0";
private const string FlashingStatusReadParamSignature = "FS\0\0";
private const string FileSizeReadParamSignature = "FZ\0\0";
private const string SecureBootStatusReadParamSignature = "GSBS";
private const string GetUEFIVariableReadParamSignature = "GUFV";
private const string GetUEFIVariableSizeReadParamSignature = "GUVS";
private const string LargestMemoryRegionReadParamSignature = "LGMR";
private const string LogSizeReadParamSignature = "LZ\0\0";
private const string MACAddressReadParamSignature = "MAC\0";
private const string ModeDataReadParamSignature = "MODE";
private const string ProcessorManufacturerReadParamSignature = "pm\0\0";
private const string SDCardSizeReadParamSignature = "SDS\0";
private const string SupportedSecureFFUProtocolsReadParamSignature = "SFPI";
private const string SMBIOSDataReadParamSignature = "SMBD";
private const string SerialNumberReadParamSignature = "SN\0\0";
private const string SizeOfSystemMemoryReadParamSignature = "SOSM";
private const string SecurityStatusReadParamSignature = "SS\0\0";
private const string TelemetryLogSizeReadParamSignature = "TELS";
private const string TransferSizeReadParamSignature = "TS\0\0";
private const string UEFIBootFlagReadParamSignature = "UBF\0";
private const string UEFIBootOptionsReadParamSignature = "UEBO";
private const string UnlockIDReadParamSignature = "UKID";
private const string UnlockTokenFilesReadParamSignature = "UKTF";
private const string USBSpeedReadParamSignature = "USBS";
private const string WriteBufferSizeReadParamSignature = "WBS\0";
//
// UFP Write Params
//
private const string BootOptionOptionalDataWriteParamSignature = "BOCL";
private const string BootOptionAsFirstEntryWriteParamSignature = "BOF\0";
private const string BootOptionAsLastEntryWriteParamSignature = "BOL\0";
private const string FlashOptionsWriteParamSignature = "FO\0\0";
private const string LogInsertWriteParamSignature = "LI\0\0";
private const string ModeWriteParamSignature = "MODE";
private const string OneTimeBootSequenceWriteParamSignature = "OBU\0";
private const string SettingUEFIVariableWriteParamSignature = "SUFV";
}
}
@@ -0,0 +1,534 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnifiedFlashingPlatform.UEFI;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace UnifiedFlashingPlatform
{
public partial class UnifiedFlashingPlatformModel
{
public byte[]? ReadParam(string Param)
{
byte[] Request = new byte[0x0B];
const string Header = ReadParamSignature; // NOKXFR
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Param), 0, Request, 7, Param.Length);
byte[]? Response = ExecuteRawMethod(Request);
if ((Response == null) || (Response.Length < 0x10))
{
return null;
}
byte[] Result = new byte[Response[0x10]];
Buffer.BlockCopy(Response, 0x11, Result, 0, Response[0x10]);
return Result;
}
public string? ReadStringParam(string Param)
{
byte[]? Bytes = ReadParam(Param);
return Bytes == null ? null : Encoding.ASCII.GetString(Bytes).Trim('\0');
}
public AppType ReadAppType()
{
byte[]? Bytes = ReadParam(AppTypeReadParamSignature);
return Bytes == null ? AppType.Min : Bytes[0] == 1 ? AppType.UEFI : AppType.Min;
}
public ResetProtectionInfo? ReadResetProtection()
{
byte[]? Bytes = ReadParam(ResetProtectionReadParamSignature);
return Bytes == null
? null
: new ResetProtectionInfo()
{
IsResetProtectionEnabled = Bytes[0] == 1,
MajorVersion = BitConverter.ToUInt32(Bytes[1..5].Reverse().ToArray()),
MinorVersion = BitConverter.ToUInt32(Bytes[5..9].Reverse().ToArray())
};
}
public bool? ReadBitlocker()
{
byte[]? Bytes = ReadParam(BitlockerStateReadParamSignature);
return Bytes == null ? null : Bytes[0] == 1;
}
public string? ReadBuildInfo()
{
return ReadStringParam(BuildInfoReadParamSignature);
}
public ushort? ReadCurrentBootOption()
{
byte[]? Bytes = ReadParam(CurrentBootOptionReadParamSignature);
return Bytes == null || Bytes.Length != 2 ? null : BitConverter.ToUInt16(Bytes.Reverse().ToArray());
}
public bool? ReadDeviceAsyncSupport()
{
byte[]? Bytes = ReadParam(AsyncProtocolSupportReadParamSignature);
return Bytes == null || Bytes.Length != 2 ? null : BitConverter.ToUInt16(Bytes.Reverse().ToArray()) == 1;
}
public ulong? ReadDirectoryEntriesSize(string PartitionName, string DirectoryName)
{
if (PartitionName.Length > 35)
{
return null;
}
byte[] PartitionNameBuffer = Encoding.Unicode.GetBytes(PartitionName);
byte[] DirectoryNameBuffer = Encoding.Unicode.GetBytes(DirectoryName);
byte[] Request = new byte[87 + DirectoryNameBuffer.Length + 2];
const string Header = ReadParamSignature; // NOKXFR
const string Param = DirectoryEntriesSizeReadParamSignature;
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Param), 0, Request, 7, Param.Length);
Buffer.BlockCopy(PartitionNameBuffer, 0, Request, 15, PartitionNameBuffer.Length);
Buffer.BlockCopy(DirectoryNameBuffer, 0, Request, 87, DirectoryNameBuffer.Length);
byte[]? Response = ExecuteRawMethod(Request);
if ((Response == null) || (Response.Length < 0x10))
{
return null;
}
byte[] Result = new byte[Response[0x10]];
Buffer.BlockCopy(Response, 0x11, Result, 0, Response[0x10]);
return BitConverter.ToUInt64(Result.Reverse().ToArray());
}
public string? ReadDevicePlatformID()
{
return ReadStringParam(DevicePlatformIDReadParamSignature);
}
//
// Reads the device properties from the UEFI Variable "MSRuntimeDeviceProperties"
// in the g_guidMSRuntimeDeviceProperties namespace and returns it as a string.
//
public string? ReadDeviceProperties()
{
return ReadStringParam(DevicePropertiesReadParamSignature);
}
public DeviceTargetingInfo? ReadDeviceTargetInfo()
{
byte[]? Bytes = ReadParam(DeviceTargetInfoReadParamSignature);
if (Bytes == null)
{
return null;
}
ushort ManufacturerLength = BitConverter.ToUInt16(Bytes[0..2].Reverse().ToArray());
ushort FamilyLength = BitConverter.ToUInt16(Bytes[2..4].Reverse().ToArray());
ushort ProductNameLength = BitConverter.ToUInt16(Bytes[4..6].Reverse().ToArray());
ushort ProductVersionLength = BitConverter.ToUInt16(Bytes[6..8].Reverse().ToArray());
ushort SKUNumberLength = BitConverter.ToUInt16(Bytes[8..10].Reverse().ToArray());
ushort BaseboardManufacturerLength = BitConverter.ToUInt16(Bytes[10..12].Reverse().ToArray());
ushort BaseboardProductLength = BitConverter.ToUInt16(Bytes[12..14].Reverse().ToArray());
int CurrentOffset = 14;
string Manufacturer = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + ManufacturerLength)]);
CurrentOffset += ManufacturerLength;
string Family = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + FamilyLength)]);
CurrentOffset += FamilyLength;
string ProductName = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + ProductNameLength)]);
CurrentOffset += ProductNameLength;
string ProductVersion = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + ProductVersionLength)]);
CurrentOffset += ProductVersionLength;
string SKUNumber = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + SKUNumberLength)]);
CurrentOffset += SKUNumberLength;
string BaseboardManufacturer = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + BaseboardManufacturerLength)]);
CurrentOffset += BaseboardManufacturerLength;
string BaseboardProduct = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + BaseboardProductLength)]);
return new DeviceTargetingInfo()
{
Manufacturer = Manufacturer,
Family = Family,
ProductName = ProductName,
ProductVersion = ProductVersion,
SKUNumber = SKUNumber,
BaseboardManufacturer = BaseboardManufacturer,
BaseboardProduct = BaseboardProduct
};
}
//
// Gets the last FFU Flash Operation Data verify speed in KB/s
//
public uint? ReadDataVerifySpeed()
{
byte[]? Bytes = ReadParam(DataVerifySpeedReadParamSignature);
return Bytes == null || Bytes.Length != 4 ? null : BitConverter.ToUInt32(Bytes.Reverse().ToArray());
}
public Guid? ReadDeviceID()
{
byte[]? Bytes = ReadParam(DeviceIDReadParamSignature);
return Bytes == null || Bytes.Length != 16 ? null : new Guid(Bytes);
}
public uint? ReadEmmcTestResult()
{
byte[]? Bytes = ReadParam(EMMCTestResultReadParamSignature);
return Bytes == null || Bytes.Length != 4 ? null : BitConverter.ToUInt32(Bytes.Reverse().ToArray());
}
//
// Gets the eMMC Size in sectors, if present
//
public uint? ReadEmmcSize()
{
byte[]? Bytes = ReadParam(EMMCSizeReadParamSignature);
return Bytes == null || Bytes.Length != 4 ? null : BitConverter.ToUInt32(Bytes.Reverse().ToArray());
}
//
// Gets the eMMC Write speed in KB/s
//
public uint? ReadEmmcWriteSpeed()
{
byte[]? Bytes = ReadParam(EMMCWriteSpeedReadParamSignature);
return Bytes == null || Bytes.Length != 4 ? null : BitConverter.ToUInt32(Bytes.Reverse().ToArray());
}
public FlashAppInfo? ReadFlashAppInfo()
{
byte[]? Bytes = ReadParam(FlashAppInfoReadParamSignature);
return Bytes == null || Bytes.Length != 6 || Bytes[0] != 2
? null
: new FlashAppInfo()
{
ProtocolMajorVersion = Bytes[1],
ProtocolMinorVersion = Bytes[2],
ImplementationMajorVersion = Bytes[3],
ImplementationMinorVersion = Bytes[4]
};
}
//
// Reads the device properties from the UEFI Variable "FfuConfigurationOptions"
// in the g_guidLumiaGuid namespace and returns it as a string.
//
public string? ReadFlashOptions()
{
return ReadStringParam(FlashAppOptionsReadParamSignature);
}
public uint? ReadFlashingStatus()
{
byte[]? Bytes = ReadParam(FlashingStatusReadParamSignature);
return Bytes == null || Bytes.Length != 4 ? null : BitConverter.ToUInt32(Bytes.Reverse().ToArray());
}
public ulong? ReadFileSize(string PartitionName, string FileName)
{
if (PartitionName.Length > 35)
{
return null;
}
byte[] PartitionNameBuffer = Encoding.Unicode.GetBytes(PartitionName);
byte[] FileNameBuffer = Encoding.Unicode.GetBytes(FileName);
byte[] Request = new byte[87 + FileNameBuffer.Length + 2];
const string Header = ReadParamSignature; // NOKXFR
const string Param = FileSizeReadParamSignature;
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Param), 0, Request, 7, Param.Length);
Buffer.BlockCopy(PartitionNameBuffer, 0, Request, 15, PartitionNameBuffer.Length);
Buffer.BlockCopy(FileNameBuffer, 0, Request, 87, FileNameBuffer.Length);
byte[]? Response = ExecuteRawMethod(Request);
if ((Response == null) || (Response.Length < 0x10))
{
return null;
}
byte[] Result = new byte[Response[0x10]];
Buffer.BlockCopy(Response, 0x11, Result, 0, Response[0x10]);
return BitConverter.ToUInt64(Result.Reverse().ToArray());
}
public bool? ReadSecureBootStatus()
{
byte[]? Bytes = ReadParam(SecureBootStatusReadParamSignature);
return Bytes == null ? null : Bytes[0] == 1;
}
public UefiVariable? ReadUEFIVariable(Guid Guid, string Name, uint Size)
{
byte[] Request = new byte[39 + ((Name.Length + 1) * 2)];
const string Header = ReadParamSignature; // NOKXFR
string Param = GetUEFIVariableReadParamSignature;
byte[] VariableNameBuffer = Encoding.Unicode.GetBytes(Name);
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Param), 0, Request, 7, Param.Length);
Buffer.BlockCopy(Guid.ToByteArray(), 0, Request, 15, 16);
Buffer.BlockCopy(BitConverter.GetBytes(Size).Reverse().ToArray(), 0, Request, 31, 4);
Buffer.BlockCopy(BitConverter.GetBytes((Name.Length + 1) * 2).Reverse().ToArray(), 0, Request, 35, 4);
Buffer.BlockCopy(VariableNameBuffer, 0, Request, 39, VariableNameBuffer.Length);
byte[]? Response = ExecuteRawMethod(Request);
if ((Response == null) || (Response.Length < 0x10))
{
return null;
}
byte[] Result = new byte[Response[0x10]];
Buffer.BlockCopy(Response, 0x11, Result, 0, Response[0x10]);
return new UefiVariable()
{
Attributes = (UefiVariableAttributes)BitConverter.ToUInt32(Result[0..4].Reverse().ToArray()),
DataSize = BitConverter.ToUInt32(Result[4..8].Reverse().ToArray()),
Data = Result[8..^0]
};
}
public uint? ReadUEFIVariableSize(Guid Guid, string Name)
{
byte[] Request = new byte[39 + ((Name.Length + 1) * 2)];
const string Header = ReadParamSignature; // NOKXFR
string Param = GetUEFIVariableSizeReadParamSignature;
byte[] VariableNameBuffer = Encoding.Unicode.GetBytes(Name);
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Param), 0, Request, 7, Param.Length);
Buffer.BlockCopy(Guid.ToByteArray(), 0, Request, 15, 16);
Buffer.BlockCopy(BitConverter.GetBytes((Name.Length + 1) * 2).Reverse().ToArray(), 0, Request, 35, 4);
Buffer.BlockCopy(VariableNameBuffer, 0, Request, 39, VariableNameBuffer.Length);
byte[]? Response = ExecuteRawMethod(Request);
if ((Response == null) || (Response.Length < 0x10))
{
return null;
}
byte[] Result = new byte[Response[0x10]];
Buffer.BlockCopy(Response, 0x11, Result, 0, Response[0x10]);
return Result == null || Result.Length != 4 ? null : BitConverter.ToUInt32(Result.Reverse().ToArray());
}
//
// Returns the largest memory region in bytes available for use by UFP
//
public ulong? ReadLargestMemoryRegion()
{
byte[]? Bytes = ReadParam(LargestMemoryRegionReadParamSignature);
return Bytes == null || Bytes.Length != 8 ? null : BitConverter.ToUInt64(Bytes.Reverse().ToArray());
}
public ulong? ReadLogSize(DeviceLogType LogType)
{
byte[] Request = new byte[0x10];
const string Header = ReadParamSignature; // NOKXFR
const string Param = LogSizeReadParamSignature;
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Param), 0, Request, 7, Param.Length);
Request[15] = (byte)LogType;
byte[]? Response = ExecuteRawMethod(Request);
if ((Response == null) || (Response.Length < 0x10))
{
return 0;
}
byte[] Result = new byte[Response[0x10]];
Buffer.BlockCopy(Response, 0x11, Result, 0, Response[0x10]);
return BitConverter.ToUInt64([.. Result.Reverse()], 0);
}
//
// Reads the MAC Address in the following format: "%02x-%02x-%02x-%02x-%02x-%02x"
//
public string? ReadMacAddress()
{
return ReadStringParam(MACAddressReadParamSignature);
}
public uint? ReadModeData(Mode Mode)
{
byte[] Request = new byte[0x10];
const string Header = ReadParamSignature; // NOKXFR
string Param = ModeDataReadParamSignature;
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Param), 0, Request, 7, Param.Length);
Request[15] = (byte)Mode;
byte[]? Response = ExecuteRawMethod(Request);
if ((Response == null) || (Response.Length < 0x10))
{
return null;
}
byte[] Result = new byte[Response[0x10]];
Buffer.BlockCopy(Response, 0x11, Result, 0, Response[0x10]);
return Result == null || Result.Length != 4 ? null : BitConverter.ToUInt32(Result.Reverse().ToArray());
}
public string? ReadProcessorManufacturer()
{
return ReadStringParam(ProcessorManufacturerReadParamSignature);
}
//
// Gets the SD Card Size in sectors, if present
//
public uint? ReadSDCardSize()
{
byte[]? Bytes = ReadParam(SDCardSizeReadParamSignature);
return Bytes == null || Bytes.Length != 4 ? null : BitConverter.ToUInt32(Bytes.Reverse().ToArray());
}
public string? ReadSupportedFFUProtocolInfo()
{
// TODO
return ReadStringParam(SupportedSecureFFUProtocolsReadParamSignature);
}
public string? ReadSMBIOSData()
{
// TODO
return ReadStringParam(SMBIOSDataReadParamSignature);
}
public Guid? ReadSerialNumber()
{
byte[]? Bytes = ReadParam(SerialNumberReadParamSignature);
return Bytes == null || Bytes.Length != 16 ? null : new Guid(Bytes);
}
//
// Returns the size of system memory in kB
//
public ulong? ReadSizeOfSystemMemory()
{
byte[]? Bytes = ReadParam(SizeOfSystemMemoryReadParamSignature);
return Bytes == null || Bytes.Length != 8 ? null : BitConverter.ToUInt64(Bytes.Reverse().ToArray());
}
public string? ReadSecurityStatus()
{
// TODO
return ReadStringParam(SecurityStatusReadParamSignature);
}
public string? ReadTelemetryLogSize()
{
// TODO
return ReadStringParam(TelemetryLogSizeReadParamSignature);
}
public uint? ReadTransferSize()
{
byte[]? Bytes = ReadParam(TransferSizeReadParamSignature);
return Bytes == null || Bytes.Length != 4 ? null : BitConverter.ToUInt32(Bytes.Reverse().ToArray());
}
//
// Reads the UEFI Boot Flag variable content and returns it as a string.
//
public string? ReadUEFIBootFlag()
{
return ReadStringParam(UEFIBootFlagReadParamSignature);
}
public BOOT_OPTION[]? ReadUEFIBootOptions()
{
byte[] Request = new byte[0x0B];
const string Header = ReadParamSignature; // NOKXFR
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(Encoding.ASCII.GetBytes(UEFIBootOptionsReadParamSignature), 0, Request, 7, UEFIBootOptionsReadParamSignature.Length);
byte[]? Response = ExecuteRawMethod(Request);
if ((Response == null) || (Response.Length < 0x10))
{
return null;
}
byte[] ResponseBuffer = Response[0x19..];
List<BOOT_OPTION> bootOptions = [];
int j = 0;
while (j != ResponseBuffer.Length)
{
BOOT_OPTION bootOption = BOOT_OPTION.ReadFromBuffer(ResponseBuffer, j);
j += bootOption.TotalSize;
bootOptions.Add(bootOption);
}
return [.. bootOptions];
}
//
// Reads the device properties from the UEFI Variable "UnlockID"
// in the g_guidOfflineDUIdEfiNamespace namespace and returns it as a string.
//
public byte[] ReadUnlockID()
{
return ReadParam(UnlockIDReadParamSignature);
}
public string? ReadUnlockTokenFiles()
{
// TODO
return ReadStringParam(UnlockTokenFilesReadParamSignature);
}
public USBSpeed? ReadUSBSpeed()
{
byte[]? Bytes = ReadParam(USBSpeedReadParamSignature);
return Bytes == null || Bytes.Length != 2
? null
: new USBSpeed()
{
CurrentUSBSpeed = Bytes[0],
MaxUSBSpeed = Bytes[1]
};
}
public uint? ReadWriteBufferSize()
{
byte[]? Bytes = ReadParam(WriteBufferSizeReadParamSignature);
return Bytes == null || Bytes.Length != 4 ? null : BitConverter.ToUInt32(Bytes.Reverse().ToArray());
}
}
}
@@ -0,0 +1,543 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using WPinternals;
using WPinternals.HelperClasses;
namespace UnifiedFlashingPlatform
{
public partial class UnifiedFlashingPlatformModel
{
private readonly PhoneInfo Info = new();
public void FlashSectors(uint StartSector, byte[] Data, byte TargetDevice = 0, int Progress = 0)
{
// Start sector is in UInt32, so max size of eMMC is 2 TB.
byte[] Request = new byte[Data.Length + 0x40];
const string Header = FlashSignature; // NOKF
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Request[0x05] = TargetDevice; // Target device: 0: eMMC, 1: SDIO, 2: Other ???, 3: ???
Buffer.BlockCopy(BigEndian.GetBytes(StartSector, 4), 0, Request, 0x0B, 4); // Start sector
Buffer.BlockCopy(BigEndian.GetBytes(Data.Length / 0x200, 4), 0, Request, 0x0F, 4); // Sector count
Request[0x13] = (byte)Progress; // Progress (0 - 100)
Request[0x18] = 0; // Verify needed
Request[0x19] = 0; // Skip write
Buffer.BlockCopy(Data, 0, Request, 0x40, Data.Length);
_ = ExecuteRawMethod(Request);
}
public void Hello()
{
byte[] Request = new byte[4];
ByteOperations.WriteAsciiString(Request, 0, HelloSignature);
byte[] Response = ExecuteRawMethod(Request) ?? throw new BadConnectionException();
if (ByteOperations.ReadAsciiString(Response, 0, 4) != HelloSignature)
{
throw new WPinternalsException("Bad response from phone!", "The phone did not answer properly to the Hello message sent.");
}
}
public void ResetPhone()
{
Debug.WriteLine("Rebooting phone");
try
{
byte[] Request = new byte[4];
ByteOperations.WriteAsciiString(Request, 0, RebootSignature);
ExecuteRawVoidMethod(Request);
}
catch
{
Debug.WriteLine("Sending reset-request failed");
Debug.WriteLine("Assuming automatic reset already in progress");
}
}
public GPT ReadGPT()
{
// If this function is used with a locked BootMgr v1,
// then the mode-switching should be done outside this function,
// because the context-switches that are used here are not supported on BootMgr v1.
// Only works in BootLoader-mode or on unlocked bootloaders in Flash-mode!!
/*PhoneInfo Info = ReadPhoneInfo(ExtendedInfo: false);
FlashAppType OriginalAppType = Info.App;
bool Switch = (Info.App != FlashAppType.BootManager) && Info.IsBootloaderSecure;
if (Switch)
{
SwitchToBootManagerContext();
}*/
byte[] Request = new byte[0x04];
const string Header = GetGPTSignature;
System.Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
byte[]? Buffer = ExecuteRawMethod(Request);
if ((Buffer == null) || (Buffer.Length < 0x4408))
{
throw new InvalidOperationException("Unable to read GPT!");
}
ushort Error = (ushort)((Buffer[6] << 8) + Buffer[7]);
if (Error > 0)
{
throw new NotSupportedException($"ReadGPT: Error 0x{Error:X4}");
}
// Length: 0x4400 for 512 (0x200) Sector Size (from sector 0 to sector 34)
// Length: 0x6000 for 4096 (0x1000) Sector Size (from sector 0 to sector 6)
uint ReturnedGPTBufferLength = (uint)Buffer.Length - 8;
uint SectorSize = Buffer.Length == 0x4408
? 512
: Buffer.Length == 0x6008
? (uint)4096
: throw new NotSupportedException($"ReadGPT: Unsupported output size! 0x{ReturnedGPTBufferLength:X4}");
byte[] GPTBuffer = new byte[ReturnedGPTBufferLength - SectorSize];
System.Buffer.BlockCopy(Buffer, 8 + (int)SectorSize, GPTBuffer, 0, (int)ReturnedGPTBufferLength - (int)SectorSize);
/*if (Switch)
{
if (OriginalAppType == FlashAppType.FlashApp)
{
SwitchToFlashAppContext();
}
else
{
SwitchToPhoneInfoAppContext();
}
}*/
return new GPT(GPTBuffer);//, SectorSize); // NOKT message header and MBR are ignored
}
private static void ThrowFlashError(int ErrorCode)
{
string SubMessage = ErrorCode switch
{
0x0008 => "Unsupported protocol / Invalid options",
0x000F => "Invalid sub block count",
0x0010 => "Invalid sub block length",
0x0012 => "Authentication required",
0x000E => "Invalid sub block type",
0x0013 => "Failed async message",
0x1000 => "Invalid header type",
0x1001 => "FFU header contain unknown extra data",
0x0001 => "Couldn't allocate memory",
0x1106 => "Security header validation failed",
0x1105 => "Invalid hash table size",
0x1104 => "Invalid catalog size",
0x1103 => "Invalid chunk size",
0x1102 => "Unsupported algorithm",
0x1101 => "Invalid struct size",
0x1100 => "Invalid signature",
0x1202 => "Invalid struct size",
0x1203 => "Unsupported algorithm",
0x1204 => "Invalid chunk size",
0x1005 => "Data not aligned correctly",
0x0009 => "Locate protocol failed",
0x1003 => "Hash mismatch",
0x1006 => "Couldn't find hash from security header for index",
0x1004 => "Security header import missing / All FFU headers have not been imported",
0x1304 => "Invalid platform ID",
0x1307 => "Invalid write descriptor info",
0x1306 => "Invalid write descriptor info",
0x1305 => "Invalid block size",
0x1303 => "Unsupported FFU version",
0x1302 => "Unsupported struct version",
0x1301 => "Invalid update type",
0x100B => "Too much payload data, all data has already been written",
0x1008 => "Internal error",
0x1007 => "Payload data does not contain all data",
0x0004 => "Flash write failed",
0x000D => "Flash verify failed",
0x0002 => "Flash read failed",
_ => "Unknown error",
};
WPinternalsException Ex = new("Flash failed!")
{
SubMessage = $"Error 0x{ErrorCode:X4}: {SubMessage}"
};
throw Ex;
}
public void SendFfuHeaderV1(byte[] FfuHeader, int Progress = 0, byte Options = 0)
{
byte[] Request = new byte[FfuHeader.Length + 0x20];
const string Header = SecureFlashSignature;
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(BigEndian.GetBytes(0x0001, 2), 0, Request, 0x06, 2); // Protocol version = 0x0001
Request[0x08] = (byte)Progress; // Progress = 0% (0 - 100)
Request[0x0B] = 1; // Subblock count = 1
Buffer.BlockCopy(BigEndian.GetBytes(0x0000000B, 4), 0, Request, 0x0C, 4); // Subblock type for header = 0x0B
Buffer.BlockCopy(BigEndian.GetBytes(FfuHeader.Length + 0x0C, 4), 0, Request, 0x10, 4); // Subblock length = length of header + 0x0C
Buffer.BlockCopy(BigEndian.GetBytes(0x00000000, 4), 0, Request, 0x14, 4); // Header type = 0
Buffer.BlockCopy(BigEndian.GetBytes(FfuHeader.Length, 4), 0, Request, 0x18, 4); // Payload length = length of header
Request[0x1C] = Options; // Header options = 0
Buffer.BlockCopy(FfuHeader, 0, Request, 0x20, FfuHeader.Length);
byte[] Response = ExecuteRawMethod(Request) ?? throw new BadConnectionException();
int ResultCode = (Response[6] << 8) + Response[7];
if (ResultCode != 0)
{
ThrowFlashError(ResultCode);
}
}
public void SendFfuHeaderV2(uint TotalHeaderLength, uint OffsetForThisPart, byte[] FfuHeader, int Progress = 0, byte Options = 0)
{
byte[] Request = new byte[FfuHeader.Length + 0x3C];
const string Header = SecureFlashSignature;
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(BigEndian.GetBytes(0x0002, 2), 0, Request, 0x06, 2); // Protocol version = 0x0002
Request[0x08] = (byte)Progress; // Progress = 0% (0 - 100)
Request[0x0B] = 1; // Subblock count = 1
Buffer.BlockCopy(BigEndian.GetBytes(0x00000021, 4), 0, Request, 0x0C, 4); // Subblock type for header v2 = 0x21
Buffer.BlockCopy(BigEndian.GetBytes(FfuHeader.Length + 0x28, 4), 0, Request, 0x10, 4); // Subblock starts at 0x14, payload starts at 0x3C.
Buffer.BlockCopy(BigEndian.GetBytes(0x00000000, 4), 0, Request, 0x14, 4); // Header type = 0
Buffer.BlockCopy(BigEndian.GetBytes(TotalHeaderLength, 4), 0, Request, 0x18, 4); // Payload length = length of header
Request[0x1C] = Options; // Header options = 0
Buffer.BlockCopy(BigEndian.GetBytes(OffsetForThisPart, 4), 0, Request, 0x1D, 4);
Buffer.BlockCopy(BigEndian.GetBytes(FfuHeader.Length, 4), 0, Request, 0x21, 4);
Request[0x25] = 0; // No Erase
Buffer.BlockCopy(FfuHeader, 0, Request, 0x3C, FfuHeader.Length);
byte[] Response = ExecuteRawMethod(Request) ?? throw new BadConnectionException();
if (Response.Length == 4)
{
throw new WPinternalsException("Flash protocol v2 not supported", "The device reported that the Flash protocol v2 was not supported while sending the FFU header.");
}
int ResultCode = (Response[6] << 8) + Response[7];
if (ResultCode != 0)
{
ThrowFlashError(ResultCode);
}
}
public void SendFfuPayloadV1(byte[] FfuChunk, int Progress = 0, byte Options = 0)
{
byte[] Request = new byte[FfuChunk.Length + 0x1C];
const string Header = SecureFlashSignature;
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(BigEndian.GetBytes((int)FfuProtocol.ProtocolSyncV1, 2), 0, Request, 0x06, 2); // Protocol version = 0x0001
Request[0x08] = (byte)Progress; // Progress = 0% (0 - 100)
Request[0x0B] = 1; // Subblock count = 1
Buffer.BlockCopy(BigEndian.GetBytes(0x0000000C, 4), 0, Request, 0x0C, 4); // Subblock type for ChunkData = 0x0C
Buffer.BlockCopy(BigEndian.GetBytes(FfuChunk.Length + 0x08, 4), 0, Request, 0x10, 4); // Subblock length = length of chunk + 0x08
Buffer.BlockCopy(BigEndian.GetBytes(FfuChunk.Length, 4), 0, Request, 0x14, 4); // Payload length = length of chunk
Request[0x18] = Options; // Data options = 0 (1 = verify)
Buffer.BlockCopy(FfuChunk, 0, Request, 0x1C, FfuChunk.Length);
byte[] Response = ExecuteRawMethod(Request) ?? throw new BadConnectionException();
int ResultCode = (Response[6] << 8) + Response[7];
if (ResultCode != 0)
{
ThrowFlashError(ResultCode);
}
}
public void SendFfuPayloadV2(byte[] FfuChunk, int Progress = 0, byte Options = 0)
{
byte[] Request = new byte[FfuChunk.Length + 0x20];
const string Header = SecureFlashSignature;
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(BigEndian.GetBytes((int)FfuProtocol.ProtocolSyncV2, 2), 0, Request, 0x06, 2); // Protocol
Request[0x08] = (byte)Progress; // Progress = 0% (0 - 100)
Request[0x0B] = 1; // Subblock count = 1
Buffer.BlockCopy(BigEndian.GetBytes(0x0000001B, 4), 0, Request, 0x0C, 4); // Subblock type for Payload v2 = 0x1B
Buffer.BlockCopy(BigEndian.GetBytes(FfuChunk.Length + 0x0C, 4), 0, Request, 0x10, 4); // Subblock length = length of chunk + 0x08
Buffer.BlockCopy(BigEndian.GetBytes(FfuChunk.Length, 4), 0, Request, 0x14, 4); // Payload length = length of chunk
Request[0x18] = Options; // Data options = 0 (1 = verify)
Buffer.BlockCopy(FfuChunk, 0, Request, 0x20, FfuChunk.Length);
byte[] Response = ExecuteRawMethod(Request) ?? throw new BadConnectionException();
int ResultCode = (Response[6] << 8) + Response[7];
if (ResultCode != 0)
{
ThrowFlashError(ResultCode);
}
}
public void SendFfuPayloadV3(byte[] FfuChunk, uint WriteDescriptorIndex, uint CRC, int Progress = 0, byte Options = 0)
{
byte[] Request = new byte[FfuChunk.Length + 0x20];
const string Header = SecureFlashSignature;
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(BigEndian.GetBytes((int)FfuProtocol.ProtocolAsyncV3, 2), 0, Request, 0x06, 2); // Protocol
Request[0x08] = (byte)Progress; // Progress = 0% (0 - 100)
Request[0x0B] = 1; // Subblock count = 1
Buffer.BlockCopy(BigEndian.GetBytes(0x0000001D, 4), 0, Request, 0x0C, 4); // Subblock type for Payload v2 = 0x1B
Buffer.BlockCopy(BigEndian.GetBytes(FfuChunk.Length + 0x2C, 4), 0, Request, 0x10, 4); // Subblock length = length of chunk + 0x08
Buffer.BlockCopy(BigEndian.GetBytes(FfuChunk.Length, 4), 0, Request, 0x14, 4); // Payload length = length of chunk
Request[0x18] = Options; // Data options = 0 (1 = verify)
Buffer.BlockCopy(BigEndian.GetBytes(WriteDescriptorIndex, 4), 0, Request, 0x19, 4); // Payload length = length of chunk
Buffer.BlockCopy(BigEndian.GetBytes(CRC, 4), 0, Request, 0x1D, 4); // Payload length = length of chunk
Buffer.BlockCopy(FfuChunk, 0, Request, 0x40, FfuChunk.Length);
byte[] Response = ExecuteRawMethod(Request) ?? throw new BadConnectionException();
int ResultCode = (Response[6] << 8) + Response[7];
if (ResultCode != 0)
{
ThrowFlashError(ResultCode);
}
}
public PhoneInfo ReadPhoneInfo()
{
// NOKV = Info Query
bool PhoneInfoLogged = Info.State != PhoneInfoState.Empty;
PhoneInfo Result = Info;
if (Result.State == PhoneInfoState.Empty)
{
byte[] Request = new byte[4];
ByteOperations.WriteAsciiString(Request, 0, InfoQuerySignature);
byte[]? Response = ExecuteRawMethod(Request);
if ((Response != null) && (ByteOperations.ReadAsciiString(Response, 0, 4) != "NOKU"))
{
Result.App = (FlashAppType)Response[5];
switch (Result.App)
{
case FlashAppType.FlashApp:
Result.FlashAppProtocolVersionMajor = Response[6];
Result.FlashAppProtocolVersionMinor = Response[7];
Result.FlashAppVersionMajor = Response[8];
Result.FlashAppVersionMinor = Response[9];
break;
}
byte SubblockCount = Response[10];
int SubblockOffset = 11;
for (int i = 0; i < SubblockCount; i++)
{
byte SubblockID = Response[SubblockOffset + 0x00];
ushort SubblockLength = BigEndian.ToUInt16(Response, SubblockOffset + 0x01);
int SubblockPayloadOffset = SubblockOffset + 3;
byte SubblockVersion;
switch (SubblockID)
{
case 0x01:
Result.TransferSize = BigEndian.ToUInt32(Response, SubblockPayloadOffset);
break;
case 0x02:
Result.WriteBufferSize = BigEndian.ToUInt32(Response, SubblockPayloadOffset);
break;
case 0x03:
Result.EmmcSizeInSectors = BigEndian.ToUInt32(Response, SubblockPayloadOffset);
break;
case 0x04:
if (Result.App == FlashAppType.FlashApp)
{
Result.SdCardSizeInSectors = BigEndian.ToUInt32(Response, SubblockPayloadOffset);
}
break;
case 0x05:
Result.PlatformID = ByteOperations.ReadAsciiString(Response, (uint)SubblockPayloadOffset, SubblockLength).Trim([' ', '\0']);
break;
case 0x0D:
Result.AsyncSupport = Response[SubblockPayloadOffset + 1] == 1;
break;
case 0x0F: // Supported but check parsing below pls
SubblockVersion = Response[SubblockPayloadOffset]; // 0x03
Result.PlatformSecureBootEnabled = Response[SubblockPayloadOffset + 0x01] == 0x01;
Result.SecureFfuEnabled = Response[SubblockPayloadOffset + 0x02] == 0x01;
Result.JtagDisabled = Response[SubblockPayloadOffset + 0x03] == 0x01;
Result.RdcPresent = Response[SubblockPayloadOffset + 0x04] == 0x01;
Result.Authenticated = (Response[SubblockPayloadOffset + 0x05] == 0x01) || (Response[SubblockPayloadOffset + 0x05] == 0x02);
Result.UefiSecureBootEnabled = Response[SubblockPayloadOffset + 0x06] == 0x01;
Result.SecondaryHardwareKeyPresent = Response[SubblockPayloadOffset + 0x07] == 0x01;
break;
case 0x10: // Also check to be sure
SubblockVersion = Response[SubblockPayloadOffset]; // 0x01
Result.SecureFfuSupportedProtocolMask = BigEndian.ToUInt16(Response, SubblockPayloadOffset + 0x01);
break;
case 0x1F: // Recheck too
Result.MmosOverUsbSupported = Response[SubblockPayloadOffset] == 1;
break;
case 0x20:
// CRC header info
break;
case 0x22:
uint SectorCount = BigEndian.ToUInt32(Response, SubblockPayloadOffset);
uint SectorSize = BigEndian.ToUInt32(Response, SubblockPayloadOffset + 4);
ushort FlashType = BigEndian.ToUInt16(Response, SubblockPayloadOffset + 8);
ushort FlashTypeIndex = BigEndian.ToUInt16(Response, SubblockPayloadOffset + 10);
uint Unknown = BigEndian.ToUInt32(Response, SubblockPayloadOffset + 12);
string DevicePath = ByteOperations.ReadUnicodeString(Response, (uint)SubblockPayloadOffset + 16, (uint)SubblockLength - 16).Trim([' ', '\0']);
Result.BootDevices.Add((SectorCount, SectorSize, FlashType, FlashTypeIndex, Unknown, DevicePath));
break;
case 0x23:
byte[] Bytes = Response[SubblockPayloadOffset..(SubblockPayloadOffset + SubblockLength)];
ushort ManufacturerLength = BitConverter.ToUInt16(Bytes[0..2].Reverse().ToArray());
ushort FamilyLength = BitConverter.ToUInt16(Bytes[2..4].Reverse().ToArray());
ushort ProductNameLength = BitConverter.ToUInt16(Bytes[4..6].Reverse().ToArray());
ushort ProductVersionLength = BitConverter.ToUInt16(Bytes[6..8].Reverse().ToArray());
ushort SKUNumberLength = BitConverter.ToUInt16(Bytes[8..10].Reverse().ToArray());
ushort BaseboardManufacturerLength = BitConverter.ToUInt16(Bytes[10..12].Reverse().ToArray());
ushort BaseboardProductLength = BitConverter.ToUInt16(Bytes[12..14].Reverse().ToArray());
int CurrentOffset = 14;
Result.Manufacturer = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + ManufacturerLength)]);
CurrentOffset += ManufacturerLength;
Result.Family = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + FamilyLength)]);
CurrentOffset += FamilyLength;
Result.ProductName = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + ProductNameLength)]);
CurrentOffset += ProductNameLength;
Result.ProductVersion = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + ProductVersionLength)]);
CurrentOffset += ProductVersionLength;
Result.SKUNumber = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + SKUNumberLength)]);
CurrentOffset += SKUNumberLength;
Result.BaseboardManufacturer = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + BaseboardManufacturerLength)]);
CurrentOffset += BaseboardManufacturerLength;
Result.BaseboardProduct = Encoding.ASCII.GetString(Bytes[CurrentOffset..(CurrentOffset + BaseboardProductLength)]);
break;
case 0x24:
Result.LargestMemoryRegion = BitConverter.ToUInt64(Response[SubblockPayloadOffset..(SubblockPayloadOffset + 8)].Reverse().ToArray());
break;
case 0x25:
Result.AppType = (AppType)Response[SubblockPayloadOffset];
break;
default:
Debug.WriteLine($"Unknown Subblock: ID: 0x{SubblockID:X2} Length: 0x{SubblockLength:X4}");
break;
}
SubblockOffset += SubblockLength + 3;
}
}
Result.State = PhoneInfoState.Basic;
}
Result.IsBootloaderSecure = !(Info.Authenticated || Info.RdcPresent || !Info.SecureFfuEnabled);
if (!PhoneInfoLogged)
{
Result.Log();
}
return Result;
}
public enum FlashAppType
{
FlashApp = 2
};
public enum PhoneInfoState
{
Empty,
Basic
};
public class PhoneInfo
{
public PhoneInfoState State = PhoneInfoState.Empty;
public FlashAppType App;
public byte FlashAppVersionMajor;
public byte FlashAppVersionMinor;
public byte FlashAppProtocolVersionMajor;
public byte FlashAppProtocolVersionMinor;
public uint TransferSize;
public bool MmosOverUsbSupported;
public uint SdCardSizeInSectors;
public uint WriteBufferSize;
public uint EmmcSizeInSectors;
public string? PlatformID;
public ushort SecureFfuSupportedProtocolMask;
public bool AsyncSupport;
public bool PlatformSecureBootEnabled;
public bool SecureFfuEnabled;
public bool JtagDisabled;
public bool RdcPresent;
public bool Authenticated;
public bool UefiSecureBootEnabled;
public bool SecondaryHardwareKeyPresent;
public string? Manufacturer;
public string? Family;
public string? ProductName;
public string? ProductVersion;
public string? SKUNumber;
public string? BaseboardManufacturer;
public string? BaseboardProduct;
public ulong LargestMemoryRegion;
public AppType AppType;
public List<(uint SectorCount, uint SectorSize, ushort FlashType, ushort FlashIndex, uint Unknown, string DevicePath)> BootDevices = [];
public bool IsBootloaderSecure;
public void Log()
{
switch (App)
{
case FlashAppType.FlashApp:
Debug.WriteLine($"Flash app: {FlashAppVersionMajor}.{FlashAppVersionMinor}");
Debug.WriteLine($"Flash protocol: {FlashAppProtocolVersionMajor}.{FlashAppProtocolVersionMinor}");
break;
}
Debug.WriteLine($"SecureBoot: {((!PlatformSecureBootEnabled || !UefiSecureBootEnabled) ? "Disabled" : "Enabled")} (Platform Secure Boot: {(PlatformSecureBootEnabled ? "Enabled" : "Disabled")}, UEFI Secure Boot: {(UefiSecureBootEnabled ? "Enabled" : "Disabled")})");
Debug.WriteLine($"Flash app security: {(!IsBootloaderSecure ? "Disabled" : "Enabled")}");
Debug.WriteLine($"Flash app security: {(!IsBootloaderSecure ? "Disabled" : "Enabled")} (FFU security: {(SecureFfuEnabled ? "Enabled" : "Disabled")}, RDC: {(RdcPresent ? "Present" : "Not found")}, Authenticated: {(Authenticated ? "True" : "False")})");
Debug.WriteLine($"JTAG: {(JtagDisabled ? "Disabled" : "Enabled")}");
}
}
public void Shutdown()
{
byte[] Request = new byte[4];
const string Header = ShutdownSignature;
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
ExecuteRawVoidMethod(Request);
}
}
}
@@ -0,0 +1,61 @@
using System;
using System.Linq;
using System.Text;
using UnifiedFlashingPlatform.UEFI;
using WPinternals.HelperClasses;
namespace UnifiedFlashingPlatform
{
public partial class UnifiedFlashingPlatformModel
{
public void WriteParam(string Param, byte[] Data)
{
byte[] Request = new byte[0x0F + Data.Length];
const string Header = WriteParamSignature; // NOKXFW
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Param), 0, Request, 7, Param.Length);
// 4 empty bytes here
Buffer.BlockCopy(Data, 0, Request, 15, Data.Length);
ExecuteRawMethod(Request);
}
// TODO: Verify proper functionality
public void SetUEFIVariable(Guid Guid, string Name, UefiVariableAttributes Attributes, byte[] Data)
{
byte[] ParamBuffer = new byte[540 + Data.Length];
/* 15..30 */ Buffer.BlockCopy(Guid.ToByteArray(), 0, ParamBuffer, 0, 16);
/* 31..34 */ Buffer.BlockCopy(BigEndian.GetBytes(Math.Min(512, Name.Length * 2), 4), 0, ParamBuffer, 16, 4);
/* 35.. */ Buffer.BlockCopy(Encoding.Unicode.GetBytes(Name), 0, ParamBuffer, 20, Math.Min(512, Name.Length * 2)); // 256 Max Size for name (unicode)
/* 547..550 */ Buffer.BlockCopy(BigEndian.GetBytes(Attributes, 4), 0, ParamBuffer, 532, 4);
/* 551..554 */ Buffer.BlockCopy(BigEndian.GetBytes(Data.Length, 4), 0, ParamBuffer, 536, 4);
/* 555.. */ Buffer.BlockCopy(Data, 0, ParamBuffer, 540, Data.Length);
WriteParam(SettingUEFIVariableWriteParamSignature, ParamBuffer);
}
public void SetOneTimeBootSequence(ushort BootEntryID)
{
//WriteParam(OneTimeBootSequenceWriteParamSignature, BigEndian.GetBytes(BootEntryID, 2));
WriteParam("UOBU", [.. BigEndian.GetBytes(BootEntryID, 2).Reverse()]);
}
public void SetBootOptionAsFirstEntry(ushort BootEntryID)
{
//WriteParam(BootOptionAsFirstEntryWriteParamSignature, BigEndian.GetBytes(BootEntryID, 2));
WriteParam("UBOF", [.. BigEndian.GetBytes(BootEntryID, 2).Reverse()]);
}
public void SetBootOptionAsLastEntry(ushort BootEntryID)
{
WriteParam(BootOptionAsLastEntryWriteParamSignature, BigEndian.GetBytes(BootEntryID, 2));
}
public void SetProgressBar(uint Percentage)
{
WriteParam("PBI\0", BigEndian.GetBytes(Percentage, 1));
}
}
}
@@ -0,0 +1,359 @@
/*
* MIT License
*
* Copyright (c) 2024 The DuoWOA authors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using MadWizard.WinUSBNet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnifiedFlashingPlatform.UEFI;
using WPinternals.HelperClasses;
namespace UnifiedFlashingPlatform
{
public partial class UnifiedFlashingPlatformModel : IDisposable
{
private bool Disposed = false;
private readonly USBDevice USBDevice;
private readonly USBPipe InputPipe;
private readonly USBPipe OutputPipe;
private readonly object UsbLock = new();
public UnifiedFlashingPlatformModel(string DevicePath)
{
USBDevice = new USBDevice(DevicePath);
foreach (USBPipe Pipe in USBDevice.Pipes)
{
if (Pipe.IsIn)
{
InputPipe = Pipe;
}
if (Pipe.IsOut)
{
OutputPipe = Pipe;
}
}
if (InputPipe == null || OutputPipe == null)
{
throw new Exception("Invalid USB device!");
}
}
public byte[]? ExecuteRawMethod(byte[] RawMethod)
{
return ExecuteRawMethod(RawMethod, RawMethod.Length);
}
public byte[]? ExecuteRawMethod(byte[] RawMethod, int Length)
{
byte[] Buffer = new byte[0xF000]; // Should be at least 0x4408 for receiving the GPT packet.
byte[]? Result = null;
lock (UsbLock)
{
OutputPipe.Write(RawMethod, 0, Length);
try
{
int OutputLength = InputPipe.Read(Buffer);
Result = new byte[OutputLength];
System.Buffer.BlockCopy(Buffer, 0, Result, 0, OutputLength);
}
catch { } // Reboot command looses connection
}
return Result;
}
public void ExecuteRawVoidMethod(byte[] RawMethod)
{
ExecuteRawVoidMethod(RawMethod, RawMethod.Length);
}
public void ExecuteRawVoidMethod(byte[] RawMethod, int Length)
{
lock (UsbLock)
{
OutputPipe.Write(RawMethod, 0, Length);
}
}
public void Relock()
{
byte[] Request = new byte[7];
const string Header = RelockSignature; // NOKXFO
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
_ = ExecuteRawMethod(Request);
}
public void MassStorage()
{
byte[] Request = new byte[7];
const string Header = MassStorageSignature; // NOKM
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
_ = ExecuteRawMethod(Request);
}
public void RebootPhone()
{
byte[] Request = new byte[7];
const string Header = $"{SwitchModeSignature}R"; // NOKXCBR
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
_ = ExecuteRawMethod(Request);
}
public void SwitchToUFP()
{
byte[] Request = new byte[7];
const string Header = $"{SwitchModeSignature}U"; // NOKXCBU
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
_ = ExecuteRawMethod(Request);
}
public void ContinueBoot()
{
byte[] Request = new byte[7];
const string Header = $"{SwitchModeSignature}W"; // NOKXCBW
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
_ = ExecuteRawMethod(Request);
}
public void PowerOff()
{
byte[] Request = new byte[7];
const string Header = $"{SwitchModeSignature}Z"; // NOKXCBZ
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
ExecuteRawVoidMethod(Request);
}
public void TransitionToUFPBootApp()
{
byte[] Request = new byte[7];
const string Header = $"{SwitchModeSignature}T"; // NOKXCBT
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
ExecuteRawVoidMethod(Request);
}
public void DisplayCustomMessage(string Message, ushort Row)
{
byte[] MessageBuffer = Encoding.Unicode.GetBytes(Message);
byte[] Request = new byte[8 + MessageBuffer.Length];
const string Header = DisplayCustomMessageSignature; // NOKXCM
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(BitConverter.GetBytes(Row).Reverse().ToArray(), 0, Request, 6, 2);
Buffer.BlockCopy(MessageBuffer, 0, Request, 8, MessageBuffer.Length);
_ = ExecuteRawMethod(Request);
}
public void ClearScreen()
{
byte[] Request = new byte[6];
const string Header = ClearScreenSignature; // NOKXCC
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
_ = ExecuteRawMethod(Request);
}
public byte[]? Echo(byte[] DataPayload)
{
byte[] Request = new byte[10 + DataPayload.Length];
const string Header = EchoSignature; // NOKXCE
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(BitConverter.GetBytes(DataPayload.Length).Reverse().ToArray(), 0, Request, 6, 4);
Buffer.BlockCopy(DataPayload, 0, Request, 10, DataPayload.Length);
byte[]? Response = ExecuteRawMethod(Request);
if ((Response == null) || (Response.Length < 6 + DataPayload.Length))
{
return null;
}
byte[] Result = new byte[DataPayload.Length];
Buffer.BlockCopy(Response, 6, Result, 0, DataPayload.Length);
return Result;
}
public FILE_INFO[]? GetDirectoryEntries(string PartitionName, string DirectoryName)
{
ulong? size = ReadDirectoryEntriesSize(PartitionName, DirectoryName);
if (size == null)
{
return null;
}
return GetDirectoryEntries(PartitionName, DirectoryName, size.Value);
}
private FILE_INFO[]? GetDirectoryEntries(string PartitionName, string DirectoryName, ulong DataStructSize)
{
if (PartitionName.Length > 35)
{
return null;
}
byte[] PartitionNameBuffer = Encoding.Unicode.GetBytes(PartitionName);
byte[] DirectoryNameBuffer = Encoding.Unicode.GetBytes(DirectoryName);
byte[] Request = new byte[1114];
const string Header = GetDirectoryEntriesSignature; // NOKXCD
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Buffer.BlockCopy(PartitionNameBuffer, 0, Request, 6, PartitionNameBuffer.Length);
Buffer.BlockCopy(DirectoryNameBuffer, 0, Request, 78, DirectoryNameBuffer.Length); // 512 max size (1024 for unicode)
Buffer.BlockCopy(BigEndian.GetBytes((int)DataStructSize, 4), 0, Request, 1102, 4);
// TODO: Investigate data size
//Buffer.BlockCopy(BigEndian.GetBytes(360, 8), 0, Request, 1106, 8);
byte[]? Response = ExecuteRawMethod(Request);
if ((Response == null) || (Response.Length < 0x10))
{
return null;
}
int ResultCode = (Response[6] << 8) + Response[7];
if (ResultCode != 0)
{
ThrowFlashError(ResultCode);
}
int ResponseLength = BigEndian.ToInt32(Response, 8);
byte[] Result = new byte[ResponseLength];
Buffer.BlockCopy(Response, 12, Result, 0, ResponseLength);
List<FILE_INFO> directoryEntries = [];
int j = 0;
while (j != Result.Length)
{
FILE_INFO directoryEntry = FILE_INFO.ReadFromBuffer(Result, j);
j += (int)directoryEntry.Size;
directoryEntries.Add(directoryEntry);
}
return [.. directoryEntries];
}
public void TelemetryStart()
{
byte[] Request = new byte[4];
const string Header = TelemetryStartSignature; // NOKS
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
ExecuteRawVoidMethod(Request);
}
public void TelemetryEnd()
{
byte[] Request = new byte[4];
const string Header = TelemetryEndSignature; // NOKN
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
ExecuteRawVoidMethod(Request);
}
// WIP!
public string? ReadLog()
{
byte[] Request = new byte[0x13];
const string Header = GetLogsSignature;
ulong BufferSize = 0xE000 - 0xC;
ulong Length = ReadLogSize(DeviceLogType.Flashing)!.Value;
if (Length == 0)
{
return null;
}
string LogContent = "";
for (ulong i = 0; i < Length; i += BufferSize)
{
if (i + BufferSize > Length)
{
BufferSize = Length - i;
}
uint BufferSizeInt = (uint)BufferSize;
Buffer.BlockCopy(Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
Request[6] = 1;
Buffer.BlockCopy(BitConverter.GetBytes(BufferSizeInt).Reverse().ToArray(), 0, Request, 7, 4);
Buffer.BlockCopy(BitConverter.GetBytes(i).Reverse().ToArray(), 0, Request, 11, 8);
byte[]? Response = ExecuteRawMethod(Request);
if ((Response == null) || (Response.Length < 0xC))
{
return null;
}
int ResultLength = Response.Length - 0xC;
byte[] Result = new byte[ResultLength];
Buffer.BlockCopy(Response, 0xC, Result, 0, ResultLength);
string PartialLogContent = Encoding.ASCII.GetString(Result);
LogContent += PartialLogContent;
}
return LogContent;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~UnifiedFlashingPlatformModel()
{
Dispose(false);
}
public void Close()
{
USBDevice?.Dispose();
}
protected virtual void Dispose(bool disposing)
{
if (Disposed)
{
return;
}
if (disposing)
{
// Other disposables
}
// Clean unmanaged resources here.
Close();
Disposed = true;
}
}
}
@@ -20,18 +20,8 @@
using Microsoft.Win32;
using 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);
});
+3 -1
View File
@@ -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;
}

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