Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d270cace79 | ||
|
|
af61c9ad29 | ||
|
|
de4d5e577a | ||
|
|
df02025a31 | ||
|
|
ad92ecdab3 | ||
|
|
b3b037a3c8 | ||
|
|
be15155c39 | ||
|
|
a17dae3931 | ||
|
|
7646e3fc76 | ||
|
|
933e9e53b6 | ||
|
|
e838168127 | ||
|
|
058cde0d91 | ||
|
|
1cc7a5cee4 | ||
|
|
132e21e58a | ||
|
|
1e5da5452b | ||
|
|
6992ed3f70 | ||
|
|
bb9702a3c3 | ||
|
|
3c66688303 | ||
|
|
bc77e8b589 | ||
|
|
6be24faee0 | ||
|
|
e078bb10ed | ||
|
|
605b19aede | ||
|
|
d9da49915e | ||
|
|
7c18a168fa | ||
|
|
303c2d4b5a | ||
|
|
d700ae5911 | ||
|
|
14bf607111 | ||
|
|
57c9595d86 | ||
|
|
7fc332e912 | ||
|
|
bcec0a72e6 | ||
|
|
00407d6f24 | ||
|
|
2d5b0fd3db | ||
|
|
a982c119fb | ||
|
|
c6dee3fe33 | ||
|
|
91961b0e7b | ||
|
|
29c6ab06d4 | ||
|
|
b03b561724 | ||
|
|
91f534a7c3 | ||
|
|
f0f3268924 | ||
|
|
c269cfe839 | ||
|
|
7d8aad0e88 | ||
|
|
310d0b97c5 | ||
|
|
8e50c46357 | ||
|
|
e6555741b0 | ||
|
|
c21692491d | ||
|
|
350b6e8f1e | ||
|
|
0101477830 | ||
|
|
a6c017986b | ||
|
|
0174fc8b30 | ||
|
|
c6f6ef4429 | ||
|
|
ab0c35e879 | ||
|
|
676a95dd97 | ||
|
|
8981fd02e9 | ||
|
|
16d3f95971 | ||
|
|
293c649edb | ||
|
|
88efc77887 | ||
|
|
dc6085f185 | ||
|
|
e2cbb9c6fc | ||
|
|
4b7b9621b4 | ||
|
|
96c42a29b5 | ||
|
|
742c89b9bf | ||
|
|
dbd303fd07 | ||
|
|
8d35be447a | ||
|
|
83c09bdc81 | ||
|
|
93a5064751 | ||
|
|
ef6a962a01 | ||
|
|
d32788198d | ||
|
|
7798dd1c34 | ||
|
|
57cd052d61 | ||
|
|
5eb523530c | ||
|
|
8a17b05398 | ||
|
|
dc5ac1e7d4 | ||
|
|
1d14d79fab | ||
|
|
846ea41883 | ||
|
|
452393aaa7 | ||
|
|
17bc763761 | ||
|
|
668a9b7fe2 | ||
|
|
8293c18406 | ||
|
|
48fbfa77df | ||
|
|
709c91cec5 | ||
|
|
611ad122f9 |
@@ -0,0 +1,60 @@
|
|||||||
|
name: Bug Report
|
||||||
|
description: Create a bug report to help improve WPinternals
|
||||||
|
labels: [bug]
|
||||||
|
body:
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Description
|
||||||
|
description: A clear and concise description of what the bug is.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Steps To Reproduce
|
||||||
|
description: Steps to reproduce the behavior.
|
||||||
|
placeholder: |
|
||||||
|
1. Go to '....'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See the error
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Expected behavior
|
||||||
|
description: A clear and concise description of what you expected to happen.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: wpi-version
|
||||||
|
attributes:
|
||||||
|
label: WPinternals Version
|
||||||
|
description: What version of WPinternals are you using?
|
||||||
|
placeholder: v2.9.2
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: Windows Version
|
||||||
|
description: What version of Windows are you using? Press <kbd>Win</kbd> + <kbd>Pause/Break</kbd> and copy.
|
||||||
|
placeholder: e.g. Windows 11 21H2 22000.132
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: Phone model
|
||||||
|
description: What phone model did you reproduce the bug on (if applicable)
|
||||||
|
placeholder: e.g. Lumia 950 XL (RM-1085)
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Relevant Assets
|
||||||
|
description: |
|
||||||
|
A list of assets (logs, screenshots) relevant to this bug.
|
||||||
|
|
||||||
|
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
|
||||||
|
placeholder: |
|
||||||
|
To upload the log
|
||||||
|
- Copy the `WPinternals.log` files from `%ALLUSERSPROFILE%\WPinternals`
|
||||||
|
- Drag and drop them into this text area.
|
||||||
@@ -11,16 +11,16 @@ jobs:
|
|||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
architecture: [x86, x64]
|
architecture: [x86, x64, arm64]
|
||||||
platform: [win]
|
platform: [win]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install .NET SDK
|
- name: Install .NET SDK
|
||||||
uses: actions/setup-dotnet@v1
|
uses: actions/setup-dotnet@v1
|
||||||
with:
|
with:
|
||||||
dotnet-version: "5.0.400"
|
dotnet-version: "8.0.x"
|
||||||
|
|
||||||
- name: Add MSBuild to PATH
|
- name: Add MSBuild to PATH
|
||||||
uses: microsoft/setup-msbuild@v1.0.2
|
uses: microsoft/setup-msbuild@v1.0.2
|
||||||
@@ -31,7 +31,7 @@ jobs:
|
|||||||
msbuild /m /t:restore,wpinternals:publish /p:Platform=${{ matrix.architecture }} /p:RuntimeIdentifier=${{ matrix.platform }}-${{ matrix.architecture }} /p:PublishDir=${{ github.workspace }}/artifacts/${{ matrix.platform }}-${{ matrix.architecture }} /p:PublishSingleFile=true /p:PublishTrimmed=false WPinternals.sln
|
msbuild /m /t:restore,wpinternals:publish /p:Platform=${{ matrix.architecture }} /p:RuntimeIdentifier=${{ matrix.platform }}-${{ matrix.architecture }} /p:PublishDir=${{ github.workspace }}/artifacts/${{ matrix.platform }}-${{ matrix.architecture }} /p:PublishSingleFile=true /p:PublishTrimmed=false WPinternals.sln
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ matrix.platform }}-${{ matrix.architecture }}
|
name: ${{ matrix.platform }}-${{ matrix.architecture }}
|
||||||
path: ${{ github.workspace }}/artifacts/${{ matrix.platform }}-${{ matrix.architecture }}
|
path: ${{ github.workspace }}/artifacts/${{ matrix.platform }}-${{ matrix.architecture }}
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -47,7 +47,7 @@ namespace SevenZip.CommandLineParser
|
|||||||
{
|
{
|
||||||
public bool ThereIs;
|
public bool ThereIs;
|
||||||
public bool WithMinus;
|
public bool WithMinus;
|
||||||
public ArrayList PostStrings = new();
|
public ArrayList PostStrings = [];
|
||||||
public int PostCharIndex;
|
public int PostCharIndex;
|
||||||
public SwitchResult()
|
public SwitchResult()
|
||||||
{
|
{
|
||||||
@@ -57,7 +57,7 @@ namespace SevenZip.CommandLineParser
|
|||||||
|
|
||||||
public class Parser
|
public class Parser
|
||||||
{
|
{
|
||||||
public ArrayList NonSwitchStrings = new();
|
public ArrayList NonSwitchStrings = [];
|
||||||
private readonly SwitchResult[] _switches;
|
private readonly SwitchResult[] _switches;
|
||||||
|
|
||||||
public Parser(int numSwitches)
|
public Parser(int numSwitches)
|
||||||
|
|||||||
@@ -1518,10 +1518,10 @@ namespace SevenZip.Compression.LZMA
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static readonly string[] kMatchFinderIDs =
|
private static readonly string[] kMatchFinderIDs =
|
||||||
{
|
[
|
||||||
"BT2",
|
"BT2",
|
||||||
"BT4",
|
"BT4",
|
||||||
};
|
];
|
||||||
|
|
||||||
private static int FindMatchFinder(string s)
|
private static int FindMatchFinder(string s)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ using System.Text;
|
|||||||
|
|
||||||
namespace DiscUtils.CoreCompat
|
namespace DiscUtils.CoreCompat
|
||||||
{
|
{
|
||||||
internal static class EncodingHelper
|
public static class EncodingHelper
|
||||||
{
|
{
|
||||||
private static bool _registered;
|
private static bool _registered;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="DiscUtils.Core" Version="0.16.13" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -28,7 +28,7 @@ using System.Text.RegularExpressions;
|
|||||||
|
|
||||||
namespace DiscUtils.Internal
|
namespace DiscUtils.Internal
|
||||||
{
|
{
|
||||||
internal static class Utilities
|
public static class Utilities
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts between two arrays.
|
/// Converts between two arrays.
|
||||||
@@ -61,14 +61,14 @@ namespace DiscUtils.Internal
|
|||||||
/// <returns>The resultant array.</returns>
|
/// <returns>The resultant array.</returns>
|
||||||
public static U[] Map<T, U>(IEnumerable<T> source, Func<T, U> func)
|
public static U[] Map<T, U>(IEnumerable<T> source, Func<T, U> func)
|
||||||
{
|
{
|
||||||
List<U> result = new();
|
List<U> result = [];
|
||||||
|
|
||||||
foreach (T sVal in source)
|
foreach (T sVal in source)
|
||||||
{
|
{
|
||||||
result.Add(func(sVal));
|
result.Add(func(sVal));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.ToArray();
|
return [.. result];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -48,15 +48,7 @@ namespace DiscUtils.Fat
|
|||||||
_fat = fileSystem.Fat;
|
_fat = fileSystem.Fat;
|
||||||
_length = length;
|
_length = length;
|
||||||
|
|
||||||
_knownClusters = new List<uint>();
|
_knownClusters = [firstCluster != 0 ? firstCluster : FatBuffer.EndOfChain];
|
||||||
if (firstCluster != 0)
|
|
||||||
{
|
|
||||||
_knownClusters.Add(firstCluster);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_knownClusters.Add(FatBuffer.EndOfChain);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_length == uint.MaxValue)
|
if (_length == uint.MaxValue)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -64,7 +64,7 @@ namespace DiscUtils.Fat
|
|||||||
{
|
{
|
||||||
_type = type;
|
_type = type;
|
||||||
_buffer = buffer;
|
_buffer = buffer;
|
||||||
_dirtySectors = new Dictionary<uint, uint>();
|
_dirtySectors = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
internal int NumEntries
|
internal int NumEntries
|
||||||
@@ -220,7 +220,7 @@ namespace DiscUtils.Fat
|
|||||||
|
|
||||||
internal List<uint> GetChain(uint head)
|
internal List<uint> GetChain(uint head)
|
||||||
{
|
{
|
||||||
List<uint> result = new();
|
List<uint> result = [];
|
||||||
|
|
||||||
if (head != 0)
|
if (head != 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -31,15 +31,15 @@ namespace DiscUtils.Fat
|
|||||||
private const byte SpaceByte = 0x20;
|
private const byte SpaceByte = 0x20;
|
||||||
|
|
||||||
public static readonly FileName SelfEntryName =
|
public static readonly FileName SelfEntryName =
|
||||||
new(new byte[] { 0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, 0);
|
new([0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20], 0);
|
||||||
|
|
||||||
public static readonly FileName ParentEntryName =
|
public static readonly FileName ParentEntryName =
|
||||||
new(new byte[] { 0x2E, 0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, 0);
|
new([0x2E, 0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20], 0);
|
||||||
|
|
||||||
public static readonly FileName Null =
|
public static readonly FileName Null =
|
||||||
new(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0);
|
new([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], 0);
|
||||||
|
|
||||||
private static readonly byte[] InvalidBytes = { 0x22, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x5B, 0x5C, 0x5D, 0x7C };
|
private static readonly byte[] InvalidBytes = [0x22, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x5B, 0x5C, 0x5D, 0x7C];
|
||||||
|
|
||||||
private readonly byte[] _raw;
|
private readonly byte[] _raw;
|
||||||
|
|
||||||
|
|||||||
@@ -33,10 +33,10 @@ namespace DiscUtils.Fat
|
|||||||
{
|
{
|
||||||
if (FatFileSystem.Detect(stream))
|
if (FatFileSystem.Detect(stream))
|
||||||
{
|
{
|
||||||
return new FileSystemInfo[] { new VfsFileSystemInfo("FAT", "Microsoft FAT", Open) };
|
return [new VfsFileSystemInfo("FAT", "Microsoft FAT", Open)];
|
||||||
}
|
}
|
||||||
|
|
||||||
return System.Array.Empty<FileSystemInfo>();
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
private DiscFileSystem Open(Stream stream, VolumeInfo volumeInfo, FileSystemParameters parameters)
|
private DiscFileSystem Open(Stream stream, VolumeInfo volumeInfo, FileSystemParameters parameters)
|
||||||
|
|||||||
@@ -80,22 +80,22 @@ namespace DiscUtils.Fat
|
|||||||
{
|
{
|
||||||
// see http://home.teleport.com/~brainy/lfn.htm
|
// see http://home.teleport.com/~brainy/lfn.htm
|
||||||
// NOTE: we assume ordinals are ok here.
|
// NOTE: we assume ordinals are ok here.
|
||||||
char[] chars = new char[13];
|
char[] chars =
|
||||||
chars[0] = (char)((256 * buffer[2]) + buffer[1]);
|
[
|
||||||
chars[1] = (char)((256 * buffer[4]) + buffer[3]);
|
(char)((256 * buffer[2]) + buffer[1]),
|
||||||
chars[2] = (char)((256 * buffer[6]) + buffer[5]);
|
(char)((256 * buffer[4]) + buffer[3]),
|
||||||
chars[3] = (char)((256 * buffer[8]) + buffer[7]);
|
(char)((256 * buffer[6]) + buffer[5]),
|
||||||
chars[4] = (char)((256 * buffer[10]) + buffer[9]);
|
(char)((256 * buffer[8]) + buffer[7]),
|
||||||
|
(char)((256 * buffer[10]) + buffer[9]),
|
||||||
chars[5] = (char)((256 * buffer[15]) + buffer[14]);
|
(char)((256 * buffer[15]) + buffer[14]),
|
||||||
chars[6] = (char)((256 * buffer[17]) + buffer[16]);
|
(char)((256 * buffer[17]) + buffer[16]),
|
||||||
chars[7] = (char)((256 * buffer[19]) + buffer[18]);
|
(char)((256 * buffer[19]) + buffer[18]),
|
||||||
chars[8] = (char)((256 * buffer[21]) + buffer[20]);
|
(char)((256 * buffer[21]) + buffer[20]),
|
||||||
chars[9] = (char)((256 * buffer[23]) + buffer[22]);
|
(char)((256 * buffer[23]) + buffer[22]),
|
||||||
chars[10] = (char)((256 * buffer[25]) + buffer[24]);
|
(char)((256 * buffer[25]) + buffer[24]),
|
||||||
|
(char)((256 * buffer[29]) + buffer[28]),
|
||||||
chars[11] = (char)((256 * buffer[29]) + buffer[28]);
|
(char)((256 * buffer[31]) + buffer[30]),
|
||||||
chars[12] = (char)((256 * buffer[31]) + buffer[30]);
|
];
|
||||||
string chunk = new(chars);
|
string chunk = new(chars);
|
||||||
int zero = chunk.IndexOf('\0');
|
int zero = chunk.IndexOf('\0');
|
||||||
return zero >= 0 ? chunk.Substring(0, zero) : chunk;
|
return zero >= 0 ? chunk.Substring(0, zero) : chunk;
|
||||||
@@ -201,7 +201,7 @@ namespace DiscUtils.Fat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return dirs.ToArray();
|
return [.. dirs];
|
||||||
}
|
}
|
||||||
|
|
||||||
public DirectoryEntry[] GetFiles()
|
public DirectoryEntry[] GetFiles()
|
||||||
@@ -215,7 +215,7 @@ namespace DiscUtils.Fat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return files.ToArray();
|
return [.. files];
|
||||||
}
|
}
|
||||||
|
|
||||||
public DirectoryEntry GetEntry(long id)
|
public DirectoryEntry GetEntry(long id)
|
||||||
@@ -452,8 +452,8 @@ namespace DiscUtils.Fat
|
|||||||
|
|
||||||
private void LoadEntries()
|
private void LoadEntries()
|
||||||
{
|
{
|
||||||
_entries = new Dictionary<long, DirectoryEntry>();
|
_entries = [];
|
||||||
_freeEntries = new List<long>();
|
_freeEntries = [];
|
||||||
|
|
||||||
_selfEntryLocation = -1;
|
_selfEntryLocation = -1;
|
||||||
_parentEntryLocation = -1;
|
_parentEntryLocation = -1;
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ namespace DiscUtils.Fat
|
|||||||
public FatFileSystem(Stream data)
|
public FatFileSystem(Stream data)
|
||||||
: base(new FatFileSystemOptions())
|
: base(new FatFileSystemOptions())
|
||||||
{
|
{
|
||||||
_dirCache = new Dictionary<uint, Directory>();
|
_dirCache = [];
|
||||||
_timeConverter = DefaultTimeConverter;
|
_timeConverter = DefaultTimeConverter;
|
||||||
Initialize(data);
|
Initialize(data);
|
||||||
}
|
}
|
||||||
@@ -111,7 +111,7 @@ namespace DiscUtils.Fat
|
|||||||
public FatFileSystem(Stream data, Ownership ownsData)
|
public FatFileSystem(Stream data, Ownership ownsData)
|
||||||
: base(new FatFileSystemOptions())
|
: base(new FatFileSystemOptions())
|
||||||
{
|
{
|
||||||
_dirCache = new Dictionary<uint, Directory>();
|
_dirCache = [];
|
||||||
_timeConverter = DefaultTimeConverter;
|
_timeConverter = DefaultTimeConverter;
|
||||||
Initialize(data);
|
Initialize(data);
|
||||||
_ownsData = ownsData;
|
_ownsData = ownsData;
|
||||||
@@ -125,7 +125,7 @@ namespace DiscUtils.Fat
|
|||||||
public FatFileSystem(Stream data, TimeConverter timeConverter)
|
public FatFileSystem(Stream data, TimeConverter timeConverter)
|
||||||
: base(new FatFileSystemOptions())
|
: base(new FatFileSystemOptions())
|
||||||
{
|
{
|
||||||
_dirCache = new Dictionary<uint, Directory>();
|
_dirCache = [];
|
||||||
_timeConverter = timeConverter;
|
_timeConverter = timeConverter;
|
||||||
Initialize(data);
|
Initialize(data);
|
||||||
}
|
}
|
||||||
@@ -140,7 +140,7 @@ namespace DiscUtils.Fat
|
|||||||
public FatFileSystem(Stream data, Ownership ownsData, TimeConverter timeConverter)
|
public FatFileSystem(Stream data, Ownership ownsData, TimeConverter timeConverter)
|
||||||
: base(new FatFileSystemOptions())
|
: base(new FatFileSystemOptions())
|
||||||
{
|
{
|
||||||
_dirCache = new Dictionary<uint, Directory>();
|
_dirCache = [];
|
||||||
_timeConverter = timeConverter;
|
_timeConverter = timeConverter;
|
||||||
Initialize(data);
|
Initialize(data);
|
||||||
_ownsData = ownsData;
|
_ownsData = ownsData;
|
||||||
@@ -156,7 +156,7 @@ namespace DiscUtils.Fat
|
|||||||
public FatFileSystem(Stream data, Ownership ownsData, FileSystemParameters parameters)
|
public FatFileSystem(Stream data, Ownership ownsData, FileSystemParameters parameters)
|
||||||
: base(new FatFileSystemOptions(parameters))
|
: base(new FatFileSystemOptions(parameters))
|
||||||
{
|
{
|
||||||
_dirCache = new Dictionary<uint, Directory>();
|
_dirCache = [];
|
||||||
|
|
||||||
if (parameters?.TimeConverter != null)
|
if (parameters?.TimeConverter != null)
|
||||||
{
|
{
|
||||||
@@ -1258,7 +1258,7 @@ namespace DiscUtils.Fat
|
|||||||
dirs.Add(Utilities.CombinePaths(path, dirEntry.Name.GetDisplayName(FatOptions.FileNameEncoding)));
|
dirs.Add(Utilities.CombinePaths(path, dirEntry.Name.GetDisplayName(FatOptions.FileNameEncoding)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return dirs.ToArray();
|
return [.. dirs];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1273,9 +1273,9 @@ namespace DiscUtils.Fat
|
|||||||
{
|
{
|
||||||
Regex re = Utilities.ConvertWildcardsToRegEx(searchPattern);
|
Regex re = Utilities.ConvertWildcardsToRegEx(searchPattern);
|
||||||
|
|
||||||
List<string> dirs = new();
|
List<string> dirs = [];
|
||||||
DoSearch(dirs, path, re, searchOption == SearchOption.AllDirectories, true, false);
|
DoSearch(dirs, path, re, searchOption == SearchOption.AllDirectories, true, false);
|
||||||
return dirs.ToArray();
|
return [.. dirs];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1294,7 +1294,7 @@ namespace DiscUtils.Fat
|
|||||||
files.Add(Utilities.CombinePaths(path, dirEntry.Name.GetDisplayName(FatOptions.FileNameEncoding)));
|
files.Add(Utilities.CombinePaths(path, dirEntry.Name.GetDisplayName(FatOptions.FileNameEncoding)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return files.ToArray();
|
return [.. files];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1309,9 +1309,9 @@ namespace DiscUtils.Fat
|
|||||||
{
|
{
|
||||||
Regex re = Utilities.ConvertWildcardsToRegEx(searchPattern);
|
Regex re = Utilities.ConvertWildcardsToRegEx(searchPattern);
|
||||||
|
|
||||||
List<string> results = new();
|
List<string> results = [];
|
||||||
DoSearch(results, path, re, searchOption == SearchOption.AllDirectories, false, true);
|
DoSearch(results, path, re, searchOption == SearchOption.AllDirectories, false, true);
|
||||||
return results.ToArray();
|
return [.. results];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1330,7 +1330,7 @@ namespace DiscUtils.Fat
|
|||||||
result.Add(Utilities.CombinePaths(path, dirEntry.Name.GetDisplayName(FatOptions.FileNameEncoding)));
|
result.Add(Utilities.CombinePaths(path, dirEntry.Name.GetDisplayName(FatOptions.FileNameEncoding)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.ToArray();
|
return [.. result];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1356,7 +1356,7 @@ namespace DiscUtils.Fat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.ToArray();
|
return [.. result];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1915,9 +1915,7 @@ namespace DiscUtils.Fat
|
|||||||
throw new DirectoryNotFoundException(string.Format(CultureInfo.InvariantCulture, "The directory '{0}' was not found", path));
|
throw new DirectoryNotFoundException(string.Format(CultureInfo.InvariantCulture, "The directory '{0}' was not found", path));
|
||||||
}
|
}
|
||||||
|
|
||||||
DirectoryEntry[] entries = dir.Entries;
|
foreach (DirectoryEntry de in dir.Entries)
|
||||||
|
|
||||||
foreach (DirectoryEntry de in entries)
|
|
||||||
{
|
{
|
||||||
bool isDir = (de.Attributes & FatAttributes.Directory) != 0;
|
bool isDir = (de.Attributes & FatAttributes.Directory) != 0;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@@ -1,860 +0,0 @@
|
|||||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
// copy of this software and associated documentation files (the "Software"),
|
|
||||||
// to deal in the Software without restriction, including without limitation
|
|
||||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
// and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
// Software is furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
// DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Net.Http.Headers;
|
|
||||||
using System.Runtime.Serialization;
|
|
||||||
using System.Runtime.Serialization.Json;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Xml;
|
|
||||||
using System.Xml.Serialization;
|
|
||||||
|
|
||||||
namespace WPinternals
|
|
||||||
{
|
|
||||||
internal static class LumiaDownloadModel
|
|
||||||
{
|
|
||||||
internal static string SearchFFU(string ProductType, string ProductCode, string OperatorCode)
|
|
||||||
{
|
|
||||||
return SearchFFU(ProductType, ProductCode, OperatorCode, out string FoundProductType);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static string SearchFFU(string ProductType, string ProductCode, string OperatorCode, out string FoundProductType)
|
|
||||||
{
|
|
||||||
if (ProductType?.Length == 0)
|
|
||||||
{
|
|
||||||
ProductType = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ProductCode?.Length == 0)
|
|
||||||
{
|
|
||||||
ProductCode = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OperatorCode?.Length == 0)
|
|
||||||
{
|
|
||||||
OperatorCode = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ProductCode != null)
|
|
||||||
{
|
|
||||||
ProductCode = ProductCode.ToUpper();
|
|
||||||
ProductType = null;
|
|
||||||
OperatorCode = null;
|
|
||||||
}
|
|
||||||
if (ProductType != null)
|
|
||||||
{
|
|
||||||
ProductType = ProductType.ToUpper();
|
|
||||||
if (ProductType.StartsWith("RM") && !ProductType.StartsWith("RM-"))
|
|
||||||
{
|
|
||||||
ProductType = "RM-" + ProductType[2..];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (OperatorCode != null)
|
|
||||||
{
|
|
||||||
OperatorCode = OperatorCode.ToUpper();
|
|
||||||
}
|
|
||||||
|
|
||||||
DiscoveryQueryParameters DiscoveryQueryParams = new()
|
|
||||||
{
|
|
||||||
manufacturerName = "Microsoft",
|
|
||||||
manufacturerProductLine = "Lumia",
|
|
||||||
packageType = "Firmware",
|
|
||||||
packageClass = "Public",
|
|
||||||
manufacturerHardwareModel = ProductType,
|
|
||||||
manufacturerHardwareVariant = ProductCode,
|
|
||||||
operatorName = OperatorCode
|
|
||||||
};
|
|
||||||
DiscoveryParameters DiscoveryParams = new()
|
|
||||||
{
|
|
||||||
query = DiscoveryQueryParams
|
|
||||||
};
|
|
||||||
|
|
||||||
DataContractJsonSerializer Serializer1 = new(typeof(DiscoveryParameters));
|
|
||||||
MemoryStream JsonStream1 = new();
|
|
||||||
Serializer1.WriteObject(JsonStream1, DiscoveryParams);
|
|
||||||
JsonStream1.Seek(0L, SeekOrigin.Begin);
|
|
||||||
string JsonContent = new StreamReader(JsonStream1).ReadToEnd();
|
|
||||||
|
|
||||||
Uri RequestUri = new("https://api.swrepository.com/rest-api/discovery/1/package");
|
|
||||||
|
|
||||||
HttpClient HttpClient = new();
|
|
||||||
HttpClient.DefaultRequestHeaders.UserAgent.TryParseAdd("SoftwareRepository");
|
|
||||||
HttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
|
||||||
|
|
||||||
Task<HttpResponseMessage> HttpPostTask = HttpClient.PostAsync(RequestUri, new StringContent(JsonContent, Encoding.UTF8, "application/json"));
|
|
||||||
HttpPostTask.Wait();
|
|
||||||
HttpResponseMessage Response = HttpPostTask.Result;
|
|
||||||
|
|
||||||
string JsonResultString = "";
|
|
||||||
if (Response.StatusCode == HttpStatusCode.OK)
|
|
||||||
{
|
|
||||||
Task<string> ReadResponseTask = Response.Content.ReadAsStringAsync();
|
|
||||||
ReadResponseTask.Wait();
|
|
||||||
JsonResultString = ReadResponseTask.Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
SoftwarePackage Package = null;
|
|
||||||
using (MemoryStream JsonStream2 = new(Encoding.UTF8.GetBytes(JsonResultString)))
|
|
||||||
{
|
|
||||||
DataContractJsonSerializer Serializer2 = new(typeof(SoftwarePackages));
|
|
||||||
SoftwarePackages SoftwarePackages = (SoftwarePackages)Serializer2.ReadObject(JsonStream2);
|
|
||||||
if (SoftwarePackages != null)
|
|
||||||
{
|
|
||||||
Package = SoftwarePackages.softwarePackages.FirstOrDefault();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Package == null)
|
|
||||||
{
|
|
||||||
throw new WPinternalsException("FFU not found", "No FFU has been found in the remote software repository for the requested model.");
|
|
||||||
}
|
|
||||||
|
|
||||||
FoundProductType = Package.manufacturerHardwareModel[0];
|
|
||||||
|
|
||||||
SoftwareFile FileInfo = Package.files.First(f => f.fileName.EndsWith(".ffu", StringComparison.OrdinalIgnoreCase));
|
|
||||||
|
|
||||||
Uri FileInfoUri = new("https://api.swrepository.com/rest-api/discovery/fileurl/1/" + Package.id + "/" + FileInfo.fileName);
|
|
||||||
Task<string> GetFileInfoTask = HttpClient.GetStringAsync(FileInfoUri);
|
|
||||||
GetFileInfoTask.Wait();
|
|
||||||
string FileInfoString = GetFileInfoTask.Result;
|
|
||||||
|
|
||||||
string FfuUrl = "";
|
|
||||||
FileUrlResult FileUrl = null;
|
|
||||||
using (MemoryStream JsonStream3 = new(Encoding.UTF8.GetBytes(FileInfoString)))
|
|
||||||
{
|
|
||||||
DataContractJsonSerializer Serializer3 = new(typeof(FileUrlResult));
|
|
||||||
FileUrl = (FileUrlResult)Serializer3.ReadObject(JsonStream3);
|
|
||||||
if (FileUrl != null)
|
|
||||||
{
|
|
||||||
FfuUrl = FileUrl.url.Replace("sr.azureedge.net", "softwarerepo.blob.core.windows.net");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpClient.Dispose();
|
|
||||||
|
|
||||||
return FfuUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static string SearchENOSW(string ProductType, string PhoneFirmwareRevision)
|
|
||||||
{
|
|
||||||
if (ProductType?.Length == 0)
|
|
||||||
{
|
|
||||||
ProductType = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ProductType != null)
|
|
||||||
{
|
|
||||||
ProductType = ProductType.ToUpper();
|
|
||||||
if (ProductType.StartsWith("RM") && !ProductType.StartsWith("RM-"))
|
|
||||||
{
|
|
||||||
ProductType = "RM-" + ProductType[2..];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DiscoveryQueryParameters DiscoveryQueryParams = new()
|
|
||||||
{
|
|
||||||
manufacturerName = "Microsoft",
|
|
||||||
manufacturerProductLine = "Lumia",
|
|
||||||
packageType = "Test Mode",
|
|
||||||
packageClass = "Public",
|
|
||||||
manufacturerHardwareModel = ProductType
|
|
||||||
};
|
|
||||||
DiscoveryParameters DiscoveryParams = new()
|
|
||||||
{
|
|
||||||
query = DiscoveryQueryParams
|
|
||||||
};
|
|
||||||
|
|
||||||
DataContractJsonSerializer Serializer1 = new(typeof(DiscoveryParameters));
|
|
||||||
MemoryStream JsonStream1 = new();
|
|
||||||
Serializer1.WriteObject(JsonStream1, DiscoveryParams);
|
|
||||||
JsonStream1.Seek(0L, SeekOrigin.Begin);
|
|
||||||
string JsonContent = new StreamReader(JsonStream1).ReadToEnd();
|
|
||||||
|
|
||||||
Uri RequestUri = new("https://api.swrepository.com/rest-api/discovery/1/package");
|
|
||||||
|
|
||||||
HttpClient HttpClient = new();
|
|
||||||
HttpClient.DefaultRequestHeaders.UserAgent.TryParseAdd("SoftwareRepository");
|
|
||||||
HttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
|
||||||
|
|
||||||
Task<HttpResponseMessage> HttpPostTask = HttpClient.PostAsync(RequestUri, new StringContent(JsonContent, Encoding.UTF8, "application/json"));
|
|
||||||
HttpPostTask.Wait();
|
|
||||||
HttpResponseMessage Response = HttpPostTask.Result;
|
|
||||||
|
|
||||||
string JsonResultString = "";
|
|
||||||
if (Response.StatusCode == HttpStatusCode.OK)
|
|
||||||
{
|
|
||||||
Task<string> ReadResponseTask = Response.Content.ReadAsStringAsync();
|
|
||||||
ReadResponseTask.Wait();
|
|
||||||
JsonResultString = ReadResponseTask.Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
SoftwarePackage Package = null;
|
|
||||||
using (MemoryStream JsonStream2 = new(Encoding.UTF8.GetBytes(JsonResultString)))
|
|
||||||
{
|
|
||||||
DataContractJsonSerializer Serializer2 = new(typeof(SoftwarePackages));
|
|
||||||
SoftwarePackages SoftwarePackages = (SoftwarePackages)Serializer2.ReadObject(JsonStream2);
|
|
||||||
if (SoftwarePackages != null)
|
|
||||||
{
|
|
||||||
foreach (SoftwarePackage pkg in SoftwarePackages.softwarePackages)
|
|
||||||
{
|
|
||||||
Package = SoftwarePackages.softwarePackages.FirstOrDefault();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Package == null)
|
|
||||||
{
|
|
||||||
throw new WPinternalsException("ENOSW package not found", "No ENOSW package has been found in the remote software repository for the requested model.");
|
|
||||||
}
|
|
||||||
|
|
||||||
SoftwareFile FileInfo = Package.files.First(f => f.fileName.EndsWith(".secwim", StringComparison.OrdinalIgnoreCase));
|
|
||||||
|
|
||||||
SoftwareFile DPLF = Package.files.First(f => f.fileName.EndsWith(".dpl", StringComparison.OrdinalIgnoreCase));
|
|
||||||
Uri DPLUri = new("https://api.swrepository.com/rest-api/discovery/fileurl/1/" + Package.id + "/" + DPLF.fileName);
|
|
||||||
Task<string> GetDPLTask = HttpClient.GetStringAsync(DPLUri);
|
|
||||||
GetDPLTask.Wait();
|
|
||||||
string DPLString = GetDPLTask.Result;
|
|
||||||
|
|
||||||
string DPLUrl = "";
|
|
||||||
FileUrlResult FileUrlDPL = null;
|
|
||||||
using (MemoryStream JsonStream3 = new(Encoding.UTF8.GetBytes(DPLString)))
|
|
||||||
{
|
|
||||||
DataContractJsonSerializer Serializer3 = new(typeof(FileUrlResult));
|
|
||||||
FileUrlDPL = (FileUrlResult)Serializer3.ReadObject(JsonStream3);
|
|
||||||
if (FileUrlDPL != null)
|
|
||||||
{
|
|
||||||
DPLUrl = FileUrlDPL.url.Replace("sr.azureedge.net", "softwarerepo.blob.core.windows.net");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DPLUrl?.Length == 0)
|
|
||||||
{
|
|
||||||
throw new WPinternalsException("DPL not found", "No DPL has been found in the remote software repository for the requested model.");
|
|
||||||
}
|
|
||||||
|
|
||||||
Task<string> GetDPLStrTask = HttpClient.GetStringAsync(DPLUrl);
|
|
||||||
GetDPLStrTask.Wait();
|
|
||||||
string DPLStrString = GetDPLStrTask.Result;
|
|
||||||
|
|
||||||
DPL.Package dpl;
|
|
||||||
XmlSerializer serializer = new(typeof(DPL.Package));
|
|
||||||
using (StringReader reader = new(DPLStrString.Replace("ft:", "").Replace("dpl:", "").Replace("typedes:", "")))
|
|
||||||
{
|
|
||||||
dpl = (DPL.Package)serializer.Deserialize(reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (DPL.File file in dpl.Content.Files.File)
|
|
||||||
{
|
|
||||||
string name = file.Name;
|
|
||||||
|
|
||||||
DPL.Range range = file.Extensions.MmosWimFile.UseCaseCompatibilities.Compatibility.FirstOrDefault().Range;
|
|
||||||
|
|
||||||
if (IsFirmwareBetween(PhoneFirmwareRevision, range.From, range.To))
|
|
||||||
{
|
|
||||||
FileInfo = Package.files.First(f => f.fileName.EndsWith(name, StringComparison.OrdinalIgnoreCase));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Uri FileInfoUri = new("https://api.swrepository.com/rest-api/discovery/fileurl/1/" + Package.id + "/" + FileInfo.fileName);
|
|
||||||
Task<string> GetFileInfoTask = HttpClient.GetStringAsync(FileInfoUri);
|
|
||||||
GetFileInfoTask.Wait();
|
|
||||||
string FileInfoString = GetFileInfoTask.Result;
|
|
||||||
|
|
||||||
string ENOSWUrl = "";
|
|
||||||
FileUrlResult FileUrl = null;
|
|
||||||
using (MemoryStream JsonStream3 = new(Encoding.UTF8.GetBytes(FileInfoString)))
|
|
||||||
{
|
|
||||||
DataContractJsonSerializer Serializer3 = new(typeof(FileUrlResult));
|
|
||||||
FileUrl = (FileUrlResult)Serializer3.ReadObject(JsonStream3);
|
|
||||||
if (FileUrl != null)
|
|
||||||
{
|
|
||||||
ENOSWUrl = FileUrl.url.Replace("sr.azureedge.net", "softwarerepo.blob.core.windows.net");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpClient.Dispose();
|
|
||||||
|
|
||||||
return ENOSWUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsFirmwareBetween(string PhoneFirmwareRevision, string Limit1, string Limit2)
|
|
||||||
{
|
|
||||||
var version = new Version(PhoneFirmwareRevision);
|
|
||||||
var version1 = new Version(Limit1);
|
|
||||||
var version2 = new Version(Limit2);
|
|
||||||
|
|
||||||
var result = version.CompareTo(version1);
|
|
||||||
var result2 = version.CompareTo(version2);
|
|
||||||
|
|
||||||
return result >= 0 && result2 <= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = new();
|
|
||||||
|
|
||||||
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
|
|
||||||
{
|
|
||||||
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.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma warning disable 0649
|
|
||||||
[DataContract]
|
|
||||||
internal class FileUrlResult
|
|
||||||
{
|
|
||||||
[DataMember]
|
|
||||||
internal string url;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
internal List<string> alternateUrl;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
internal long fileSize;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
internal List<SoftwareFileChecksum> checksum;
|
|
||||||
}
|
|
||||||
#pragma warning restore 0649
|
|
||||||
|
|
||||||
[DataContract]
|
|
||||||
public class DiscoveryQueryParameters
|
|
||||||
{
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
|
||||||
public string customerName;
|
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
|
||||||
public ExtendedAttributes extendedAttributes;
|
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
|
||||||
public string manufacturerHardwareModel;
|
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
|
||||||
public string manufacturerHardwareVariant;
|
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
|
||||||
public string manufacturerModelName;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public string manufacturerName;
|
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
|
||||||
public string manufacturerPackageId;
|
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
|
||||||
public string manufacturerPlatformId;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public string manufacturerProductLine;
|
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
|
||||||
public string manufacturerVariantName;
|
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
|
||||||
public string operatorName;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public string packageClass;
|
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
|
||||||
public string packageRevision;
|
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
|
||||||
public string packageState;
|
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
|
||||||
public string packageSubRevision;
|
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
|
||||||
public string packageSubtitle;
|
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
|
||||||
public string packageTitle;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public string packageType;
|
|
||||||
}
|
|
||||||
|
|
||||||
[DataContract]
|
|
||||||
public class DiscoveryParameters
|
|
||||||
{
|
|
||||||
[DataMember(Name = "api-version")]
|
|
||||||
public string apiVersion;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public DiscoveryQueryParameters query;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public List<string> condition;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public List<string> response;
|
|
||||||
|
|
||||||
public DiscoveryParameters() : this(DiscoveryCondition.Default)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public DiscoveryParameters(DiscoveryCondition Condition)
|
|
||||||
{
|
|
||||||
this.apiVersion = "1";
|
|
||||||
this.query = new DiscoveryQueryParameters();
|
|
||||||
this.condition = new List<string>();
|
|
||||||
if (Condition == DiscoveryCondition.All)
|
|
||||||
{
|
|
||||||
this.condition.Add("all");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (Condition == DiscoveryCondition.Latest)
|
|
||||||
{
|
|
||||||
this.condition.Add("latest");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.condition.Add("default");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum DiscoveryCondition
|
|
||||||
{
|
|
||||||
Default,
|
|
||||||
All,
|
|
||||||
Latest
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class ExtendedAttributes : ISerializable
|
|
||||||
{
|
|
||||||
public Dictionary<string, string> Dictionary;
|
|
||||||
|
|
||||||
public ExtendedAttributes()
|
|
||||||
{
|
|
||||||
this.Dictionary = new Dictionary<string, string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ExtendedAttributes(SerializationInfo info, StreamingContext context)
|
|
||||||
{
|
|
||||||
if (info != null)
|
|
||||||
{
|
|
||||||
this.Dictionary = new Dictionary<string, string>();
|
|
||||||
SerializationInfoEnumerator Enumerator = info.GetEnumerator();
|
|
||||||
while (Enumerator.MoveNext())
|
|
||||||
{
|
|
||||||
this.Dictionary.Add(Enumerator.Current.Name, (string)Enumerator.Current.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
|
|
||||||
{
|
|
||||||
if (info != null)
|
|
||||||
{
|
|
||||||
foreach (string Current in this.Dictionary.Keys)
|
|
||||||
{
|
|
||||||
info.AddValue(Current, this.Dictionary[Current]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[DataContract]
|
|
||||||
public class SoftwareFileChecksum
|
|
||||||
{
|
|
||||||
[DataMember]
|
|
||||||
public string type;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public string value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[DataContract]
|
|
||||||
public class SoftwarePackages
|
|
||||||
{
|
|
||||||
[DataMember]
|
|
||||||
public List<SoftwarePackage> softwarePackages;
|
|
||||||
}
|
|
||||||
|
|
||||||
[DataContract]
|
|
||||||
public class SoftwarePackage
|
|
||||||
{
|
|
||||||
[DataMember]
|
|
||||||
public List<string> customerName;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public ExtendedAttributes extendedAttributes;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public List<SoftwareFile> files;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public string id;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public List<string> manufacturerHardwareModel;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public List<string> manufacturerHardwareVariant;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public List<string> manufacturerModelName;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public string manufacturerName;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public string manufacturerPackageId;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public List<string> manufacturerPlatformId;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public string manufacturerProductLine;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public List<string> manufacturerVariantName;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public List<string> operatorName;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public List<string> packageClass;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public string packageDescription;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public string packageRevision;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public string packageState;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public string packageSubRevision;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public string packageSubtitle;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public string packageTitle;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public string packageType;
|
|
||||||
}
|
|
||||||
|
|
||||||
[DataContract]
|
|
||||||
public class SoftwareFile
|
|
||||||
{
|
|
||||||
[DataMember]
|
|
||||||
public List<SoftwareFileChecksum> checksum;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public string fileName;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public long fileSize;
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public string fileType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class DPL
|
|
||||||
{
|
|
||||||
[XmlRoot(ElementName = "BasicProductCodes")]
|
|
||||||
public class BasicProductCodes
|
|
||||||
{
|
|
||||||
[XmlElement(ElementName = "BasicProductCode")]
|
|
||||||
public List<string> BasicProductCode { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[XmlRoot(ElementName = "Identification")]
|
|
||||||
public class Identification
|
|
||||||
{
|
|
||||||
[XmlElement(ElementName = "TypeDesignator")]
|
|
||||||
public string TypeDesignator { get; set; }
|
|
||||||
[XmlElement(ElementName = "BasicProductCodes")]
|
|
||||||
public BasicProductCodes BasicProductCodes { get; set; }
|
|
||||||
[XmlElement(ElementName = "Purpose")]
|
|
||||||
public string Purpose { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[XmlRoot(ElementName = "Extensions")]
|
|
||||||
public class Extensions
|
|
||||||
{
|
|
||||||
[XmlElement(ElementName = "PackageType")]
|
|
||||||
public string PackageType { get; set; }
|
|
||||||
[XmlElement(ElementName = "Identification")]
|
|
||||||
public Identification Identification { get; set; }
|
|
||||||
[XmlElement(ElementName = "FileType")]
|
|
||||||
public string FileType { get; set; }
|
|
||||||
[XmlElement(ElementName = "MmosWimFile")]
|
|
||||||
public MmosWimFile MmosWimFile { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[XmlRoot(ElementName = "PackageDescription")]
|
|
||||||
public class PackageDescription
|
|
||||||
{
|
|
||||||
[XmlElement(ElementName = "Identifier")]
|
|
||||||
public string Identifier { get; set; }
|
|
||||||
[XmlElement(ElementName = "Revision")]
|
|
||||||
public string Revision { get; set; }
|
|
||||||
[XmlElement(ElementName = "Extensions")]
|
|
||||||
public Extensions Extensions { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[XmlRoot(ElementName = "Digest")]
|
|
||||||
public class Digest
|
|
||||||
{
|
|
||||||
[XmlAttribute(AttributeName = "method")]
|
|
||||||
public string Method { get; set; }
|
|
||||||
[XmlAttribute(AttributeName = "encoding")]
|
|
||||||
public string Encoding { get; set; }
|
|
||||||
[XmlText]
|
|
||||||
public string Text { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[XmlRoot(ElementName = "Digests")]
|
|
||||||
public class Digests
|
|
||||||
{
|
|
||||||
[XmlElement(ElementName = "Digest")]
|
|
||||||
public List<Digest> Digest { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[XmlRoot(ElementName = "Range")]
|
|
||||||
public class Range
|
|
||||||
{
|
|
||||||
[XmlAttribute(AttributeName = "from")]
|
|
||||||
public string From { get; set; }
|
|
||||||
[XmlAttribute(AttributeName = "to")]
|
|
||||||
public string To { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[XmlRoot(ElementName = "Compatibility")]
|
|
||||||
public class Compatibility
|
|
||||||
{
|
|
||||||
[XmlElement(ElementName = "Range")]
|
|
||||||
public Range Range { get; set; }
|
|
||||||
[XmlAttribute(AttributeName = "useCase")]
|
|
||||||
public string UseCase { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[XmlRoot(ElementName = "UseCaseCompatibilities")]
|
|
||||||
public class UseCaseCompatibilities
|
|
||||||
{
|
|
||||||
[XmlElement(ElementName = "Compatibility")]
|
|
||||||
public List<Compatibility> Compatibility { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[XmlRoot(ElementName = "MmosWimFile")]
|
|
||||||
public class MmosWimFile
|
|
||||||
{
|
|
||||||
[XmlElement(ElementName = "UseCaseCompatibilities")]
|
|
||||||
public UseCaseCompatibilities UseCaseCompatibilities { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[XmlRoot(ElementName = "File")]
|
|
||||||
public class File
|
|
||||||
{
|
|
||||||
[XmlElement(ElementName = "Name")]
|
|
||||||
public string Name { get; set; }
|
|
||||||
[XmlElement(ElementName = "Digests")]
|
|
||||||
public Digests Digests { get; set; }
|
|
||||||
[XmlElement(ElementName = "Revision")]
|
|
||||||
public string Revision { get; set; }
|
|
||||||
[XmlElement(ElementName = "Extensions")]
|
|
||||||
public Extensions Extensions { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[XmlRoot(ElementName = "Files")]
|
|
||||||
public class Files
|
|
||||||
{
|
|
||||||
[XmlElement(ElementName = "File")]
|
|
||||||
public List<File> File { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[XmlRoot(ElementName = "Content")]
|
|
||||||
public class Content
|
|
||||||
{
|
|
||||||
[XmlElement(ElementName = "PackageDescription")]
|
|
||||||
public PackageDescription PackageDescription { get; set; }
|
|
||||||
[XmlElement(ElementName = "Files")]
|
|
||||||
public Files Files { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[XmlRoot(ElementName = "CanonicalizationMethod", Namespace = "http://www.w3.org/2000/09/xmldsig#")]
|
|
||||||
public class CanonicalizationMethod
|
|
||||||
{
|
|
||||||
[XmlAttribute(AttributeName = "Algorithm")]
|
|
||||||
public string Algorithm { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[XmlRoot(ElementName = "SignatureMethod", Namespace = "http://www.w3.org/2000/09/xmldsig#")]
|
|
||||||
public class SignatureMethod
|
|
||||||
{
|
|
||||||
[XmlAttribute(AttributeName = "Algorithm")]
|
|
||||||
public string Algorithm { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[XmlRoot(ElementName = "Transform", Namespace = "http://www.w3.org/2000/09/xmldsig#")]
|
|
||||||
public class Transform
|
|
||||||
{
|
|
||||||
[XmlAttribute(AttributeName = "Algorithm")]
|
|
||||||
public string Algorithm { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[XmlRoot(ElementName = "Transforms", Namespace = "http://www.w3.org/2000/09/xmldsig#")]
|
|
||||||
public class Transforms
|
|
||||||
{
|
|
||||||
[XmlElement(ElementName = "Transform", Namespace = "http://www.w3.org/2000/09/xmldsig#")]
|
|
||||||
public Transform Transform { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[XmlRoot(ElementName = "DigestMethod", Namespace = "http://www.w3.org/2000/09/xmldsig#")]
|
|
||||||
public class DigestMethod
|
|
||||||
{
|
|
||||||
[XmlAttribute(AttributeName = "Algorithm")]
|
|
||||||
public string Algorithm { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[XmlRoot(ElementName = "Reference", Namespace = "http://www.w3.org/2000/09/xmldsig#")]
|
|
||||||
public class Reference
|
|
||||||
{
|
|
||||||
[XmlElement(ElementName = "Transforms", Namespace = "http://www.w3.org/2000/09/xmldsig#")]
|
|
||||||
public Transforms Transforms { get; set; }
|
|
||||||
[XmlElement(ElementName = "DigestMethod", Namespace = "http://www.w3.org/2000/09/xmldsig#")]
|
|
||||||
public DigestMethod DigestMethod { get; set; }
|
|
||||||
[XmlElement(ElementName = "DigestValue", Namespace = "http://www.w3.org/2000/09/xmldsig#")]
|
|
||||||
public string DigestValue { get; set; }
|
|
||||||
[XmlAttribute(AttributeName = "URI")]
|
|
||||||
public string URI { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[XmlRoot(ElementName = "SignedInfo", Namespace = "http://www.w3.org/2000/09/xmldsig#")]
|
|
||||||
public class SignedInfo
|
|
||||||
{
|
|
||||||
[XmlElement(ElementName = "CanonicalizationMethod", Namespace = "http://www.w3.org/2000/09/xmldsig#")]
|
|
||||||
public CanonicalizationMethod CanonicalizationMethod { get; set; }
|
|
||||||
[XmlElement(ElementName = "SignatureMethod", Namespace = "http://www.w3.org/2000/09/xmldsig#")]
|
|
||||||
public SignatureMethod SignatureMethod { get; set; }
|
|
||||||
[XmlElement(ElementName = "Reference", Namespace = "http://www.w3.org/2000/09/xmldsig#")]
|
|
||||||
public Reference Reference { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[XmlRoot(ElementName = "KeyInfo", Namespace = "http://www.w3.org/2000/09/xmldsig#")]
|
|
||||||
public class KeyInfo
|
|
||||||
{
|
|
||||||
[XmlElement(ElementName = "KeyName", Namespace = "http://www.w3.org/2000/09/xmldsig#")]
|
|
||||||
public string KeyName { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[XmlRoot(ElementName = "Signature", Namespace = "http://www.w3.org/2000/09/xmldsig#")]
|
|
||||||
public class Signature
|
|
||||||
{
|
|
||||||
[XmlElement(ElementName = "SignedInfo", Namespace = "http://www.w3.org/2000/09/xmldsig#")]
|
|
||||||
public SignedInfo SignedInfo { get; set; }
|
|
||||||
[XmlElement(ElementName = "SignatureValue", Namespace = "http://www.w3.org/2000/09/xmldsig#")]
|
|
||||||
public string SignatureValue { get; set; }
|
|
||||||
[XmlElement(ElementName = "KeyInfo", Namespace = "http://www.w3.org/2000/09/xmldsig#")]
|
|
||||||
public KeyInfo KeyInfo { get; set; }
|
|
||||||
[XmlAttribute(AttributeName = "xmlns")]
|
|
||||||
public string Xmlns { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[XmlRoot(ElementName = "Package")]
|
|
||||||
public class Package
|
|
||||||
{
|
|
||||||
[XmlElement(ElementName = "Content")]
|
|
||||||
public Content Content { get; set; }
|
|
||||||
[XmlElement(ElementName = "Signature", Namespace = "http://www.w3.org/2000/09/xmldsig#")]
|
|
||||||
public Signature Signature { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,334 @@
|
|||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
# *.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUNIT
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# JustCode is a .NET coding add-in
|
||||||
|
.JustCode
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# JetBrains Rider
|
||||||
|
.idea/
|
||||||
|
*.sln.iml
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
||||||
@@ -0,0 +1,301 @@
|
|||||||
|
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Gee.External.Capstone;
|
||||||
|
using Gee.External.Capstone.Arm;
|
||||||
|
//using PeNet;
|
||||||
|
|
||||||
|
namespace Patcher
|
||||||
|
{
|
||||||
|
public static class ArmDisassembler
|
||||||
|
{
|
||||||
|
public static AnalyzedFile Analyze(string FilePath, string AsmPath = null)
|
||||||
|
{
|
||||||
|
PeFile File = new(FilePath);
|
||||||
|
|
||||||
|
SortedList<UInt32, ArmInstruction> AnalyzedCode = new(0x1000000); // Default capacity of 0x100000 was not enough for analyzing ntoskrnl.exe
|
||||||
|
|
||||||
|
if ((AsmPath != null) && System.IO.File.Exists(AsmPath))
|
||||||
|
{
|
||||||
|
using StreamReader Reader = new(AsmPath);
|
||||||
|
while (Reader.Peek() >= 0)
|
||||||
|
{
|
||||||
|
ArmInstruction Instruction = new(Reader.ReadLine());
|
||||||
|
AnalyzedCode.Add(Instruction.Address, Instruction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CapstoneArmDisassembler Disassembler = CapstoneDisassembler.CreateArmDisassembler(ArmDisassembleMode.Thumb);
|
||||||
|
|
||||||
|
// Initially use a Dictionary and sort it afterwards. For analyzing ntoskrnl.exe this is about 60 times faster than using a SortedList from the start.
|
||||||
|
// Default capacity of 0x100000 was not enough for analyzing ntoskrnl.exe
|
||||||
|
Dictionary<UInt32, ArmInstruction> TempCode = new(0x1000000);
|
||||||
|
|
||||||
|
// Analyze from entrypoint
|
||||||
|
Analyze(Disassembler, File.Sections, TempCode, (UInt32)(File.ImageBase + File.EntryPoint));
|
||||||
|
|
||||||
|
// Analyze from exports
|
||||||
|
foreach (FunctionDescriptor Function in File.Exports)
|
||||||
|
Analyze(Disassembler, File.Sections, TempCode, (UInt32)Function.VirtualAddress);
|
||||||
|
|
||||||
|
// Analyze from imports
|
||||||
|
foreach (FunctionDescriptor Function in File.Imports)
|
||||||
|
Analyze(Disassembler, File.Sections, TempCode, (UInt32)Function.VirtualAddress);
|
||||||
|
|
||||||
|
// Analyze from runtime-functions
|
||||||
|
foreach (FunctionDescriptor Function in File.RuntimeFunctions)
|
||||||
|
Analyze(Disassembler, File.Sections, TempCode, (UInt32)Function.VirtualAddress);
|
||||||
|
|
||||||
|
// Sort the instructions.
|
||||||
|
// SortedList is used, because it can be indexed by value (not only by key).
|
||||||
|
List<UInt32> Keys = TempCode.Keys.ToList();
|
||||||
|
Keys.Sort();
|
||||||
|
foreach (UInt32 Key in Keys)
|
||||||
|
AnalyzedCode.Add(Key, TempCode[Key]);
|
||||||
|
|
||||||
|
if (AsmPath != null)
|
||||||
|
{
|
||||||
|
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(AsmPath));
|
||||||
|
|
||||||
|
using StreamWriter Writer = new(AsmPath, false);
|
||||||
|
for (int i = 0; i < AnalyzedCode.Count; i++)
|
||||||
|
{
|
||||||
|
Writer.WriteLine(AnalyzedCode.Values[i].ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AnalyzedFile() { File = File, Code = AnalyzedCode };
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Analyze(CapstoneArmDisassembler Disassembler, List<Section> Sections, Dictionary<UInt32, ArmInstruction> AnalyzedCode, UInt32 VirtualAddress)
|
||||||
|
{
|
||||||
|
VirtualAddress -= (VirtualAddress % 2);
|
||||||
|
List<UInt32> AddressesToAnalyze = new();
|
||||||
|
AddressesToAnalyze.Add(VirtualAddress);
|
||||||
|
Section CurrentSection = null;
|
||||||
|
|
||||||
|
while (AddressesToAnalyze.Count > 0)
|
||||||
|
{
|
||||||
|
UInt32 CurrentAddress = AddressesToAnalyze[0];
|
||||||
|
if ((CurrentSection == null) || (CurrentAddress < CurrentSection.VirtualAddress) || (CurrentAddress > (CurrentSection.VirtualAddress + CurrentSection.VirtualSize)))
|
||||||
|
{
|
||||||
|
CurrentSection = Sections.Find(s => (CurrentAddress >= s.VirtualAddress) && (CurrentAddress < (s.VirtualAddress + s.VirtualSize)) && s.IsCode);
|
||||||
|
if (CurrentSection == null)
|
||||||
|
{
|
||||||
|
// throw new Exception("Address 0x" + CurrentAddress.ToString("X8") + " is not inside boundaries of code-sections");
|
||||||
|
// Probably jumped to this address because data was disassembled as if it were code. Ignore this.
|
||||||
|
// return;
|
||||||
|
AddressesToAnalyze.RemoveAt(0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AnalyzedCode.ContainsKey(CurrentAddress))
|
||||||
|
{
|
||||||
|
// return;
|
||||||
|
AddressesToAnalyze.RemoveAt(0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gee.External.Capstone.Arm.ArmInstruction[] NewInstructions = Disassembler.Disassemble(CurrentSection.Buffer.Skip((int)CurrentAddress - (int)CurrentSection.VirtualAddress).ToArray(), CurrentAddress);
|
||||||
|
if (NewInstructions.Any())
|
||||||
|
{
|
||||||
|
UInt32 StartAddress = (UInt32)NewInstructions.First().Address;
|
||||||
|
UInt32 EndAddress = (UInt32)NewInstructions.Last().Address;
|
||||||
|
|
||||||
|
ArmInstruction PreviousInstruction = null;
|
||||||
|
foreach (Gee.External.Capstone.Arm.ArmInstruction DisassemblerInstruction in NewInstructions)
|
||||||
|
{
|
||||||
|
// ArmInstruction Instruction = new ArmInstruction(DisassemblerInstruction);
|
||||||
|
ArmInstruction Instruction = new()
|
||||||
|
{
|
||||||
|
Address = (UInt32)DisassemblerInstruction.Address,
|
||||||
|
Bytes = DisassemblerInstruction.Bytes,
|
||||||
|
Mnemonic = DisassemblerInstruction.Mnemonic,
|
||||||
|
Operand = DisassemblerInstruction.Operand.Replace("sb", "r9").Replace("sl", "r10").Replace("fp", "r11").Replace("ip", "r12")
|
||||||
|
};
|
||||||
|
|
||||||
|
if (AnalyzedCode.ContainsKey((UInt32)Instruction.Address))
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Merge movw + movt into one command
|
||||||
|
// movw r3, #0x6010 + movt r3, #0x1000 = mov r3, #0x10006010
|
||||||
|
UInt32 HighPart, LowPart;
|
||||||
|
string HighString, LowString;
|
||||||
|
if ((PreviousInstruction?.Mnemonic == "movt") && (Instruction.Mnemonic == "movw") && (PreviousInstruction.Operand.Split(new char[] { ',' })[0] == Instruction.Operand.Split(new char[] { ',' })[0]))
|
||||||
|
{
|
||||||
|
byte[] Combined = new byte[8];
|
||||||
|
System.Buffer.BlockCopy(PreviousInstruction.Bytes, 0, Combined, 0, 4);
|
||||||
|
System.Buffer.BlockCopy(Instruction.Bytes, 0, Combined, 4, 4);
|
||||||
|
PreviousInstruction.Bytes = Combined;
|
||||||
|
PreviousInstruction.Mnemonic = "mov";
|
||||||
|
|
||||||
|
HighString = PreviousInstruction.Operand[(PreviousInstruction.Operand.IndexOf('#') + 1)..];
|
||||||
|
HighPart = (HighString.Length >= 2) && (HighString.Substring(0, 2) == "0x")
|
||||||
|
? UInt32.Parse(HighString[2..], System.Globalization.NumberStyles.HexNumber)
|
||||||
|
: UInt32.Parse(HighString);
|
||||||
|
LowString = Instruction.Operand[(Instruction.Operand.IndexOf('#') + 1)..];
|
||||||
|
LowPart = (LowString.Length >= 2) && (LowString.Substring(0, 2) == "0x")
|
||||||
|
? UInt32.Parse(LowString[2..], System.Globalization.NumberStyles.HexNumber)
|
||||||
|
: UInt32.Parse(LowString);
|
||||||
|
PreviousInstruction.Operand = string.Concat(PreviousInstruction.Operand.AsSpan(0, PreviousInstruction.Operand.IndexOf('#') + 1), "0x", ((HighPart << 16) + LowPart).ToString("X8"));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((PreviousInstruction?.Mnemonic == "movw") && (Instruction.Mnemonic == "movt") && (PreviousInstruction.Operand.Split(new char[] { ',' })[0] == Instruction.Operand.Split(new char[] { ',' })[0]))
|
||||||
|
{
|
||||||
|
byte[] Combined = new byte[8];
|
||||||
|
System.Buffer.BlockCopy(PreviousInstruction.Bytes, 0, Combined, 0, 4);
|
||||||
|
System.Buffer.BlockCopy(Instruction.Bytes, 0, Combined, 4, 4);
|
||||||
|
PreviousInstruction.Bytes = Combined;
|
||||||
|
PreviousInstruction.Mnemonic = "mov";
|
||||||
|
|
||||||
|
HighString = Instruction.Operand[(Instruction.Operand.IndexOf('#') + 1)..];
|
||||||
|
HighPart = (HighString.Length >= 2) && (HighString.Substring(0, 2) == "0x")
|
||||||
|
? UInt32.Parse(HighString[2..], System.Globalization.NumberStyles.HexNumber)
|
||||||
|
: UInt32.Parse(HighString);
|
||||||
|
LowString = PreviousInstruction.Operand[(PreviousInstruction.Operand.IndexOf('#') + 1)..];
|
||||||
|
LowPart = (LowString.Length >= 2) && (LowString.Substring(0, 2) == "0x")
|
||||||
|
? UInt32.Parse(LowString[2..], System.Globalization.NumberStyles.HexNumber)
|
||||||
|
: UInt32.Parse(LowString);
|
||||||
|
PreviousInstruction.Operand = string.Concat(PreviousInstruction.Operand.AsSpan(0, PreviousInstruction.Operand.IndexOf('#') + 1), "0x", ((HighPart << 16) + LowPart).ToString("X8"));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AnalyzedCode.Add((UInt32)Instruction.Address, Instruction);
|
||||||
|
|
||||||
|
int IndexOfIndirectConstant = Instruction.Operand.IndexOf("[pc, #0x");
|
||||||
|
if (IndexOfIndirectConstant >= 0)
|
||||||
|
{
|
||||||
|
int IndexOfEnd = Instruction.Operand.IndexOf("]", IndexOfIndirectConstant);
|
||||||
|
string PCOffsetString = Instruction.Operand.Substring(IndexOfIndirectConstant + 8, IndexOfEnd - IndexOfIndirectConstant - 8);
|
||||||
|
UInt32 PCOffset = UInt32.Parse(PCOffsetString, System.Globalization.NumberStyles.HexNumber);
|
||||||
|
UInt32 PC = (UInt32)Instruction.Address + 4;
|
||||||
|
UInt32 PCforIndirect = PC - (PC % 4);
|
||||||
|
UInt32 VirtualAddressOfIndirectConstant = PCforIndirect + PCOffset;
|
||||||
|
|
||||||
|
// If the address is outside the range of the section, then this is probably data which is compiled as code.
|
||||||
|
// In this case we will ignore this and not do this part of the analysis.
|
||||||
|
if ((VirtualAddressOfIndirectConstant >= CurrentSection.VirtualAddress) && (VirtualAddressOfIndirectConstant < (CurrentSection.VirtualAddress + CurrentSection.VirtualSize)))
|
||||||
|
{
|
||||||
|
UInt32 RawOffsetOfIndirectConstant = VirtualAddressOfIndirectConstant - CurrentSection.VirtualAddress;
|
||||||
|
UInt32 IndirectConstant = BitConverter.ToUInt32(CurrentSection.Buffer, (int)RawOffsetOfIndirectConstant);
|
||||||
|
Instruction.Operand = Instruction.Operand.Substring(0, IndexOfIndirectConstant) + "#0x" + IndirectConstant.ToString("x8") + Instruction.Operand[(IndexOfEnd + 1)..];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (JumpCommands.Contains(Instruction.Mnemonic))
|
||||||
|
{
|
||||||
|
UInt32 NewAddress = UInt32.Parse(Instruction.Operand[(Instruction.Operand.IndexOf("#0x") + 3)..], System.Globalization.NumberStyles.HexNumber);
|
||||||
|
NewAddress -= (NewAddress % 2);
|
||||||
|
if (((NewAddress < StartAddress) || (NewAddress > EndAddress)) && !AddressesToAnalyze.Any(a => a == NewAddress))
|
||||||
|
AddressesToAnalyze.Add(NewAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
PreviousInstruction = Instruction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AddressesToAnalyze.RemoveAt(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string[] JumpCommands = new string[]
|
||||||
|
{
|
||||||
|
"b", "b.w", "bl", "bl.w", "beq", "beq.w", "bne", "bne.w", "bhs", "bhs.w", "blo", "blo.w",
|
||||||
|
"bmi", "bmi.w", "bpl", "bpl.w", "bvs", "bvs.w", "bvc", "bvc.w", "bhi", "bhi.w", "bls", "bls.w",
|
||||||
|
"bge", "bge.w", "blt", "blt.w", "bgt", "bgt.w", "ble", "ble.w", "bal", "bal.w", "cbnz", "cbz"
|
||||||
|
};
|
||||||
|
|
||||||
|
public static string[] ConditionalJumpInstructions = new string[]
|
||||||
|
{
|
||||||
|
"beq", "beq.w", "bne", "bne.w", "bhs", "bhs.w", "blo", "blo.w", "bmi", "bmi.w",
|
||||||
|
"bpl", "bpl.w", "bvs", "bvs.w", "bvc", "bvc.w", "bhi", "bhi.w", "bls", "bls.w",
|
||||||
|
"bge", "bge.w", "blt", "blt.w", "bgt", "bgt.w", "ble", "ble.w", "bal", "bal.w", "cbnz", "cbz"
|
||||||
|
};
|
||||||
|
|
||||||
|
public static string WriteCode(SortedDictionary<UInt32, ArmInstruction> AnalyzedCode)
|
||||||
|
{
|
||||||
|
StringBuilder Code = new(1000);
|
||||||
|
|
||||||
|
foreach (var Instruction in AnalyzedCode)
|
||||||
|
{
|
||||||
|
Code.AppendFormat("{0:X}: \t {1} \t {2}\r\n", Instruction.Value.Address, Instruction.Value.Mnemonic, Instruction.Value.Operand);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Code.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ArmInstruction
|
||||||
|
{
|
||||||
|
public UInt32 Address;
|
||||||
|
public byte[] Bytes;
|
||||||
|
public string Mnemonic;
|
||||||
|
public string Operand;
|
||||||
|
|
||||||
|
public ArmInstruction()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArmInstruction(string Assembly)
|
||||||
|
{
|
||||||
|
Address = UInt32.Parse(Assembly.Substring(0, 8), System.Globalization.NumberStyles.HexNumber);
|
||||||
|
string Hex = Assembly.Substring(12, 24).Trim();
|
||||||
|
Bytes = new byte[(Hex.Length + 1) / 3];
|
||||||
|
for (int i = 0; i < Bytes.Length; i++)
|
||||||
|
Bytes[i] = byte.Parse(Hex.Substring(i * 3, 2), System.Globalization.NumberStyles.HexNumber);
|
||||||
|
Mnemonic = Assembly.Substring(39, 16).Trim();
|
||||||
|
Operand = Assembly[55..];
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
StringBuilder Result = new();
|
||||||
|
|
||||||
|
Result.Append(Address.ToString("X8")); // 0
|
||||||
|
Result.Append(" ");
|
||||||
|
for (int i = 0; i < Bytes.Length; i++) // 12
|
||||||
|
{
|
||||||
|
Result.Append(Bytes[i].ToString("X2"));
|
||||||
|
Result.Append(' ');
|
||||||
|
}
|
||||||
|
Result.Append(new String(' ', (8 - Bytes.Length) * 3));
|
||||||
|
Result.Append(" ");
|
||||||
|
Result.Append(Mnemonic.PadRight(16)); // 39
|
||||||
|
Result.Append(Operand); // 55
|
||||||
|
|
||||||
|
return Result.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AnalyzedFile
|
||||||
|
{
|
||||||
|
public PeFile File;
|
||||||
|
public SortedList<UInt32, ArmInstruction> Code;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<RootNamespace>Patcher</RootNamespace>
|
||||||
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
|
<Platforms>x86</Platforms>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="..\Patcher\ArmCompiler.cs">
|
||||||
|
<Link>ArmCompiler.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Patcher\ByteOperations.cs">
|
||||||
|
<Link>ByteOperations.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Patcher\HelperClasses.cs">
|
||||||
|
<Link>HelperClasses.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Patcher\ObjectFileParser.cs">
|
||||||
|
<Link>ObjectFileParser.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Patcher\PatchEngine.cs">
|
||||||
|
<Link>PatchEngine.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Patcher\PeFile.cs">
|
||||||
|
<Link>PeFile.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<None Include="..\Patcher\LICENSE">
|
||||||
|
<Link>LICENSE</Link>
|
||||||
|
</None>
|
||||||
|
<None Update="BootUnllockAndRootAccessPatchScript.pds">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Gee.External.Capstone" Version="2.0.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup />
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Update="MainForm.cs">
|
||||||
|
<SubType>Form</SubType>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,698 @@
|
|||||||
|
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||||
|
//
|
||||||
|
// Patch Definition Script for Boot Unlock and Root Access on Windows Mobile
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
PatchDefinition Name="RootAccess-MainOS" VersionFrom="EFIESP\Windows\System32\Boot\mobilestartup.efi"
|
||||||
|
|
||||||
|
PatchFile Path="Windows\System32\sspisrv.dll"
|
||||||
|
|
||||||
|
JumpToImport "RpcImpersonateClient"
|
||||||
|
JumpToReference
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
CreateLabel "CheckLowboxAccess" // Optional here
|
||||||
|
PatchCode
|
||||||
|
MOVS R1, #1
|
||||||
|
STR R1, [R0]
|
||||||
|
MOVS R0, #0
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
PatchChecksum
|
||||||
|
|
||||||
|
PatchFile Path="Windows\System32\NtlmShared.dll"
|
||||||
|
|
||||||
|
JumpToExport "MsvpPasswordValidate"
|
||||||
|
PatchCode
|
||||||
|
MOVS R0, #1
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
PatchChecksum
|
||||||
|
|
||||||
|
PatchFile Path="Windows\System32\pacmanserver.dll"
|
||||||
|
|
||||||
|
FindFirstUnicode "GetMaxCountForDeployedApp"
|
||||||
|
JumpToReference
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
PatchCode
|
||||||
|
LDR R1, =0x7FFFFFFF
|
||||||
|
STR R1, [R0]
|
||||||
|
MOVS R0, #0
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
PatchChecksum
|
||||||
|
|
||||||
|
PatchFile Path="Windows\System32\mscoree.dll"
|
||||||
|
|
||||||
|
JumpToImport "GetModuleFileNameW"
|
||||||
|
JumpToReference
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
CreateLabel "CompareWithWhiteList" // Optional here
|
||||||
|
PatchCode
|
||||||
|
MOVS R0, #0
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
PatchChecksum
|
||||||
|
|
||||||
|
PatchFile Path="Windows\System32\DeploymentExt.dll"
|
||||||
|
|
||||||
|
FindFirstUnicode "MaxUnsignedApp"
|
||||||
|
JumpToReference
|
||||||
|
FindValue 0x800413A0
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
MakeJumpUnconditional
|
||||||
|
PatchChecksum
|
||||||
|
|
||||||
|
PatchFile Path="Windows\System32\ntoskrnl.exe"
|
||||||
|
|
||||||
|
// Phase 1: find all kernel-functions
|
||||||
|
|
||||||
|
JumpToExport "SeAccessCheckWithHint"
|
||||||
|
CreateLabel "SeAccessCheckWithHint"
|
||||||
|
|
||||||
|
FindFunctionCall R0 = "ADD R0, SP, #0x7C" R1 = "MOV R1, R?"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "SepFilterToDiscretionary"
|
||||||
|
|
||||||
|
JumpToReference R0 = "ADDS R0, R?, #0xD0"
|
||||||
|
FindPreviousInstruction "PUSH"
|
||||||
|
FindPreviousInstruction "PUSH"
|
||||||
|
CreateLabel "SeAccessCheckByType"
|
||||||
|
|
||||||
|
FindFunctionCall R0 = "ADDS R0, R?, #0xF8" R1 = "MOV R1, R?" R2 = "LDR R2, [R?,#0x28]" R3 = "MOV R3, R?"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "SepConstrainByMandatory"
|
||||||
|
|
||||||
|
JumpBack // to SeAccessCheckByType
|
||||||
|
JumpBack // to SepFilterToDiscretionary
|
||||||
|
|
||||||
|
JumpToReference R1 = "LDR R1, [R?,#8]"
|
||||||
|
FindPreviousInstruction "PUSH"
|
||||||
|
CreateLabel "SepCommonAccessCheckEx"
|
||||||
|
|
||||||
|
FindFunctionCall Result = "STR R0, [SP,#0xD4]"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "SepAccessCheckEx"
|
||||||
|
|
||||||
|
JumpBack // to SepCommonAccessCheckEx
|
||||||
|
JumpBack // to SepFilterToDiscretionary
|
||||||
|
|
||||||
|
JumpToReference R0 = "ADDS R0, R?, #0x130"
|
||||||
|
FindPreviousInstruction "PUSH"
|
||||||
|
FindPreviousInstruction "PUSH"
|
||||||
|
CreateLabel "SepAccessCheckAndAuditAlarm"
|
||||||
|
|
||||||
|
FindFunctionCall R0 = "LDR R0, [R?,#0x130]" R1 = "MOV R1, R?" R2 = "LDR R2, [R?,#0x50]" R3 = "MOV R3, R?"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "SepConstrainByConstraintMask"
|
||||||
|
FindNextConditionalJump
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "SepConstrainByConstraintMask_FunctionChunk01"
|
||||||
|
|
||||||
|
JumpBack // to SepConstrainByConstraintMask
|
||||||
|
JumpBack // to SepAccessCheckAndAuditAlarm
|
||||||
|
JumpBack // to SepFilterToDiscretionary
|
||||||
|
JumpBack // to SeAccessCheckWithHint
|
||||||
|
|
||||||
|
FindFunctionCall R0 = "ADD R0, SP, #0x88" R1 = "MOV R1, R?"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "SepMandatoryToDiscretionary"
|
||||||
|
JumpBack
|
||||||
|
|
||||||
|
FindFunctionCall Result = "STR R0, [SP,#0x70]"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "SepAccessCheck"
|
||||||
|
|
||||||
|
JumpToExport "SePrivilegeCheck"
|
||||||
|
FindFunctionCall
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "SepPrivilegeCheck"
|
||||||
|
|
||||||
|
JumpToExport "SeSinglePrivilegeCheck"
|
||||||
|
CreateLabel "SeSinglePrivilegeCheck"
|
||||||
|
|
||||||
|
JumpToExport "ObReferenceObjectByHandleWithTag"
|
||||||
|
CreateLabel "ObReferenceObjectByHandleWithTag"
|
||||||
|
|
||||||
|
// Phase 2: patches
|
||||||
|
|
||||||
|
JumpToLabel "SeAccessCheckByType"
|
||||||
|
|
||||||
|
// Patch 1:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
MakeJumpUnconditional
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
|
||||||
|
// Patch 2:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindStore
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
MakeJumpUnconditional
|
||||||
|
|
||||||
|
// Patch 3:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
MakeJumpUnconditional // This jump is right above the value 0xC0000022. After patch the pointer is back on that value.
|
||||||
|
// FindNextValue 0xC0000022
|
||||||
|
|
||||||
|
// Patch 4:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
MakeJumpUnconditional // This jump is right above the value 0xC0000022. After patch the pointer is back on that value.
|
||||||
|
// FindNextValue 0xC0000022
|
||||||
|
|
||||||
|
// Patch 5:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindNextInstruction "BNE"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "TargetPatch5"
|
||||||
|
JumpBack
|
||||||
|
FindPreviousInstruction "BEQ"
|
||||||
|
PatchCode
|
||||||
|
B TargetPatch5
|
||||||
|
EndPatch
|
||||||
|
|
||||||
|
// Patch 6:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindNextConditionalJump
|
||||||
|
MakeJumpUnconditional
|
||||||
|
|
||||||
|
// Patch 7:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindStore
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
MakeJumpUnconditional
|
||||||
|
|
||||||
|
// Patch 8:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
JumpToReference
|
||||||
|
ClearInstruction
|
||||||
|
JumpBack
|
||||||
|
|
||||||
|
// Patch 9:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
JumpToReference
|
||||||
|
ClearInstruction
|
||||||
|
JumpBack
|
||||||
|
|
||||||
|
JumpToLabel "SepAccessCheckAndAuditAlarm"
|
||||||
|
|
||||||
|
// Patch 10:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
MakeJumpUnconditional
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
|
||||||
|
// Patch 11:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindStore
|
||||||
|
CreateLabel "Patch11"
|
||||||
|
FindNextConditionalJump
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "TargetPatch11"
|
||||||
|
JumpToLabel "Patch11"
|
||||||
|
PatchCode
|
||||||
|
B TargetPatch11
|
||||||
|
EndPatch
|
||||||
|
|
||||||
|
// Patch 12:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
PatchCode
|
||||||
|
MOV.W R2, #0
|
||||||
|
EndPatch
|
||||||
|
|
||||||
|
JumpToLabel "SepCommonAccessCheckEx"
|
||||||
|
|
||||||
|
// Patch 13:
|
||||||
|
FindNextInstruction "TST"
|
||||||
|
FindNextInstruction "TST"
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
ClearInstruction
|
||||||
|
|
||||||
|
JumpToLabel "SeAccessCheckWithHint"
|
||||||
|
|
||||||
|
// Patch 14:
|
||||||
|
FindNextInstruction "BEQ"
|
||||||
|
MakeJumpUnconditional
|
||||||
|
|
||||||
|
JumpToLabel "SeSinglePrivilegeCheck"
|
||||||
|
|
||||||
|
// Patch 15:
|
||||||
|
PatchCode
|
||||||
|
MOVS R0, #1
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
|
||||||
|
JumpToLabel "ObReferenceObjectByHandleWithTag"
|
||||||
|
|
||||||
|
FindFunctionCall
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "ObpReferenceObjectByHandleWithTag"
|
||||||
|
FindInstructionPattern "LDR R?, [R?,#0x74]; CMP R?, #0; BNE ?" InstructionIndex = 2
|
||||||
|
JumpToTarget
|
||||||
|
|
||||||
|
// Patch 16:
|
||||||
|
FindNextConditionalJump
|
||||||
|
MakeJumpUnconditional // This jump is right above the value 0xC0000022. After patch the pointer is on the error-value.
|
||||||
|
|
||||||
|
// Patch 17:
|
||||||
|
JumpToReference
|
||||||
|
ClearInstruction
|
||||||
|
JumpBack
|
||||||
|
JumpBack
|
||||||
|
|
||||||
|
// Patch 18:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
JumpToReference
|
||||||
|
ClearInstruction
|
||||||
|
|
||||||
|
JumpToLabel "SepPrivilegeCheck"
|
||||||
|
|
||||||
|
// Patch 19:
|
||||||
|
PatchCode
|
||||||
|
MOVS R0, #1
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
|
||||||
|
JumpToLabel "SepMandatoryToDiscretionary"
|
||||||
|
|
||||||
|
// Patch 20:
|
||||||
|
PatchCode
|
||||||
|
MOVS R0, #0
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
|
||||||
|
JumpToLabel "SepAccessCheckEx"
|
||||||
|
|
||||||
|
// Patch 21:
|
||||||
|
FindNextValue 0x2000000
|
||||||
|
CreateLabel "Patch21"
|
||||||
|
FindNextInstruction "B"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "TargetPatch21"
|
||||||
|
JumpToLabel "Patch21"
|
||||||
|
PatchCode
|
||||||
|
B TargetPatch21
|
||||||
|
EndPatch
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
|
||||||
|
// Patch 22:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
MakeJumpUnconditional // This jump is right above the value 0xC0000022. After patch the pointer is back on that value.
|
||||||
|
// FindNextValue 0xC0000022
|
||||||
|
|
||||||
|
// Patch 23:
|
||||||
|
JumpToReference 0
|
||||||
|
ClearInstruction
|
||||||
|
JumpBack
|
||||||
|
|
||||||
|
// Patch 24:
|
||||||
|
JumpToReference 1
|
||||||
|
ClearInstruction
|
||||||
|
JumpBack
|
||||||
|
|
||||||
|
// Patch 25:
|
||||||
|
JumpToReference 2
|
||||||
|
ClearInstruction
|
||||||
|
JumpBack
|
||||||
|
|
||||||
|
// Patch 26:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
MakeJumpUnconditional
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
|
||||||
|
// Patch 27:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
MakeJumpUnconditional
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
|
||||||
|
// Patch 28:
|
||||||
|
JumpToReference
|
||||||
|
ClearInstruction
|
||||||
|
|
||||||
|
JumpToLabel "SepAccessCheck"
|
||||||
|
|
||||||
|
// Patch 29:
|
||||||
|
FindFunctionCall R0 = "LDR R0, [SP,#0x28]"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "SepNormalAccessCheck"
|
||||||
|
JumpBack
|
||||||
|
FindNextInstruction "TST"
|
||||||
|
FindNextConditionalJump
|
||||||
|
ClearInstruction
|
||||||
|
|
||||||
|
// Patch 30:
|
||||||
|
FindFunctionCall R0 = "MOV R0, R?" R1 = "MOV R1, R?" R2 = "MOV R2, R?" R3 = "LDR R3, [SP,#0x38]"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "SepMaximumAccessCheck"
|
||||||
|
JumpBack
|
||||||
|
FindNextConditionalJump
|
||||||
|
ClearInstruction
|
||||||
|
|
||||||
|
// Patch 31:
|
||||||
|
FindNextConditionalJump
|
||||||
|
ClearInstruction
|
||||||
|
|
||||||
|
// Patch 32:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
JumpToReference 1
|
||||||
|
ClearInstruction
|
||||||
|
JumpBack
|
||||||
|
|
||||||
|
// Patch 33:
|
||||||
|
JumpToReference 2
|
||||||
|
ClearInstruction
|
||||||
|
JumpBack
|
||||||
|
|
||||||
|
// Patch 34:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindPreviousInstruction "MOVS"
|
||||||
|
FindPreviousInstruction "MOVS"
|
||||||
|
JumpToReference
|
||||||
|
ClearInstruction
|
||||||
|
JumpBack
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
|
||||||
|
// Patch 35:
|
||||||
|
JumpToReference CodePattern = "BEQ"
|
||||||
|
ClearInstruction
|
||||||
|
JumpBack
|
||||||
|
|
||||||
|
// Patch 36:
|
||||||
|
JumpToReference CodePattern = "MOVS; B"
|
||||||
|
FindPreviousInstruction "B"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "TargetPatch36"
|
||||||
|
JumpBack
|
||||||
|
FindPreviousInstruction "CMP"
|
||||||
|
PatchCode
|
||||||
|
B.W TargetPatch36
|
||||||
|
EndPatch
|
||||||
|
JumpBack
|
||||||
|
|
||||||
|
// Patch 37:
|
||||||
|
JumpToReference CodePattern = "STR; B"
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
MakeJumpUnconditional
|
||||||
|
|
||||||
|
// Patch 38:
|
||||||
|
// Stay in function-chunk. Error-code is between previous two patches.
|
||||||
|
FindPreviousValue 0xC0000022
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
MakeJumpUnconditional
|
||||||
|
|
||||||
|
JumpToLabel "SepConstrainByMandatory"
|
||||||
|
|
||||||
|
// Patch 39:
|
||||||
|
FindNextInstruction "BNE"
|
||||||
|
JumpToTarget
|
||||||
|
FindNextInstruction "CBNZ"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "TargetPatch39"
|
||||||
|
JumpBack
|
||||||
|
FindPreviousInstruction "BEQ"
|
||||||
|
PatchCode
|
||||||
|
B TargetPatch39
|
||||||
|
EndPatch
|
||||||
|
JumpBack
|
||||||
|
|
||||||
|
// Patch 40:
|
||||||
|
FindNextInstruction "B"
|
||||||
|
JumpToTarget
|
||||||
|
FindNextInstruction "CBNZ"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "TargetPatch40"
|
||||||
|
JumpBack
|
||||||
|
FindPreviousInstruction "BEQ"
|
||||||
|
PatchCode
|
||||||
|
B TargetPatch40
|
||||||
|
EndPatch
|
||||||
|
|
||||||
|
JumpToLabel "SepFilterToDiscretionary"
|
||||||
|
|
||||||
|
// Patch 41:
|
||||||
|
PatchCode
|
||||||
|
MOVS R0, #0
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
|
||||||
|
JumpToLabel "SepConstrainByConstraintMask_FunctionChunk01"
|
||||||
|
|
||||||
|
// Patch 42:
|
||||||
|
FindNextInstruction "TST"
|
||||||
|
FindNextInstruction "CBNZ"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "TargetPatch42"
|
||||||
|
JumpBack
|
||||||
|
FindPreviousInstruction "BEQ"
|
||||||
|
PatchCode
|
||||||
|
B TargetPatch42
|
||||||
|
EndPatch
|
||||||
|
|
||||||
|
// Patch 43:
|
||||||
|
FindNextInstruction "TST"
|
||||||
|
FindNextInstruction "CBNZ"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "TargetPatch43"
|
||||||
|
JumpBack
|
||||||
|
FindPreviousInstruction "BEQ"
|
||||||
|
FindPreviousInstruction "BEQ" // This one is actually not necessary. Kept here for consistency.
|
||||||
|
PatchCode
|
||||||
|
B TargetPatch43
|
||||||
|
EndPatch
|
||||||
|
|
||||||
|
PatchChecksum
|
||||||
|
|
||||||
|
PatchDefinition Name="SecureBootHack-MainOS" VersionFrom="EFIESP\Windows\System32\Boot\mobilestartup.efi"
|
||||||
|
|
||||||
|
PatchFile Path="Windows\System32\BOOT\winload.efi"
|
||||||
|
|
||||||
|
FindFirstAscii "1.3.6.1.4.1.311.61.4.1"
|
||||||
|
JumpToReference
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
CreateLabel "ImgpValidateImageHash"
|
||||||
|
PatchCode
|
||||||
|
MOVS R0, #0
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
PatchChecksum
|
||||||
|
|
||||||
|
PatchFile Path="Windows\System32\ci.dll"
|
||||||
|
|
||||||
|
JumpToImport "PsGetProcessSignatureLevel"
|
||||||
|
JumpToReference
|
||||||
|
CreateLabel "PsGetProcessSignatureLevelWrapper"
|
||||||
|
JumpToReference
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
CreateLabel "CipReportAndReprieveUMCIFailure"
|
||||||
|
FindNextInstruction "TST.W"
|
||||||
|
FindNextConditionalJump
|
||||||
|
MakeJumpUnconditional "BNE" // BNE -> B, BEQ -> NOP
|
||||||
|
PatchChecksum
|
||||||
|
|
||||||
|
PatchDefinition Name="SecureBootHack-V1-EFIESP" VersionFrom="EFIESP\Windows\System32\Boot\mobilestartup.efi" RelativePath="EFIESP" RelativeOutputPath="SecureBootHack-V1"
|
||||||
|
|
||||||
|
PatchFile Path="Windows\System32\boot\mobilestartup.efi" // Symbols taken from pdb from version 10.0.10586.107
|
||||||
|
|
||||||
|
FindFirstAscii "1.3.6.1.4.1.311.61.4.1"
|
||||||
|
JumpToReference
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
CreateLabel "ImgpValidateImageHash"
|
||||||
|
PatchCode
|
||||||
|
MOVS R0, #0
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
FindFirstUnicode "BootDebugPolicyApplied"
|
||||||
|
JumpToReference
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
CreateLabel "ApplyBootDebugPolicy"
|
||||||
|
PatchCode // This patch is for the new unlock for Lumia Spec A
|
||||||
|
MOVS R0, #0
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
PatchChecksum
|
||||||
|
|
||||||
|
PatchFile Path="efi\boot\bootarm.efi"
|
||||||
|
|
||||||
|
FindFirstAscii "1.3.6.1.4.1.311.61.4.1"
|
||||||
|
JumpToReference
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
CreateLabel "ImgpValidateImageHash"
|
||||||
|
PatchCode
|
||||||
|
MOVS R0, #0
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
PatchChecksum
|
||||||
|
|
||||||
|
PatchDefinition Name="SecureBootHack-V2-EFIESP" VersionFrom="EFIESP\Windows\System32\Boot\mobilestartup.efi" RelativePath="EFIESP"
|
||||||
|
|
||||||
|
PatchFile Path="Windows\System32\boot\mobilestartup.efi"
|
||||||
|
|
||||||
|
FindFirstAscii "MZ"
|
||||||
|
CreateLabel "ImageBase"
|
||||||
|
FindFirstAscii "1.3.6.1.4.1.311.61.4.1"
|
||||||
|
JumpToReference
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
CreateLabel "ImgpValidateImageHash"
|
||||||
|
PatchCode
|
||||||
|
MOVS R0, #0
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
FindFirstUnicode "BootDebugPolicyApplied"
|
||||||
|
JumpToReference
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
CreateLabel "ApplyBootDebugPolicy"
|
||||||
|
PatchCode
|
||||||
|
MOVS R0, #0
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
CreateLabel "EnterMassStorageModeShellCode" // Use the left-over space of the ApplyBootDebugPolicy-function to insert shell-code later on
|
||||||
|
FindFirstUnicode "MassStorageFlag"
|
||||||
|
CreateLabel "MassStorageName"
|
||||||
|
PatchUnicode "Heathcliff74MSM"
|
||||||
|
FindFirstBytes "41 E5 C1 A0 CE 73 7F 46 88 EC D4 4F 92 34 50 4A"
|
||||||
|
CreateLabel "MassStorageGuid"
|
||||||
|
JumpToLabel "MassStorageName"
|
||||||
|
JumpToReference
|
||||||
|
FindNextInstruction "BL"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "EfiGetVariableVolatile"
|
||||||
|
FindValue 2
|
||||||
|
FindNextConditionalJump
|
||||||
|
MakeJumpUnconditional "BEQ"
|
||||||
|
FindFirstUnicode "\Windows\System32\boot\ui\boot.ums.waiting.bmpx"
|
||||||
|
JumpToReference
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
CreateLabel "EnterMassStorageMode"
|
||||||
|
JumpToReference
|
||||||
|
PatchCode
|
||||||
|
B.W EnterMassStorageModeShellCode
|
||||||
|
EndPatch
|
||||||
|
CreateLabel ReturnFromMassStorageMode
|
||||||
|
FindFirstValue 0x26000145
|
||||||
|
IfNotFoundGo PatchForSetErrorDone
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
CreateLabel "SetError"
|
||||||
|
PatchCode
|
||||||
|
MOVS R0, #1
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
PatchForSetErrorDone:
|
||||||
|
FindFirstUnicode "DeviceIDVersion"
|
||||||
|
JumpToReference
|
||||||
|
FindNextInstruction "BL"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "EfiSetVariable"
|
||||||
|
FindFirstAscii "charge: DisplayPowerState protocol successfully loaded"
|
||||||
|
JumpToReference
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
CreateLabel "InitGraphicsSubsystem"
|
||||||
|
FindNextInstruction "BL"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "BlpArchQueryCurrentContextType"
|
||||||
|
JumpBack
|
||||||
|
FindNextInstruction "BL"
|
||||||
|
FindNextInstruction "BL"
|
||||||
|
FindNextInstruction "BL"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "BlpArchSwitchContext"
|
||||||
|
JumpBack
|
||||||
|
FindNextInstruction "LDR"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "EfiBS"
|
||||||
|
JumpToLabel "EnterMassStorageModeShellCode"
|
||||||
|
PatchCode
|
||||||
|
MOV R0, PC
|
||||||
|
LDR R1, =(ApplyBootDebugPolicy - ImageBase + 8) // Subtract (Offset of shell-code + 4)
|
||||||
|
SUB R0, R0, R1 // R0 = relocated base of mobilestartup.efi
|
||||||
|
PUSH {R4-R6}
|
||||||
|
SUB SP, SP, #4
|
||||||
|
MOV R4, R0 // R4 = relocated base of mobilestartup.efi
|
||||||
|
|
||||||
|
LDR R3, =(MassStorageName - ImageBase) // Offset of NV var name (which is patched to "Heathcliff74MSM")
|
||||||
|
ADD R0, R4, R3
|
||||||
|
LDR R3, =(MassStorageGuid - ImageBase) // Offset of NV var Guid
|
||||||
|
ADD R1, R4, R3
|
||||||
|
MOVS R2, #3 // Non-volatile, boot-services
|
||||||
|
MOVS R3, #0 // Data-size
|
||||||
|
STR R3, [SP] // Pointer to data-buffer = NULL
|
||||||
|
LDR R6, =(EfiSetVariable - ImageBase + 1) // Offset of SetVariable + 1
|
||||||
|
ADD R5, R4, R6
|
||||||
|
BLX R5 // EfiSetVariable -> Delete variable
|
||||||
|
|
||||||
|
LDR R1, =(BlpArchQueryCurrentContextType - ImageBase + 1) // Offset to first thread-function + 1
|
||||||
|
ADD R5, R4, R1
|
||||||
|
BLX R5
|
||||||
|
MOV R6, R0
|
||||||
|
CMP R6, #1
|
||||||
|
BEQ ContextSwitchDone1
|
||||||
|
MOVS R0, #1
|
||||||
|
LDR R1, =(BlpArchSwitchContext - ImageBase + 1) // Offset to second thread-function + 1
|
||||||
|
ADD R5, R4, R1
|
||||||
|
BLX R5
|
||||||
|
ContextSwitchDone1:
|
||||||
|
|
||||||
|
LDR R0, =(EfiBS - ImageBase) // Offset of pointer to BootServices function-table
|
||||||
|
ADD R1, R4, R0 // R1 = pointer to pointer to BootServices function-table
|
||||||
|
LDR R1, [R1] // R1 = pointer to BootServices function-table
|
||||||
|
LDR.W R5, [R1,#0xAC] // LocateProtocol
|
||||||
|
ADR R0, VarServicesGuid // This is relative, no need to relocate
|
||||||
|
MOVS R1, #0
|
||||||
|
MOV R2, SP
|
||||||
|
BLX R5 // LocateProtocol - pVarServices in [SP]
|
||||||
|
LDR R5, [SP] // R5 = Pointer to VariableServices interface
|
||||||
|
LDR R5, [R5,#4] // R5 = pointer to FlushVariableNV()
|
||||||
|
CMP R5, #0
|
||||||
|
BNE PointerFound
|
||||||
|
LDR R5, [SP] // R5 = Pointer to VariableServices interface
|
||||||
|
LDR R5, [R5,#8] // R5 = pointer to FlushVariableNV()
|
||||||
|
PointerFound:
|
||||||
|
BLX R5 // FlushVariableNV()
|
||||||
|
|
||||||
|
CMP R6, #1
|
||||||
|
BEQ ContextSwitchDone2
|
||||||
|
MOV R0, R6
|
||||||
|
LDR R1, =(BlpArchSwitchContext - ImageBase + 1) // Offset to second thread-function + 1
|
||||||
|
ADD R5, R4, R1
|
||||||
|
BLX R5
|
||||||
|
ContextSwitchDone2:
|
||||||
|
|
||||||
|
LDR R6, =(EnterMassStorageMode - ImageBase + 1) // Offset of EnterMassStorageMode + 1
|
||||||
|
ADD R5, R4, R6
|
||||||
|
BLX R5 // EnterMassStorageMode
|
||||||
|
|
||||||
|
LDR R6, =(ReturnFromMassStorageMode - ImageBase + 1) // Offset of return address + 1
|
||||||
|
ADD R0, R4, R6
|
||||||
|
ADD SP, SP, #4
|
||||||
|
POP {R4-R6}
|
||||||
|
BX R0
|
||||||
|
|
||||||
|
VarServicesGuid:
|
||||||
|
DCD 0xf9085b9d
|
||||||
|
DCW 0x9304, 0x40fb
|
||||||
|
DCB 0x8f, 0xe0, 0x4a, 0xee, 0x3b, 0x1a, 0x78, 0x4b
|
||||||
|
EndPatch
|
||||||
|
PatchChecksum
|
||||||
@@ -0,0 +1,423 @@
|
|||||||
|
namespace Patcher
|
||||||
|
{
|
||||||
|
partial class MainForm
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Required designer variable.
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clean up any resources being used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && (components != null))
|
||||||
|
{
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Windows Form Designer generated code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required method for Designer support - do not modify
|
||||||
|
/// the contents of this method with the code editor.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
this.label1 = new System.Windows.Forms.Label();
|
||||||
|
this.txtVisualStudioPath = new System.Windows.Forms.TextBox();
|
||||||
|
this.FolderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog();
|
||||||
|
this.OpenFileDialog = new System.Windows.Forms.OpenFileDialog();
|
||||||
|
this.SaveFileDialog = new System.Windows.Forms.SaveFileDialog();
|
||||||
|
this.cmdVisualStudioPath = new System.Windows.Forms.Button();
|
||||||
|
this.cmdInputFolder = new System.Windows.Forms.Button();
|
||||||
|
this.txtInputFolder = new System.Windows.Forms.TextBox();
|
||||||
|
this.label2 = new System.Windows.Forms.Label();
|
||||||
|
this.cmdOutputFolder = new System.Windows.Forms.Button();
|
||||||
|
this.txtOutputFolder = new System.Windows.Forms.TextBox();
|
||||||
|
this.label3 = new System.Windows.Forms.Label();
|
||||||
|
this.cmdPatchDefinitionsFile = new System.Windows.Forms.Button();
|
||||||
|
this.txtPatchDefinitionsFile = new System.Windows.Forms.TextBox();
|
||||||
|
this.label4 = new System.Windows.Forms.Label();
|
||||||
|
this.txtConsole = new System.Windows.Forms.TextBox();
|
||||||
|
this.label9 = new System.Windows.Forms.Label();
|
||||||
|
this.cmdCompile = new System.Windows.Forms.Button();
|
||||||
|
this.cmdPatch = new System.Windows.Forms.Button();
|
||||||
|
this.cmdScriptFile = new System.Windows.Forms.Button();
|
||||||
|
this.txtScriptFile = new System.Windows.Forms.TextBox();
|
||||||
|
this.label5 = new System.Windows.Forms.Label();
|
||||||
|
this.cmdBackupFolder = new System.Windows.Forms.Button();
|
||||||
|
this.txtBackupFolder = new System.Windows.Forms.TextBox();
|
||||||
|
this.label6 = new System.Windows.Forms.Label();
|
||||||
|
this.label7 = new System.Windows.Forms.Label();
|
||||||
|
this.CapstoneLink = new System.Windows.Forms.LinkLabel();
|
||||||
|
this.label8 = new System.Windows.Forms.Label();
|
||||||
|
this.CapstoneNetLink = new System.Windows.Forms.LinkLabel();
|
||||||
|
this.label10 = new System.Windows.Forms.Label();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// label1
|
||||||
|
//
|
||||||
|
this.label1.AutoSize = true;
|
||||||
|
this.label1.Location = new System.Drawing.Point(15, 13);
|
||||||
|
this.label1.Name = "label1";
|
||||||
|
this.label1.Size = new System.Drawing.Size(191, 13);
|
||||||
|
this.label1.TabIndex = 0;
|
||||||
|
this.label1.Text = "Path to Visual Studio with ARM32 SDK";
|
||||||
|
//
|
||||||
|
// txtVisualStudioPath
|
||||||
|
//
|
||||||
|
this.txtVisualStudioPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtVisualStudioPath.Location = new System.Drawing.Point(18, 29);
|
||||||
|
this.txtVisualStudioPath.Name = "txtVisualStudioPath";
|
||||||
|
this.txtVisualStudioPath.Size = new System.Drawing.Size(665, 20);
|
||||||
|
this.txtVisualStudioPath.TabIndex = 1;
|
||||||
|
//
|
||||||
|
// OpenFileDialog
|
||||||
|
//
|
||||||
|
this.OpenFileDialog.FileName = "openFileDialog1";
|
||||||
|
//
|
||||||
|
// cmdVisualStudioPath
|
||||||
|
//
|
||||||
|
this.cmdVisualStudioPath.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdVisualStudioPath.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.cmdVisualStudioPath.Location = new System.Drawing.Point(689, 28);
|
||||||
|
this.cmdVisualStudioPath.Name = "cmdVisualStudioPath";
|
||||||
|
this.cmdVisualStudioPath.Size = new System.Drawing.Size(35, 22);
|
||||||
|
this.cmdVisualStudioPath.TabIndex = 2;
|
||||||
|
this.cmdVisualStudioPath.Text = "...";
|
||||||
|
this.cmdVisualStudioPath.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdVisualStudioPath.Click += new System.EventHandler(this.cmdVisualStudioPath_Click);
|
||||||
|
//
|
||||||
|
// cmdInputFolder
|
||||||
|
//
|
||||||
|
this.cmdInputFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdInputFolder.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.cmdInputFolder.Location = new System.Drawing.Point(689, 224);
|
||||||
|
this.cmdInputFolder.Name = "cmdInputFolder";
|
||||||
|
this.cmdInputFolder.Size = new System.Drawing.Size(35, 22);
|
||||||
|
this.cmdInputFolder.TabIndex = 8;
|
||||||
|
this.cmdInputFolder.Text = "...";
|
||||||
|
this.cmdInputFolder.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdInputFolder.Click += new System.EventHandler(this.cmdInputFolder_Click);
|
||||||
|
//
|
||||||
|
// txtInputFolder
|
||||||
|
//
|
||||||
|
this.txtInputFolder.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtInputFolder.Location = new System.Drawing.Point(18, 225);
|
||||||
|
this.txtInputFolder.Name = "txtInputFolder";
|
||||||
|
this.txtInputFolder.Size = new System.Drawing.Size(665, 20);
|
||||||
|
this.txtInputFolder.TabIndex = 7;
|
||||||
|
//
|
||||||
|
// label2
|
||||||
|
//
|
||||||
|
this.label2.AutoSize = true;
|
||||||
|
this.label2.Location = new System.Drawing.Point(15, 209);
|
||||||
|
this.label2.Name = "label2";
|
||||||
|
this.label2.Size = new System.Drawing.Size(71, 13);
|
||||||
|
this.label2.TabIndex = 12;
|
||||||
|
this.label2.Text = "Input location";
|
||||||
|
//
|
||||||
|
// cmdOutputFolder
|
||||||
|
//
|
||||||
|
this.cmdOutputFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdOutputFolder.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.cmdOutputFolder.Location = new System.Drawing.Point(689, 322);
|
||||||
|
this.cmdOutputFolder.Name = "cmdOutputFolder";
|
||||||
|
this.cmdOutputFolder.Size = new System.Drawing.Size(35, 22);
|
||||||
|
this.cmdOutputFolder.TabIndex = 12;
|
||||||
|
this.cmdOutputFolder.Text = "...";
|
||||||
|
this.cmdOutputFolder.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdOutputFolder.Click += new System.EventHandler(this.cmdOutputFolder_Click);
|
||||||
|
//
|
||||||
|
// txtOutputFolder
|
||||||
|
//
|
||||||
|
this.txtOutputFolder.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtOutputFolder.Location = new System.Drawing.Point(18, 323);
|
||||||
|
this.txtOutputFolder.Name = "txtOutputFolder";
|
||||||
|
this.txtOutputFolder.Size = new System.Drawing.Size(665, 20);
|
||||||
|
this.txtOutputFolder.TabIndex = 11;
|
||||||
|
//
|
||||||
|
// label3
|
||||||
|
//
|
||||||
|
this.label3.AutoSize = true;
|
||||||
|
this.label3.Location = new System.Drawing.Point(15, 307);
|
||||||
|
this.label3.Name = "label3";
|
||||||
|
this.label3.Size = new System.Drawing.Size(125, 13);
|
||||||
|
this.label3.TabIndex = 15;
|
||||||
|
this.label3.Text = "Output location (optional)";
|
||||||
|
//
|
||||||
|
// cmdPatchDefinitionsFile
|
||||||
|
//
|
||||||
|
this.cmdPatchDefinitionsFile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdPatchDefinitionsFile.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.cmdPatchDefinitionsFile.Location = new System.Drawing.Point(689, 91);
|
||||||
|
this.cmdPatchDefinitionsFile.Name = "cmdPatchDefinitionsFile";
|
||||||
|
this.cmdPatchDefinitionsFile.Size = new System.Drawing.Size(35, 22);
|
||||||
|
this.cmdPatchDefinitionsFile.TabIndex = 4;
|
||||||
|
this.cmdPatchDefinitionsFile.Text = "...";
|
||||||
|
this.cmdPatchDefinitionsFile.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdPatchDefinitionsFile.Click += new System.EventHandler(this.cmdPatchDefinitionsFile_Click);
|
||||||
|
//
|
||||||
|
// txtPatchDefinitionsFile
|
||||||
|
//
|
||||||
|
this.txtPatchDefinitionsFile.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtPatchDefinitionsFile.Location = new System.Drawing.Point(18, 92);
|
||||||
|
this.txtPatchDefinitionsFile.Name = "txtPatchDefinitionsFile";
|
||||||
|
this.txtPatchDefinitionsFile.Size = new System.Drawing.Size(665, 20);
|
||||||
|
this.txtPatchDefinitionsFile.TabIndex = 3;
|
||||||
|
this.txtPatchDefinitionsFile.Leave += new System.EventHandler(this.txtPatchDefinitionsFile_Leave);
|
||||||
|
//
|
||||||
|
// label4
|
||||||
|
//
|
||||||
|
this.label4.AutoSize = true;
|
||||||
|
this.label4.Location = new System.Drawing.Point(15, 76);
|
||||||
|
this.label4.Name = "label4";
|
||||||
|
this.label4.Size = new System.Drawing.Size(117, 13);
|
||||||
|
this.label4.TabIndex = 3;
|
||||||
|
this.label4.Text = "Patch definitions xml-file";
|
||||||
|
//
|
||||||
|
// txtConsole
|
||||||
|
//
|
||||||
|
this.txtConsole.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtConsole.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.txtConsole.Location = new System.Drawing.Point(18, 383);
|
||||||
|
this.txtConsole.Multiline = true;
|
||||||
|
this.txtConsole.Name = "txtConsole";
|
||||||
|
this.txtConsole.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
|
||||||
|
this.txtConsole.Size = new System.Drawing.Size(706, 392);
|
||||||
|
this.txtConsole.TabIndex = 13;
|
||||||
|
//
|
||||||
|
// label9
|
||||||
|
//
|
||||||
|
this.label9.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.label9.AutoSize = true;
|
||||||
|
this.label9.Location = new System.Drawing.Point(15, 367);
|
||||||
|
this.label9.Name = "label9";
|
||||||
|
this.label9.Size = new System.Drawing.Size(78, 13);
|
||||||
|
this.label9.TabIndex = 24;
|
||||||
|
this.label9.Text = "Console output";
|
||||||
|
//
|
||||||
|
// cmdCompile
|
||||||
|
//
|
||||||
|
this.cmdCompile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdCompile.Location = new System.Drawing.Point(470, 792);
|
||||||
|
this.cmdCompile.Name = "cmdCompile";
|
||||||
|
this.cmdCompile.Size = new System.Drawing.Size(120, 33);
|
||||||
|
this.cmdCompile.TabIndex = 14;
|
||||||
|
this.cmdCompile.Text = "Compile";
|
||||||
|
this.cmdCompile.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdCompile.Click += new System.EventHandler(this.cmdCompile_Click);
|
||||||
|
//
|
||||||
|
// cmdPatch
|
||||||
|
//
|
||||||
|
this.cmdPatch.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdPatch.Location = new System.Drawing.Point(604, 792);
|
||||||
|
this.cmdPatch.Name = "cmdPatch";
|
||||||
|
this.cmdPatch.Size = new System.Drawing.Size(120, 33);
|
||||||
|
this.cmdPatch.TabIndex = 15;
|
||||||
|
this.cmdPatch.Text = "Patch";
|
||||||
|
this.cmdPatch.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdPatch.Click += new System.EventHandler(this.cmdPatch_Click);
|
||||||
|
//
|
||||||
|
// cmdScriptFile
|
||||||
|
//
|
||||||
|
this.cmdScriptFile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdScriptFile.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.cmdScriptFile.Location = new System.Drawing.Point(689, 155);
|
||||||
|
this.cmdScriptFile.Name = "cmdScriptFile";
|
||||||
|
this.cmdScriptFile.Size = new System.Drawing.Size(35, 22);
|
||||||
|
this.cmdScriptFile.TabIndex = 6;
|
||||||
|
this.cmdScriptFile.Text = "...";
|
||||||
|
this.cmdScriptFile.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdScriptFile.Click += new System.EventHandler(this.cmdScriptFile_Click);
|
||||||
|
//
|
||||||
|
// txtScriptFile
|
||||||
|
//
|
||||||
|
this.txtScriptFile.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtScriptFile.Location = new System.Drawing.Point(18, 156);
|
||||||
|
this.txtScriptFile.Name = "txtScriptFile";
|
||||||
|
this.txtScriptFile.Size = new System.Drawing.Size(665, 20);
|
||||||
|
this.txtScriptFile.TabIndex = 5;
|
||||||
|
//
|
||||||
|
// label5
|
||||||
|
//
|
||||||
|
this.label5.AutoSize = true;
|
||||||
|
this.label5.Location = new System.Drawing.Point(15, 140);
|
||||||
|
this.label5.Name = "label5";
|
||||||
|
this.label5.Size = new System.Drawing.Size(50, 13);
|
||||||
|
this.label5.TabIndex = 28;
|
||||||
|
this.label5.Text = "Script-file";
|
||||||
|
//
|
||||||
|
// cmdBackupFolder
|
||||||
|
//
|
||||||
|
this.cmdBackupFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdBackupFolder.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.cmdBackupFolder.Location = new System.Drawing.Point(689, 273);
|
||||||
|
this.cmdBackupFolder.Name = "cmdBackupFolder";
|
||||||
|
this.cmdBackupFolder.Size = new System.Drawing.Size(35, 22);
|
||||||
|
this.cmdBackupFolder.TabIndex = 10;
|
||||||
|
this.cmdBackupFolder.Text = "...";
|
||||||
|
this.cmdBackupFolder.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdBackupFolder.Click += new System.EventHandler(this.cmdBackupFolder_Click);
|
||||||
|
//
|
||||||
|
// txtBackupFolder
|
||||||
|
//
|
||||||
|
this.txtBackupFolder.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtBackupFolder.Location = new System.Drawing.Point(18, 274);
|
||||||
|
this.txtBackupFolder.Name = "txtBackupFolder";
|
||||||
|
this.txtBackupFolder.Size = new System.Drawing.Size(665, 20);
|
||||||
|
this.txtBackupFolder.TabIndex = 9;
|
||||||
|
//
|
||||||
|
// label6
|
||||||
|
//
|
||||||
|
this.label6.AutoSize = true;
|
||||||
|
this.label6.Location = new System.Drawing.Point(15, 258);
|
||||||
|
this.label6.Name = "label6";
|
||||||
|
this.label6.Size = new System.Drawing.Size(130, 13);
|
||||||
|
this.label6.TabIndex = 31;
|
||||||
|
this.label6.Text = "Backup location (optional)";
|
||||||
|
//
|
||||||
|
// label7
|
||||||
|
//
|
||||||
|
this.label7.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
|
this.label7.AutoSize = true;
|
||||||
|
this.label7.Location = new System.Drawing.Point(20, 807);
|
||||||
|
this.label7.Name = "label7";
|
||||||
|
this.label7.Size = new System.Drawing.Size(66, 13);
|
||||||
|
this.label7.TabIndex = 32;
|
||||||
|
this.label7.Text = "Powered by ";
|
||||||
|
//
|
||||||
|
// CapstoneLink
|
||||||
|
//
|
||||||
|
this.CapstoneLink.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
|
this.CapstoneLink.AutoSize = true;
|
||||||
|
this.CapstoneLink.Location = new System.Drawing.Point(80, 807);
|
||||||
|
this.CapstoneLink.Name = "CapstoneLink";
|
||||||
|
this.CapstoneLink.Size = new System.Drawing.Size(52, 13);
|
||||||
|
this.CapstoneLink.TabIndex = 33;
|
||||||
|
this.CapstoneLink.TabStop = true;
|
||||||
|
this.CapstoneLink.Text = "Capstone";
|
||||||
|
this.CapstoneLink.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.CapstoneLink_LinkClicked);
|
||||||
|
//
|
||||||
|
// label8
|
||||||
|
//
|
||||||
|
this.label8.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
|
this.label8.AutoSize = true;
|
||||||
|
this.label8.Location = new System.Drawing.Point(129, 807);
|
||||||
|
this.label8.Name = "label8";
|
||||||
|
this.label8.Size = new System.Drawing.Size(28, 13);
|
||||||
|
this.label8.TabIndex = 34;
|
||||||
|
this.label8.Text = "and ";
|
||||||
|
//
|
||||||
|
// CapstoneNetLink
|
||||||
|
//
|
||||||
|
this.CapstoneNetLink.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
|
this.CapstoneNetLink.AutoSize = true;
|
||||||
|
this.CapstoneNetLink.Location = new System.Drawing.Point(151, 807);
|
||||||
|
this.CapstoneNetLink.Name = "CapstoneNetLink";
|
||||||
|
this.CapstoneNetLink.Size = new System.Drawing.Size(77, 13);
|
||||||
|
this.CapstoneNetLink.TabIndex = 35;
|
||||||
|
this.CapstoneNetLink.TabStop = true;
|
||||||
|
this.CapstoneNetLink.Text = "Capstone.NET";
|
||||||
|
this.CapstoneNetLink.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.CapstoneNetLink_LinkClicked);
|
||||||
|
//
|
||||||
|
// label10
|
||||||
|
//
|
||||||
|
this.label10.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
|
this.label10.AutoSize = true;
|
||||||
|
this.label10.Location = new System.Drawing.Point(225, 807);
|
||||||
|
this.label10.Name = "label10";
|
||||||
|
this.label10.Size = new System.Drawing.Size(42, 13);
|
||||||
|
this.label10.TabIndex = 36;
|
||||||
|
this.label10.Text = "libraries";
|
||||||
|
//
|
||||||
|
// MainForm
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.ClientSize = new System.Drawing.Size(742, 840);
|
||||||
|
this.Controls.Add(this.label10);
|
||||||
|
this.Controls.Add(this.CapstoneNetLink);
|
||||||
|
this.Controls.Add(this.label8);
|
||||||
|
this.Controls.Add(this.CapstoneLink);
|
||||||
|
this.Controls.Add(this.label7);
|
||||||
|
this.Controls.Add(this.cmdBackupFolder);
|
||||||
|
this.Controls.Add(this.txtBackupFolder);
|
||||||
|
this.Controls.Add(this.label6);
|
||||||
|
this.Controls.Add(this.cmdScriptFile);
|
||||||
|
this.Controls.Add(this.txtScriptFile);
|
||||||
|
this.Controls.Add(this.label5);
|
||||||
|
this.Controls.Add(this.cmdPatch);
|
||||||
|
this.Controls.Add(this.cmdCompile);
|
||||||
|
this.Controls.Add(this.txtConsole);
|
||||||
|
this.Controls.Add(this.label9);
|
||||||
|
this.Controls.Add(this.cmdPatchDefinitionsFile);
|
||||||
|
this.Controls.Add(this.txtPatchDefinitionsFile);
|
||||||
|
this.Controls.Add(this.label4);
|
||||||
|
this.Controls.Add(this.cmdOutputFolder);
|
||||||
|
this.Controls.Add(this.txtOutputFolder);
|
||||||
|
this.Controls.Add(this.label3);
|
||||||
|
this.Controls.Add(this.cmdInputFolder);
|
||||||
|
this.Controls.Add(this.txtInputFolder);
|
||||||
|
this.Controls.Add(this.label2);
|
||||||
|
this.Controls.Add(this.cmdVisualStudioPath);
|
||||||
|
this.Controls.Add(this.txtVisualStudioPath);
|
||||||
|
this.Controls.Add(this.label1);
|
||||||
|
this.Name = "MainForm";
|
||||||
|
this.Text = "ARM Auto-patcher by Rene Lergner";
|
||||||
|
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.MainForm_FormClosed);
|
||||||
|
this.Load += new System.EventHandler(this.MainForm_Load);
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private System.Windows.Forms.Label label1;
|
||||||
|
private System.Windows.Forms.TextBox txtVisualStudioPath;
|
||||||
|
private System.Windows.Forms.FolderBrowserDialog FolderBrowserDialog;
|
||||||
|
private System.Windows.Forms.OpenFileDialog OpenFileDialog;
|
||||||
|
private System.Windows.Forms.SaveFileDialog SaveFileDialog;
|
||||||
|
private System.Windows.Forms.Button cmdVisualStudioPath;
|
||||||
|
private System.Windows.Forms.Button cmdInputFolder;
|
||||||
|
private System.Windows.Forms.TextBox txtInputFolder;
|
||||||
|
private System.Windows.Forms.Label label2;
|
||||||
|
private System.Windows.Forms.Button cmdOutputFolder;
|
||||||
|
private System.Windows.Forms.TextBox txtOutputFolder;
|
||||||
|
private System.Windows.Forms.Label label3;
|
||||||
|
private System.Windows.Forms.Button cmdPatchDefinitionsFile;
|
||||||
|
private System.Windows.Forms.TextBox txtPatchDefinitionsFile;
|
||||||
|
private System.Windows.Forms.Label label4;
|
||||||
|
private System.Windows.Forms.TextBox txtConsole;
|
||||||
|
private System.Windows.Forms.Label label9;
|
||||||
|
private System.Windows.Forms.Button cmdCompile;
|
||||||
|
private System.Windows.Forms.Button cmdPatch;
|
||||||
|
private System.Windows.Forms.Button cmdScriptFile;
|
||||||
|
private System.Windows.Forms.TextBox txtScriptFile;
|
||||||
|
private System.Windows.Forms.Label label5;
|
||||||
|
private System.Windows.Forms.Button cmdBackupFolder;
|
||||||
|
private System.Windows.Forms.TextBox txtBackupFolder;
|
||||||
|
private System.Windows.Forms.Label label6;
|
||||||
|
private System.Windows.Forms.Label label7;
|
||||||
|
private System.Windows.Forms.LinkLabel CapstoneLink;
|
||||||
|
private System.Windows.Forms.Label label8;
|
||||||
|
private System.Windows.Forms.LinkLabel CapstoneNetLink;
|
||||||
|
private System.Windows.Forms.Label label10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,371 @@
|
|||||||
|
// 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 Microsoft.Win32;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using WPinternals;
|
||||||
|
|
||||||
|
namespace Patcher
|
||||||
|
{
|
||||||
|
public partial class MainForm : Form
|
||||||
|
{
|
||||||
|
private PatchEngine PatchEngine = null;
|
||||||
|
|
||||||
|
public MainForm()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MainForm_Load(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
LoadPaths();
|
||||||
|
CenterToScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadPaths()
|
||||||
|
{
|
||||||
|
RegistryKey Key = Registry.CurrentUser.OpenSubKey(@"Software\Patcher", true) ?? Registry.CurrentUser.CreateSubKey(@"Software\Patcher");
|
||||||
|
|
||||||
|
txtVisualStudioPath.Text = (string)Key.GetValue("VisualStudioPath", "");
|
||||||
|
if (txtVisualStudioPath.Text.Length == 0)
|
||||||
|
txtVisualStudioPath.Text = FindVisualStudioPath();
|
||||||
|
|
||||||
|
txtPatchDefinitionsFile.Text = (string)Key.GetValue("PatchDefinitionsFilePath", "");
|
||||||
|
txtScriptFile.Text = (string)Key.GetValue("ScriptFilePath", "");
|
||||||
|
txtInputFolder.Text = (string)Key.GetValue("InputFolderPath", "");
|
||||||
|
txtOutputFolder.Text = (string)Key.GetValue("OutputFolderPath", "");
|
||||||
|
txtBackupFolder.Text = (string)Key.GetValue("BackupFolderPath", "");
|
||||||
|
|
||||||
|
LoadPatchDefinitions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string[] FindMSVCBinaryPaths(string s)
|
||||||
|
{
|
||||||
|
string LegacyPath = Path.Combine(s, @"VC\bin");
|
||||||
|
if (Directory.Exists(LegacyPath))
|
||||||
|
{
|
||||||
|
return new string[] { LegacyPath };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Directory.Exists(Path.Combine(s, @"VC\Tools\MSVC")))
|
||||||
|
{
|
||||||
|
IEnumerable<string> MSVCs = Directory.EnumerateDirectories(Path.Combine(s, @"VC\Tools\MSVC"));
|
||||||
|
IEnumerable<string> Bins = MSVCs.Select(s => Path.Combine(s, "bin")).Where(s => Directory.Exists(s));
|
||||||
|
return Bins.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.Empty<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string FindArmAsmPath(string s)
|
||||||
|
{
|
||||||
|
foreach (string MSVCBin in FindMSVCBinaryPaths(s))
|
||||||
|
{
|
||||||
|
string path1 = Path.Combine(MSVCBin, "x86_arm");
|
||||||
|
string path2 = Path.Combine(MSVCBin, @"Hostx86\arm");
|
||||||
|
|
||||||
|
if (File.Exists(Path.Combine(path1, "armasm.exe")))
|
||||||
|
{
|
||||||
|
return path1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (File.Exists(Path.Combine(path2, "armasm.exe")))
|
||||||
|
{
|
||||||
|
return path2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FindVisualStudioPath()
|
||||||
|
{
|
||||||
|
IEnumerable<string> MainX86VSDirectories = Directory.EnumerateDirectories(@"C:\Program Files (x86)\", "Microsoft Visual Studio*");
|
||||||
|
IEnumerable<string> MainX64VSDirectories = Directory.EnumerateDirectories(@"C:\Program Files\", "Microsoft Visual Studio*");
|
||||||
|
|
||||||
|
IEnumerable<string> MainVSDirectories = MainX86VSDirectories.Union(MainX64VSDirectories);
|
||||||
|
|
||||||
|
IEnumerable<string> SubMainVSDirectories = MainVSDirectories.SelectMany(s => Directory.EnumerateDirectories(s));
|
||||||
|
IEnumerable<string> SubSubMainVSDirectories = SubMainVSDirectories.SelectMany(s => Directory.EnumerateDirectories(s));
|
||||||
|
IEnumerable<string> Directories = MainVSDirectories.Union(SubMainVSDirectories).Union(SubSubMainVSDirectories);
|
||||||
|
|
||||||
|
string attempt1 = Directories.Where(s => FindArmAsmPath(s) != "").OrderByDescending(s => File.GetCreationTime(Path.Combine(s, @"VC\bin\x86_arm\armasm.exe"))).FirstOrDefault() ?? "";
|
||||||
|
|
||||||
|
if (attempt1 != "")
|
||||||
|
return attempt1;
|
||||||
|
|
||||||
|
return Directories.Where(s => Directory.Exists(Path.Combine(s, @"VC\Tools\MSVC"))).Select(s => Path.Combine(s, @"VC\Tools\MSVC")).SelectMany(s => Directory.EnumerateDirectories(s)).Where(s => File.Exists(Path.Combine(s, @"bin\Hostx86\arm\armasm.exe"))).OrderByDescending(s => File.GetCreationTime(Path.Combine(s, @"bin\Hostx86\arm\armasm.exe"))).FirstOrDefault() ?? "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StorePaths()
|
||||||
|
{
|
||||||
|
RegistryKey Key = Registry.CurrentUser.OpenSubKey(@"Software\Patcher", true) ?? Registry.CurrentUser.CreateSubKey(@"Software\Patcher");
|
||||||
|
|
||||||
|
string VisualStudioPath = txtVisualStudioPath.Text.Trim();
|
||||||
|
if (VisualStudioPath.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("VisualStudioPath") != null)
|
||||||
|
Key.DeleteValue("VisualStudioPath");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("VisualStudioPath", VisualStudioPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
string PatchDefinitionsFilePath = txtPatchDefinitionsFile.Text.Trim();
|
||||||
|
if (PatchDefinitionsFilePath.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("PatchDefinitionsFilePath") != null)
|
||||||
|
Key.DeleteValue("PatchDefinitionsFilePath");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("PatchDefinitionsFilePath", PatchDefinitionsFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
string ScriptFilePath = txtScriptFile.Text.Trim();
|
||||||
|
if (ScriptFilePath.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("ScriptFilePath") != null)
|
||||||
|
Key.DeleteValue("ScriptFilePath");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("ScriptFilePath", ScriptFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
string InputFolderPath = txtInputFolder.Text.Trim();
|
||||||
|
if (InputFolderPath.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("InputFolderPath") != null)
|
||||||
|
Key.DeleteValue("InputFolderPath");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("InputFolderPath", InputFolderPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
string OutputFolderPath = txtOutputFolder.Text.Trim();
|
||||||
|
if (OutputFolderPath.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("OutputFolderPath") != null)
|
||||||
|
Key.DeleteValue("OutputFolderPath");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("OutputFolderPath", OutputFolderPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
string BackupFolderPath = txtBackupFolder.Text.Trim();
|
||||||
|
if (BackupFolderPath.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("BackupFolderPath") != null)
|
||||||
|
Key.DeleteValue("BackupFolderPath");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("BackupFolderPath", BackupFolderPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool LoadingPatchDefinitions = false;
|
||||||
|
|
||||||
|
private void LoadPatchDefinitions()
|
||||||
|
{
|
||||||
|
if (LoadingPatchDefinitions)
|
||||||
|
return;
|
||||||
|
LoadingPatchDefinitions = true;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string Definitions = File.ReadAllText(txtPatchDefinitionsFile.Text);
|
||||||
|
PatchEngine = new PatchEngine(Definitions);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
PatchEngine = new PatchEngine();
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadingPatchDefinitions = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdVisualStudioPath_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
FolderBrowserDialog.SelectedPath = txtVisualStudioPath.Text;
|
||||||
|
FolderBrowserDialog.Description = "Select path to Visual Studio with ARM32 SDK";
|
||||||
|
System.Windows.Forms.DialogResult Result = FolderBrowserDialog.ShowDialog();
|
||||||
|
if (Result == System.Windows.Forms.DialogResult.OK)
|
||||||
|
txtVisualStudioPath.Text = FolderBrowserDialog.SelectedPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdPatchDefinitionsFile_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
OpenFileDialog.CheckFileExists = false;
|
||||||
|
OpenFileDialog.DefaultExt = "xml";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
OpenFileDialog.FileName = Path.GetFileName(txtPatchDefinitionsFile.Text);
|
||||||
|
OpenFileDialog.InitialDirectory = Path.GetDirectoryName(txtPatchDefinitionsFile.Text);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
OpenFileDialog.Multiselect = false;
|
||||||
|
OpenFileDialog.Title = "Open patch-definitions file";
|
||||||
|
System.Windows.Forms.DialogResult Result = OpenFileDialog.ShowDialog();
|
||||||
|
if (Result == System.Windows.Forms.DialogResult.OK)
|
||||||
|
{
|
||||||
|
txtPatchDefinitionsFile.Text = OpenFileDialog.FileName;
|
||||||
|
WindowsFormsSynchronizationContext.Current.Post(s => LoadPatchDefinitions(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void txtPatchDefinitionsFile_Leave(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
WindowsFormsSynchronizationContext.Current.Post(s => LoadPatchDefinitions(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
|
||||||
|
{
|
||||||
|
StorePaths();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdInputFolder_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
FolderSelectDialog Dialog = new();
|
||||||
|
Dialog.Title = "Select input location";
|
||||||
|
Dialog.InitialDirectory = txtInputFolder.Text;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Dialog.InitialDirectory = txtInputFolder.Text;
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
bool Result = Dialog.ShowDialog();
|
||||||
|
if (Result)
|
||||||
|
{
|
||||||
|
txtInputFolder.Text = Dialog.FileName;
|
||||||
|
txtOutputFolder.Text = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdOutputFolder_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
FolderSelectDialog Dialog = new();
|
||||||
|
Dialog.Title = "Select output location";
|
||||||
|
Dialog.InitialDirectory = txtOutputFolder.Text;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Dialog.InitialDirectory = txtOutputFolder.Text;
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
bool Result = Dialog.ShowDialog();
|
||||||
|
if (Result)
|
||||||
|
{
|
||||||
|
txtOutputFolder.Text = Dialog.FileName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdScriptFile_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
OpenFileDialog.CheckFileExists = true;
|
||||||
|
OpenFileDialog.DefaultExt = "pds";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
OpenFileDialog.FileName = Path.GetFileName(txtScriptFile.Text);
|
||||||
|
OpenFileDialog.InitialDirectory = Path.GetDirectoryName(txtScriptFile.Text);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
OpenFileDialog.Multiselect = false;
|
||||||
|
OpenFileDialog.Title = "Open patch-definition-script-file";
|
||||||
|
System.Windows.Forms.DialogResult Result = OpenFileDialog.ShowDialog();
|
||||||
|
if (Result == System.Windows.Forms.DialogResult.OK)
|
||||||
|
{
|
||||||
|
txtScriptFile.Text = OpenFileDialog.FileName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdCompile_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
ClearLog();
|
||||||
|
StorePaths();
|
||||||
|
ScriptEngine.ExecuteScript(txtVisualStudioPath.Text.Trim(), txtScriptFile.Text.Trim(), txtInputFolder.Text.Trim(), PatchEngine: PatchEngine, WriteLog: WriteLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdPatch_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
ClearLog();
|
||||||
|
StorePaths();
|
||||||
|
ScriptEngine.ExecuteScript(txtVisualStudioPath.Text.Trim(), txtScriptFile.Text.Trim(), txtInputFolder.Text.Trim(), PatchEngine, txtOutputFolder.Text.Trim(), txtBackupFolder.Text.Trim().Length == 0 ? null : txtBackupFolder.Text.Trim(), WriteLog);
|
||||||
|
|
||||||
|
PatchEngine.WriteDefinitions(txtPatchDefinitionsFile.Text);
|
||||||
|
WriteLog("Patch-definitions written to: " + txtPatchDefinitionsFile.Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClearLog()
|
||||||
|
{
|
||||||
|
txtConsole.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteLog(string Line)
|
||||||
|
{
|
||||||
|
if (txtConsole.InvokeRequired)
|
||||||
|
{
|
||||||
|
txtConsole.Invoke((MethodInvoker)delegate { WriteLog(Line); });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
txtConsole.AppendText(Line + Environment.NewLine);
|
||||||
|
txtConsole.Select(txtConsole.Text.Length, 0);
|
||||||
|
txtConsole.ScrollToCaret();
|
||||||
|
System.Diagnostics.Debug.WriteLine(Line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdBackupFolder_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
FolderSelectDialog Dialog = new();
|
||||||
|
Dialog.Title = "Select backup location";
|
||||||
|
Dialog.InitialDirectory = txtBackupFolder.Text;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Dialog.InitialDirectory = txtBackupFolder.Text;
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
bool Result = Dialog.ShowDialog();
|
||||||
|
if (Result)
|
||||||
|
{
|
||||||
|
txtBackupFolder.Text = Dialog.FileName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CapstoneLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Process.Start("https://github.com/aquynh/capstone/blob/master/LICENSE.TXT");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CapstoneNetLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Process.Start("https://github.com/9ee1/Capstone.NET/blob/master/LICENSE");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<metadata name="FolderBrowserDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
<value>17, 17</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="OpenFileDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
<value>182, 17</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="SaveFileDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
<value>317, 17</value>
|
||||||
|
</metadata>
|
||||||
|
</root>
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
// 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.Windows.Forms;
|
||||||
|
|
||||||
|
namespace Patcher
|
||||||
|
{
|
||||||
|
internal static class Program
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The main entry point for the application.
|
||||||
|
/// </summary>
|
||||||
|
[STAThread]
|
||||||
|
private static void Main()
|
||||||
|
{
|
||||||
|
Application.EnableVisualStyles();
|
||||||
|
Application.SetCompatibleTextRenderingDefault(false);
|
||||||
|
Application.Run(new MainForm());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
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("ARM Auto-patcher")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("WPinternals.net")]
|
||||||
|
[assembly: AssemblyProduct("ARM Auto-patcher")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2018 by Rene Lergner")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("95cf9509-c1c4-40f5-a60e-9d93ea6f438c")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace Patcher.Properties {
|
||||||
|
using System;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||||
|
/// </summary>
|
||||||
|
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||||
|
// class via a tool like ResGen or Visual Studio.
|
||||||
|
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
|
// with the /str option, or rebuild your VS project.
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
internal class Resources {
|
||||||
|
|
||||||
|
private static global::System.Resources.ResourceManager resourceMan;
|
||||||
|
|
||||||
|
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||||
|
|
||||||
|
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
internal Resources() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the cached ResourceManager instance used by this class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||||
|
get {
|
||||||
|
if (object.ReferenceEquals(resourceMan, null)) {
|
||||||
|
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Patcher.Properties.Resources", typeof(Resources).Assembly);
|
||||||
|
resourceMan = temp;
|
||||||
|
}
|
||||||
|
return resourceMan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overrides the current thread's CurrentUICulture property for all
|
||||||
|
/// resource lookups using this strongly typed resource class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Globalization.CultureInfo Culture {
|
||||||
|
get {
|
||||||
|
return resourceCulture;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
resourceCulture = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace Patcher.Properties {
|
||||||
|
|
||||||
|
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.8.0.0")]
|
||||||
|
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||||
|
|
||||||
|
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||||
|
|
||||||
|
public static Settings Default {
|
||||||
|
get {
|
||||||
|
return defaultInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
|
||||||
|
<Profiles>
|
||||||
|
<Profile Name="(Default)" />
|
||||||
|
</Profiles>
|
||||||
|
<Settings />
|
||||||
|
</SettingsFile>
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# 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
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoPatcher", "AutoPatcher\AutoPatcher.csproj", "{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
.NET45Debug|x86 = .NET45Debug|x86
|
||||||
|
.NET45Release|x86 = .NET45Release|x86
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{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|x86.ActiveCfg = Release|x86
|
||||||
|
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Release|x86.Build.0 = Release|x86
|
||||||
|
{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|x86.ActiveCfg = Debug|x86
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Debug|x86.Build.0 = Debug|x86
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Release|x86.ActiveCfg = Release|x86
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Release|x86.Build.0 = Release|x86
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Debug|x86.Build.0 = Debug|x86
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Release|x86.ActiveCfg = Release|x86
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Release|x86.Build.0 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {6763D5C5-7BCE-437C-9FD0-67BDD8D79FD2}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
||||||
@@ -0,0 +1,229 @@
|
|||||||
|
// 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.Diagnostics;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Patcher
|
||||||
|
{
|
||||||
|
public enum CodeType
|
||||||
|
{
|
||||||
|
ARM,
|
||||||
|
Thumb,
|
||||||
|
Thumb2
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ArmCompiler
|
||||||
|
{
|
||||||
|
public static Int32 LastErrorCode;
|
||||||
|
public static string Output;
|
||||||
|
|
||||||
|
public static byte[] Compile(string PathToVisualStudio, UInt32 Origin, CodeType CodeType, string ArmCodeFragment)
|
||||||
|
{
|
||||||
|
if (PathToVisualStudio.Length == 0)
|
||||||
|
{
|
||||||
|
Output = "ARM SDK is missing.";
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
string AssemblyFilePath = Path.GetTempFileName();
|
||||||
|
string ObjectFilePathTmp = Path.GetTempFileName();
|
||||||
|
string ObjectFilePath = ObjectFilePathTmp.Replace(".tmp", ".obj");
|
||||||
|
File.Move(ObjectFilePathTmp, ObjectFilePath);
|
||||||
|
|
||||||
|
string CodeTypeDirective = null;
|
||||||
|
switch (CodeType)
|
||||||
|
{
|
||||||
|
case Patcher.CodeType.ARM:
|
||||||
|
CodeTypeDirective = "CODE32";
|
||||||
|
break;
|
||||||
|
case Patcher.CodeType.Thumb:
|
||||||
|
CodeTypeDirective = "CODE16";
|
||||||
|
break;
|
||||||
|
case Patcher.CodeType.Thumb2:
|
||||||
|
CodeTypeDirective = "THUMB";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
string FullAssemblyCode =
|
||||||
|
" AREA ARM_AREA, CODE, READONLY" + Environment.NewLine +
|
||||||
|
" " + CodeTypeDirective + Environment.NewLine;
|
||||||
|
|
||||||
|
string ProcessedAssembly = ProcessArmCodeFragment(ArmCodeFragment, Origin, out uint Padding);
|
||||||
|
|
||||||
|
if (Padding > 0)
|
||||||
|
FullAssemblyCode += " SPACE " + Padding.ToString() + Environment.NewLine;
|
||||||
|
|
||||||
|
FullAssemblyCode +=
|
||||||
|
"start" + Environment.NewLine +
|
||||||
|
ProcessedAssembly;
|
||||||
|
|
||||||
|
FullAssemblyCode += " end" + Environment.NewLine;
|
||||||
|
|
||||||
|
File.WriteAllText(AssemblyFilePath, FullAssemblyCode);
|
||||||
|
|
||||||
|
string ArmAsmPath = MainForm.FindArmAsmPath(PathToVisualStudio);
|
||||||
|
string BinPath = MainForm.FindMSVCBinaryPaths(PathToVisualStudio).FirstOrDefault() ?? "";
|
||||||
|
ProcessStartInfo psi = new(Path.Combine(ArmAsmPath, "armasm.exe"));
|
||||||
|
psi.EnvironmentVariables["PATH"] += ";" + Path.Combine(PathToVisualStudio, @"Common7\IDE\");
|
||||||
|
psi.EnvironmentVariables["PATH"] += ";" + Path.Combine(PathToVisualStudio, @"Common7\Tools\");
|
||||||
|
psi.EnvironmentVariables["PATH"] += ";" + BinPath;
|
||||||
|
psi.EnvironmentVariables["PATH"] += ";" + ArmAsmPath;
|
||||||
|
psi.UseShellExecute = false;
|
||||||
|
psi.RedirectStandardOutput = true;
|
||||||
|
psi.CreateNoWindow = true;
|
||||||
|
psi.Arguments = "-g \"" + AssemblyFilePath + "\" \"" + ObjectFilePath + "\"";
|
||||||
|
Process ArmAsmProcess = Process.Start(psi);
|
||||||
|
ArmAsmProcess.WaitForExit();
|
||||||
|
LastErrorCode = ArmAsmProcess.ExitCode;
|
||||||
|
if (ArmAsmProcess.ExitCode != 0)
|
||||||
|
{
|
||||||
|
using StreamReader reader = ArmAsmProcess.StandardOutput;
|
||||||
|
Output = reader.ReadToEnd();
|
||||||
|
|
||||||
|
string[] Lines = Output.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
|
||||||
|
|
||||||
|
Output = "";
|
||||||
|
|
||||||
|
foreach (string Line in Lines)
|
||||||
|
{
|
||||||
|
string Out = Line.Trim();
|
||||||
|
if (Out.Length == 0) continue;
|
||||||
|
if (Out.StartsWith("Microsoft (R) ARM Macro Assembler")) continue;
|
||||||
|
if (Out.StartsWith("Copyright (C) Microsoft Corporation")) continue;
|
||||||
|
if (Out.StartsWith(AssemblyFilePath))
|
||||||
|
{
|
||||||
|
Out = Out[AssemblyFilePath.Length..];
|
||||||
|
int P = Out.IndexOf(':');
|
||||||
|
Out = Out[(P + 1)..].Trim();
|
||||||
|
}
|
||||||
|
Output += Out + Environment.NewLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] Result = null;
|
||||||
|
|
||||||
|
if (LastErrorCode == 0)
|
||||||
|
Result = COFF.ObjectFileParser.ParseObjectFile(ObjectFilePath).SectionHeaders.First(h => h.Name == "ARM_AREA").RawData;
|
||||||
|
|
||||||
|
File.Delete(AssemblyFilePath);
|
||||||
|
File.Delete(ObjectFilePath);
|
||||||
|
|
||||||
|
if ((Result != null) && (Padding > 0))
|
||||||
|
{
|
||||||
|
byte[] RemovedPadding = new byte[Result.Length - Padding];
|
||||||
|
Buffer.BlockCopy(Result, (int)Padding, RemovedPadding, 0, RemovedPadding.Length);
|
||||||
|
Result = RemovedPadding;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ProcessArmCodeFragment(string ArmCodeFragment, UInt32 Origin, out UInt32 Padding)
|
||||||
|
{
|
||||||
|
string[] BranchOpcodes = new string[] { "B", "BEQ", "BNE", "BCS", "BHS", "BCC", "BLO", "BMI", "BPL", "BVS", "BVC", "BHI", "BLS", "BGE", "BLT", "BGT", "BLE", "BAL"};
|
||||||
|
|
||||||
|
StringBuilder Result = new(1000);
|
||||||
|
Padding = 0;
|
||||||
|
|
||||||
|
string[] Lines = ArmCodeFragment.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
|
||||||
|
List<Tuple<string, string>> Labels = new();
|
||||||
|
|
||||||
|
foreach (string Line in Lines)
|
||||||
|
{
|
||||||
|
string Code = Line;
|
||||||
|
if (Line.Contains(':'))
|
||||||
|
{
|
||||||
|
string Label = Line.Substring(0, Line.IndexOf(':'));
|
||||||
|
Label = Label.Trim();
|
||||||
|
if (Label.Length > 0)
|
||||||
|
Result.AppendLine(Label);
|
||||||
|
Code = Line[(Line.IndexOf(':') + 1)..];
|
||||||
|
}
|
||||||
|
|
||||||
|
int EquPos = Code.IndexOf("EQU", StringComparison.OrdinalIgnoreCase);
|
||||||
|
if ((EquPos > 0) && (EquPos > 0) && (EquPos < (Code.Length - 3)))
|
||||||
|
{
|
||||||
|
if (new char[] { '\t', ' ' }.Contains(Line[EquPos - 1]) &&
|
||||||
|
new char[] { '\t', ' ' }.Contains(Line[EquPos + 3]))
|
||||||
|
{
|
||||||
|
Result.AppendLine(Line.Trim());
|
||||||
|
Labels.Add(new Tuple<string, string>(Line.Substring(0, EquPos).Trim(), Line[(EquPos + 3)..].Trim()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Code = Code.Trim();
|
||||||
|
|
||||||
|
bool IsAbsoluteAddress = false;
|
||||||
|
|
||||||
|
int OpcodeLength = Code.IndexOfAny(new char [] { '\t', ' ', '.' });
|
||||||
|
if (OpcodeLength > 0)
|
||||||
|
{
|
||||||
|
string Opcode = Code.Substring(0, OpcodeLength).ToUpper();
|
||||||
|
|
||||||
|
string PossibleAddress = null;
|
||||||
|
|
||||||
|
if (Opcode == "LDR")
|
||||||
|
{
|
||||||
|
PossibleAddress = Code[(Code.IndexOf(',') + 1)..].Trim();
|
||||||
|
}
|
||||||
|
else if (BranchOpcodes.Contains(Opcode))
|
||||||
|
{
|
||||||
|
PossibleAddress = Code[(Code.IndexOfAny(new char[] { '\t', ' ' }) + 1)..].Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PossibleAddress != null)
|
||||||
|
{
|
||||||
|
foreach (Tuple<string, string> Label in Labels)
|
||||||
|
{
|
||||||
|
if (string.Equals(Label.Item1, PossibleAddress, StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
PossibleAddress = Label.Item2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (PossibleAddress.StartsWith("0x"))
|
||||||
|
PossibleAddress = PossibleAddress[2..];
|
||||||
|
IsAbsoluteAddress = UInt32.TryParse(PossibleAddress, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out uint ParsedValue);
|
||||||
|
if (IsAbsoluteAddress && (ParsedValue < Origin))
|
||||||
|
Padding = Math.Max(Padding, Origin - ParsedValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result.Append(' ');
|
||||||
|
Result.Append(Code);
|
||||||
|
if (IsAbsoluteAddress)
|
||||||
|
{
|
||||||
|
Result.Append(" + start - 0x");
|
||||||
|
Result.Append(Origin.ToString("X8"));
|
||||||
|
}
|
||||||
|
Result.Append(Environment.NewLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,382 @@
|
|||||||
|
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace WPinternals
|
||||||
|
{
|
||||||
|
internal static class ByteOperations
|
||||||
|
{
|
||||||
|
internal static string ReadAsciiString(byte[] ByteArray, UInt32 Offset)
|
||||||
|
{
|
||||||
|
UInt32 Length = 0;
|
||||||
|
while (((Offset + Length) < ByteArray.Length) && (ByteArray[Offset + Length] != 0))
|
||||||
|
Length++;
|
||||||
|
byte[] Bytes = new byte[Length];
|
||||||
|
Buffer.BlockCopy(ByteArray, (int)Offset, Bytes, 0, (int)Length);
|
||||||
|
return System.Text.Encoding.ASCII.GetString(Bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string ReadAsciiString(byte[] ByteArray, UInt32 Offset, UInt32 Length)
|
||||||
|
{
|
||||||
|
byte[] Bytes = new byte[Length];
|
||||||
|
Buffer.BlockCopy(ByteArray, (int)Offset, Bytes, 0, (int)Length);
|
||||||
|
return System.Text.Encoding.ASCII.GetString(Bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string ReadUnicodeString(byte[] ByteArray, UInt32 Offset, UInt32 Length)
|
||||||
|
{
|
||||||
|
byte[] Bytes = new byte[Length];
|
||||||
|
Buffer.BlockCopy(ByteArray, (int)Offset, Bytes, 0, (int)Length);
|
||||||
|
return System.Text.Encoding.Unicode.GetString(Bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void WriteUnicodeString(byte[] ByteArray, UInt32 Offset, string Text, UInt32? MaxBufferLength = null)
|
||||||
|
{
|
||||||
|
if (MaxBufferLength != null)
|
||||||
|
Array.Clear(ByteArray, (int)Offset, (int)MaxBufferLength);
|
||||||
|
|
||||||
|
byte[] TextBytes = System.Text.UnicodeEncoding.Unicode.GetBytes(Text);
|
||||||
|
int WriteLength = TextBytes.Length;
|
||||||
|
if (WriteLength > MaxBufferLength)
|
||||||
|
WriteLength = (int)MaxBufferLength;
|
||||||
|
|
||||||
|
Buffer.BlockCopy(TextBytes, 0, ByteArray, (int)Offset, WriteLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt32 ReadUInt32(byte[] ByteArray, UInt32 Offset)
|
||||||
|
{
|
||||||
|
// Assume CPU and FFU are both Little Endian
|
||||||
|
return BitConverter.ToUInt32(ByteArray, (int)Offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void WriteUInt32(byte[] ByteArray, UInt32 Offset, UInt32 Value)
|
||||||
|
{
|
||||||
|
System.Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Int32 ReadInt32(byte[] ByteArray, UInt32 Offset)
|
||||||
|
{
|
||||||
|
// Assume CPU and FFU are both Little Endian
|
||||||
|
return BitConverter.ToInt32(ByteArray, (int)Offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void WriteInt32(byte[] ByteArray, UInt32 Offset, Int32 Value)
|
||||||
|
{
|
||||||
|
System.Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt16 ReadUInt16(byte[] ByteArray, UInt32 Offset)
|
||||||
|
{
|
||||||
|
// Assume CPU and FFU are both Little Endian
|
||||||
|
return BitConverter.ToUInt16(ByteArray, (int)Offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void WriteUInt16(byte[] ByteArray, UInt32 Offset, UInt16 Value)
|
||||||
|
{
|
||||||
|
System.Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Int16 ReadInt16(byte[] ByteArray, UInt32 Offset)
|
||||||
|
{
|
||||||
|
// Assume CPU and FFU are both Little Endian
|
||||||
|
return BitConverter.ToInt16(ByteArray, (int)Offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void WriteInt16(byte[] ByteArray, UInt32 Offset, Int16 Value)
|
||||||
|
{
|
||||||
|
System.Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static byte ReadUInt8(byte[] ByteArray, UInt32 Offset)
|
||||||
|
{
|
||||||
|
return ByteArray[Offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void WriteUInt8(byte[] ByteArray, UInt32 Offset, byte Value)
|
||||||
|
{
|
||||||
|
ByteArray[Offset] = Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt32 ReadUInt24(byte[] ByteArray, UInt32 Offset)
|
||||||
|
{
|
||||||
|
return (UInt32)(ByteArray[Offset] + (ByteArray[Offset + 1] << 8) + (ByteArray[Offset + 2] << 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void WriteUInt24(byte[] ByteArray, UInt32 Offset, UInt32 Value)
|
||||||
|
{
|
||||||
|
System.Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt64 ReadUInt64(byte[] ByteArray, UInt32 Offset)
|
||||||
|
{
|
||||||
|
// Assume CPU and FFU are both Little Endian
|
||||||
|
return BitConverter.ToUInt64(ByteArray, (int)Offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void WriteUInt64(byte[] ByteArray, UInt32 Offset, UInt64 Value)
|
||||||
|
{
|
||||||
|
System.Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Guid ReadGuid(byte[] ByteArray, UInt32 Offset)
|
||||||
|
{
|
||||||
|
byte[] GuidBuffer = new byte[0x10];
|
||||||
|
Buffer.BlockCopy(ByteArray, (int)Offset, GuidBuffer, 0, 0x10);
|
||||||
|
return new Guid(GuidBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void WriteGuid(byte[] ByteArray, UInt32 Offset, Guid Value)
|
||||||
|
{
|
||||||
|
Buffer.BlockCopy(Value.ToByteArray(), 0, ByteArray, (int)Offset, 0x10);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt32 Align(UInt32 Base, UInt32 Offset, UInt32 Alignment)
|
||||||
|
{
|
||||||
|
if (((Offset - Base) % Alignment) == 0)
|
||||||
|
return Offset;
|
||||||
|
else
|
||||||
|
return ((((Offset - Base) / Alignment) + 1) * Alignment) + Base;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt32? FindPatternInFile(string FileName, byte[] Pattern, byte[] Mask, out byte[] OutPattern)
|
||||||
|
{
|
||||||
|
// The mask is optional.
|
||||||
|
// In the mask 0x00 means the value must match, and 0xFF means that this position is a wildcard.
|
||||||
|
|
||||||
|
UInt32? Result = null;
|
||||||
|
|
||||||
|
FileStream Stream = new(FileName, FileMode.Open, FileAccess.Read);
|
||||||
|
|
||||||
|
byte[] Buffer = new byte[0x10000 + Pattern.Length - 1];
|
||||||
|
UInt32 BytesInBuffer = 0;
|
||||||
|
UInt32 BytesRead;
|
||||||
|
UInt32 SearchPositionFile = 0;
|
||||||
|
UInt32 SearchPositionBuffer = 0;
|
||||||
|
UInt32 BufferFileOffset = 0; // Offset in file where data from buffer is located.
|
||||||
|
int i;
|
||||||
|
|
||||||
|
OutPattern = null;
|
||||||
|
|
||||||
|
while (SearchPositionFile <= (Stream.Length - Pattern.Length))
|
||||||
|
{
|
||||||
|
if ((SearchPositionBuffer + Pattern.Length) > BytesInBuffer)
|
||||||
|
{
|
||||||
|
// Need to read next chunk
|
||||||
|
if ((BytesInBuffer - SearchPositionBuffer) > 0)
|
||||||
|
{
|
||||||
|
System.Buffer.BlockCopy(Buffer, (int)SearchPositionBuffer, Buffer, 0, (int)(BytesInBuffer - SearchPositionBuffer));
|
||||||
|
}
|
||||||
|
uint BufferReadPosition = BytesInBuffer - SearchPositionBuffer;
|
||||||
|
BytesInBuffer -= SearchPositionBuffer;
|
||||||
|
BufferFileOffset += SearchPositionBuffer;
|
||||||
|
SearchPositionBuffer = 0;
|
||||||
|
|
||||||
|
BytesRead = (UInt32)Stream.Read(Buffer, (int)BufferReadPosition, Buffer.Length - (int)BufferReadPosition);
|
||||||
|
BytesInBuffer += BytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Match = true;
|
||||||
|
for (i = 0; i < Pattern.Length; i++)
|
||||||
|
{
|
||||||
|
if (Buffer[SearchPositionBuffer + i] != Pattern[i])
|
||||||
|
{
|
||||||
|
if ((Mask == null) || (Mask[i] == 0))
|
||||||
|
{
|
||||||
|
Match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Match)
|
||||||
|
{
|
||||||
|
Result = SearchPositionFile;
|
||||||
|
|
||||||
|
OutPattern = new byte[Pattern.Length];
|
||||||
|
System.Buffer.BlockCopy(Buffer, (int)SearchPositionBuffer, OutPattern, 0, Pattern.Length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchPositionBuffer++;
|
||||||
|
SearchPositionFile++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream.Close();
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt32? FindAscii(byte[] SourceBuffer, string Pattern)
|
||||||
|
{
|
||||||
|
return FindPattern(SourceBuffer, System.Text.ASCIIEncoding.ASCII.GetBytes((string)Pattern), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt32? FindAscii(byte[] SourceBuffer, uint SourceOffset, string Pattern)
|
||||||
|
{
|
||||||
|
return FindPattern(SourceBuffer, SourceOffset, null, System.Text.ASCIIEncoding.ASCII.GetBytes((string)Pattern), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt32? FindUnicode(byte[] SourceBuffer, string Pattern)
|
||||||
|
{
|
||||||
|
return FindPattern(SourceBuffer, System.Text.UnicodeEncoding.Unicode.GetBytes((string)Pattern), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt32? FindUnicode(byte[] SourceBuffer, uint SourceOffset, string Pattern)
|
||||||
|
{
|
||||||
|
return FindPattern(SourceBuffer, SourceOffset, null, System.Text.UnicodeEncoding.Unicode.GetBytes((string)Pattern), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt32? FindUint(byte[] SourceBuffer, UInt32 Pattern)
|
||||||
|
{
|
||||||
|
return FindPattern(SourceBuffer, BitConverter.GetBytes((UInt32)Pattern), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt32? FindPattern(byte[] SourceBuffer, byte[] Pattern, byte[] Mask, byte[] OutPattern)
|
||||||
|
{
|
||||||
|
return FindPattern(SourceBuffer, 0, null, Pattern, Mask, OutPattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt32? FindPattern(byte[] SourceBuffer, uint SourceOffset, uint? SourceSize, byte[] Pattern, byte[] Mask, byte[] OutPattern)
|
||||||
|
{
|
||||||
|
// The mask is optional.
|
||||||
|
// In the mask 0x00 means the value must match, and 0xFF means that this position is a wildcard.
|
||||||
|
|
||||||
|
UInt32? Result = null;
|
||||||
|
|
||||||
|
UInt32 SearchPosition = SourceOffset;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
while ((SearchPosition <= (SourceBuffer.Length - Pattern.Length)) && ((SourceSize == null) || (SearchPosition <= (SourceOffset + SourceSize - Pattern.Length))))
|
||||||
|
{
|
||||||
|
bool Match = true;
|
||||||
|
for (i = 0; i < Pattern.Length; i++)
|
||||||
|
{
|
||||||
|
if (SourceBuffer[SearchPosition + i] != Pattern[i])
|
||||||
|
{
|
||||||
|
if ((Mask == null) || (Mask[i] == 0))
|
||||||
|
{
|
||||||
|
Match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Match)
|
||||||
|
{
|
||||||
|
Result = SearchPosition;
|
||||||
|
|
||||||
|
if (OutPattern != null)
|
||||||
|
System.Buffer.BlockCopy(SourceBuffer, (int)SearchPosition, OutPattern, 0, Pattern.Length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchPosition++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static byte CalculateChecksum8(byte[] Buffer, UInt32 Offset, UInt32 Size)
|
||||||
|
{
|
||||||
|
byte Checksum = 0;
|
||||||
|
|
||||||
|
for (UInt32 i = Offset; i < (Offset + Size); i++)
|
||||||
|
Checksum += Buffer[i];
|
||||||
|
|
||||||
|
return (byte)(0x100 - Checksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt16 CalculateChecksum16(byte[] Buffer, UInt32 Offset, UInt32 Size)
|
||||||
|
{
|
||||||
|
UInt16 Checksum = 0;
|
||||||
|
|
||||||
|
for (UInt32 i = Offset; i < (Offset + Size - 1); i += 2)
|
||||||
|
Checksum += BitConverter.ToUInt16(Buffer, (int)i);
|
||||||
|
|
||||||
|
return (UInt16)(0x10000 - Checksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly UInt32[] CRC32Table = new UInt32[] {
|
||||||
|
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
|
||||||
|
0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
|
||||||
|
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
|
||||||
|
0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
||||||
|
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
|
||||||
|
0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
|
||||||
|
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
|
||||||
|
0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
||||||
|
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
|
||||||
|
0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
|
||||||
|
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
|
||||||
|
0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
||||||
|
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
|
||||||
|
0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
|
||||||
|
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
|
||||||
|
0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
||||||
|
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
|
||||||
|
0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
|
||||||
|
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
|
||||||
|
0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
||||||
|
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
|
||||||
|
0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
|
||||||
|
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
|
||||||
|
0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
||||||
|
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
|
||||||
|
0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
|
||||||
|
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
|
||||||
|
0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
||||||
|
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
|
||||||
|
0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
|
||||||
|
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
|
||||||
|
0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
||||||
|
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
|
||||||
|
0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
|
||||||
|
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
|
||||||
|
0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
||||||
|
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
|
||||||
|
0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
|
||||||
|
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
|
||||||
|
0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
||||||
|
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
|
||||||
|
0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
|
||||||
|
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
|
||||||
|
};
|
||||||
|
|
||||||
|
internal static UInt32 CRC32(byte[] Input, UInt32 Offset, UInt32 Length)
|
||||||
|
{
|
||||||
|
if ((Input == null) || ((Offset + Length) > Input.Length))
|
||||||
|
throw new ArgumentException();
|
||||||
|
|
||||||
|
unchecked
|
||||||
|
{
|
||||||
|
uint crc = (uint)(((uint)0) ^ (-1));
|
||||||
|
for (var i = Offset; i < (Offset + Length); i++)
|
||||||
|
{
|
||||||
|
crc = (crc >> 8) ^ CRC32Table[ (crc ^ Input[i]) & 0xFF ];
|
||||||
|
}
|
||||||
|
crc = (uint)(crc ^ (-1));
|
||||||
|
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
// 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.Text;
|
||||||
|
|
||||||
|
namespace WPinternals
|
||||||
|
{
|
||||||
|
public static class Converter
|
||||||
|
{
|
||||||
|
public static string ConvertHexToString(byte[] Bytes, string Separator)
|
||||||
|
{
|
||||||
|
StringBuilder s = new(1000);
|
||||||
|
for (int i = Bytes.GetLowerBound(0); i <= Bytes.GetUpperBound(0); i++)
|
||||||
|
{
|
||||||
|
if (i != Bytes.GetLowerBound(0))
|
||||||
|
s.Append(Separator);
|
||||||
|
s.Append(Bytes[i].ToString("X2"));
|
||||||
|
}
|
||||||
|
return s.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] ConvertStringToHex(string HexString)
|
||||||
|
{
|
||||||
|
if (HexString.Length % 2 == 1)
|
||||||
|
throw new Exception("The binary key cannot have an odd number of digits");
|
||||||
|
|
||||||
|
byte[] arr = new byte[HexString.Length >> 1];
|
||||||
|
|
||||||
|
for (int i = 0; i < (HexString.Length >> 1); ++i)
|
||||||
|
{
|
||||||
|
arr[i] = (byte)((GetHexVal(HexString[i << 1]) << 4) + GetHexVal(HexString[(i << 1) + 1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetHexVal(char hex)
|
||||||
|
{
|
||||||
|
int val = (int)hex;
|
||||||
|
//For uppercase A-F letters:
|
||||||
|
//return val - (val < 58 ? 48 : 55);
|
||||||
|
//For lowercase a-f letters:
|
||||||
|
//return val - (val < 58 ? 48 : 87);
|
||||||
|
//Or the two combined, but a bit slower:
|
||||||
|
return val - (val < 58 ? 48 : (val < 97 ? 55 : 87));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
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.
|
||||||
@@ -0,0 +1,426 @@
|
|||||||
|
namespace Patcher
|
||||||
|
{
|
||||||
|
partial class MainForm
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Required designer variable.
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clean up any resources being used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && (components != null))
|
||||||
|
{
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Windows Form Designer generated code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required method for Designer support - do not modify
|
||||||
|
/// the contents of this method with the code editor.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
this.label1 = new System.Windows.Forms.Label();
|
||||||
|
this.txtVisualStudioPath = new System.Windows.Forms.TextBox();
|
||||||
|
this.FolderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog();
|
||||||
|
this.OpenFileDialog = new System.Windows.Forms.OpenFileDialog();
|
||||||
|
this.SaveFileDialog = new System.Windows.Forms.SaveFileDialog();
|
||||||
|
this.cmdVisualStudioPath = new System.Windows.Forms.Button();
|
||||||
|
this.cmdInputFile = new System.Windows.Forms.Button();
|
||||||
|
this.txtInputFile = new System.Windows.Forms.TextBox();
|
||||||
|
this.label2 = new System.Windows.Forms.Label();
|
||||||
|
this.cmdOutputFile = new System.Windows.Forms.Button();
|
||||||
|
this.txtOutputFile = new System.Windows.Forms.TextBox();
|
||||||
|
this.label3 = new System.Windows.Forms.Label();
|
||||||
|
this.cmdPatchDefinitionsFile = new System.Windows.Forms.Button();
|
||||||
|
this.txtPatchDefinitionsFile = new System.Windows.Forms.TextBox();
|
||||||
|
this.label4 = new System.Windows.Forms.Label();
|
||||||
|
this.label5 = new System.Windows.Forms.Label();
|
||||||
|
this.cmbPatchDefinitionName = new System.Windows.Forms.ComboBox();
|
||||||
|
this.cmbTargetVersion = new System.Windows.Forms.ComboBox();
|
||||||
|
this.label6 = new System.Windows.Forms.Label();
|
||||||
|
this.cmbTargetPath = new System.Windows.Forms.ComboBox();
|
||||||
|
this.label7 = new System.Windows.Forms.Label();
|
||||||
|
this.label8 = new System.Windows.Forms.Label();
|
||||||
|
this.txtAssemblyCode = new System.Windows.Forms.TextBox();
|
||||||
|
this.txtCompiledOpcodes = new System.Windows.Forms.TextBox();
|
||||||
|
this.label9 = new System.Windows.Forms.Label();
|
||||||
|
this.txtVirtualOffset = new System.Windows.Forms.TextBox();
|
||||||
|
this.label10 = new System.Windows.Forms.Label();
|
||||||
|
this.cmbCodeType = new System.Windows.Forms.ComboBox();
|
||||||
|
this.label11 = new System.Windows.Forms.Label();
|
||||||
|
this.cmdCompile = new System.Windows.Forms.Button();
|
||||||
|
this.cmdPatch = new System.Windows.Forms.Button();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// label1
|
||||||
|
//
|
||||||
|
this.label1.AutoSize = true;
|
||||||
|
this.label1.Location = new System.Drawing.Point(15, 13);
|
||||||
|
this.label1.Name = "label1";
|
||||||
|
this.label1.Size = new System.Drawing.Size(191, 13);
|
||||||
|
this.label1.TabIndex = 0;
|
||||||
|
this.label1.Text = "Path to Visual Studio with ARM32 SDK";
|
||||||
|
//
|
||||||
|
// txtVisualStudioPath
|
||||||
|
//
|
||||||
|
this.txtVisualStudioPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtVisualStudioPath.Location = new System.Drawing.Point(18, 29);
|
||||||
|
this.txtVisualStudioPath.Name = "txtVisualStudioPath";
|
||||||
|
this.txtVisualStudioPath.Size = new System.Drawing.Size(665, 20);
|
||||||
|
this.txtVisualStudioPath.TabIndex = 1;
|
||||||
|
//
|
||||||
|
// OpenFileDialog
|
||||||
|
//
|
||||||
|
this.OpenFileDialog.FileName = "openFileDialog1";
|
||||||
|
//
|
||||||
|
// cmdVisualStudioPath
|
||||||
|
//
|
||||||
|
this.cmdVisualStudioPath.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdVisualStudioPath.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.cmdVisualStudioPath.Location = new System.Drawing.Point(689, 28);
|
||||||
|
this.cmdVisualStudioPath.Name = "cmdVisualStudioPath";
|
||||||
|
this.cmdVisualStudioPath.Size = new System.Drawing.Size(35, 22);
|
||||||
|
this.cmdVisualStudioPath.TabIndex = 2;
|
||||||
|
this.cmdVisualStudioPath.Text = "...";
|
||||||
|
this.cmdVisualStudioPath.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdVisualStudioPath.Click += new System.EventHandler(this.cmdVisualStudioPath_Click);
|
||||||
|
//
|
||||||
|
// cmdInputFile
|
||||||
|
//
|
||||||
|
this.cmdInputFile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdInputFile.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.cmdInputFile.Location = new System.Drawing.Point(689, 301);
|
||||||
|
this.cmdInputFile.Name = "cmdInputFile";
|
||||||
|
this.cmdInputFile.Size = new System.Drawing.Size(35, 22);
|
||||||
|
this.cmdInputFile.TabIndex = 14;
|
||||||
|
this.cmdInputFile.Text = "...";
|
||||||
|
this.cmdInputFile.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdInputFile.Click += new System.EventHandler(this.cmdInputFile_Click);
|
||||||
|
//
|
||||||
|
// txtInputFile
|
||||||
|
//
|
||||||
|
this.txtInputFile.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtInputFile.Location = new System.Drawing.Point(18, 302);
|
||||||
|
this.txtInputFile.Name = "txtInputFile";
|
||||||
|
this.txtInputFile.Size = new System.Drawing.Size(665, 20);
|
||||||
|
this.txtInputFile.TabIndex = 13;
|
||||||
|
//
|
||||||
|
// label2
|
||||||
|
//
|
||||||
|
this.label2.AutoSize = true;
|
||||||
|
this.label2.Location = new System.Drawing.Point(15, 286);
|
||||||
|
this.label2.Name = "label2";
|
||||||
|
this.label2.Size = new System.Drawing.Size(47, 13);
|
||||||
|
this.label2.TabIndex = 12;
|
||||||
|
this.label2.Text = "Input file";
|
||||||
|
//
|
||||||
|
// cmdOutputFile
|
||||||
|
//
|
||||||
|
this.cmdOutputFile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdOutputFile.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.cmdOutputFile.Location = new System.Drawing.Point(689, 349);
|
||||||
|
this.cmdOutputFile.Name = "cmdOutputFile";
|
||||||
|
this.cmdOutputFile.Size = new System.Drawing.Size(35, 22);
|
||||||
|
this.cmdOutputFile.TabIndex = 17;
|
||||||
|
this.cmdOutputFile.Text = "...";
|
||||||
|
this.cmdOutputFile.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdOutputFile.Click += new System.EventHandler(this.cmdOutputFile_Click);
|
||||||
|
//
|
||||||
|
// txtOutputFile
|
||||||
|
//
|
||||||
|
this.txtOutputFile.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtOutputFile.Location = new System.Drawing.Point(18, 350);
|
||||||
|
this.txtOutputFile.Name = "txtOutputFile";
|
||||||
|
this.txtOutputFile.Size = new System.Drawing.Size(665, 20);
|
||||||
|
this.txtOutputFile.TabIndex = 16;
|
||||||
|
//
|
||||||
|
// label3
|
||||||
|
//
|
||||||
|
this.label3.AutoSize = true;
|
||||||
|
this.label3.Location = new System.Drawing.Point(15, 334);
|
||||||
|
this.label3.Name = "label3";
|
||||||
|
this.label3.Size = new System.Drawing.Size(101, 13);
|
||||||
|
this.label3.TabIndex = 15;
|
||||||
|
this.label3.Text = "Output file (optional)";
|
||||||
|
//
|
||||||
|
// cmdPatchDefinitionsFile
|
||||||
|
//
|
||||||
|
this.cmdPatchDefinitionsFile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdPatchDefinitionsFile.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.cmdPatchDefinitionsFile.Location = new System.Drawing.Point(689, 91);
|
||||||
|
this.cmdPatchDefinitionsFile.Name = "cmdPatchDefinitionsFile";
|
||||||
|
this.cmdPatchDefinitionsFile.Size = new System.Drawing.Size(35, 22);
|
||||||
|
this.cmdPatchDefinitionsFile.TabIndex = 5;
|
||||||
|
this.cmdPatchDefinitionsFile.Text = "...";
|
||||||
|
this.cmdPatchDefinitionsFile.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdPatchDefinitionsFile.Click += new System.EventHandler(this.cmdPatchDefinitionsFile_Click);
|
||||||
|
//
|
||||||
|
// txtPatchDefinitionsFile
|
||||||
|
//
|
||||||
|
this.txtPatchDefinitionsFile.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtPatchDefinitionsFile.Location = new System.Drawing.Point(18, 92);
|
||||||
|
this.txtPatchDefinitionsFile.Name = "txtPatchDefinitionsFile";
|
||||||
|
this.txtPatchDefinitionsFile.Size = new System.Drawing.Size(665, 20);
|
||||||
|
this.txtPatchDefinitionsFile.TabIndex = 4;
|
||||||
|
this.txtPatchDefinitionsFile.Leave += new System.EventHandler(this.txtPatchDefinitionsFile_Leave);
|
||||||
|
//
|
||||||
|
// label4
|
||||||
|
//
|
||||||
|
this.label4.AutoSize = true;
|
||||||
|
this.label4.Location = new System.Drawing.Point(15, 76);
|
||||||
|
this.label4.Name = "label4";
|
||||||
|
this.label4.Size = new System.Drawing.Size(117, 13);
|
||||||
|
this.label4.TabIndex = 3;
|
||||||
|
this.label4.Text = "Patch definitions xml-file";
|
||||||
|
//
|
||||||
|
// label5
|
||||||
|
//
|
||||||
|
this.label5.AutoSize = true;
|
||||||
|
this.label5.Location = new System.Drawing.Point(15, 124);
|
||||||
|
this.label5.Name = "label5";
|
||||||
|
this.label5.Size = new System.Drawing.Size(107, 13);
|
||||||
|
this.label5.TabIndex = 6;
|
||||||
|
this.label5.Text = "Patch definition name";
|
||||||
|
//
|
||||||
|
// cmbPatchDefinitionName
|
||||||
|
//
|
||||||
|
this.cmbPatchDefinitionName.FormattingEnabled = true;
|
||||||
|
this.cmbPatchDefinitionName.Location = new System.Drawing.Point(18, 140);
|
||||||
|
this.cmbPatchDefinitionName.Name = "cmbPatchDefinitionName";
|
||||||
|
this.cmbPatchDefinitionName.Size = new System.Drawing.Size(302, 21);
|
||||||
|
this.cmbPatchDefinitionName.TabIndex = 7;
|
||||||
|
this.cmbPatchDefinitionName.SelectedValueChanged += new System.EventHandler(this.cmbPatchDefinitionName_SelectedValueChanged);
|
||||||
|
this.cmbPatchDefinitionName.Leave += new System.EventHandler(this.cmbPatchDefinitionName_Leave);
|
||||||
|
//
|
||||||
|
// cmbTargetVersion
|
||||||
|
//
|
||||||
|
this.cmbTargetVersion.FormattingEnabled = true;
|
||||||
|
this.cmbTargetVersion.Location = new System.Drawing.Point(18, 189);
|
||||||
|
this.cmbTargetVersion.Name = "cmbTargetVersion";
|
||||||
|
this.cmbTargetVersion.Size = new System.Drawing.Size(302, 21);
|
||||||
|
this.cmbTargetVersion.TabIndex = 9;
|
||||||
|
this.cmbTargetVersion.SelectedValueChanged += new System.EventHandler(this.cmbTargetVersion_SelectedValueChanged);
|
||||||
|
this.cmbTargetVersion.Leave += new System.EventHandler(this.cmbTargetVersion_Leave);
|
||||||
|
//
|
||||||
|
// label6
|
||||||
|
//
|
||||||
|
this.label6.AutoSize = true;
|
||||||
|
this.label6.Location = new System.Drawing.Point(15, 173);
|
||||||
|
this.label6.Name = "label6";
|
||||||
|
this.label6.Size = new System.Drawing.Size(129, 13);
|
||||||
|
this.label6.TabIndex = 8;
|
||||||
|
this.label6.Text = "Target version description";
|
||||||
|
//
|
||||||
|
// cmbTargetPath
|
||||||
|
//
|
||||||
|
this.cmbTargetPath.FormattingEnabled = true;
|
||||||
|
this.cmbTargetPath.Location = new System.Drawing.Point(18, 238);
|
||||||
|
this.cmbTargetPath.Name = "cmbTargetPath";
|
||||||
|
this.cmbTargetPath.Size = new System.Drawing.Size(302, 21);
|
||||||
|
this.cmbTargetPath.TabIndex = 11;
|
||||||
|
//
|
||||||
|
// label7
|
||||||
|
//
|
||||||
|
this.label7.AutoSize = true;
|
||||||
|
this.label7.Location = new System.Drawing.Point(15, 222);
|
||||||
|
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 Definition rootfolder";
|
||||||
|
//
|
||||||
|
// label8
|
||||||
|
//
|
||||||
|
this.label8.AutoSize = true;
|
||||||
|
this.label8.Location = new System.Drawing.Point(15, 497);
|
||||||
|
this.label8.Name = "label8";
|
||||||
|
this.label8.Size = new System.Drawing.Size(365, 13);
|
||||||
|
this.label8.TabIndex = 22;
|
||||||
|
this.label8.Text = "ARM32 Patch / Shell assembly code (labels need to be followed by a colon)";
|
||||||
|
//
|
||||||
|
// txtAssemblyCode
|
||||||
|
//
|
||||||
|
this.txtAssemblyCode.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtAssemblyCode.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.txtAssemblyCode.Location = new System.Drawing.Point(18, 513);
|
||||||
|
this.txtAssemblyCode.Multiline = true;
|
||||||
|
this.txtAssemblyCode.Name = "txtAssemblyCode";
|
||||||
|
this.txtAssemblyCode.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
|
||||||
|
this.txtAssemblyCode.Size = new System.Drawing.Size(706, 161);
|
||||||
|
this.txtAssemblyCode.TabIndex = 23;
|
||||||
|
//
|
||||||
|
// txtCompiledOpcodes
|
||||||
|
//
|
||||||
|
this.txtCompiledOpcodes.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtCompiledOpcodes.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.txtCompiledOpcodes.Location = new System.Drawing.Point(18, 713);
|
||||||
|
this.txtCompiledOpcodes.Multiline = true;
|
||||||
|
this.txtCompiledOpcodes.Name = "txtCompiledOpcodes";
|
||||||
|
this.txtCompiledOpcodes.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
|
||||||
|
this.txtCompiledOpcodes.Size = new System.Drawing.Size(706, 59);
|
||||||
|
this.txtCompiledOpcodes.TabIndex = 25;
|
||||||
|
//
|
||||||
|
// label9
|
||||||
|
//
|
||||||
|
this.label9.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.label9.AutoSize = true;
|
||||||
|
this.label9.Location = new System.Drawing.Point(15, 697);
|
||||||
|
this.label9.Name = "label9";
|
||||||
|
this.label9.Size = new System.Drawing.Size(94, 13);
|
||||||
|
this.label9.TabIndex = 24;
|
||||||
|
this.label9.Text = "Compiled opcodes";
|
||||||
|
//
|
||||||
|
// txtVirtualOffset
|
||||||
|
//
|
||||||
|
this.txtVirtualOffset.Location = new System.Drawing.Point(18, 416);
|
||||||
|
this.txtVirtualOffset.Name = "txtVirtualOffset";
|
||||||
|
this.txtVirtualOffset.Size = new System.Drawing.Size(302, 20);
|
||||||
|
this.txtVirtualOffset.TabIndex = 19;
|
||||||
|
//
|
||||||
|
// label10
|
||||||
|
//
|
||||||
|
this.label10.AutoSize = true;
|
||||||
|
this.label10.Location = new System.Drawing.Point(15, 400);
|
||||||
|
this.label10.Name = "label10";
|
||||||
|
this.label10.Size = new System.Drawing.Size(309, 13);
|
||||||
|
this.label10.TabIndex = 18;
|
||||||
|
this.label10.Text = "Virtual offset (hex) (leave empty for only recalculating checksum)";
|
||||||
|
//
|
||||||
|
// cmbCodeType
|
||||||
|
//
|
||||||
|
this.cmbCodeType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||||
|
this.cmbCodeType.FormattingEnabled = true;
|
||||||
|
this.cmbCodeType.Items.AddRange(new object[] {
|
||||||
|
"ARM",
|
||||||
|
"Thumb",
|
||||||
|
"Thumb2"});
|
||||||
|
this.cmbCodeType.Location = new System.Drawing.Point(18, 464);
|
||||||
|
this.cmbCodeType.Name = "cmbCodeType";
|
||||||
|
this.cmbCodeType.Size = new System.Drawing.Size(302, 21);
|
||||||
|
this.cmbCodeType.TabIndex = 21;
|
||||||
|
//
|
||||||
|
// label11
|
||||||
|
//
|
||||||
|
this.label11.AutoSize = true;
|
||||||
|
this.label11.Location = new System.Drawing.Point(15, 448);
|
||||||
|
this.label11.Name = "label11";
|
||||||
|
this.label11.Size = new System.Drawing.Size(55, 13);
|
||||||
|
this.label11.TabIndex = 20;
|
||||||
|
this.label11.Text = "Code type";
|
||||||
|
//
|
||||||
|
// cmdCompile
|
||||||
|
//
|
||||||
|
this.cmdCompile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdCompile.Location = new System.Drawing.Point(470, 792);
|
||||||
|
this.cmdCompile.Name = "cmdCompile";
|
||||||
|
this.cmdCompile.Size = new System.Drawing.Size(120, 33);
|
||||||
|
this.cmdCompile.TabIndex = 26;
|
||||||
|
this.cmdCompile.Text = "Compile";
|
||||||
|
this.cmdCompile.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdCompile.Click += new System.EventHandler(this.cmdCompile_Click);
|
||||||
|
//
|
||||||
|
// cmdPatch
|
||||||
|
//
|
||||||
|
this.cmdPatch.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdPatch.Location = new System.Drawing.Point(604, 792);
|
||||||
|
this.cmdPatch.Name = "cmdPatch";
|
||||||
|
this.cmdPatch.Size = new System.Drawing.Size(120, 33);
|
||||||
|
this.cmdPatch.TabIndex = 27;
|
||||||
|
this.cmdPatch.Text = "Patch";
|
||||||
|
this.cmdPatch.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdPatch.Click += new System.EventHandler(this.cmdPatch_Click);
|
||||||
|
//
|
||||||
|
// MainForm
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.ClientSize = new System.Drawing.Size(742, 840);
|
||||||
|
this.Controls.Add(this.cmdPatch);
|
||||||
|
this.Controls.Add(this.cmdCompile);
|
||||||
|
this.Controls.Add(this.cmbCodeType);
|
||||||
|
this.Controls.Add(this.label11);
|
||||||
|
this.Controls.Add(this.txtVirtualOffset);
|
||||||
|
this.Controls.Add(this.label10);
|
||||||
|
this.Controls.Add(this.txtCompiledOpcodes);
|
||||||
|
this.Controls.Add(this.label9);
|
||||||
|
this.Controls.Add(this.txtAssemblyCode);
|
||||||
|
this.Controls.Add(this.label8);
|
||||||
|
this.Controls.Add(this.cmbTargetPath);
|
||||||
|
this.Controls.Add(this.label7);
|
||||||
|
this.Controls.Add(this.cmbTargetVersion);
|
||||||
|
this.Controls.Add(this.label6);
|
||||||
|
this.Controls.Add(this.cmbPatchDefinitionName);
|
||||||
|
this.Controls.Add(this.label5);
|
||||||
|
this.Controls.Add(this.cmdPatchDefinitionsFile);
|
||||||
|
this.Controls.Add(this.txtPatchDefinitionsFile);
|
||||||
|
this.Controls.Add(this.label4);
|
||||||
|
this.Controls.Add(this.cmdOutputFile);
|
||||||
|
this.Controls.Add(this.txtOutputFile);
|
||||||
|
this.Controls.Add(this.label3);
|
||||||
|
this.Controls.Add(this.cmdInputFile);
|
||||||
|
this.Controls.Add(this.txtInputFile);
|
||||||
|
this.Controls.Add(this.label2);
|
||||||
|
this.Controls.Add(this.cmdVisualStudioPath);
|
||||||
|
this.Controls.Add(this.txtVisualStudioPath);
|
||||||
|
this.Controls.Add(this.label1);
|
||||||
|
this.Name = "MainForm";
|
||||||
|
this.Text = "ARM patcher by Rene Lergner";
|
||||||
|
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.MainForm_FormClosed);
|
||||||
|
this.Load += new System.EventHandler(this.MainForm_Load);
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private System.Windows.Forms.Label label1;
|
||||||
|
private System.Windows.Forms.TextBox txtVisualStudioPath;
|
||||||
|
private System.Windows.Forms.FolderBrowserDialog FolderBrowserDialog;
|
||||||
|
private System.Windows.Forms.OpenFileDialog OpenFileDialog;
|
||||||
|
private System.Windows.Forms.SaveFileDialog SaveFileDialog;
|
||||||
|
private System.Windows.Forms.Button cmdVisualStudioPath;
|
||||||
|
private System.Windows.Forms.Button cmdInputFile;
|
||||||
|
private System.Windows.Forms.TextBox txtInputFile;
|
||||||
|
private System.Windows.Forms.Label label2;
|
||||||
|
private System.Windows.Forms.Button cmdOutputFile;
|
||||||
|
private System.Windows.Forms.TextBox txtOutputFile;
|
||||||
|
private System.Windows.Forms.Label label3;
|
||||||
|
private System.Windows.Forms.Button cmdPatchDefinitionsFile;
|
||||||
|
private System.Windows.Forms.TextBox txtPatchDefinitionsFile;
|
||||||
|
private System.Windows.Forms.Label label4;
|
||||||
|
private System.Windows.Forms.Label label5;
|
||||||
|
private System.Windows.Forms.ComboBox cmbPatchDefinitionName;
|
||||||
|
private System.Windows.Forms.ComboBox cmbTargetVersion;
|
||||||
|
private System.Windows.Forms.Label label6;
|
||||||
|
private System.Windows.Forms.ComboBox cmbTargetPath;
|
||||||
|
private System.Windows.Forms.Label label7;
|
||||||
|
private System.Windows.Forms.Label label8;
|
||||||
|
private System.Windows.Forms.TextBox txtAssemblyCode;
|
||||||
|
private System.Windows.Forms.TextBox txtCompiledOpcodes;
|
||||||
|
private System.Windows.Forms.Label label9;
|
||||||
|
private System.Windows.Forms.TextBox txtVirtualOffset;
|
||||||
|
private System.Windows.Forms.Label label10;
|
||||||
|
private System.Windows.Forms.ComboBox cmbCodeType;
|
||||||
|
private System.Windows.Forms.Label label11;
|
||||||
|
private System.Windows.Forms.Button cmdCompile;
|
||||||
|
private System.Windows.Forms.Button cmdPatch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,410 @@
|
|||||||
|
// 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 Microsoft.Win32;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using WPinternals;
|
||||||
|
|
||||||
|
namespace Patcher
|
||||||
|
{
|
||||||
|
public partial class MainForm : Form
|
||||||
|
{
|
||||||
|
public MainForm()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MainForm_Load(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
cmbCodeType.SelectedItem = "Thumb2";
|
||||||
|
LoadPaths();
|
||||||
|
CenterToScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdCompile_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
string VirtualOffsetString = txtVirtualOffset.Text.Trim();
|
||||||
|
if (VirtualOffsetString.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||||
|
VirtualOffsetString = VirtualOffsetString[2..];
|
||||||
|
|
||||||
|
CodeType CodeType = Patcher.CodeType.Thumb2;
|
||||||
|
byte[] CompiledCode = null;
|
||||||
|
if (UInt32.TryParse(VirtualOffsetString, System.Globalization.NumberStyles.HexNumber, null, out uint VirtualOffset))
|
||||||
|
{
|
||||||
|
CodeType = (CodeType)Enum.Parse(typeof(Patcher.CodeType), cmbCodeType.SelectedItem.ToString());
|
||||||
|
CompiledCode = ArmCompiler.Compile(txtVisualStudioPath.Text, VirtualOffset, CodeType, txtAssemblyCode.Text);
|
||||||
|
}
|
||||||
|
if ((VirtualOffset != 0) && (CompiledCode == null))
|
||||||
|
txtCompiledOpcodes.Text = ArmCompiler.Output;
|
||||||
|
else if (CompiledCode != null)
|
||||||
|
txtCompiledOpcodes.Text = Converter.ConvertHexToString(CompiledCode, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadPaths()
|
||||||
|
{
|
||||||
|
RegistryKey Key = Registry.CurrentUser.OpenSubKey(@"Software\Patcher", true) ?? Registry.CurrentUser.CreateSubKey(@"Software\Patcher");
|
||||||
|
|
||||||
|
txtVisualStudioPath.Text = (string)Key.GetValue("VisualStudioPath", "");
|
||||||
|
if (txtVisualStudioPath.Text.Length == 0)
|
||||||
|
txtVisualStudioPath.Text = FindVisualStudioPath();
|
||||||
|
|
||||||
|
txtPatchDefinitionsFile.Text = (string)Key.GetValue("PatchDefinitionsFilePath", "");
|
||||||
|
cmbPatchDefinitionName.Text = (string)Key.GetValue("PatchDefinitionName", "");
|
||||||
|
cmbTargetVersion.Text = (string)Key.GetValue("TargetVersion", "");
|
||||||
|
cmbTargetPath.Text = (string)Key.GetValue("TargetFilePath", "");
|
||||||
|
txtInputFile.Text = (string)Key.GetValue("InputFilePath", "");
|
||||||
|
txtOutputFile.Text = (string)Key.GetValue("OutputFilePath", "");
|
||||||
|
|
||||||
|
LoadPatchDefinitions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string[] FindMSVCBinaryPaths(string s)
|
||||||
|
{
|
||||||
|
string LegacyPath = Path.Combine(s, @"VC\bin");
|
||||||
|
if (Directory.Exists(LegacyPath))
|
||||||
|
{
|
||||||
|
return new string[] { LegacyPath };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Directory.Exists(Path.Combine(s, @"VC\Tools\MSVC")))
|
||||||
|
{
|
||||||
|
IEnumerable<string> MSVCs = Directory.EnumerateDirectories(Path.Combine(s, @"VC\Tools\MSVC"));
|
||||||
|
IEnumerable<string> Bins = MSVCs.Select(s => Path.Combine(s, "bin")).Where(s => Directory.Exists(s));
|
||||||
|
return Bins.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.Empty<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string FindArmAsmPath(string s)
|
||||||
|
{
|
||||||
|
foreach (string MSVCBin in FindMSVCBinaryPaths(s))
|
||||||
|
{
|
||||||
|
string path1 = Path.Combine(MSVCBin, "x86_arm");
|
||||||
|
string path2 = Path.Combine(MSVCBin, @"Hostx86\arm");
|
||||||
|
|
||||||
|
if (File.Exists(Path.Combine(path1, "armasm.exe")))
|
||||||
|
{
|
||||||
|
return path1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (File.Exists(Path.Combine(path2, "armasm.exe")))
|
||||||
|
{
|
||||||
|
return path2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FindVisualStudioPath()
|
||||||
|
{
|
||||||
|
IEnumerable<string> MainX86VSDirectories = Directory.EnumerateDirectories(@"C:\Program Files (x86)\", "Microsoft Visual Studio*");
|
||||||
|
IEnumerable<string> MainX64VSDirectories = Directory.EnumerateDirectories(@"C:\Program Files\", "Microsoft Visual Studio*");
|
||||||
|
|
||||||
|
IEnumerable<string> MainVSDirectories = MainX86VSDirectories.Union(MainX64VSDirectories);
|
||||||
|
|
||||||
|
IEnumerable<string> SubMainVSDirectories = MainVSDirectories.SelectMany(s => Directory.EnumerateDirectories(s));
|
||||||
|
IEnumerable<string> SubSubMainVSDirectories = SubMainVSDirectories.SelectMany(s => Directory.EnumerateDirectories(s));
|
||||||
|
IEnumerable<string> Directories = MainVSDirectories.Union(SubMainVSDirectories).Union(SubSubMainVSDirectories);
|
||||||
|
|
||||||
|
string attempt1 = Directories.Where(s => FindArmAsmPath(s) != "").OrderByDescending(s => File.GetCreationTime(Path.Combine(s, @"VC\bin\x86_arm\armasm.exe"))).FirstOrDefault() ?? "";
|
||||||
|
|
||||||
|
if (attempt1 != "")
|
||||||
|
return attempt1;
|
||||||
|
|
||||||
|
return Directories.Where(s => Directory.Exists(Path.Combine(s, @"VC\Tools\MSVC"))).Select(s => Path.Combine(s, @"VC\Tools\MSVC")).SelectMany(s => Directory.EnumerateDirectories(s)).Where(s => File.Exists(Path.Combine(s, @"bin\Hostx86\arm\armasm.exe"))).OrderByDescending(s => File.GetCreationTime(Path.Combine(s, @"bin\Hostx86\arm\armasm.exe"))).FirstOrDefault() ?? "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StorePaths()
|
||||||
|
{
|
||||||
|
RegistryKey Key = Registry.CurrentUser.OpenSubKey(@"Software\Patcher", true) ?? Registry.CurrentUser.CreateSubKey(@"Software\Patcher");
|
||||||
|
|
||||||
|
string VisualStudioPath = txtVisualStudioPath.Text.Trim();
|
||||||
|
if (VisualStudioPath.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("VisualStudioPath") != null)
|
||||||
|
Key.DeleteValue("VisualStudioPath");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("VisualStudioPath", VisualStudioPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
string PatchDefinitionsFilePath = txtPatchDefinitionsFile.Text.Trim();
|
||||||
|
if (PatchDefinitionsFilePath.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("PatchDefinitionsFilePath") != null)
|
||||||
|
Key.DeleteValue("PatchDefinitionsFilePath");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("PatchDefinitionsFilePath", PatchDefinitionsFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
string PatchDefinitionName = cmbPatchDefinitionName.Text.Trim();
|
||||||
|
if (PatchDefinitionName.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("PatchDefinitionName") != null)
|
||||||
|
Key.DeleteValue("PatchDefinitionName");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("PatchDefinitionName", PatchDefinitionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
string TargetVersion = cmbTargetVersion.Text.Trim();
|
||||||
|
if (TargetVersion.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("TargetVersion") != null)
|
||||||
|
Key.DeleteValue("TargetVersion");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("TargetVersion", TargetVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
string TargetFilePath = cmbTargetPath.Text.Trim();
|
||||||
|
if (TargetFilePath.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("TargetFilePath") != null)
|
||||||
|
Key.DeleteValue("TargetFilePath");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("TargetFilePath", TargetFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
string InputFilePath = txtInputFile.Text.Trim();
|
||||||
|
if (InputFilePath.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("InputFilePath") != null)
|
||||||
|
Key.DeleteValue("InputFilePath");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("InputFilePath", InputFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
string OutputFilePath = txtOutputFile.Text.Trim();
|
||||||
|
if (OutputFilePath.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("OutputFilePath") != null)
|
||||||
|
Key.DeleteValue("OutputFilePath");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("OutputFilePath", OutputFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool LoadingPatchDefinitions = false;
|
||||||
|
|
||||||
|
private void LoadPatchDefinitions()
|
||||||
|
{
|
||||||
|
if (LoadingPatchDefinitions)
|
||||||
|
return;
|
||||||
|
LoadingPatchDefinitions = true;
|
||||||
|
|
||||||
|
string PatchDefinitionName = cmbPatchDefinitionName.Text;
|
||||||
|
string TargetVersion = cmbTargetVersion.Text;
|
||||||
|
string TargetPath = cmbTargetPath.Text;
|
||||||
|
|
||||||
|
cmbPatchDefinitionName.SelectedIndex = -1;
|
||||||
|
cmbTargetVersion.SelectedIndex = -1;
|
||||||
|
cmbTargetPath.SelectedIndex = -1;
|
||||||
|
|
||||||
|
cmbPatchDefinitionName.Items.Clear();
|
||||||
|
cmbTargetVersion.Items.Clear();
|
||||||
|
cmbTargetPath.Items.Clear();
|
||||||
|
|
||||||
|
cmbPatchDefinitionName.Text = PatchDefinitionName;
|
||||||
|
cmbTargetVersion.Text = TargetVersion;
|
||||||
|
cmbTargetPath.Text = TargetPath;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string Definitions = File.ReadAllText(txtPatchDefinitionsFile.Text);
|
||||||
|
PatchEngine Engine = new(Definitions);
|
||||||
|
Engine.PatchDefinitions.Where(d => !string.IsNullOrEmpty(d.Name)).Select(d => d.Name).Distinct().ToList().ForEach(n => cmbPatchDefinitionName.Items.Add(n));
|
||||||
|
PatchDefinition Definition = null;
|
||||||
|
if (cmbPatchDefinitionName.Text.Trim().Length > 0)
|
||||||
|
Definition = Engine.PatchDefinitions.Find(d => string.Equals(d.Name, cmbPatchDefinitionName.Text.Trim(), StringComparison.CurrentCultureIgnoreCase));
|
||||||
|
if (Definition != null)
|
||||||
|
{
|
||||||
|
Definition.TargetVersions.Where(v => !string.IsNullOrEmpty(v.Description)).Select(v => v.Description).Distinct().ToList().ForEach(d => cmbTargetVersion.Items.Add(d));
|
||||||
|
TargetVersion Version = null;
|
||||||
|
if (cmbTargetVersion.Text.Trim().Length > 0)
|
||||||
|
Version = Definition.TargetVersions.Find(v => string.Equals(v.Description, cmbTargetVersion.Text.Trim(), StringComparison.CurrentCultureIgnoreCase));
|
||||||
|
if (Version != null)
|
||||||
|
{
|
||||||
|
Version.TargetFiles.Where(f => !string.IsNullOrEmpty(f.Path)).Select(f => Path.GetDirectoryName(f.Path)).Distinct().ToList().ForEach(f => cmbTargetPath.Items.Add(f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
LoadingPatchDefinitions = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdVisualStudioPath_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
FolderBrowserDialog.SelectedPath = txtVisualStudioPath.Text;
|
||||||
|
FolderBrowserDialog.Description = "Select path to Visual Studio with ARM32 SDK";
|
||||||
|
System.Windows.Forms.DialogResult Result = FolderBrowserDialog.ShowDialog();
|
||||||
|
if (Result == System.Windows.Forms.DialogResult.OK)
|
||||||
|
txtVisualStudioPath.Text = FolderBrowserDialog.SelectedPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdPatchDefinitionsFile_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
OpenFileDialog.CheckFileExists = false;
|
||||||
|
OpenFileDialog.DefaultExt = "xml";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
OpenFileDialog.FileName = Path.GetFileName(txtPatchDefinitionsFile.Text);
|
||||||
|
OpenFileDialog.InitialDirectory = Path.GetDirectoryName(txtPatchDefinitionsFile.Text);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
OpenFileDialog.Multiselect = false;
|
||||||
|
OpenFileDialog.Title = "Open patch-definitions file";
|
||||||
|
System.Windows.Forms.DialogResult Result = OpenFileDialog.ShowDialog();
|
||||||
|
if (Result == System.Windows.Forms.DialogResult.OK)
|
||||||
|
{
|
||||||
|
txtPatchDefinitionsFile.Text = OpenFileDialog.FileName;
|
||||||
|
WindowsFormsSynchronizationContext.Current.Post(s => LoadPatchDefinitions(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void txtPatchDefinitionsFile_Leave(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
WindowsFormsSynchronizationContext.Current.Post(s => LoadPatchDefinitions(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
|
||||||
|
{
|
||||||
|
StorePaths();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmbPatchDefinitionName_SelectedValueChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
WindowsFormsSynchronizationContext.Current.Post(s => LoadPatchDefinitions(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmbPatchDefinitionName_Leave(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
WindowsFormsSynchronizationContext.Current.Post(s => LoadPatchDefinitions(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmbTargetVersion_SelectedValueChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
WindowsFormsSynchronizationContext.Current.Post(s => LoadPatchDefinitions(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmbTargetVersion_Leave(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
WindowsFormsSynchronizationContext.Current.Post(s => LoadPatchDefinitions(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdInputFile_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
OpenFileDialog.CheckFileExists = true;
|
||||||
|
OpenFileDialog.DefaultExt = "";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
OpenFileDialog.FileName = Path.GetFileName(txtInputFile.Text);
|
||||||
|
OpenFileDialog.InitialDirectory = Path.GetDirectoryName(txtInputFile.Text);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
OpenFileDialog.Multiselect = false;
|
||||||
|
OpenFileDialog.Title = "Open input file";
|
||||||
|
System.Windows.Forms.DialogResult Result = OpenFileDialog.ShowDialog();
|
||||||
|
if (Result == System.Windows.Forms.DialogResult.OK)
|
||||||
|
{
|
||||||
|
txtInputFile.Text = OpenFileDialog.FileName;
|
||||||
|
txtOutputFile.Text = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdOutputFile_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
SaveFileDialog.CheckFileExists = false;
|
||||||
|
SaveFileDialog.DefaultExt = "";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SaveFileDialog.FileName = Path.GetFileName(txtInputFile.Text);
|
||||||
|
SaveFileDialog.InitialDirectory = Path.GetDirectoryName(txtOutputFile.Text);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
SaveFileDialog.Title = "Open input file";
|
||||||
|
System.Windows.Forms.DialogResult Result = SaveFileDialog.ShowDialog();
|
||||||
|
if (Result == System.Windows.Forms.DialogResult.OK)
|
||||||
|
txtOutputFile.Text = SaveFileDialog.FileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdPatch_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
string VirtualOffsetString = txtVirtualOffset.Text.Trim();
|
||||||
|
if (VirtualOffsetString.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||||
|
VirtualOffsetString = VirtualOffsetString[2..];
|
||||||
|
CodeType CodeType = Patcher.CodeType.Thumb2;
|
||||||
|
byte[] CompiledCode = null;
|
||||||
|
if (UInt32.TryParse(VirtualOffsetString, System.Globalization.NumberStyles.HexNumber, null, out uint VirtualAddress))
|
||||||
|
{
|
||||||
|
CodeType = (CodeType)Enum.Parse(typeof(Patcher.CodeType), cmbCodeType.SelectedItem.ToString());
|
||||||
|
CompiledCode = ArmCompiler.Compile(txtVisualStudioPath.Text, VirtualAddress, CodeType, txtAssemblyCode.Text);
|
||||||
|
}
|
||||||
|
if ((VirtualAddress != 0) && (CompiledCode == null))
|
||||||
|
{
|
||||||
|
txtCompiledOpcodes.Text = ArmCompiler.Output;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (CompiledCode != null)
|
||||||
|
txtCompiledOpcodes.Text = Converter.ConvertHexToString(CompiledCode, " ");
|
||||||
|
|
||||||
|
string TargetFilePath = Path.Combine(cmbTargetPath.Text, Path.GetFileName(txtInputFile.Text));
|
||||||
|
if (TargetFilePath.StartsWith(@"\"))
|
||||||
|
TargetFilePath = TargetFilePath[1..];
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
MainPatcher.AddPatch(txtInputFile.Text, (txtOutputFile.Text.Trim().Length > 0) ? txtOutputFile.Text : null, cmbPatchDefinitionName.Text, cmbTargetVersion.Text, TargetFilePath, txtVisualStudioPath.Text, VirtualAddress, CodeType, txtAssemblyCode.Text, txtPatchDefinitionsFile.Text);
|
||||||
|
}
|
||||||
|
catch (ArgumentOutOfRangeException)
|
||||||
|
{
|
||||||
|
txtCompiledOpcodes.Text = "BAD VIRTUAL OFFSET";
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
txtCompiledOpcodes.Text = "UNKNOWN ERROR";
|
||||||
|
}
|
||||||
|
|
||||||
|
txtVirtualOffset.Focus();
|
||||||
|
txtVirtualOffset.SelectAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<metadata name="FolderBrowserDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
<value>17, 17</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="OpenFileDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
<value>182, 17</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="SaveFileDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
<value>317, 17</value>
|
||||||
|
</metadata>
|
||||||
|
</root>
|
||||||
@@ -0,0 +1,189 @@
|
|||||||
|
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using WPinternals;
|
||||||
|
|
||||||
|
namespace Patcher
|
||||||
|
{
|
||||||
|
public static class MainPatcher
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// TargetFilePath is relative to the root of the PatchDefinition
|
||||||
|
/// OutputFilePath can be null
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="InputFilePath"></param>
|
||||||
|
/// <param name="OutputFilePath"></param>
|
||||||
|
/// <param name="PatchDefinitionName"></param>
|
||||||
|
/// <param name="TargetVersionDescription"></param>
|
||||||
|
/// <param name="TargetFilePath"></param>
|
||||||
|
/// <param name="PathToVisualStudioWithWP8SDK"></param>
|
||||||
|
/// <param name="VirtualAddress"></param>
|
||||||
|
/// <param name="CodeType"></param>
|
||||||
|
/// <param name="ArmCodeFragment"></param>
|
||||||
|
/// <param name="PatchDefinitionsXmlPath"></param>
|
||||||
|
public static void AddPatch(string InputFilePath, string OutputFilePath, string PatchDefinitionName, string TargetVersionDescription, string TargetFilePath, string PathToVisualStudioWithWP8SDK, UInt32 VirtualAddress, CodeType CodeType, string ArmCodeFragment, string PatchDefinitionsXmlPath)
|
||||||
|
{
|
||||||
|
SHA1Managed SHA = new();
|
||||||
|
|
||||||
|
// Compile ARM code
|
||||||
|
byte[] CompiledCode = null;
|
||||||
|
if (VirtualAddress != 0)
|
||||||
|
CompiledCode = ArmCompiler.Compile(PathToVisualStudioWithWP8SDK, VirtualAddress, CodeType, ArmCodeFragment);
|
||||||
|
|
||||||
|
// Read original binary
|
||||||
|
byte[] Binary = File.ReadAllBytes(InputFilePath);
|
||||||
|
|
||||||
|
// Backup original checksum
|
||||||
|
UInt32 ChecksumOffset = GetChecksumOffset(Binary);
|
||||||
|
UInt32 OriginalChecksum = ByteOperations.ReadUInt32(Binary, ChecksumOffset);
|
||||||
|
|
||||||
|
// Determine Raw Offset
|
||||||
|
PeFile PeFile = new(Binary);
|
||||||
|
UInt32 RawOffset = 0;
|
||||||
|
if (VirtualAddress != 0)
|
||||||
|
RawOffset = PeFile.ConvertVirtualAddressToRawOffset(VirtualAddress);
|
||||||
|
|
||||||
|
// Add or replace patch
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
PatchDefinition = new PatchDefinition
|
||||||
|
{
|
||||||
|
Name = PatchDefinitionName
|
||||||
|
};
|
||||||
|
PatchEngine.PatchDefinitions.Add(PatchDefinition);
|
||||||
|
}
|
||||||
|
TargetVersion TargetVersion = PatchDefinition.TargetVersions.Find(v => string.Equals(v.Description, TargetVersionDescription, StringComparison.CurrentCultureIgnoreCase));
|
||||||
|
if (TargetVersion == null)
|
||||||
|
{
|
||||||
|
TargetVersion = new TargetVersion
|
||||||
|
{
|
||||||
|
Description = TargetVersionDescription
|
||||||
|
};
|
||||||
|
PatchDefinition.TargetVersions.Add(TargetVersion);
|
||||||
|
}
|
||||||
|
TargetFile TargetFile = TargetVersion.TargetFiles.Find(f => (f.Path != null) && (string.Equals(f.Path.TrimStart(new char[] { '\\' }), TargetFilePath.TrimStart(new char[] { '\\' }), StringComparison.CurrentCultureIgnoreCase)));
|
||||||
|
if (TargetFile == null)
|
||||||
|
{
|
||||||
|
TargetFile = new TargetFile();
|
||||||
|
TargetVersion.TargetFiles.Add(TargetFile);
|
||||||
|
}
|
||||||
|
TargetFile.Path = TargetFilePath;
|
||||||
|
TargetFile.HashOriginal = SHA.ComputeHash(Binary);
|
||||||
|
Patch Patch;
|
||||||
|
if (VirtualAddress != 0)
|
||||||
|
{
|
||||||
|
Patch = TargetFile.Patches.Find(p => p.Address == RawOffset);
|
||||||
|
if (Patch == null)
|
||||||
|
{
|
||||||
|
Patch = new Patch
|
||||||
|
{
|
||||||
|
Address = RawOffset
|
||||||
|
};
|
||||||
|
TargetFile.Patches.Add(Patch);
|
||||||
|
}
|
||||||
|
Patch.OriginalBytes = new byte[CompiledCode.Length];
|
||||||
|
Buffer.BlockCopy(Binary, (int)RawOffset, Patch.OriginalBytes, 0, CompiledCode.Length);
|
||||||
|
Patch.PatchedBytes = CompiledCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply all patches
|
||||||
|
foreach (Patch CurrentPatch in TargetFile.Patches)
|
||||||
|
{
|
||||||
|
Buffer.BlockCopy(CurrentPatch.PatchedBytes, 0, Binary, (int)CurrentPatch.Address, CurrentPatch.PatchedBytes.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate checksum
|
||||||
|
// This also modifies the binary
|
||||||
|
// Original checksum is already backed up
|
||||||
|
UInt32 Checksum = CalculateChecksum(Binary);
|
||||||
|
|
||||||
|
// Add or replace checksum patch
|
||||||
|
Patch = TargetFile.Patches.Find(p => p.Address == ChecksumOffset);
|
||||||
|
if (Patch == null)
|
||||||
|
{
|
||||||
|
Patch = new Patch
|
||||||
|
{
|
||||||
|
Address = ChecksumOffset
|
||||||
|
};
|
||||||
|
TargetFile.Patches.Add(Patch);
|
||||||
|
}
|
||||||
|
Patch.OriginalBytes = new byte[4];
|
||||||
|
ByteOperations.WriteUInt32(Patch.OriginalBytes, 0, OriginalChecksum);
|
||||||
|
Patch.PatchedBytes = new byte[4];
|
||||||
|
ByteOperations.WriteUInt32(Patch.PatchedBytes, 0, Checksum);
|
||||||
|
|
||||||
|
// Calculate hash for patched target file
|
||||||
|
TargetFile.HashPatched = SHA.ComputeHash(Binary);
|
||||||
|
|
||||||
|
// Write patched file
|
||||||
|
if (OutputFilePath != null)
|
||||||
|
File.WriteAllBytes(OutputFilePath, Binary);
|
||||||
|
|
||||||
|
// Write PatchDefinitions
|
||||||
|
PatchEngine.WriteDefinitions(PatchDefinitionsXmlPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static UInt32 CalculateChecksum(byte[] PEFile)
|
||||||
|
{
|
||||||
|
UInt32 Checksum = 0;
|
||||||
|
UInt32 Hi;
|
||||||
|
|
||||||
|
// Clear file checksum
|
||||||
|
ByteOperations.WriteUInt32(PEFile, GetChecksumOffset(PEFile), 0);
|
||||||
|
|
||||||
|
for (UInt32 i = 0; i < ((UInt32)PEFile.Length & 0xfffffffe); i += 2)
|
||||||
|
{
|
||||||
|
Checksum += ByteOperations.ReadUInt16(PEFile, i);
|
||||||
|
Hi = Checksum >> 16;
|
||||||
|
if (Hi != 0)
|
||||||
|
{
|
||||||
|
Checksum = Hi + (Checksum & 0xFFFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((PEFile.Length % 2) != 0)
|
||||||
|
{
|
||||||
|
Checksum += (UInt32)ByteOperations.ReadUInt8(PEFile, (UInt32)PEFile.Length - 1);
|
||||||
|
Hi = Checksum >> 16;
|
||||||
|
if (Hi != 0)
|
||||||
|
{
|
||||||
|
Checksum = Hi + (Checksum & 0xFFFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Checksum += (UInt32)PEFile.Length;
|
||||||
|
|
||||||
|
// Write file checksum
|
||||||
|
ByteOperations.WriteUInt32(PEFile, GetChecksumOffset(PEFile), Checksum);
|
||||||
|
|
||||||
|
return Checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static UInt32 GetChecksumOffset(byte[] PEFile)
|
||||||
|
{
|
||||||
|
return ByteOperations.ReadUInt32(PEFile, 0x3C) + +0x58;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,819 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// This code is based on Get-ObjDump from Matthew Graeber (@mattifestation)
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace COFF
|
||||||
|
{
|
||||||
|
public enum Machine : ushort
|
||||||
|
{
|
||||||
|
UNKNOWN = 0,
|
||||||
|
/// <summary>
|
||||||
|
/// Intel 386.
|
||||||
|
/// </summary>
|
||||||
|
I386 = 0x014C,
|
||||||
|
/// <summary>
|
||||||
|
/// MIPS little-endian =0x160 big-endian
|
||||||
|
/// </summary>
|
||||||
|
R3000 = 0x0162,
|
||||||
|
/// <summary>
|
||||||
|
/// MIPS little-endian
|
||||||
|
/// </summary>
|
||||||
|
R4000 = 0x0166,
|
||||||
|
/// <summary>
|
||||||
|
/// MIPS little-endian
|
||||||
|
/// </summary>
|
||||||
|
R10000 = 0x0168,
|
||||||
|
/// <summary>
|
||||||
|
/// MIPS little-endian WCE v2
|
||||||
|
/// </summary>
|
||||||
|
WCEMIPSV2 = 0x0169,
|
||||||
|
/// <summary>
|
||||||
|
/// Alpha_AXP
|
||||||
|
/// </summary>
|
||||||
|
ALPHA = 0x0184,
|
||||||
|
/// <summary>
|
||||||
|
/// SH3 little-endian
|
||||||
|
/// </summary>
|
||||||
|
SH3 = 0x01A2,
|
||||||
|
SH3DSP = 0x01A3,
|
||||||
|
/// <summary>
|
||||||
|
/// SH3E little-endian
|
||||||
|
/// </summary>
|
||||||
|
SH3E = 0x01A4,
|
||||||
|
/// <summary>
|
||||||
|
/// SH4 little-endian
|
||||||
|
/// </summary>
|
||||||
|
SH4 = 0x01A6,
|
||||||
|
/// <summary>
|
||||||
|
/// SH5
|
||||||
|
/// </summary>
|
||||||
|
SH5 = 0x01A8,
|
||||||
|
/// <summary>
|
||||||
|
/// ARM Little-Endian
|
||||||
|
/// </summary>
|
||||||
|
ARM = 0x01C0,
|
||||||
|
THUMB = 0x01C2,
|
||||||
|
/// <summary>
|
||||||
|
/// ARM Thumb-2 Little-Endian
|
||||||
|
/// </summary>
|
||||||
|
ARMV7 = 0x01C4,
|
||||||
|
AM33 = 0x01D3,
|
||||||
|
/// <summary>
|
||||||
|
/// IBM PowerPC Little-Endian
|
||||||
|
/// </summary>
|
||||||
|
POWERPC = 0x01F0,
|
||||||
|
POWERPCFP = 0x01F1,
|
||||||
|
/// <summary>
|
||||||
|
/// Intel 64
|
||||||
|
/// </summary>
|
||||||
|
IA64 = 0x0200,
|
||||||
|
/// <summary>
|
||||||
|
/// MIPS
|
||||||
|
/// </summary>
|
||||||
|
MIPS16 = 0x0266,
|
||||||
|
/// <summary>
|
||||||
|
/// ALPHA64
|
||||||
|
/// </summary>
|
||||||
|
ALPHA64 = 0x0284,
|
||||||
|
/// <summary>
|
||||||
|
/// MIPS
|
||||||
|
/// </summary>
|
||||||
|
MIPSFPU = 0x0366,
|
||||||
|
/// <summary>
|
||||||
|
/// MIPS
|
||||||
|
/// </summary>
|
||||||
|
MIPSFPU16 = 0x0466,
|
||||||
|
AXP64 = ALPHA64,
|
||||||
|
/// <summary>
|
||||||
|
/// Infineon
|
||||||
|
/// </summary>
|
||||||
|
TRICORE = 0x0520,
|
||||||
|
CEF = 0x0CEF,
|
||||||
|
/// <summary>
|
||||||
|
/// EFI public byte Code
|
||||||
|
/// </summary>
|
||||||
|
EBC = 0x0EBC,
|
||||||
|
/// <summary>
|
||||||
|
/// AMD64 (K8)
|
||||||
|
/// </summary>
|
||||||
|
AMD64 = 0x8664,
|
||||||
|
/// <summary>
|
||||||
|
/// M32R little-endian
|
||||||
|
/// </summary>
|
||||||
|
M32R = 0x9041,
|
||||||
|
/// <summary>
|
||||||
|
/// ARMv8 in 64-bit mode
|
||||||
|
/// </summary>
|
||||||
|
ARM64 = 0xAA64,
|
||||||
|
CEE = 0xC0EE
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum CoffHeaderCharacteristics : ushort
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Relocation info stripped from file.
|
||||||
|
/// </summary>
|
||||||
|
RELOCS_STRIPPED = 0x0001,
|
||||||
|
/// <summary>
|
||||||
|
/// File is executable (i.e. no unresolved external references).
|
||||||
|
/// </summary>
|
||||||
|
EXECUTABLE_IMAGE = 0x0002,
|
||||||
|
/// <summary>
|
||||||
|
/// Line nunbers stripped from file.
|
||||||
|
/// </summary>
|
||||||
|
LINE_NUMS_STRIPPED = 0x0004,
|
||||||
|
/// <summary>
|
||||||
|
/// Local symbols stripped from file.
|
||||||
|
/// </summary>
|
||||||
|
LOCAL_SYMS_STRIPPED = 0x0008,
|
||||||
|
/// <summary>
|
||||||
|
/// Agressively trim working set
|
||||||
|
/// </summary>
|
||||||
|
AGGRESIVE_WS_TRIM = 0x0010,
|
||||||
|
/// <summary>
|
||||||
|
/// App can handle >2gb addresses
|
||||||
|
/// </summary>
|
||||||
|
LARGE_ADDRESS_AWARE = 0x0020,
|
||||||
|
/// <summary>
|
||||||
|
/// public bytes of machine public ushort are reversed.
|
||||||
|
/// </summary>
|
||||||
|
REVERSED_LO = 0x0080,
|
||||||
|
/// <summary>
|
||||||
|
/// 32 bit public ushort machine.
|
||||||
|
/// </summary>
|
||||||
|
BIT32_MACHINE = 0x0100,
|
||||||
|
/// <summary>
|
||||||
|
/// Debugging info stripped from file in .DBG file
|
||||||
|
/// </summary>
|
||||||
|
DEBUG_STRIPPED = 0x0200,
|
||||||
|
/// <summary>
|
||||||
|
/// If Image is on removable media =copy and run from the swap file.
|
||||||
|
/// </summary>
|
||||||
|
REMOVABLE_RUN_FROM_SWAP = 0x0400,
|
||||||
|
/// <summary>
|
||||||
|
/// If Image is on Net =copy and run from the swap file.
|
||||||
|
/// </summary>
|
||||||
|
NET_RUN_FROM_SWAP = 0x0800,
|
||||||
|
/// <summary>
|
||||||
|
/// System File.
|
||||||
|
/// </summary>
|
||||||
|
SYSTEM = 0x1000,
|
||||||
|
/// <summary>
|
||||||
|
/// File is a DLL.
|
||||||
|
/// </summary>
|
||||||
|
DLL = 0x2000,
|
||||||
|
/// <summary>
|
||||||
|
/// File should only be run on a UP machine
|
||||||
|
/// </summary>
|
||||||
|
UP_SYSTEM_ONLY = 0x4000,
|
||||||
|
/// <summary>
|
||||||
|
/// public bytes of machine public ushort are reversed.
|
||||||
|
/// </summary>
|
||||||
|
REVERSED_HI = 0x8000
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HEADER
|
||||||
|
{
|
||||||
|
public Machine Machine;
|
||||||
|
public ushort NumberOfSections;
|
||||||
|
public DateTime TimeDateStamp;
|
||||||
|
public uint PointerToSymbolTable;
|
||||||
|
public uint NumberOfSymbols;
|
||||||
|
public ushort SizeOfOptionalHeader;
|
||||||
|
public CoffHeaderCharacteristics Characteristics;
|
||||||
|
|
||||||
|
public HEADER(BinaryReader br)
|
||||||
|
{
|
||||||
|
this.Machine = (Machine)br.ReadUInt16();
|
||||||
|
this.NumberOfSections = br.ReadUInt16();
|
||||||
|
this.TimeDateStamp = new DateTime(1970, 1, 1, 0, 0, 0).AddSeconds(br.ReadUInt32());
|
||||||
|
this.PointerToSymbolTable = br.ReadUInt32();
|
||||||
|
this.NumberOfSymbols = br.ReadUInt32();
|
||||||
|
this.SizeOfOptionalHeader = br.ReadUInt16();
|
||||||
|
this.Characteristics = (CoffHeaderCharacteristics)br.ReadUInt16();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum SectionHeaderCharacteristics : uint
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Reserved.
|
||||||
|
/// </summary>
|
||||||
|
TYPE_NO_PAD = 0x00000008,
|
||||||
|
/// <summary>
|
||||||
|
/// Section contains code.
|
||||||
|
/// </summary>
|
||||||
|
CNT_CODE = 0x00000020,
|
||||||
|
/// <summary>
|
||||||
|
/// Section contains initialized data.
|
||||||
|
/// </summary>
|
||||||
|
CNT_INITIALIZED_DATA = 0x00000040,
|
||||||
|
/// <summary>
|
||||||
|
/// Section contains uninitialized data.
|
||||||
|
/// </summary>
|
||||||
|
CNT_UNINITIALIZED_DATA = 0x00000080,
|
||||||
|
/// <summary>
|
||||||
|
/// Section contains comments or some other type of information.
|
||||||
|
/// </summary>
|
||||||
|
LNK_INFO = 0x00000200,
|
||||||
|
/// <summary>
|
||||||
|
/// Section contents will not become part of image.
|
||||||
|
/// </summary>
|
||||||
|
LNK_REMOVE = 0x00000800,
|
||||||
|
/// <summary>
|
||||||
|
/// Section contents comdat.
|
||||||
|
/// </summary>
|
||||||
|
LNK_COMDAT = 0x00001000,
|
||||||
|
/// <summary>
|
||||||
|
/// Reset speculative exceptions handling bits in the TLB entries for this section.
|
||||||
|
/// </summary>
|
||||||
|
NO_DEFER_SPEC_EXC = 0x00004000,
|
||||||
|
/// <summary>
|
||||||
|
/// Section content can be accessed relative to GP
|
||||||
|
/// </summary>
|
||||||
|
GPREL = 0x00008000,
|
||||||
|
MEM_FARDATA = 0x00008000,
|
||||||
|
MEM_PURGEABLE = 0x00020000,
|
||||||
|
MEM_16BIT = 0x00020000,
|
||||||
|
MEM_LOCKED = 0x00040000,
|
||||||
|
MEM_PRELOAD = 0x00080000,
|
||||||
|
ALIGN_1BYTES = 0x00100000,
|
||||||
|
ALIGN_2BYTES = 0x00200000,
|
||||||
|
ALIGN_4BYTES = 0x00300000,
|
||||||
|
ALIGN_8BYTES = 0x00400000,
|
||||||
|
/// <summary>
|
||||||
|
/// Default alignment if no others are specified.
|
||||||
|
/// </summary>
|
||||||
|
ALIGN_16BYTES = 0x00500000,
|
||||||
|
ALIGN_32BYTES = 0x00600000,
|
||||||
|
ALIGN_64BYTES = 0x00700000,
|
||||||
|
ALIGN_128BYTES = 0x00800000,
|
||||||
|
ALIGN_256BYTES = 0x00900000,
|
||||||
|
ALIGN_512BYTES = 0x00A00000,
|
||||||
|
ALIGN_1024BYTES = 0x00B00000,
|
||||||
|
ALIGN_2048BYTES = 0x00C00000,
|
||||||
|
ALIGN_4096BYTES = 0x00D00000,
|
||||||
|
ALIGN_8192BYTES = 0x00E00000,
|
||||||
|
ALIGN_MASK = 0x00F00000,
|
||||||
|
/// <summary>
|
||||||
|
/// Section contains extended relocations.
|
||||||
|
/// </summary>
|
||||||
|
LNK_NRELOC_OVFL = 0x01000000,
|
||||||
|
/// <summary>
|
||||||
|
/// Section can be discarded.
|
||||||
|
/// </summary>
|
||||||
|
MEM_DISCARDABLE = 0x02000000,
|
||||||
|
/// <summary>
|
||||||
|
/// Section is not cachable.
|
||||||
|
/// </summary>
|
||||||
|
MEM_NOT_CACHED = 0x04000000,
|
||||||
|
/// <summary>
|
||||||
|
/// Section is not pageable.
|
||||||
|
/// </summary>
|
||||||
|
MEM_NOT_PAGED = 0x08000000,
|
||||||
|
/// <summary>
|
||||||
|
/// Section is shareable.
|
||||||
|
/// </summary>
|
||||||
|
MEM_SHARED = 0x10000000,
|
||||||
|
/// <summary>
|
||||||
|
/// Section is executable.
|
||||||
|
/// </summary>
|
||||||
|
MEM_EXECUTE = 0x20000000,
|
||||||
|
/// <summary>
|
||||||
|
/// Section is readable.
|
||||||
|
/// </summary>
|
||||||
|
MEM_READ = 0x40000000,
|
||||||
|
/// <summary>
|
||||||
|
/// Section is writeable.
|
||||||
|
/// </summary>
|
||||||
|
MEM_WRITE = 0x80000000
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum AMD64RelocationType : ushort
|
||||||
|
{
|
||||||
|
ABSOLUTE,
|
||||||
|
ADDR64,
|
||||||
|
ADDR32,
|
||||||
|
ADDR32NB,
|
||||||
|
REL32,
|
||||||
|
REL32_1,
|
||||||
|
REL32_2,
|
||||||
|
REL32_3,
|
||||||
|
REL32_4,
|
||||||
|
REL32_5,
|
||||||
|
SECTION,
|
||||||
|
SECREL,
|
||||||
|
SECREL7,
|
||||||
|
TOKEN,
|
||||||
|
SREL32,
|
||||||
|
PAIR,
|
||||||
|
SSPAN32
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ARMRelocationType : ushort
|
||||||
|
{
|
||||||
|
ABSOLUTE,
|
||||||
|
ADDR32,
|
||||||
|
ADDR32NB,
|
||||||
|
BRANCH24,
|
||||||
|
BRANCH11,
|
||||||
|
TOKEN,
|
||||||
|
BLX24 = 0x08,
|
||||||
|
BLX11 = 0x09,
|
||||||
|
SECTION = 0x0E,
|
||||||
|
SECREL = 0x0F,
|
||||||
|
MOV32A = 0x10,
|
||||||
|
MOV32T = 0x11,
|
||||||
|
BRANCH20T = 0x12,
|
||||||
|
BRANCH24T = 0x14,
|
||||||
|
BLX23T = 0x15
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ARMv8RelocationType : ushort
|
||||||
|
{
|
||||||
|
ABSOLUTE,
|
||||||
|
ADDR32,
|
||||||
|
ADDR32NB,
|
||||||
|
BRANCH26,
|
||||||
|
PAGEBASE_REL21,
|
||||||
|
REL21,
|
||||||
|
PAGEOFFSET_12A,
|
||||||
|
PAGEOFFSET_12L,
|
||||||
|
SECREL,
|
||||||
|
SECREL_LOW12A,
|
||||||
|
SECREL_HIGH12A,
|
||||||
|
SECREL_LOW12L,
|
||||||
|
TOKEN,
|
||||||
|
SECTION,
|
||||||
|
ADDR64
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum X86RelocationType : ushort
|
||||||
|
{
|
||||||
|
ABSOLUTE,
|
||||||
|
DIR16,
|
||||||
|
DIR32 = 0x06,
|
||||||
|
DIR32NB = 0x07,
|
||||||
|
SEG12 = 0x09,
|
||||||
|
SECTION = 0x0A,
|
||||||
|
SECREL = 0x0B,
|
||||||
|
TOKEN = 0x0C,
|
||||||
|
SECREL7 = 0x0D,
|
||||||
|
REL32 = 0x14
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RelocationEntry
|
||||||
|
{
|
||||||
|
public uint VirtualAddress;
|
||||||
|
public uint SymbolTableIndex;
|
||||||
|
public Enum Type;
|
||||||
|
public string Name;
|
||||||
|
|
||||||
|
public RelocationEntry(BinaryReader br)
|
||||||
|
{
|
||||||
|
this.VirtualAddress = br.ReadUInt32();
|
||||||
|
this.SymbolTableIndex = br.ReadUInt32();
|
||||||
|
// Default to X86RelocationType. This will be changed once the processor type is determined
|
||||||
|
this.Type = (X86RelocationType)br.ReadUInt16();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SECTION_HEADER
|
||||||
|
{
|
||||||
|
public string Name;
|
||||||
|
public uint PhysicalAddress;
|
||||||
|
public uint VirtualSize;
|
||||||
|
public uint VirtualAddress;
|
||||||
|
public uint SizeOfRawData;
|
||||||
|
public uint PointerToRawData;
|
||||||
|
public uint PointerToRelocations;
|
||||||
|
public uint PointerToLinenumbers;
|
||||||
|
public ushort NumberOfRelocations;
|
||||||
|
public ushort NumberOfLinenumbers;
|
||||||
|
public SectionHeaderCharacteristics Characteristics;
|
||||||
|
public Byte[] RawData;
|
||||||
|
public RelocationEntry[] Relocations;
|
||||||
|
|
||||||
|
public SECTION_HEADER(BinaryReader br)
|
||||||
|
{
|
||||||
|
this.Name = Encoding.UTF8.GetString(br.ReadBytes(8)).Split((Char)0)[0];
|
||||||
|
this.PhysicalAddress = br.ReadUInt32();
|
||||||
|
this.VirtualSize = this.PhysicalAddress;
|
||||||
|
this.VirtualAddress = br.ReadUInt32();
|
||||||
|
this.SizeOfRawData = br.ReadUInt32();
|
||||||
|
this.PointerToRawData = br.ReadUInt32();
|
||||||
|
this.PointerToRelocations = br.ReadUInt32();
|
||||||
|
this.PointerToLinenumbers = br.ReadUInt32();
|
||||||
|
this.NumberOfRelocations = br.ReadUInt16();
|
||||||
|
this.NumberOfLinenumbers = br.ReadUInt16();
|
||||||
|
this.Characteristics = (SectionHeaderCharacteristics)br.ReadUInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum SectionNumber : short
|
||||||
|
{
|
||||||
|
UNDEFINED,
|
||||||
|
ABSOLUTE = -1,
|
||||||
|
DEBUG = -2
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum TypeClass : short
|
||||||
|
{
|
||||||
|
TYPE_NULL,
|
||||||
|
TYPE_VOID,
|
||||||
|
TYPE_CHAR,
|
||||||
|
TYPE_SHORT,
|
||||||
|
TYPE_INT,
|
||||||
|
TYPE_LONG,
|
||||||
|
TYPE_FLOAT,
|
||||||
|
TYPE_DOUBLE,
|
||||||
|
TYPE_STRUCT,
|
||||||
|
TYPE_UNION,
|
||||||
|
TYPE_ENUM,
|
||||||
|
TYPE_MOE,
|
||||||
|
TYPE_BYTE,
|
||||||
|
TYPE_WORD,
|
||||||
|
TYPE_UINT,
|
||||||
|
TYPE_DWORD,
|
||||||
|
DTYPE_POINTER = 0x100,
|
||||||
|
DTYPE_FUNCTION = 0x200,
|
||||||
|
DTYPE_ARRAY = 0x300,
|
||||||
|
/// <summary>
|
||||||
|
/// Technically, this is defined as 0 in the MSB
|
||||||
|
/// </summary>
|
||||||
|
DTYPE_NULL = 0x400
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum StorageClass : byte
|
||||||
|
{
|
||||||
|
NULL,
|
||||||
|
AUTOMATIC,
|
||||||
|
EXTERNAL,
|
||||||
|
STATIC,
|
||||||
|
REGISTER,
|
||||||
|
EXTERNAL_DEF,
|
||||||
|
LABEL,
|
||||||
|
UNDEFINED_LABEL,
|
||||||
|
MEMBER_OF_STRUCT,
|
||||||
|
ARGUMENT,
|
||||||
|
STRUCT_TAG,
|
||||||
|
MEMBER_OF_UNION,
|
||||||
|
UNION_TAG,
|
||||||
|
TYPE_DEFINITION,
|
||||||
|
ENUM_TAG,
|
||||||
|
MEMBER_OF_ENUM,
|
||||||
|
REGISTER_PARAM,
|
||||||
|
BIT_FIELD,
|
||||||
|
BLOCK = 0x64,
|
||||||
|
FUNCTION = 0x65,
|
||||||
|
END_OF_STRUCT = 0x66,
|
||||||
|
FILE = 0x67,
|
||||||
|
SECTION = 0x68,
|
||||||
|
WEAK_EXTERNAL = 0x69,
|
||||||
|
CLR_TOKEN = 0x6B,
|
||||||
|
END_OF_FUNCTION = 0xFF
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SYMBOL_TABLE
|
||||||
|
{
|
||||||
|
public string Name;
|
||||||
|
public uint Value;
|
||||||
|
public SectionNumber SectionNumber;
|
||||||
|
public TypeClass Type;
|
||||||
|
public StorageClass StorageClass;
|
||||||
|
public byte NumberOfAuxSymbols;
|
||||||
|
public Object AuxSymbols;
|
||||||
|
private readonly Byte[] NameArray;
|
||||||
|
|
||||||
|
public SYMBOL_TABLE(BinaryReader br)
|
||||||
|
{
|
||||||
|
this.NameArray = br.ReadBytes(8);
|
||||||
|
|
||||||
|
if (this.NameArray[0] == 0 && this.NameArray[1] == 0 && this.NameArray[2] == 0 && this.NameArray[3] == 0)
|
||||||
|
{
|
||||||
|
// Per specification, if the high DWORD is 0, then then low DWORD is an index into the string table
|
||||||
|
this.Name = "/" + BitConverter.ToInt32(NameArray, 4).ToString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.Name = Encoding.UTF8.GetString(NameArray).Trim((char)0);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Value = br.ReadUInt32();
|
||||||
|
this.SectionNumber = (SectionNumber)br.ReadInt16();
|
||||||
|
this.Type = (TypeClass)br.ReadInt16();
|
||||||
|
if ((((int)this.Type) & 0xff00) == 0) { this.Type = (TypeClass)Enum.Parse(typeof(TypeClass), ((int)this.Type | 0x400).ToString()); }
|
||||||
|
this.StorageClass = (StorageClass)br.ReadByte();
|
||||||
|
this.NumberOfAuxSymbols = br.ReadByte();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SECTION_DEFINITION
|
||||||
|
{
|
||||||
|
public uint Length;
|
||||||
|
public ushort NumberOfRelocations;
|
||||||
|
public ushort NumberOfLinenumbers;
|
||||||
|
public uint CheckSum;
|
||||||
|
public ushort Number;
|
||||||
|
public byte Selection;
|
||||||
|
|
||||||
|
public SECTION_DEFINITION(BinaryReader br)
|
||||||
|
{
|
||||||
|
this.Length = br.ReadUInt32();
|
||||||
|
this.NumberOfRelocations = br.ReadUInt16();
|
||||||
|
this.NumberOfLinenumbers = br.ReadUInt16();
|
||||||
|
this.CheckSum = br.ReadUInt32();
|
||||||
|
this.Number = br.ReadUInt16();
|
||||||
|
this.Selection = br.ReadByte();
|
||||||
|
br.ReadBytes(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ParsedObjectFile
|
||||||
|
{
|
||||||
|
public HEADER CoffHeader;
|
||||||
|
public SECTION_HEADER[] SectionHeaders;
|
||||||
|
public SYMBOL_TABLE[] SymbolTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ObjectFileParser
|
||||||
|
{
|
||||||
|
public static ParsedObjectFile ParseObjectFile(string ObjectFilePath)
|
||||||
|
{
|
||||||
|
ParsedObjectFile Result = null;
|
||||||
|
|
||||||
|
// Fixed structure sizes
|
||||||
|
const int SizeofCOFFFileHeader = 20;
|
||||||
|
const int SizeofSectionHeader = 40;
|
||||||
|
const int SizeofSymbolTableEntry = 18;
|
||||||
|
const int SizeofRelocationEntry = 10;
|
||||||
|
|
||||||
|
// Open the object file for reading
|
||||||
|
using (FileStream FileStream = System.IO.File.OpenRead(ObjectFilePath))
|
||||||
|
{
|
||||||
|
long FileLength = FileStream.Length;
|
||||||
|
|
||||||
|
if (FileLength < SizeofCOFFFileHeader)
|
||||||
|
{
|
||||||
|
// You cannot parse the COFF header if the file is not big enough to contain a COFF header.
|
||||||
|
throw new Exception("ObjectFile is too small to store a COFF header.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open a BinaryReader object for the object file
|
||||||
|
using BinaryReader BinaryReader = new(FileStream);
|
||||||
|
// Parse the COFF header
|
||||||
|
COFF.HEADER CoffHeader = new(BinaryReader);
|
||||||
|
|
||||||
|
if (CoffHeader.SizeOfOptionalHeader != 0)
|
||||||
|
{
|
||||||
|
// Per the PECOFF specification, an object file does not have an optional header
|
||||||
|
throw new Exception("Coff header indicates the existence of an optional header. An object file cannot have an optional header.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CoffHeader.PointerToSymbolTable == 0)
|
||||||
|
{
|
||||||
|
throw new Exception("An object file is supposed to have a symbol table.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FileLength < ((CoffHeader.NumberOfSections * SizeofSectionHeader) + SizeofCOFFFileHeader))
|
||||||
|
{
|
||||||
|
// The object file isn't big enough to store the number of sections present.
|
||||||
|
throw new Exception("ObjectFile is too small to store section header data.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// A string collection used to store section header names. This collection is referenced while
|
||||||
|
// parsing the symbol table entries whose name is the same as the section header. In this case,
|
||||||
|
// the symbol entry will have a particular auxiliary symbol table entry.
|
||||||
|
System.Collections.Specialized.StringCollection SectionHeaderNames = new();
|
||||||
|
|
||||||
|
// Correlate the processor type to the relocation type. There are more relocation type defined
|
||||||
|
// in the PECOFF specification, but I don't expect those to be present. In that case, relocation
|
||||||
|
// entries default to X86RelocationType.
|
||||||
|
COFF.SECTION_HEADER[] SectionHeaders = new COFF.SECTION_HEADER[CoffHeader.NumberOfSections];
|
||||||
|
|
||||||
|
// Parse section headers
|
||||||
|
for (int i = 0; i < CoffHeader.NumberOfSections; i++)
|
||||||
|
{
|
||||||
|
SectionHeaders[i] = new COFF.SECTION_HEADER(BinaryReader);
|
||||||
|
|
||||||
|
// Add the section name to the string collection. This will be referenced during symbol table parsing.
|
||||||
|
SectionHeaderNames.Add(SectionHeaders[i].Name);
|
||||||
|
|
||||||
|
// Save the current filestream position. We are about to jump out of place.
|
||||||
|
long SavedFilePosition = FileStream.Position;
|
||||||
|
|
||||||
|
// Check to see if the raw data points beyond the actual file size
|
||||||
|
if ((SectionHeaders[i].PointerToRawData + SectionHeaders[i].SizeOfRawData) > FileLength)
|
||||||
|
{
|
||||||
|
throw new Exception("Section header's raw data exceeds the size of the object file.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Read the raw data into a byte array
|
||||||
|
FileStream.Seek(SectionHeaders[i].PointerToRawData, SeekOrigin.Begin);
|
||||||
|
SectionHeaders[i].RawData = BinaryReader.ReadBytes((int)SectionHeaders[i].SizeOfRawData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check to see if the section has a relocation table
|
||||||
|
if ((SectionHeaders[i].PointerToRelocations != 0) && (SectionHeaders[i].NumberOfRelocations != 0))
|
||||||
|
{
|
||||||
|
// Check to see if the relocation entries point beyond the actual file size
|
||||||
|
if ((SectionHeaders[i].PointerToRelocations + (SizeofRelocationEntry * SectionHeaders[i].NumberOfRelocations)) > FileLength)
|
||||||
|
{
|
||||||
|
throw new Exception("(SectionHeaders[i].Name) section header's relocation entries exceeds the soze of the object file.");
|
||||||
|
}
|
||||||
|
|
||||||
|
FileStream.Seek(SectionHeaders[i].PointerToRelocations, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
COFF.RelocationEntry[] Relocations = new COFF.RelocationEntry[SectionHeaders[i].NumberOfRelocations];
|
||||||
|
|
||||||
|
for (int j = 0; j < SectionHeaders[i].NumberOfRelocations; j++)
|
||||||
|
{
|
||||||
|
Relocations[j] = new COFF.RelocationEntry(BinaryReader);
|
||||||
|
// Cast the relocation as its respective type
|
||||||
|
switch (CoffHeader.Machine)
|
||||||
|
{
|
||||||
|
case Machine.I386:
|
||||||
|
Relocations[j].Type = (COFF.X86RelocationType)Relocations[j].Type;
|
||||||
|
break;
|
||||||
|
case Machine.AMD64:
|
||||||
|
Relocations[j].Type = (COFF.AMD64RelocationType)Relocations[j].Type;
|
||||||
|
break;
|
||||||
|
case Machine.ARMV7:
|
||||||
|
Relocations[j].Type = (COFF.ARMRelocationType)Relocations[j].Type;
|
||||||
|
break;
|
||||||
|
case Machine.ARM64:
|
||||||
|
Relocations[j].Type = (COFF.ARMv8RelocationType)Relocations[j].Type;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the relocation table entry to the section header
|
||||||
|
SectionHeaders[i].Relocations = Relocations;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore the original filestream pointer
|
||||||
|
FileStream.Seek(SavedFilePosition, SeekOrigin.Begin);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the contents of the COFF string table
|
||||||
|
long SymTableSize = CoffHeader.NumberOfSymbols * SizeofSymbolTableEntry;
|
||||||
|
long StringTableOffset = CoffHeader.PointerToSymbolTable + SymTableSize;
|
||||||
|
|
||||||
|
if (StringTableOffset > FileLength)
|
||||||
|
{
|
||||||
|
throw new Exception("The string table points beyond the end of the file.");
|
||||||
|
}
|
||||||
|
|
||||||
|
FileStream.Seek(StringTableOffset, SeekOrigin.Begin);
|
||||||
|
UInt32 StringTableLength = BinaryReader.ReadUInt32();
|
||||||
|
|
||||||
|
if (StringTableLength > FileLength)
|
||||||
|
{
|
||||||
|
throw new Exception("The string table's length exceeds the length of the file.");
|
||||||
|
}
|
||||||
|
|
||||||
|
string StringTable = System.Text.Encoding.UTF8.GetString(BinaryReader.ReadBytes((int)StringTableLength));
|
||||||
|
|
||||||
|
COFF.SYMBOL_TABLE[] RawSymbolTable = new COFF.SYMBOL_TABLE[CoffHeader.NumberOfSymbols];
|
||||||
|
|
||||||
|
// Retrieve the symbol table
|
||||||
|
if (FileLength < StringTableOffset)
|
||||||
|
{
|
||||||
|
throw new Exception("Symbol table is larger than the file size.");
|
||||||
|
}
|
||||||
|
|
||||||
|
FileStream.Seek(CoffHeader.PointerToSymbolTable, SeekOrigin.Begin);
|
||||||
|
int NumberofRegularSymbols = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Go through each symbol table looking for auxiliary symbols to parse
|
||||||
|
|
||||||
|
Currently supported auxiliary symbol table entry formats:
|
||||||
|
1) .file
|
||||||
|
2) Entry names that match the name of a section header
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (int i = 0; i < CoffHeader.NumberOfSymbols; i++)
|
||||||
|
{
|
||||||
|
// Parse the symbol tables regardless of whether they are normal or auxiliary symbols
|
||||||
|
RawSymbolTable[i] = new COFF.SYMBOL_TABLE(BinaryReader);
|
||||||
|
|
||||||
|
if (RawSymbolTable[i].NumberOfAuxSymbols == 0)
|
||||||
|
{
|
||||||
|
// This symbol table entry has no auxiliary symbols
|
||||||
|
NumberofRegularSymbols++;
|
||||||
|
}
|
||||||
|
else if (RawSymbolTable[i].Name == ".file")
|
||||||
|
{
|
||||||
|
long TempPosition = FileStream.Position; // Save filestream position
|
||||||
|
// Retrieve the file name
|
||||||
|
RawSymbolTable[i].AuxSymbols = System.Text.Encoding.UTF8.GetString(BinaryReader.ReadBytes(RawSymbolTable[i].NumberOfAuxSymbols * SizeofSymbolTableEntry)).TrimEnd((Char)0);
|
||||||
|
FileStream.Seek(TempPosition, SeekOrigin.Begin); // Restore filestream position
|
||||||
|
}
|
||||||
|
else if (SectionHeaderNames.Contains(RawSymbolTable[i].Name))
|
||||||
|
{
|
||||||
|
long TempPosition = FileStream.Position; // Save filestream position
|
||||||
|
RawSymbolTable[i].AuxSymbols = new COFF.SECTION_DEFINITION(BinaryReader);
|
||||||
|
FileStream.Seek(TempPosition, SeekOrigin.Begin); // Restore filestream position
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an array of symbol table entries without auxiliary table entries
|
||||||
|
COFF.SYMBOL_TABLE[] SymbolTable = new COFF.SYMBOL_TABLE[NumberofRegularSymbols];
|
||||||
|
int k = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < CoffHeader.NumberOfSymbols; i++)
|
||||||
|
{
|
||||||
|
SymbolTable[k] = RawSymbolTable[i]; // FYI, the first symbol table entry will never be an aux symbol
|
||||||
|
k++;
|
||||||
|
|
||||||
|
// Skip over the auxiliary symbols
|
||||||
|
if (RawSymbolTable[i].NumberOfAuxSymbols != 0)
|
||||||
|
{
|
||||||
|
i += RawSymbolTable[i].NumberOfAuxSymbols;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix the section names if any of them point to the COFF string table
|
||||||
|
for (int i = 0; i < CoffHeader.NumberOfSections; i++)
|
||||||
|
{
|
||||||
|
if (SectionHeaders[i].Name?.IndexOf('/') == 0)
|
||||||
|
{
|
||||||
|
string StringTableIndexString = SectionHeaders[i].Name[1..];
|
||||||
|
|
||||||
|
if (int.TryParse(StringTableIndexString, out int StringTableIndex))
|
||||||
|
{
|
||||||
|
StringTableIndex -= 4;
|
||||||
|
|
||||||
|
if (StringTableIndex > (StringTableLength + 4))
|
||||||
|
{
|
||||||
|
throw new Exception("String table entry exceeds the bounds of the object file.");
|
||||||
|
}
|
||||||
|
|
||||||
|
int Length = StringTable.IndexOf((Char)0, StringTableIndex);
|
||||||
|
SectionHeaders[i].Name = StringTable.Substring(StringTableIndex, Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix the symbol table names
|
||||||
|
for (int i = 0; i < SymbolTable.Length; i++)
|
||||||
|
{
|
||||||
|
if (SymbolTable[i].Name?.IndexOf('/') == 0)
|
||||||
|
{
|
||||||
|
string StringTableIndexString = SymbolTable[i].Name[1..];
|
||||||
|
|
||||||
|
if (int.TryParse(StringTableIndexString, out int StringTableIndex))
|
||||||
|
{
|
||||||
|
StringTableIndex -= 4;
|
||||||
|
int Length = StringTable.IndexOf((Char)0, StringTableIndex) - StringTableIndex;
|
||||||
|
SymbolTable[i].Name = StringTable.Substring(StringTableIndex, Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply symbol names to the relocation entries
|
||||||
|
// SectionHeaders | Where-Object { _.Relocations } | % {
|
||||||
|
// _.Relocations | % { _.Name = RawSymbolTable[_.SymbolTableIndex].Name }
|
||||||
|
// }
|
||||||
|
SectionHeaders.Where(h => h.Relocations != null).ToList().ForEach(h => h.Relocations.ToList().ForEach(r => r.Name = RawSymbolTable[r.SymbolTableIndex].Name));
|
||||||
|
|
||||||
|
Result = new ParsedObjectFile
|
||||||
|
{
|
||||||
|
CoffHeader = CoffHeader,
|
||||||
|
SectionHeaders = SectionHeaders,
|
||||||
|
SymbolTable = SymbolTable
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,261 @@
|
|||||||
|
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Xml;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace WPinternals
|
||||||
|
{
|
||||||
|
internal class PatchEngine
|
||||||
|
{
|
||||||
|
internal List<PatchDefinition> PatchDefinitions = new();
|
||||||
|
internal readonly List<TargetRedirection> TargetRedirections = new();
|
||||||
|
|
||||||
|
internal PatchEngine() { }
|
||||||
|
|
||||||
|
internal PatchEngine(string PatchDefinitionsXmlString)
|
||||||
|
{
|
||||||
|
XmlSerializer x = new(PatchDefinitions.GetType(), null, Array.Empty<Type>(), new XmlRootAttribute("PatchDefinitions"), "");
|
||||||
|
MemoryStream s = new(System.Text.Encoding.ASCII.GetBytes(PatchDefinitionsXmlString));
|
||||||
|
PatchDefinitions = (List<PatchDefinition>)x.Deserialize(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void WriteDefinitions(string FilePath)
|
||||||
|
{
|
||||||
|
XmlSerializer x = new(PatchDefinitions.GetType(), null, Array.Empty<Type>(), new XmlRootAttribute("PatchDefinitions"), "");
|
||||||
|
|
||||||
|
XmlSerializerNamespaces ns = new();
|
||||||
|
ns.Add("", "");
|
||||||
|
|
||||||
|
System.IO.StreamWriter FileWriter = new(FilePath);
|
||||||
|
XmlWriter XmlWriter = XmlWriter.Create(FileWriter, new XmlWriterSettings() { OmitXmlDeclaration = true, Indent = true, NewLineHandling = NewLineHandling.Entitize });
|
||||||
|
|
||||||
|
FileWriter.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
|
||||||
|
FileWriter.WriteLine("");
|
||||||
|
FileWriter.WriteLine("<!--");
|
||||||
|
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\"),");
|
||||||
|
FileWriter.WriteLine("to deal in the Software without restriction, including without limitation");
|
||||||
|
FileWriter.WriteLine("the rights to use, copy, modify, merge, publish, distribute, sublicense,");
|
||||||
|
FileWriter.WriteLine("and / or sell copies of the Software, and to permit persons to whom the");
|
||||||
|
FileWriter.WriteLine("Software is furnished to do so, subject to the following conditions:");
|
||||||
|
FileWriter.WriteLine("");
|
||||||
|
FileWriter.WriteLine("The above copyright notice and this permission notice shall be included in");
|
||||||
|
FileWriter.WriteLine("all copies or substantial portions of the Software.");
|
||||||
|
FileWriter.WriteLine("");
|
||||||
|
FileWriter.WriteLine("THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR");
|
||||||
|
FileWriter.WriteLine("IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,");
|
||||||
|
FileWriter.WriteLine("FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE");
|
||||||
|
FileWriter.WriteLine("AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER");
|
||||||
|
FileWriter.WriteLine("LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING");
|
||||||
|
FileWriter.WriteLine("FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER");
|
||||||
|
FileWriter.WriteLine("DEALINGS IN THE SOFTWARE.");
|
||||||
|
FileWriter.WriteLine("-->");
|
||||||
|
FileWriter.WriteLine("");
|
||||||
|
|
||||||
|
x.Serialize(XmlWriter, PatchDefinitions, ns);
|
||||||
|
|
||||||
|
FileWriter.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _TargetPath = null;
|
||||||
|
internal string TargetPath
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _TargetPath;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_TargetPath = value.TrimEnd(new char[] { '\\' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class TargetRedirection
|
||||||
|
{
|
||||||
|
private string _RelativePath;
|
||||||
|
private string _TargetPath;
|
||||||
|
|
||||||
|
internal TargetRedirection(string RelativePath, string TargetPath)
|
||||||
|
{
|
||||||
|
this.RelativePath = RelativePath;
|
||||||
|
this.TargetPath = TargetPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal string RelativePath
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _RelativePath;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_RelativePath = value.TrimStart(new char[] { '\\' }).TrimEnd(new char[] { '\\' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal string TargetPath
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _TargetPath;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_TargetPath = value.TrimEnd(new char[] { '\\' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Must be public to be serializable
|
||||||
|
/// </summary>
|
||||||
|
public class PatchDefinition
|
||||||
|
{
|
||||||
|
[XmlAttribute]
|
||||||
|
public string Name;
|
||||||
|
|
||||||
|
public List<TargetVersion> TargetVersions = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Must be public to be serializable
|
||||||
|
/// </summary>
|
||||||
|
public class TargetVersion
|
||||||
|
{
|
||||||
|
[XmlAttribute]
|
||||||
|
public string Description;
|
||||||
|
|
||||||
|
public List<TargetFile> TargetFiles = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Must be public to be serializable
|
||||||
|
/// </summary>
|
||||||
|
public class TargetFile
|
||||||
|
{
|
||||||
|
private string _Path;
|
||||||
|
[XmlAttribute]
|
||||||
|
public string Path
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _Path;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_Path = value.TrimStart(new char[] { '\\' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[XmlIgnore]
|
||||||
|
public byte[] HashOriginal;
|
||||||
|
[XmlAttribute("HashOriginal")]
|
||||||
|
public string HashOriginalAsString
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Converter.ConvertHexToString(HashOriginal, "");
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
HashOriginal = Converter.ConvertStringToHex(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[XmlIgnore]
|
||||||
|
public byte[] HashPatched;
|
||||||
|
[XmlAttribute("HashPatched")]
|
||||||
|
public string HashPatchedAsString
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Converter.ConvertHexToString(HashPatched, "");
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
HashPatched = Converter.ConvertStringToHex(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Patch> Patches = new();
|
||||||
|
public List<TargetFile> Obsolete = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Must be public to be serializable
|
||||||
|
/// </summary>
|
||||||
|
public class Patch
|
||||||
|
{
|
||||||
|
[XmlIgnore]
|
||||||
|
public UInt32 Address;
|
||||||
|
[XmlAttribute("Address")]
|
||||||
|
public string AddressAsString
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return "0x" + Address.ToString("X8");
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
string NewValue = value;
|
||||||
|
if (NewValue.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||||
|
NewValue = NewValue[2..];
|
||||||
|
Address = Convert.ToUInt32(NewValue, 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[XmlIgnore]
|
||||||
|
public byte[] OriginalBytes;
|
||||||
|
[XmlAttribute("OriginalBytes")]
|
||||||
|
public string OriginalBytesAsString
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Converter.ConvertHexToString(OriginalBytes, "");
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
OriginalBytes = Converter.ConvertStringToHex(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[XmlIgnore]
|
||||||
|
public byte[] PatchedBytes;
|
||||||
|
[XmlAttribute("PatchedBytes")]
|
||||||
|
public string PatchedBytesAsString
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Converter.ConvertHexToString(PatchedBytes, "");
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
PatchedBytes = Converter.ConvertStringToHex(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
|
<Platforms>x86</Platforms>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\AutoPatcher\AutoPatcher.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup />
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Update="MainForm.cs">
|
||||||
|
<SubType>Form</SubType>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,818 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// Explanation of PE header here:
|
||||||
|
// https://msdn.microsoft.com/en-us/library/ms809762.aspx
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Linq;
|
||||||
|
using WPinternals;
|
||||||
|
|
||||||
|
namespace Patcher
|
||||||
|
{
|
||||||
|
#region Structs
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct IMAGE_DOS_HEADER
|
||||||
|
{
|
||||||
|
public UInt16 e_magic;
|
||||||
|
public UInt16 e_cblp;
|
||||||
|
public UInt16 e_cp;
|
||||||
|
public UInt16 e_crlc;
|
||||||
|
public UInt16 e_cparhdr;
|
||||||
|
public UInt16 e_minalloc;
|
||||||
|
public UInt16 e_maxalloc;
|
||||||
|
public UInt16 e_ss;
|
||||||
|
public UInt16 e_sp;
|
||||||
|
public UInt16 e_csum;
|
||||||
|
public UInt16 e_ip;
|
||||||
|
public UInt16 e_cs;
|
||||||
|
public UInt16 e_lfarlc;
|
||||||
|
public UInt16 e_ovno;
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||||
|
public UInt16[] e_res1;
|
||||||
|
public UInt16 e_oemid;
|
||||||
|
public UInt16 e_oeminfo;
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
|
||||||
|
public UInt16[] e_res2;
|
||||||
|
public UInt32 e_lfanew;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct IMAGE_NT_HEADERS
|
||||||
|
{
|
||||||
|
public UInt32 Signature;
|
||||||
|
public IMAGE_FILE_HEADER FileHeader;
|
||||||
|
public IMAGE_OPTIONAL_HEADER32 OptionalHeader32;
|
||||||
|
public IMAGE_OPTIONAL_HEADER64 OptionalHeader64;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct IMAGE_FILE_HEADER
|
||||||
|
{
|
||||||
|
public UInt16 Machine;
|
||||||
|
public UInt16 NumberOfSections;
|
||||||
|
public UInt32 TimeDateStamp;
|
||||||
|
public UInt32 PointerToSymbolTable;
|
||||||
|
public UInt32 NumberOfSymbols;
|
||||||
|
public UInt16 SizeOfOptionalHeader;
|
||||||
|
public UInt16 Characteristics;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct IMAGE_OPTIONAL_HEADER32
|
||||||
|
{
|
||||||
|
public UInt16 Magic;
|
||||||
|
public Byte MajorLinkerVersion;
|
||||||
|
public Byte MinorLinkerVersion;
|
||||||
|
public UInt32 SizeOfCode;
|
||||||
|
public UInt32 SizeOfInitializedData;
|
||||||
|
public UInt32 SizeOfUninitializedData;
|
||||||
|
public UInt32 AddressOfEntryPoint;
|
||||||
|
public UInt32 BaseOfCode;
|
||||||
|
public UInt32 BaseOfData;
|
||||||
|
public UInt32 ImageBase;
|
||||||
|
public UInt32 SectionAlignment;
|
||||||
|
public UInt32 FileAlignment;
|
||||||
|
public UInt16 MajorOperatingSystemVersion;
|
||||||
|
public UInt16 MinorOperatingSystemVersion;
|
||||||
|
public UInt16 MajorImageVersion;
|
||||||
|
public UInt16 MinorImageVersion;
|
||||||
|
public UInt16 MajorSubsystemVersion;
|
||||||
|
public UInt16 MinorSubsystemVersion;
|
||||||
|
public UInt32 Win32VersionValue;
|
||||||
|
public UInt32 SizeOfImage;
|
||||||
|
public UInt32 SizeOfHeaders;
|
||||||
|
public UInt32 CheckSum;
|
||||||
|
public UInt16 Subsystem;
|
||||||
|
public UInt16 DllCharacteristics;
|
||||||
|
public UInt32 SizeOfStackReserve;
|
||||||
|
public UInt32 SizeOfStackCommit;
|
||||||
|
public UInt32 SizeOfHeapReserve;
|
||||||
|
public UInt32 SizeOfHeapCommit;
|
||||||
|
public UInt32 LoaderFlags;
|
||||||
|
public UInt32 NumberOfRvaAndSizes;
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
|
||||||
|
public IMAGE_DATA_DIRECTORY[] DataDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct IMAGE_OPTIONAL_HEADER64
|
||||||
|
{
|
||||||
|
public UInt16 Magic;
|
||||||
|
public Byte MajorLinkerVersion;
|
||||||
|
public Byte MinorLinkerVersion;
|
||||||
|
public UInt32 SizeOfCode;
|
||||||
|
public UInt32 SizeOfInitializedData;
|
||||||
|
public UInt32 SizeOfUninitializedData;
|
||||||
|
public UInt32 AddressOfEntryPoint;
|
||||||
|
public UInt32 BaseOfCode;
|
||||||
|
public UInt64 ImageBase;
|
||||||
|
public UInt32 SectionAlignment;
|
||||||
|
public UInt32 FileAlignment;
|
||||||
|
public UInt16 MajorOperatingSystemVersion;
|
||||||
|
public UInt16 MinorOperatingSystemVersion;
|
||||||
|
public UInt16 MajorImageVersion;
|
||||||
|
public UInt16 MinorImageVersion;
|
||||||
|
public UInt16 MajorSubsystemVersion;
|
||||||
|
public UInt16 MinorSubsystemVersion;
|
||||||
|
public UInt32 Win32VersionValue;
|
||||||
|
public UInt32 SizeOfImage;
|
||||||
|
public UInt32 SizeOfHeaders;
|
||||||
|
public UInt32 CheckSum;
|
||||||
|
public UInt16 Subsystem;
|
||||||
|
public UInt16 DllCharacteristics;
|
||||||
|
public UInt64 SizeOfStackReserve;
|
||||||
|
public UInt64 SizeOfStackCommit;
|
||||||
|
public UInt64 SizeOfHeapReserve;
|
||||||
|
public UInt64 SizeOfHeapCommit;
|
||||||
|
public UInt32 LoaderFlags;
|
||||||
|
public UInt32 NumberOfRvaAndSizes;
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
|
||||||
|
public IMAGE_DATA_DIRECTORY[] DataDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct IMAGE_DATA_DIRECTORY
|
||||||
|
{
|
||||||
|
public UInt32 VirtualAddress;
|
||||||
|
public UInt32 Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct IMAGE_SECTION_HEADER
|
||||||
|
{
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
|
||||||
|
public string Name;
|
||||||
|
public Misc Misc;
|
||||||
|
public UInt32 VirtualAddress;
|
||||||
|
public UInt32 SizeOfRawData;
|
||||||
|
public UInt32 PointerToRawData;
|
||||||
|
public UInt32 PointerToRelocations;
|
||||||
|
public UInt32 PointerToLinenumbers;
|
||||||
|
public UInt16 NumberOfRelocations;
|
||||||
|
public UInt16 NumberOfLinenumbers;
|
||||||
|
public UInt32 Characteristics;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
public struct Misc
|
||||||
|
{
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public UInt32 PhysicalAddress;
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public UInt32 VirtualSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct IMAGE_EXPORT_DIRECTORY
|
||||||
|
{
|
||||||
|
public UInt32 Characteristics;
|
||||||
|
public UInt32 TimeDateStamp;
|
||||||
|
public UInt16 MajorVersion;
|
||||||
|
public UInt16 MinorVersion;
|
||||||
|
public UInt32 Name;
|
||||||
|
public UInt32 Base;
|
||||||
|
public UInt32 NumberOfFunctions;
|
||||||
|
public UInt32 NumberOfNames;
|
||||||
|
/// <summary>
|
||||||
|
/// RVA from base of image
|
||||||
|
/// </summary>
|
||||||
|
public UInt32 AddressOfFunctions;
|
||||||
|
/// <summary>
|
||||||
|
/// RVA from base of image
|
||||||
|
/// </summary>
|
||||||
|
public UInt32 AddressOfNames;
|
||||||
|
/// <summary>
|
||||||
|
/// RVA from base of image
|
||||||
|
/// </summary>
|
||||||
|
public UInt32 AddressOfNameOrdinals;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
public struct IMAGE_IMPORT_DESCRIPTOR
|
||||||
|
{
|
||||||
|
#region union
|
||||||
|
/// <summary>
|
||||||
|
/// CSharp doesnt really support unions, but they can be emulated by a field offset 0
|
||||||
|
/// </summary>
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public uint Characteristics; // 0 for terminating null import descriptor
|
||||||
|
/// <summary>
|
||||||
|
/// RVA to original unbound IAT (PIMAGE_THUNK_DATA)
|
||||||
|
/// </summary>
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public uint OriginalFirstThunk;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
[FieldOffset(4)]
|
||||||
|
public uint TimeDateStamp;
|
||||||
|
[FieldOffset(8)]
|
||||||
|
public uint ForwarderChain;
|
||||||
|
[FieldOffset(12)]
|
||||||
|
public uint Name;
|
||||||
|
[FieldOffset(16)]
|
||||||
|
public uint FirstThunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct RUNTIME_FUNCTION_64
|
||||||
|
{
|
||||||
|
public UInt64 RVAofBeginAddress;
|
||||||
|
public UInt64 RVAofEndAddress;
|
||||||
|
public UInt64 RVAofUnwindData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct RUNTIME_FUNCTION_32
|
||||||
|
{
|
||||||
|
public UInt32 RVAofBeginAddress;
|
||||||
|
public UInt32 RVAofUnwindData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Constants
|
||||||
|
{
|
||||||
|
public static class SectionFlags
|
||||||
|
{
|
||||||
|
public const UInt32 IMAGE_SCN_CNT_CODE = 0x00000020;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal enum ResourceType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Accelerator table.
|
||||||
|
/// </summary>
|
||||||
|
RT_ACCELERATOR = 9,
|
||||||
|
/// <summary>
|
||||||
|
/// Animated cursor.
|
||||||
|
/// </summary>
|
||||||
|
RT_ANICURSOR = 21,
|
||||||
|
/// <summary>
|
||||||
|
/// Animated icon.
|
||||||
|
/// </summary>
|
||||||
|
RT_ANIICON = 22,
|
||||||
|
/// <summary>
|
||||||
|
/// Bitmap resource.
|
||||||
|
/// </summary>
|
||||||
|
RT_BITMAP = 2,
|
||||||
|
/// <summary>
|
||||||
|
/// Hardware-dependent cursor resource.
|
||||||
|
/// </summary>
|
||||||
|
RT_CURSOR = 1,
|
||||||
|
/// <summary>
|
||||||
|
/// Dialog box.
|
||||||
|
/// </summary>
|
||||||
|
RT_DIALOG = 5,
|
||||||
|
/// <summary>
|
||||||
|
/// Allows
|
||||||
|
/// </summary>
|
||||||
|
RT_DLGINCLUDE = 17,
|
||||||
|
/// <summary>
|
||||||
|
/// Font resource.
|
||||||
|
/// </summary>
|
||||||
|
RT_FONT = 8,
|
||||||
|
/// <summary>
|
||||||
|
/// Font directory resource.
|
||||||
|
/// </summary>
|
||||||
|
RT_FONTDIR = 7,
|
||||||
|
/// <summary>
|
||||||
|
/// Hardware-independent cursor resource.
|
||||||
|
/// </summary>
|
||||||
|
RT_GROUP_CURSOR = RT_CURSOR + 11,
|
||||||
|
/// <summary>
|
||||||
|
/// Hardware-independent icon resource.
|
||||||
|
/// </summary>
|
||||||
|
RT_GROUP_ICON = RT_ICON + 11,
|
||||||
|
/// <summary>
|
||||||
|
/// HTML resource.
|
||||||
|
/// </summary>
|
||||||
|
RT_HTML = 23,
|
||||||
|
/// <summary>
|
||||||
|
/// Hardware-dependent icon resource.
|
||||||
|
/// </summary>
|
||||||
|
RT_ICON = 3,
|
||||||
|
/// <summary>
|
||||||
|
/// Side-by-Side Assembly Manifest.
|
||||||
|
/// </summary>
|
||||||
|
RT_MANIFEST = 24,
|
||||||
|
/// <summary>
|
||||||
|
/// Menu resource.
|
||||||
|
/// </summary>
|
||||||
|
RT_MENU = 4,
|
||||||
|
/// <summary>
|
||||||
|
/// Message-table entry.
|
||||||
|
/// </summary>
|
||||||
|
RT_MESSAGETABLE = 11,
|
||||||
|
/// <summary>
|
||||||
|
/// Plug and Play resource.
|
||||||
|
/// </summary>
|
||||||
|
RT_PLUGPLAY = 19,
|
||||||
|
/// <summary>
|
||||||
|
/// Application-defined resource (raw data).
|
||||||
|
/// </summary>
|
||||||
|
RT_RCDATA = 10,
|
||||||
|
/// <summary>
|
||||||
|
/// String-table entry.
|
||||||
|
/// </summary>
|
||||||
|
RT_STRING = 6,
|
||||||
|
/// <summary>
|
||||||
|
/// Version resource.
|
||||||
|
/// </summary>
|
||||||
|
RT_VERSION = 16,
|
||||||
|
/// <summary>
|
||||||
|
/// VXD
|
||||||
|
/// </summary>
|
||||||
|
RT_VXD = 20,
|
||||||
|
RT_DLGINIT = 240,
|
||||||
|
RT_TOOLBAR = 241
|
||||||
|
};
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public class PeFile
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
public readonly IMAGE_DOS_HEADER DosHeader;
|
||||||
|
public IMAGE_NT_HEADERS NtHeaders;
|
||||||
|
private readonly IList<IMAGE_SECTION_HEADER> _sectionHeaders = new List<IMAGE_SECTION_HEADER>();
|
||||||
|
|
||||||
|
public List<Section> Sections = new();
|
||||||
|
public List<FunctionDescriptor> Exports = new();
|
||||||
|
public List<FunctionDescriptor> Imports = new();
|
||||||
|
public List<FunctionDescriptor> RuntimeFunctions = new();
|
||||||
|
public byte[] Buffer;
|
||||||
|
public UInt64 ImageBase;
|
||||||
|
public UInt64 EntryPoint;
|
||||||
|
public UInt64 ExportDirectoryVirtualOffset;
|
||||||
|
public UInt64 ImportDirectoryVirtualOffset;
|
||||||
|
public UInt64 RuntimeDirectoryVirtualOffset;
|
||||||
|
public UInt32 RuntimeDirectorySize;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public PeFile(string Path): this(File.ReadAllBytes(Path))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public PeFile(byte[] Buffer)
|
||||||
|
{
|
||||||
|
int P = 0;
|
||||||
|
|
||||||
|
this.Buffer = Buffer;
|
||||||
|
|
||||||
|
// Read MS-DOS header section
|
||||||
|
DosHeader = MarshalBytesTo<IMAGE_DOS_HEADER>(Buffer, P);
|
||||||
|
|
||||||
|
// MS-DOS magic number should read 'MZ'
|
||||||
|
if (DosHeader.e_magic != 0x5a4d)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("File is not a portable executable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read NT Headers
|
||||||
|
P = (int)DosHeader.e_lfanew;
|
||||||
|
NtHeaders.Signature = MarshalBytesTo<UInt32>(Buffer, P);
|
||||||
|
|
||||||
|
// Make sure we have 'PE' in the pe signature
|
||||||
|
if (NtHeaders.Signature != 0x4550)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Invalid portable executable signature in NT header.");
|
||||||
|
}
|
||||||
|
|
||||||
|
P += sizeof(UInt32);
|
||||||
|
NtHeaders.FileHeader = MarshalBytesTo<IMAGE_FILE_HEADER>(Buffer, P);
|
||||||
|
|
||||||
|
// Read optional headers
|
||||||
|
P += Marshal.SizeOf(typeof(IMAGE_FILE_HEADER));
|
||||||
|
if (Is32bitAssembly())
|
||||||
|
{
|
||||||
|
Load32bitOptionalHeaders(Buffer, P);
|
||||||
|
ImageBase = NtHeaders.OptionalHeader32.ImageBase;
|
||||||
|
EntryPoint = NtHeaders.OptionalHeader32.AddressOfEntryPoint;
|
||||||
|
ExportDirectoryVirtualOffset = NtHeaders.OptionalHeader32.DataDirectory[0].VirtualAddress;
|
||||||
|
ImportDirectoryVirtualOffset = NtHeaders.OptionalHeader32.DataDirectory[1].VirtualAddress;
|
||||||
|
RuntimeDirectoryVirtualOffset = NtHeaders.OptionalHeader32.DataDirectory[3].VirtualAddress;
|
||||||
|
RuntimeDirectorySize = NtHeaders.OptionalHeader32.DataDirectory[3].Size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Load64bitOptionalHeaders(Buffer, P);
|
||||||
|
ImageBase = NtHeaders.OptionalHeader64.ImageBase;
|
||||||
|
EntryPoint = NtHeaders.OptionalHeader64.AddressOfEntryPoint;
|
||||||
|
ExportDirectoryVirtualOffset = NtHeaders.OptionalHeader64.DataDirectory[0].VirtualAddress;
|
||||||
|
ImportDirectoryVirtualOffset = NtHeaders.OptionalHeader64.DataDirectory[1].VirtualAddress;
|
||||||
|
RuntimeDirectoryVirtualOffset = NtHeaders.OptionalHeader64.DataDirectory[3].VirtualAddress;
|
||||||
|
RuntimeDirectorySize = NtHeaders.OptionalHeader64.DataDirectory[3].Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read Sections
|
||||||
|
_sectionHeaders.ToList().ForEach(s =>
|
||||||
|
{
|
||||||
|
byte[] RawCode = new byte[s.SizeOfRawData];
|
||||||
|
System.Buffer.BlockCopy(Buffer, (int)s.PointerToRawData, RawCode, 0, (int)s.SizeOfRawData);
|
||||||
|
|
||||||
|
Sections.Add(new Section { Header = s, Buffer = RawCode, VirtualAddress = s.VirtualAddress + (UInt32)ImageBase, VirtualSize = s.Misc.VirtualSize, IsCode = (s.Characteristics & (uint)Constants.SectionFlags.IMAGE_SCN_CNT_CODE) != 0 });
|
||||||
|
});
|
||||||
|
|
||||||
|
// Read Exports
|
||||||
|
// TODO: Proper support for 64-bit files
|
||||||
|
if (ExportDirectoryVirtualOffset != 0)
|
||||||
|
{
|
||||||
|
IMAGE_EXPORT_DIRECTORY ExportDirectory = MarshalBytesTo<IMAGE_EXPORT_DIRECTORY>(Buffer, (int)ConvertVirtualOffsetToRawOffset((uint)ExportDirectoryVirtualOffset));
|
||||||
|
if (ExportDirectory.AddressOfNames != 0)
|
||||||
|
{
|
||||||
|
Section ExportsSection = GetSectionForVirtualAddress((uint)(ImageBase + ExportDirectory.AddressOfNames));
|
||||||
|
UInt32 OffsetNames = (UInt32)(ImageBase + ExportDirectory.AddressOfNames - ExportsSection.VirtualAddress);
|
||||||
|
UInt32 OffsetOrdinals = (UInt32)(ImageBase + ExportDirectory.AddressOfNameOrdinals - ExportsSection.VirtualAddress);
|
||||||
|
UInt32 OffsetFunctions = (UInt32)(ImageBase + ExportDirectory.AddressOfFunctions - ExportsSection.VirtualAddress);
|
||||||
|
string[] ExportNames = new string[ExportDirectory.NumberOfNames];
|
||||||
|
UInt16[] Ordinals = new UInt16[ExportDirectory.NumberOfNames];
|
||||||
|
UInt32[] VirtualAddresses = new UInt32[ExportDirectory.NumberOfFunctions];
|
||||||
|
for (int i = 0; i < ExportDirectory.NumberOfNames; i++)
|
||||||
|
{
|
||||||
|
UInt32 NamesRVA = ByteOperations.ReadUInt32(ExportsSection.Buffer, (UInt32)(OffsetNames + (i * sizeof(UInt32))));
|
||||||
|
UInt32 NameOffset = (UInt32)(NamesRVA + ImageBase - ExportsSection.VirtualAddress);
|
||||||
|
ExportNames[i] = ByteOperations.ReadAsciiString(ExportsSection.Buffer, NameOffset);
|
||||||
|
|
||||||
|
Ordinals[i] = ByteOperations.ReadUInt16(ExportsSection.Buffer, (UInt32)(OffsetOrdinals + (i * sizeof(UInt16))));
|
||||||
|
}
|
||||||
|
for (int i = 0; i < ExportDirectory.NumberOfFunctions; i++)
|
||||||
|
{
|
||||||
|
VirtualAddresses[i] = ByteOperations.ReadUInt32(ExportsSection.Buffer, (UInt32)(OffsetFunctions + (i * sizeof(UInt32))));
|
||||||
|
VirtualAddresses[i] -= VirtualAddresses[i] % 2; // Round down for Thumb2
|
||||||
|
}
|
||||||
|
for (int i = 0; i < ExportDirectory.NumberOfNames; i++)
|
||||||
|
{
|
||||||
|
Exports.Add(new FunctionDescriptor() { Name = ExportNames[i], VirtualAddress = (UInt32)(ImageBase + VirtualAddresses[Ordinals[i]]) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read Imports
|
||||||
|
// TODO: Proper support for 64-bit files
|
||||||
|
if (ImportDirectoryVirtualOffset != 0)
|
||||||
|
{
|
||||||
|
Section ImportsSection = GetSectionForVirtualAddress((uint)(ImageBase + ImportDirectoryVirtualOffset));
|
||||||
|
IMAGE_IMPORT_DESCRIPTOR ImportDirectory;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ImportDirectory = MarshalBytesTo<IMAGE_IMPORT_DESCRIPTOR>(ImportsSection.Buffer, (int)(ImportDirectoryVirtualOffset - (ImportsSection.VirtualAddress - ImageBase)));
|
||||||
|
if (ImportDirectory.OriginalFirstThunk != 0)
|
||||||
|
{
|
||||||
|
// ImportDirectory.OriginalFirstThunk is the VirtualOffset to an array of VirtualOffsets. They point to a struct with a word-value, followed by a zero-terminated ascii-string, which is the name of the import.
|
||||||
|
// ImportDirectory.FirstThunk points to an array pointers which is the actual import table.
|
||||||
|
UInt32 NameArrayOffset = ImportDirectory.OriginalFirstThunk - (ImportsSection.VirtualAddress - (UInt32)ImageBase);
|
||||||
|
UInt32 NameOffset;
|
||||||
|
int i = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
NameOffset = ByteOperations.ReadUInt32(ImportsSection.Buffer, NameArrayOffset);
|
||||||
|
if ((NameOffset < (ImportsSection.VirtualAddress - ImageBase)) || (NameOffset >= (ImportsSection.VirtualAddress + ImportsSection.VirtualSize - ImageBase)))
|
||||||
|
NameOffset = 0; // ImportDirectory.OriginalFirstThunk seems to contain Characteristics, not an offset to an array.
|
||||||
|
NameArrayOffset += sizeof(UInt32);
|
||||||
|
if (NameOffset != 0)
|
||||||
|
{
|
||||||
|
string Name = ByteOperations.ReadAsciiString(ImportsSection.Buffer, NameOffset + 2 - (ImportsSection.VirtualAddress - (UInt32)ImageBase));
|
||||||
|
Imports.Add(new FunctionDescriptor() { Name = Name, VirtualAddress = ImportDirectory.FirstThunk + (UInt32)ImageBase + (UInt32)(i * sizeof(UInt32)) });
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (NameOffset != 0);
|
||||||
|
|
||||||
|
ImportDirectoryVirtualOffset += (UInt64)Marshal.SizeOf(typeof(IMAGE_IMPORT_DESCRIPTOR));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (ImportDirectory.OriginalFirstThunk != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read Runtime functions
|
||||||
|
// TODO: Proper support for 64-bit files
|
||||||
|
if (RuntimeDirectoryVirtualOffset != 0)
|
||||||
|
{
|
||||||
|
Section RuntimeSection = GetSectionForVirtualAddress((uint)(ImageBase + RuntimeDirectoryVirtualOffset));
|
||||||
|
RUNTIME_FUNCTION_32 RuntimeFunction;
|
||||||
|
for (int i = 0; i < (RuntimeDirectorySize / Marshal.SizeOf(typeof(RUNTIME_FUNCTION_32))); i++)
|
||||||
|
{
|
||||||
|
RuntimeFunction = MarshalBytesTo<RUNTIME_FUNCTION_32>(RuntimeSection.Buffer, (int)(RuntimeDirectoryVirtualOffset - (RuntimeSection.VirtualAddress - ImageBase)) + (i * Marshal.SizeOf(typeof(RUNTIME_FUNCTION_32))));
|
||||||
|
RuntimeFunctions.Add(new FunctionDescriptor() { Name = null, VirtualAddress = (UInt32)(RuntimeFunction.RVAofBeginAddress + ImageBase) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public UInt32 GetChecksumOffset()
|
||||||
|
{
|
||||||
|
return ByteOperations.ReadUInt32(Buffer, 0x3C) + +0x58;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal UInt32 CalculateChecksum()
|
||||||
|
{
|
||||||
|
UInt32 Checksum = 0;
|
||||||
|
UInt32 Hi;
|
||||||
|
|
||||||
|
// Clear file checksum
|
||||||
|
// ByteOperations.WriteUInt32(PEFile, GetChecksumOffset(), 0);
|
||||||
|
UInt32 ChecksumOffset = GetChecksumOffset();
|
||||||
|
|
||||||
|
for (UInt32 i = 0; i < ((UInt32)Buffer.Length & 0xfffffffe); i += 2)
|
||||||
|
{
|
||||||
|
if ((i < ChecksumOffset) || (i >= (ChecksumOffset + 4)))
|
||||||
|
Checksum += ByteOperations.ReadUInt16(Buffer, i);
|
||||||
|
|
||||||
|
Hi = Checksum >> 16;
|
||||||
|
if (Hi != 0)
|
||||||
|
{
|
||||||
|
Checksum = Hi + (Checksum & 0xFFFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((Buffer.Length % 2) != 0)
|
||||||
|
{
|
||||||
|
Checksum += (UInt32)ByteOperations.ReadUInt8(Buffer, (UInt32)Buffer.Length - 1);
|
||||||
|
Hi = Checksum >> 16;
|
||||||
|
if (Hi != 0)
|
||||||
|
{
|
||||||
|
Checksum = Hi + (Checksum & 0xFFFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Checksum += (UInt32)Buffer.Length;
|
||||||
|
|
||||||
|
// Write file checksum
|
||||||
|
// ByteOperations.WriteUInt32(Buffer, GetChecksumOffset(), Checksum);
|
||||||
|
|
||||||
|
return Checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IMAGE_DOS_HEADER GetDOSHeader()
|
||||||
|
{
|
||||||
|
return DosHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UInt32 GetPESignature()
|
||||||
|
{
|
||||||
|
return NtHeaders.Signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IMAGE_FILE_HEADER GetFileHeader()
|
||||||
|
{
|
||||||
|
return NtHeaders.FileHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IMAGE_OPTIONAL_HEADER32 GetOptionalHeaders32()
|
||||||
|
{
|
||||||
|
return NtHeaders.OptionalHeader32;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IMAGE_OPTIONAL_HEADER64 GetOptionalHeaders64()
|
||||||
|
{
|
||||||
|
return NtHeaders.OptionalHeader64;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IList<IMAGE_SECTION_HEADER> GetSectionHeaders()
|
||||||
|
{
|
||||||
|
return _sectionHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Is32bitAssembly()
|
||||||
|
{
|
||||||
|
return (NtHeaders.FileHeader.Characteristics & 0x0100) == 0x0100;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Load64bitOptionalHeaders(byte[] Buffer, int Offset)
|
||||||
|
{
|
||||||
|
NtHeaders.OptionalHeader64 = MarshalBytesTo<IMAGE_OPTIONAL_HEADER64>(Buffer, Offset);
|
||||||
|
|
||||||
|
// Should have 10 data directories
|
||||||
|
if (NtHeaders.OptionalHeader64.NumberOfRvaAndSizes != 0x10)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Invalid number of data directories in NT header");
|
||||||
|
}
|
||||||
|
Offset += Marshal.SizeOf(typeof(IMAGE_OPTIONAL_HEADER64));
|
||||||
|
|
||||||
|
for (int i = 0; i < NtHeaders.FileHeader.NumberOfSections; i++)
|
||||||
|
{
|
||||||
|
_sectionHeaders.Add(MarshalBytesTo<IMAGE_SECTION_HEADER>(Buffer, Offset));
|
||||||
|
Offset += Marshal.SizeOf(typeof(IMAGE_SECTION_HEADER));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Load32bitOptionalHeaders(byte[] Buffer, int Offset)
|
||||||
|
{
|
||||||
|
NtHeaders.OptionalHeader32 = MarshalBytesTo<IMAGE_OPTIONAL_HEADER32>(Buffer, Offset);
|
||||||
|
|
||||||
|
// Should have 10 data directories
|
||||||
|
if (NtHeaders.OptionalHeader32.NumberOfRvaAndSizes != 0x10)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Invalid number of data directories in NT header");
|
||||||
|
}
|
||||||
|
Offset += Marshal.SizeOf(typeof(IMAGE_OPTIONAL_HEADER32));
|
||||||
|
|
||||||
|
for (int i = 0; i < NtHeaders.FileHeader.NumberOfSections; i++)
|
||||||
|
{
|
||||||
|
_sectionHeaders.Add(MarshalBytesTo<IMAGE_SECTION_HEADER>(Buffer, Offset));
|
||||||
|
Offset += Marshal.SizeOf(typeof(IMAGE_SECTION_HEADER));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public UInt32 ConvertVirtualOffsetToRawOffset(UInt32 VirtualOffset)
|
||||||
|
{
|
||||||
|
// TODO: Add 64-bit support
|
||||||
|
if (VirtualOffset < (Sections.OrderBy(s => s.VirtualAddress).First().VirtualAddress - GetOptionalHeaders32().ImageBase))
|
||||||
|
return VirtualOffset;
|
||||||
|
|
||||||
|
IMAGE_SECTION_HEADER? SectionHeaderSelection = _sectionHeaders.FirstOrDefault(h => (h.VirtualAddress <= VirtualOffset) && ((h.VirtualAddress + h.SizeOfRawData) > VirtualOffset));
|
||||||
|
if (SectionHeaderSelection == null)
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
|
||||||
|
IMAGE_SECTION_HEADER SectionHeader = (IMAGE_SECTION_HEADER)SectionHeaderSelection;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(SectionHeader.Name) || (SectionHeader.SizeOfRawData == 0))
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
|
||||||
|
return SectionHeader.PointerToRawData + (VirtualOffset - SectionHeader.VirtualAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UInt32 ConvertVirtualAddressToRawOffset(UInt32 VirtualAddress)
|
||||||
|
{
|
||||||
|
return ConvertVirtualOffsetToRawOffset((UInt32)(VirtualAddress - ImageBase));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal uint ConvertRawOffsetToVirtualAddress(uint RawOffset)
|
||||||
|
{
|
||||||
|
// TODO: Add 64-bit support
|
||||||
|
if (RawOffset < Sections.OrderBy(s => s.VirtualAddress).First().Header.PointerToRawData)
|
||||||
|
return RawOffset + GetOptionalHeaders32().ImageBase;
|
||||||
|
|
||||||
|
IMAGE_SECTION_HEADER? SectionHeaderSelection = _sectionHeaders.FirstOrDefault(h => (h.PointerToRawData <= RawOffset) && ((h.PointerToRawData + h.SizeOfRawData) > RawOffset));
|
||||||
|
if (SectionHeaderSelection == null)
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
|
||||||
|
IMAGE_SECTION_HEADER SectionHeader = (IMAGE_SECTION_HEADER)SectionHeaderSelection;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(SectionHeader.Name) || (SectionHeader.SizeOfRawData == 0))
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
|
||||||
|
return RawOffset - SectionHeader.PointerToRawData + SectionHeader.VirtualAddress + GetOptionalHeaders32().ImageBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Section GetSectionForVirtualAddress(UInt32 VirtualAddress)
|
||||||
|
{
|
||||||
|
return Sections.Find(s => (VirtualAddress >= s.VirtualAddress) && (VirtualAddress < (s.VirtualAddress + s.VirtualSize)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static T MarshalBytesTo<T>(BinaryReader reader)
|
||||||
|
{
|
||||||
|
// Unmanaged data
|
||||||
|
byte[] bytes = reader.ReadBytes(Marshal.SizeOf(typeof(T)));
|
||||||
|
|
||||||
|
// Create a pointer to the unmanaged data pinned in memory to be accessed by unmanaged code
|
||||||
|
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
|
||||||
|
|
||||||
|
// Use our previously created pointer to unmanaged data and marshal to the specified type
|
||||||
|
T theStructure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
|
||||||
|
|
||||||
|
// Deallocate pointer
|
||||||
|
handle.Free();
|
||||||
|
|
||||||
|
return theStructure;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static T MarshalBytesTo<T>(byte[] Binary, int Offset)
|
||||||
|
{
|
||||||
|
// Unmanaged data
|
||||||
|
byte[] bytes = new byte[Marshal.SizeOf(typeof(T))];
|
||||||
|
System.Buffer.BlockCopy(Binary, Offset, bytes, 0, Marshal.SizeOf(typeof(T)));
|
||||||
|
|
||||||
|
// Create a pointer to the unmanaged data pinned in memory to be accessed by unmanaged code
|
||||||
|
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
|
||||||
|
|
||||||
|
// Use our previously created pointer to unmanaged data and marshal to the specified type
|
||||||
|
T theStructure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
|
||||||
|
|
||||||
|
// Deallocate pointer
|
||||||
|
handle.Free();
|
||||||
|
|
||||||
|
return theStructure;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal byte[] GetResource(int[] Index)
|
||||||
|
{
|
||||||
|
UInt32 PEPointer = ByteOperations.ReadUInt32(Buffer, 0x3C);
|
||||||
|
UInt16 OptionalHeaderSize = ByteOperations.ReadUInt16(Buffer, PEPointer + 0x14);
|
||||||
|
UInt32 SectionTablePointer = PEPointer + 0x18 + OptionalHeaderSize;
|
||||||
|
UInt16 SectionCount = ByteOperations.ReadUInt16(Buffer, PEPointer + 0x06);
|
||||||
|
UInt32? ResourceSectionEntryPointer = null;
|
||||||
|
for (int i = 0; i < SectionCount; i++)
|
||||||
|
{
|
||||||
|
string SectionName = ByteOperations.ReadAsciiString(Buffer, (UInt32)(SectionTablePointer + (i * 0x28)), 8);
|
||||||
|
int e = SectionName.IndexOf('\0');
|
||||||
|
if (e >= 0)
|
||||||
|
SectionName = SectionName.Substring(0, e);
|
||||||
|
if (SectionName == ".rsrc")
|
||||||
|
{
|
||||||
|
ResourceSectionEntryPointer = (UInt32)(SectionTablePointer + (i * 0x28));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ResourceSectionEntryPointer == null)
|
||||||
|
throw new Exception("Resource-section not found");
|
||||||
|
UInt32 ResourceRawSize = ByteOperations.ReadUInt32(Buffer, (UInt32)ResourceSectionEntryPointer + 0x10);
|
||||||
|
UInt32 ResourceRawPointer = ByteOperations.ReadUInt32(Buffer, (UInt32)ResourceSectionEntryPointer + 0x14);
|
||||||
|
UInt32 ResourceVirtualPointer = ByteOperations.ReadUInt32(Buffer, (UInt32)ResourceSectionEntryPointer + 0x0C);
|
||||||
|
|
||||||
|
UInt32 p = ResourceRawPointer;
|
||||||
|
for (int i = 0; i < Index.Length; i++)
|
||||||
|
{
|
||||||
|
UInt16 ResourceNamedEntryCount = ByteOperations.ReadUInt16(Buffer, p + 0x0c);
|
||||||
|
UInt16 ResourceIdEntryCount = ByteOperations.ReadUInt16(Buffer, p + 0x0e);
|
||||||
|
for (int j = ResourceNamedEntryCount; j < ResourceNamedEntryCount + ResourceIdEntryCount; j++)
|
||||||
|
{
|
||||||
|
UInt32 ResourceID = ByteOperations.ReadUInt32(Buffer, (UInt32)(p + 0x10 + (j * 8)));
|
||||||
|
UInt32 NextPointer = ByteOperations.ReadUInt32(Buffer, (UInt32)(p + 0x10 + (j * 8) + 4));
|
||||||
|
if (ResourceID == (UInt32)Index[i])
|
||||||
|
{
|
||||||
|
// Check high bit
|
||||||
|
if ((NextPointer & 0x80000000) == 0 != (i == (Index.Length - 1)))
|
||||||
|
throw new Exception("Bad resource path");
|
||||||
|
|
||||||
|
p = ResourceRawPointer + (NextPointer & 0x7fffffff);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt32 ResourceValuePointer = ByteOperations.ReadUInt32(Buffer, p) - ResourceVirtualPointer + ResourceRawPointer;
|
||||||
|
UInt32 ResourceValueSize = ByteOperations.ReadUInt32(Buffer, p + 4);
|
||||||
|
|
||||||
|
byte[] ResourceValue = new byte[ResourceValueSize];
|
||||||
|
Array.Copy(Buffer, ResourceValuePointer, ResourceValue, 0, ResourceValueSize);
|
||||||
|
|
||||||
|
return ResourceValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Version GetFileVersion()
|
||||||
|
{
|
||||||
|
byte[] version = GetResource(new int[] { (int)ResourceType.RT_VERSION, 1, 1033 });
|
||||||
|
|
||||||
|
// RT_VERSION format:
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms647001(v=vs.85).aspx
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms646997(v=vs.85).aspx
|
||||||
|
const UInt32 FixedFileInfoPointer = 0x28;
|
||||||
|
UInt16 Major = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x0A);
|
||||||
|
UInt16 Minor = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x08);
|
||||||
|
UInt16 Build = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x0E);
|
||||||
|
UInt16 Revision = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x0C);
|
||||||
|
|
||||||
|
return new Version(Major, Minor, Build, Revision);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Version GetProductVersion()
|
||||||
|
{
|
||||||
|
byte[] version = GetResource(new int[] { (int)ResourceType.RT_VERSION, 1, 1033 });
|
||||||
|
|
||||||
|
// RT_VERSION format:
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms647001(v=vs.85).aspx
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms646997(v=vs.85).aspx
|
||||||
|
const UInt32 FixedFileInfoPointer = 0x28;
|
||||||
|
UInt16 Major = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x12);
|
||||||
|
UInt16 Minor = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x10);
|
||||||
|
UInt16 Build = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x16);
|
||||||
|
UInt16 Revision = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x14);
|
||||||
|
|
||||||
|
return new Version(Major, Minor, Build, Revision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Section
|
||||||
|
{
|
||||||
|
public IMAGE_SECTION_HEADER Header;
|
||||||
|
public byte[] Buffer;
|
||||||
|
public UInt32 VirtualAddress;
|
||||||
|
public UInt32 VirtualSize;
|
||||||
|
public bool IsCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FunctionDescriptor
|
||||||
|
{
|
||||||
|
public string Name;
|
||||||
|
public UInt32 VirtualAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
// 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.Windows.Forms;
|
||||||
|
|
||||||
|
namespace Patcher
|
||||||
|
{
|
||||||
|
internal static class Program
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The main entry point for the application.
|
||||||
|
/// </summary>
|
||||||
|
[STAThread]
|
||||||
|
private static void Main()
|
||||||
|
{
|
||||||
|
Application.EnableVisualStyles();
|
||||||
|
Application.SetCompatibleTextRenderingDefault(false);
|
||||||
|
Application.Run(new MainForm());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
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("ARM Patcher")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("WPinternals.net")]
|
||||||
|
[assembly: AssemblyProduct("ARM Patcher")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2018 by Rene Lergner")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("b9aebca3-bcf8-4e4a-bf0e-5e764867be07")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace Patcher.Properties
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||||
|
/// </summary>
|
||||||
|
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||||
|
// class via a tool like ResGen or Visual Studio.
|
||||||
|
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
|
// with the /str option, or rebuild your VS project.
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
internal class Resources
|
||||||
|
{
|
||||||
|
|
||||||
|
private static global::System.Resources.ResourceManager resourceMan;
|
||||||
|
|
||||||
|
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||||
|
|
||||||
|
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
internal Resources()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the cached ResourceManager instance used by this class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Resources.ResourceManager ResourceManager
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if ((resourceMan == null))
|
||||||
|
{
|
||||||
|
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Patcher.Properties.Resources", typeof(Resources).Assembly);
|
||||||
|
resourceMan = temp;
|
||||||
|
}
|
||||||
|
return resourceMan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overrides the current thread's CurrentUICulture property for all
|
||||||
|
/// resource lookups using this strongly typed resource class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Globalization.CultureInfo Culture
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return resourceCulture;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
resourceCulture = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
</root>
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace Patcher.Properties
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
|
||||||
|
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
|
||||||
|
{
|
||||||
|
|
||||||
|
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||||
|
|
||||||
|
public static Settings Default
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return defaultInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
|
||||||
|
<Profiles>
|
||||||
|
<Profile Name="(Default)" />
|
||||||
|
</Profiles>
|
||||||
|
<Settings />
|
||||||
|
</SettingsFile>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Workaround for intermittent issue
|
||||||
|
https://developercommunity.visualstudio.com/content/problem/983843/dotnet-build-task-does-not-use-nugetorg-for-one-pr.html
|
||||||
|
-->
|
||||||
|
<configuration>
|
||||||
|
<packageSources>
|
||||||
|
<clear />
|
||||||
|
<add key="nuget" value="https://api.nuget.org/v3/index.json" />
|
||||||
|
</packageSources>
|
||||||
|
</configuration>
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# Windows Phone Internals
|
||||||
|
|
||||||
|
Windows Phone Internals (WPinternals or WPI for short) is a tool designed to unlock the bootloader and/or secure boot of select Lumia devices made by Nokia and Microsoft.
|
||||||
|
Thanks to specifically crafted exploits/techniques the tool is able to disable Bootloader Security/SecureBoot on select Lumia models.
|
||||||
|
|
||||||
|
After unlocking your bootloader you will be able to notably perform the following actions:
|
||||||
|
|
||||||
|
- Boot other Operating Systems
|
||||||
|
- Enable Root Access (on select OS versions)
|
||||||
|
- Flash Custom ROMs
|
||||||
|
- Backup your current Windows Phone ROM
|
||||||
|
- Access your phone internal storage over USB
|
||||||
|
|
||||||
|
## Root Access
|
||||||
|
|
||||||
|
Root Access is a set of patches/hacks disabling security inside Windows Phone at its root. Kernel Security, Permission checks, application container security, deployment capability security and much gets disabled as part of enabling root access.
|
||||||
|
|
||||||
|
## How to get started?
|
||||||
|
|
||||||
|
The tool contains all the documentation you need to know more about the tool, we invite you to read the getting started section of the tool to know more.
|
||||||
|
|
||||||
|
## Where do I download the tool?
|
||||||
|
|
||||||
|
Here: https://github.com/ReneLergner/WPinternals/releases/latest
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<Application
|
||||||
|
x:Class="RootAccessTestUWP.App"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:local="using:RootAccessTestUWP"
|
||||||
|
RequestedTheme="Dark">
|
||||||
|
|
||||||
|
</Application>
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices.WindowsRuntime;
|
||||||
|
using Windows.ApplicationModel;
|
||||||
|
using Windows.ApplicationModel.Activation;
|
||||||
|
using Windows.Foundation;
|
||||||
|
using Windows.Foundation.Collections;
|
||||||
|
using Windows.UI.Xaml;
|
||||||
|
using Windows.UI.Xaml.Controls;
|
||||||
|
using Windows.UI.Xaml.Controls.Primitives;
|
||||||
|
using Windows.UI.Xaml.Data;
|
||||||
|
using Windows.UI.Xaml.Input;
|
||||||
|
using Windows.UI.Xaml.Media;
|
||||||
|
using Windows.UI.Xaml.Navigation;
|
||||||
|
|
||||||
|
namespace RootAccessTestUWP
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides application-specific behavior to supplement the default Application class.
|
||||||
|
/// </summary>
|
||||||
|
sealed partial class App : Application
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the singleton application object. This is the first line of authored code
|
||||||
|
/// executed, and as such is the logical equivalent of main() or WinMain().
|
||||||
|
/// </summary>
|
||||||
|
public App()
|
||||||
|
{
|
||||||
|
this.InitializeComponent();
|
||||||
|
this.Suspending += OnSuspending;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when the application is launched normally by the end user. Other entry points
|
||||||
|
/// will be used such as when the application is launched to open a specific file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="e">Details about the launch request and process.</param>
|
||||||
|
protected override void OnLaunched(LaunchActivatedEventArgs e)
|
||||||
|
{
|
||||||
|
Frame rootFrame = Window.Current.Content as Frame;
|
||||||
|
|
||||||
|
// Do not repeat app initialization when the Window already has content,
|
||||||
|
// just ensure that the window is active
|
||||||
|
if (rootFrame == null)
|
||||||
|
{
|
||||||
|
// Create a Frame to act as the navigation context and navigate to the first page
|
||||||
|
rootFrame = new Frame();
|
||||||
|
|
||||||
|
rootFrame.NavigationFailed += OnNavigationFailed;
|
||||||
|
|
||||||
|
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
|
||||||
|
{
|
||||||
|
//TODO: Load state from previously suspended application
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place the frame in the current Window
|
||||||
|
Window.Current.Content = rootFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.PrelaunchActivated == false)
|
||||||
|
{
|
||||||
|
if (rootFrame.Content == null)
|
||||||
|
{
|
||||||
|
// When the navigation stack isn't restored navigate to the first page,
|
||||||
|
// configuring the new page by passing required information as a navigation
|
||||||
|
// parameter
|
||||||
|
rootFrame.Navigate(typeof(MainPage), e.Arguments);
|
||||||
|
}
|
||||||
|
// Ensure the current window is active
|
||||||
|
Window.Current.Activate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when Navigation to a certain page fails
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The Frame which failed navigation</param>
|
||||||
|
/// <param name="e">Details about the navigation failure</param>
|
||||||
|
void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
|
||||||
|
{
|
||||||
|
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when application execution is being suspended. Application state is saved
|
||||||
|
/// without knowing whether the application will be terminated or resumed with the contents
|
||||||
|
/// of memory still intact.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The source of the suspend request.</param>
|
||||||
|
/// <param name="e">Details about the suspend request.</param>
|
||||||
|
private void OnSuspending(object sender, SuspendingEventArgs e)
|
||||||
|
{
|
||||||
|
var deferral = e.SuspendingOperation.GetDeferral();
|
||||||
|
//TODO: Save application state and stop any background activity
|
||||||
|
deferral.Complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
@@ -0,0 +1,89 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace RootAccessTestUWP
|
||||||
|
{
|
||||||
|
public static class Core
|
||||||
|
{
|
||||||
|
[DllImport("KERNELBASE.DLL", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||||
|
private static extern int RegQueryValueEx(UIntPtr hKey, string lpValueName, int lpReserved, out Core.RegistryValueKind lpType, IntPtr lpData, ref int lpcbData);
|
||||||
|
|
||||||
|
[DllImport("KERNELBASE.DLL", CharSet = CharSet.Unicode)]
|
||||||
|
private static extern int RegOpenKeyEx(UIntPtr hKey, string subKey, int ulOptions, int samDesired, out UIntPtr hkResult);
|
||||||
|
|
||||||
|
[DllImport("KERNELBASE.DLL", SetLastError = true)]
|
||||||
|
private static extern int RegCloseKey(UIntPtr hKey);
|
||||||
|
|
||||||
|
internal static string RegReadStringValue(UIntPtr rootKey, string keyPath, string valueName)
|
||||||
|
{
|
||||||
|
UIntPtr hKey;
|
||||||
|
int num = Core.RegOpenKeyEx(rootKey, keyPath, 0, Core.KEY_READ, out hKey);
|
||||||
|
if (num != 0)
|
||||||
|
{
|
||||||
|
throw new COMException("Failed to open registry key", num);
|
||||||
|
}
|
||||||
|
int cb = 1024;
|
||||||
|
IntPtr intPtr = Marshal.AllocHGlobal(cb);
|
||||||
|
Core.RegistryValueKind registryValueKind;
|
||||||
|
num = Core.RegQueryValueEx(hKey, valueName, 0, out registryValueKind, intPtr, ref cb);
|
||||||
|
if (num != 0)
|
||||||
|
{
|
||||||
|
throw new COMException("Failed to read registry value", num);
|
||||||
|
}
|
||||||
|
if (registryValueKind != Core.RegistryValueKind.String)
|
||||||
|
{
|
||||||
|
throw new Exception("Wrong registry value type");
|
||||||
|
}
|
||||||
|
string result = Marshal.PtrToStringUni(intPtr);
|
||||||
|
Core.RegCloseKey(hKey);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static uint RegReadDwordValue(UIntPtr rootKey, string keyPath, string valueName)
|
||||||
|
{
|
||||||
|
UIntPtr hKey;
|
||||||
|
int num = Core.RegOpenKeyEx(rootKey, keyPath, 0, Core.KEY_READ, out hKey);
|
||||||
|
if (num != 0)
|
||||||
|
{
|
||||||
|
throw new COMException("Failed to open registry key", num);
|
||||||
|
}
|
||||||
|
int cb = 1024;
|
||||||
|
IntPtr intPtr = Marshal.AllocHGlobal(cb);
|
||||||
|
Core.RegistryValueKind registryValueKind;
|
||||||
|
num = Core.RegQueryValueEx(hKey, valueName, 0, out registryValueKind, intPtr, ref cb);
|
||||||
|
if (num != 0)
|
||||||
|
{
|
||||||
|
throw new COMException("Failed to read registry value", num);
|
||||||
|
}
|
||||||
|
if (registryValueKind != Core.RegistryValueKind.DWord)
|
||||||
|
{
|
||||||
|
throw new Exception("Wrong registry value type");
|
||||||
|
}
|
||||||
|
uint result = (uint)Marshal.ReadInt32(intPtr);
|
||||||
|
Core.RegCloseKey(hKey);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UIntPtr HKEY_CLASSES_ROOT = (UIntPtr)2147483648U;
|
||||||
|
|
||||||
|
public static UIntPtr HKEY_CURRENT_USER = (UIntPtr)2147483649U;
|
||||||
|
|
||||||
|
public static UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)2147483650U;
|
||||||
|
|
||||||
|
public static UIntPtr HKEY_USERS = (UIntPtr)2147483651U;
|
||||||
|
|
||||||
|
private static int KEY_READ = 131097;
|
||||||
|
|
||||||
|
public enum RegistryValueKind
|
||||||
|
{
|
||||||
|
Unknown,
|
||||||
|
String,
|
||||||
|
ExpandString,
|
||||||
|
Binary,
|
||||||
|
DWord,
|
||||||
|
MultiString = 7,
|
||||||
|
QWord = 11,
|
||||||
|
None = -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<Page
|
||||||
|
x:Class="RootAccessTestUWP.MainPage"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:local="using:RootAccessTestUWP"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||||
|
<TextBlock x:Name="TextBlock"
|
||||||
|
Margin="10"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
Text=""
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
FontFamily="Courier New" />
|
||||||
|
</Grid>
|
||||||
|
</Page>
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices.WindowsRuntime;
|
||||||
|
using Windows.Foundation;
|
||||||
|
using Windows.Foundation.Collections;
|
||||||
|
using Windows.UI.Xaml;
|
||||||
|
using Windows.UI.Xaml.Controls;
|
||||||
|
using Windows.UI.Xaml.Controls.Primitives;
|
||||||
|
using Windows.UI.Xaml.Data;
|
||||||
|
using Windows.UI.Xaml.Input;
|
||||||
|
using Windows.UI.Xaml.Media;
|
||||||
|
using Windows.UI.Xaml.Navigation;
|
||||||
|
|
||||||
|
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
|
||||||
|
|
||||||
|
namespace RootAccessTestUWP
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class MainPage : Page
|
||||||
|
{
|
||||||
|
public MainPage()
|
||||||
|
{
|
||||||
|
this.InitializeComponent();
|
||||||
|
|
||||||
|
TextBlock.Text = "Reading: HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\PhoneProvisioner\\ColdBootDone" + Environment.NewLine + Environment.NewLine;
|
||||||
|
|
||||||
|
bool flag = false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Core.RegReadDwordValue(Core.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\PhoneProvisioner", "ColdBootDone");
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flag)
|
||||||
|
{
|
||||||
|
TextBlock.Text = string.Concat(new string[]
|
||||||
|
{
|
||||||
|
TextBlock.Text,
|
||||||
|
"Success!",
|
||||||
|
Environment.NewLine,
|
||||||
|
Environment.NewLine,
|
||||||
|
"Root Access: Enabled"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TextBlock.Text = string.Concat(new string[]
|
||||||
|
{
|
||||||
|
TextBlock.Text,
|
||||||
|
"Failed!",
|
||||||
|
Environment.NewLine,
|
||||||
|
Environment.NewLine,
|
||||||
|
"Root Access: Disabled"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<Package
|
||||||
|
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||||
|
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
|
||||||
|
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||||
|
IgnorableNamespaces="uap mp">
|
||||||
|
|
||||||
|
<Identity
|
||||||
|
Name="66bf96f4-f5ba-41f1-8ceb-ac4e9065ac52"
|
||||||
|
Publisher="CN=Rene"
|
||||||
|
Version="1.0.0.0" />
|
||||||
|
|
||||||
|
<mp:PhoneIdentity PhoneProductId="66bf96f4-f5ba-41f1-8ceb-ac4e9065ac52" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||||
|
|
||||||
|
<Properties>
|
||||||
|
<DisplayName>RootAccessTestUWP</DisplayName>
|
||||||
|
<PublisherDisplayName>Rene</PublisherDisplayName>
|
||||||
|
<Logo>Assets\StoreLogo.png</Logo>
|
||||||
|
</Properties>
|
||||||
|
|
||||||
|
<Dependencies>
|
||||||
|
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
|
||||||
|
</Dependencies>
|
||||||
|
|
||||||
|
<Resources>
|
||||||
|
<Resource Language="x-generate"/>
|
||||||
|
</Resources>
|
||||||
|
|
||||||
|
<Applications>
|
||||||
|
<Application Id="App"
|
||||||
|
Executable="$targetnametoken$.exe"
|
||||||
|
EntryPoint="RootAccessTestUWP.App">
|
||||||
|
<uap:VisualElements
|
||||||
|
DisplayName="RootAccessTestUWP"
|
||||||
|
Square150x150Logo="Assets\Square150x150Logo.png"
|
||||||
|
Square44x44Logo="Assets\Square44x44Logo.png"
|
||||||
|
Description="RootAccessTestUWP"
|
||||||
|
BackgroundColor="transparent">
|
||||||
|
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png"/>
|
||||||
|
<uap:SplashScreen Image="Assets\SplashScreen.png" />
|
||||||
|
</uap:VisualElements>
|
||||||
|
</Application>
|
||||||
|
</Applications>
|
||||||
|
|
||||||
|
<Capabilities>
|
||||||
|
<Capability Name="internetClient" />
|
||||||
|
</Capabilities>
|
||||||
|
</Package>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
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("RootAccessTestUWP")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("RootAccessTestUWP")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2021")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<!--
|
||||||
|
This file contains Runtime Directives used by .NET Native. The defaults here are suitable for most
|
||||||
|
developers. However, you can modify these parameters to modify the behavior of the .NET Native
|
||||||
|
optimizer.
|
||||||
|
|
||||||
|
Runtime Directives are documented at https://go.microsoft.com/fwlink/?LinkID=391919
|
||||||
|
|
||||||
|
To fully enable reflection for App1.MyClass and all of its public/private members
|
||||||
|
<Type Name="App1.MyClass" Dynamic="Required All"/>
|
||||||
|
|
||||||
|
To enable dynamic creation of the specific instantiation of AppClass<T> over System.Int32
|
||||||
|
<TypeInstantiation Name="App1.AppClass" Arguments="System.Int32" Activate="Required Public" />
|
||||||
|
|
||||||
|
Using the Namespace directive to apply reflection policy to all the types in a particular namespace
|
||||||
|
<Namespace Name="DataClasses.ViewModels" Serialize="All" />
|
||||||
|
-->
|
||||||
|
|
||||||
|
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
|
||||||
|
<Application>
|
||||||
|
<!--
|
||||||
|
An Assembly element with Name="*Application*" applies to all assemblies in
|
||||||
|
the application package. The asterisks are not wildcards.
|
||||||
|
-->
|
||||||
|
<Assembly Name="*Application*" Dynamic="Required All" />
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Add your application specific runtime directives here. -->
|
||||||
|
|
||||||
|
|
||||||
|
</Application>
|
||||||
|
</Directives>
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||||
|
<ProjectGuid>{8B6AADBB-C750-492E-AF60-82F6323401CC}</ProjectGuid>
|
||||||
|
<OutputType>AppContainerExe</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>RootAccessTestUWP</RootNamespace>
|
||||||
|
<AssemblyName>RootAccessTestUWP</AssemblyName>
|
||||||
|
<DefaultLanguage>en-US</DefaultLanguage>
|
||||||
|
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||||
|
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.22000.0</TargetPlatformVersion>
|
||||||
|
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
|
||||||
|
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
<WindowsXamlEnableOverview>true</WindowsXamlEnableOverview>
|
||||||
|
<AppxPackageSigningEnabled>false</AppxPackageSigningEnabled>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||||
|
<NoWarn>;2008</NoWarn>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||||
|
<OutputPath>bin\x86\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<NoWarn>;2008</NoWarn>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<OutputPath>bin\ARM\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||||
|
<NoWarn>;2008</NoWarn>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<PlatformTarget>ARM</PlatformTarget>
|
||||||
|
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
|
||||||
|
<OutputPath>bin\ARM\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<NoWarn>;2008</NoWarn>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<PlatformTarget>ARM</PlatformTarget>
|
||||||
|
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM64'">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<OutputPath>bin\ARM64\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||||
|
<NoWarn>;2008</NoWarn>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<PlatformTarget>ARM64</PlatformTarget>
|
||||||
|
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM64'">
|
||||||
|
<OutputPath>bin\ARM64\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<NoWarn>;2008</NoWarn>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<PlatformTarget>ARM64</PlatformTarget>
|
||||||
|
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||||
|
<NoWarn>;2008</NoWarn>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||||
|
<OutputPath>bin\x64\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<NoWarn>;2008</NoWarn>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="App.xaml.cs">
|
||||||
|
<DependentUpon>App.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Core.cs" />
|
||||||
|
<Compile Include="MainPage.xaml.cs">
|
||||||
|
<DependentUpon>MainPage.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AppxManifest Include="Package.appxmanifest">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</AppxManifest>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Properties\Default.rd.xml" />
|
||||||
|
<Content Include="Assets\LockScreenLogo.scale-200.png" />
|
||||||
|
<Content Include="Assets\SplashScreen.scale-200.png" />
|
||||||
|
<Content Include="Assets\Square150x150Logo.scale-200.png" />
|
||||||
|
<Content Include="Assets\Square44x44Logo.scale-200.png" />
|
||||||
|
<Content Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
|
||||||
|
<Content Include="Assets\StoreLogo.png" />
|
||||||
|
<Content Include="Assets\Wide310x150Logo.scale-200.png" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ApplicationDefinition Include="App.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</ApplicationDefinition>
|
||||||
|
<Page Include="MainPage.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
|
||||||
|
<Version>6.2.13</Version>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' < '14.0' ">
|
||||||
|
<VisualStudioVersion>14.0</VisualStudioVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
||||||
@@ -1,966 +0,0 @@
|
|||||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @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 Microsoft.Win32;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
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;
|
|
||||||
|
|
||||||
namespace WPinternals
|
|
||||||
{
|
|
||||||
internal class DownloadsViewModel : ContextViewModel
|
|
||||||
{
|
|
||||||
private readonly PhoneNotifierViewModel Notifier;
|
|
||||||
private readonly Timer SpeedTimer;
|
|
||||||
private bool IsSearching = false;
|
|
||||||
|
|
||||||
internal DownloadsViewModel(PhoneNotifierViewModel Notifier)
|
|
||||||
{
|
|
||||||
IsSwitchingInterface = false;
|
|
||||||
IsFlashModeOperation = false;
|
|
||||||
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();
|
|
||||||
|
|
||||||
SpeedTimer = new Timer(TimerCallback, this, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));
|
|
||||||
|
|
||||||
AddFFUCommand = new DelegateCommand(() =>
|
|
||||||
{
|
|
||||||
string FFUPath = null;
|
|
||||||
|
|
||||||
OpenFileDialog dlg = new();
|
|
||||||
dlg.DefaultExt = ".ffu"; // Default file extension
|
|
||||||
dlg.Filter = "ROM images (.ffu)|*.ffu"; // Filter files by extension
|
|
||||||
|
|
||||||
bool? result = dlg.ShowDialog();
|
|
||||||
|
|
||||||
if (result == true)
|
|
||||||
{
|
|
||||||
FFUPath = dlg.FileName;
|
|
||||||
string FFUFile = Path.GetFileName(FFUPath);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
App.Config.AddFfuToRepository(FFUPath);
|
|
||||||
App.Config.WriteConfig();
|
|
||||||
LastStatusText = "File \"" + FFUFile + "\" was added to the repository.";
|
|
||||||
}
|
|
||||||
catch (WPinternalsException Ex)
|
|
||||||
{
|
|
||||||
LastStatusText = "Error: " + Ex.Message + ". File \"" + FFUFile + "\" was not added.";
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
LastStatusText = "Error: File \"" + FFUFile + "\" was not added.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LastStatusText = null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private string _LastStatusText = null;
|
|
||||||
public string LastStatusText
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _LastStatusText;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_LastStatusText = value;
|
|
||||||
OnPropertyChanged(nameof(LastStatusText));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(URL);
|
|
||||||
req.Method = "HEAD";
|
|
||||||
req.ServicePoint.ConnectionLimit = 10;
|
|
||||||
using (WebResponse resp = req.GetResponse())
|
|
||||||
{
|
|
||||||
long.TryParse(resp.Headers.Get("Content-Length"), out Length);
|
|
||||||
}
|
|
||||||
return Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 FFUURL = null;
|
|
||||||
string[] EmergencyURLs = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string TempProductType = ProductType.ToUpper();
|
|
||||||
if ((TempProductType?.StartsWith("RM") == true) && !TempProductType.StartsWith("RM-"))
|
|
||||||
{
|
|
||||||
TempProductType = "RM-" + TempProductType[2..];
|
|
||||||
}
|
|
||||||
|
|
||||||
ProductType = TempProductType;
|
|
||||||
FFUURL = LumiaDownloadModel.SearchFFU(ProductType, ProductCode, OperatorCode, out TempProductType);
|
|
||||||
if (TempProductType != null)
|
|
||||||
{
|
|
||||||
ProductType = TempProductType;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ProductType != null)
|
|
||||||
{
|
|
||||||
EmergencyURLs = LumiaDownloadModel.SearchEmergencyFiles(ProductType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
|
|
||||||
UIContext.Post(s =>
|
|
||||||
{
|
|
||||||
if (FFUURL != null)
|
|
||||||
{
|
|
||||||
SearchResultList.Add(new SearchResult(FFUURL, ProductType, FFUDownloaded, null));
|
|
||||||
}
|
|
||||||
|
|
||||||
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 FFUURL = null;
|
|
||||||
string[] EmergencyURLs = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string TempProductType = ProductType.ToUpper();
|
|
||||||
if ((TempProductType?.StartsWith("RM") == true) && !TempProductType.StartsWith("RM-"))
|
|
||||||
{
|
|
||||||
TempProductType = "RM-" + TempProductType[2..];
|
|
||||||
}
|
|
||||||
|
|
||||||
ProductType = TempProductType;
|
|
||||||
FFUURL = LumiaDownloadModel.SearchFFU(ProductType, ProductCode, OperatorCode, out TempProductType);
|
|
||||||
if (TempProductType != null)
|
|
||||||
{
|
|
||||||
ProductType = TempProductType;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ProductType != null)
|
|
||||||
{
|
|
||||||
EmergencyURLs = LumiaDownloadModel.SearchEmergencyFiles(ProductType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
|
|
||||||
UIContext.Post(s =>
|
|
||||||
{
|
|
||||||
if (FFUURL != null)
|
|
||||||
{
|
|
||||||
Download(FFUURL, ProductType, FFUDownloadedAndCheckSupported, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EmergencyURLs != null)
|
|
||||||
{
|
|
||||||
Download(EmergencyURLs, ProductType, EmergencyDownloaded, ProductType);
|
|
||||||
}
|
|
||||||
}, null);
|
|
||||||
}).Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DownloadSelected()
|
|
||||||
{
|
|
||||||
IEnumerable<SearchResult> Selection = SearchResultList.Where(r => r.IsSelected);
|
|
||||||
foreach (SearchResult Result in Selection)
|
|
||||||
{
|
|
||||||
App.DownloadManager.Download(Result.URLs, Result.Category, Result.Callback, Result.State);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void FFUDownloaded(string[] Files, object State)
|
|
||||||
{
|
|
||||||
App.Config.AddFfuToRepository(Files[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void FFUDownloadedAndCheckSupported(string[] Files, object State)
|
|
||||||
{
|
|
||||||
App.Config.AddFfuToRepository(Files[0]);
|
|
||||||
|
|
||||||
if (!App.Config.FFURepository.Any(e => App.PatchEngine.PatchDefinitions.First(p => p.Name == "SecureBootHack-V2-EFIESP").TargetVersions.Any(v => v.Description == e.OSVersion)))
|
|
||||||
{
|
|
||||||
const string ProductType2 = "RM-1085";
|
|
||||||
string URL = LumiaDownloadModel.SearchFFU(ProductType2, null, null);
|
|
||||||
Download(URL, ProductType2, FFUDownloaded, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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; } = new();
|
|
||||||
public ObservableCollection<SearchResult> SearchResultList { get; } = new();
|
|
||||||
|
|
||||||
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 { }
|
|
||||||
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 _OperatorCode = null;
|
|
||||||
public string OperatorCode
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _OperatorCode;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_OperatorCode != value)
|
|
||||||
{
|
|
||||||
_OperatorCode = value;
|
|
||||||
|
|
||||||
OnPropertyChanged(nameof(OperatorCode));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal override void EvaluateViewState()
|
|
||||||
{
|
|
||||||
if (!IsActive)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Flash)
|
|
||||||
{
|
|
||||||
NokiaFlashModel LumiaFlashModel = (NokiaFlashModel)Notifier.CurrentModel;
|
|
||||||
PhoneInfo Info = LumiaFlashModel.ReadPhoneInfo();
|
|
||||||
ProductType = Info.Type;
|
|
||||||
OperatorCode = "";
|
|
||||||
ProductCode = Info.ProductCode;
|
|
||||||
}
|
|
||||||
else if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Normal)
|
|
||||||
{
|
|
||||||
NokiaPhoneModel LumiaNormalModel = (NokiaPhoneModel)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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public DelegateCommand AddFFUCommand { get; } = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal enum DownloadStatus
|
|
||||||
{
|
|
||||||
Downloading,
|
|
||||||
Ready,
|
|
||||||
Failed
|
|
||||||
};
|
|
||||||
|
|
||||||
internal class DownloadEntry : INotifyPropertyChanged
|
|
||||||
{
|
|
||||||
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 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);
|
|
||||||
}).Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
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.
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
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(CancellationToken))
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
if (completed != null)
|
|
||||||
completed(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Progress<long> progressWrapper = new Progress<long>(totalBytes => progress(new HttpClientDownloadProgress(totalBytes, contentLength.Value)));
|
|
||||||
await download.CopyToAsync(destination, 81920, progressWrapper, cancellationToken);
|
|
||||||
|
|
||||||
if (completed != null)
|
|
||||||
completed(true);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
if (completed != null)
|
|
||||||
completed(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task CopyToAsync(this Stream source, Stream destination, int bufferSize, IProgress<long> progress = null, CancellationToken cancellationToken = default(CancellationToken))
|
|
||||||
{
|
|
||||||
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, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0)
|
|
||||||
{
|
|
||||||
await destination.WriteAsync(buffer, 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,918 +0,0 @@
|
|||||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
// copy of this software and associated documentation files (the "Software"),
|
|
||||||
// to deal in the Software without restriction, including without limitation
|
|
||||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
// and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
// Software is furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
// DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace WPinternals
|
|
||||||
{
|
|
||||||
internal delegate void ModeSwitchProgressHandler(string Message, string SubMessage);
|
|
||||||
internal delegate void ModeSwitchErrorHandler(string Message);
|
|
||||||
internal delegate void ModeSwitchSuccessHandler(IDisposable NewModel, PhoneInterfaces NewInterface);
|
|
||||||
|
|
||||||
internal class SwitchModeViewModel : ContextViewModel
|
|
||||||
{
|
|
||||||
protected PhoneNotifierViewModel PhoneNotifier;
|
|
||||||
protected IDisposable CurrentModel;
|
|
||||||
protected PhoneInterfaces? CurrentMode;
|
|
||||||
protected PhoneInterfaces? TargetMode;
|
|
||||||
protected bool IsSwitching = false;
|
|
||||||
internal event ModeSwitchProgressHandler ModeSwitchProgress = delegate { };
|
|
||||||
internal event ModeSwitchErrorHandler ModeSwitchError = delegate { };
|
|
||||||
internal event ModeSwitchSuccessHandler ModeSwitchSuccess = delegate { };
|
|
||||||
internal new SetWorkingStatus SetWorkingStatus = (m, s, v, a, st) => { };
|
|
||||||
internal new UpdateWorkingStatus UpdateWorkingStatus = (m, s, v, st) => { };
|
|
||||||
private string MassStorageWarning = null;
|
|
||||||
|
|
||||||
internal SwitchModeViewModel(PhoneNotifierViewModel PhoneNotifier, PhoneInterfaces? TargetMode)
|
|
||||||
: base()
|
|
||||||
{
|
|
||||||
if ((PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_Flash) && (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_Bootloader) && (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_Label) && (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_Normal))
|
|
||||||
{
|
|
||||||
throw new ArgumentException();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.PhoneNotifier = PhoneNotifier;
|
|
||||||
this.CurrentModel = (NokiaPhoneModel)PhoneNotifier.CurrentModel;
|
|
||||||
this.CurrentMode = PhoneNotifier.CurrentInterface;
|
|
||||||
this.TargetMode = TargetMode;
|
|
||||||
|
|
||||||
if (this.CurrentMode == null)
|
|
||||||
{
|
|
||||||
LogFile.Log("Waiting for phone to connect...", LogType.FileAndConsole);
|
|
||||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Make sure this ViewModel has its View loaded before we continue,
|
|
||||||
// or else loading of Views can get mixed up.
|
|
||||||
if (SynchronizationContext.Current == null)
|
|
||||||
{
|
|
||||||
StartSwitch();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SynchronizationContext.Current.Post((s) => ((SwitchModeViewModel)s).StartSwitch(), this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal SwitchModeViewModel(PhoneNotifierViewModel PhoneNotifier, PhoneInterfaces? TargetMode, ModeSwitchProgressHandler ModeSwitchProgress, ModeSwitchErrorHandler ModeSwitchError, ModeSwitchSuccessHandler ModeSwitchSuccess, SetWorkingStatus SetWorkingStatus = null, UpdateWorkingStatus UpdateWorkingStatus = null)
|
|
||||||
: base()
|
|
||||||
{
|
|
||||||
if ((PhoneNotifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) && (TargetMode == PhoneInterfaces.Lumia_Flash))
|
|
||||||
{
|
|
||||||
PhoneInfo Info = ((NokiaFlashModel)PhoneNotifier.CurrentModel).ReadPhoneInfo(false);
|
|
||||||
if (Info.BootManagerProtocolVersionMajor >= 2)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// The implementation of SwitchToFlashAppContext() is improved
|
|
||||||
// SwitchToFlashAppContext() should only be used with BootMgr v2
|
|
||||||
// For switching from BootMgr to FlashApp, it will use NOKS
|
|
||||||
// That will switch to a charging state, whereas a normal context switch will not start charging
|
|
||||||
// The implementation of NOKS in BootMgr mode has changed in BootMgr v2
|
|
||||||
// It does not disconnect / reconnect anymore and the apptype is changed immediately
|
|
||||||
// NOKS still doesnt return a status
|
|
||||||
// BootMgr v1 uses normal NOKS and waits for arrival of FlashApp
|
|
||||||
((NokiaFlashModel)PhoneNotifier.CurrentModel).SwitchToFlashAppContext();
|
|
||||||
|
|
||||||
// But this was called as a real switch, so we will raise an arrival event.
|
|
||||||
PhoneNotifier.CurrentInterface = PhoneInterfaces.Lumia_Flash;
|
|
||||||
PhoneNotifier.NotifyArrival();
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PhoneNotifier.CurrentInterface == TargetMode)
|
|
||||||
{
|
|
||||||
ModeSwitchSuccess(PhoneNotifier.CurrentModel, (PhoneInterfaces)PhoneNotifier.CurrentInterface);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.PhoneNotifier = PhoneNotifier;
|
|
||||||
this.CurrentModel = (NokiaPhoneModel)PhoneNotifier.CurrentModel;
|
|
||||||
this.CurrentMode = PhoneNotifier.CurrentInterface;
|
|
||||||
this.TargetMode = TargetMode;
|
|
||||||
if (ModeSwitchProgress != null)
|
|
||||||
{
|
|
||||||
this.ModeSwitchProgress += ModeSwitchProgress;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ModeSwitchError != null)
|
|
||||||
{
|
|
||||||
this.ModeSwitchError += ModeSwitchError;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ModeSwitchSuccess != null)
|
|
||||||
{
|
|
||||||
this.ModeSwitchSuccess += ModeSwitchSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SetWorkingStatus != null)
|
|
||||||
{
|
|
||||||
this.SetWorkingStatus = SetWorkingStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (UpdateWorkingStatus != null)
|
|
||||||
{
|
|
||||||
this.UpdateWorkingStatus = UpdateWorkingStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.CurrentMode == null)
|
|
||||||
{
|
|
||||||
LogFile.Log("Waiting for phone to connect...", LogType.FileAndConsole);
|
|
||||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Make sure this ViewModel has its View loaded before we continue,
|
|
||||||
// or else loading of Views can get mixed up.
|
|
||||||
if (SynchronizationContext.Current == null)
|
|
||||||
{
|
|
||||||
StartSwitch();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SynchronizationContext.Current.Post((s) => ((SwitchModeViewModel)s).StartSwitch(), this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ModeSwitchProgressWrapper(string Message, string SubMessage)
|
|
||||||
{
|
|
||||||
if ((UIContext == null) || (SynchronizationContext.Current == UIContext))
|
|
||||||
{
|
|
||||||
ModeSwitchProgress(Message, SubMessage);
|
|
||||||
SetWorkingStatus(Message, SubMessage);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
UIContext.Post(s =>
|
|
||||||
{
|
|
||||||
ModeSwitchProgress(Message, SubMessage);
|
|
||||||
SetWorkingStatus(Message, SubMessage);
|
|
||||||
}, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ModeSwitchErrorWrapper(string Message)
|
|
||||||
{
|
|
||||||
IsSwitching = false;
|
|
||||||
if ((UIContext == null) || (SynchronizationContext.Current == UIContext))
|
|
||||||
{
|
|
||||||
ModeSwitchError(Message);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
UIContext.Post(s => ModeSwitchError(Message), null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ModeSwitchSuccessWrapper()
|
|
||||||
{
|
|
||||||
IsSwitching = false;
|
|
||||||
if ((UIContext == null) || (SynchronizationContext.Current == UIContext))
|
|
||||||
{
|
|
||||||
if (PhoneNotifier.CurrentInterface == null)
|
|
||||||
{
|
|
||||||
ModeSwitchErrorWrapper("Phone disconnected");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ModeSwitchSuccess(PhoneNotifier.CurrentModel, (PhoneInterfaces)PhoneNotifier.CurrentInterface);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (PhoneNotifier.CurrentInterface == null)
|
|
||||||
{
|
|
||||||
UIContext.Post(s => ModeSwitchErrorWrapper("Phone disconnected"), null);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
UIContext.Post(s => ModeSwitchSuccess(PhoneNotifier.CurrentModel, (PhoneInterfaces)PhoneNotifier.CurrentInterface), null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~SwitchModeViewModel()
|
|
||||||
{
|
|
||||||
if (PhoneNotifier != null)
|
|
||||||
{
|
|
||||||
PhoneNotifier.NewDeviceArrived -= NewDeviceArrived;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void StartSwitch()
|
|
||||||
{
|
|
||||||
IsSwitching = true;
|
|
||||||
|
|
||||||
// Make switch and set message or navigate to error
|
|
||||||
switch (CurrentMode)
|
|
||||||
{
|
|
||||||
case PhoneInterfaces.Lumia_Normal:
|
|
||||||
case PhoneInterfaces.Lumia_Label:
|
|
||||||
string DeviceMode;
|
|
||||||
|
|
||||||
switch (TargetMode)
|
|
||||||
{
|
|
||||||
case PhoneInterfaces.Lumia_Normal:
|
|
||||||
DeviceMode = "Normal";
|
|
||||||
IsSwitchingInterface = true;
|
|
||||||
ModeSwitchProgressWrapper("Rebooting phone to Normal mode...", null);
|
|
||||||
LogFile.Log("Rebooting phone to Normal mode", LogType.FileAndConsole);
|
|
||||||
break;
|
|
||||||
case PhoneInterfaces.Lumia_Bootloader:
|
|
||||||
DeviceMode = "Normal";
|
|
||||||
IsSwitchingInterface = true;
|
|
||||||
ModeSwitchProgressWrapper("Rebooting phone to Bootloader mode...", null);
|
|
||||||
LogFile.Log("Rebooting phone to Bootloader mode", LogType.FileAndConsole);
|
|
||||||
break;
|
|
||||||
case PhoneInterfaces.Lumia_Flash:
|
|
||||||
DeviceMode = "Flash";
|
|
||||||
IsSwitchingInterface = true;
|
|
||||||
ModeSwitchProgressWrapper("Rebooting phone to Flash mode...", null);
|
|
||||||
LogFile.Log("Rebooting phone to Flash mode", LogType.FileAndConsole);
|
|
||||||
break;
|
|
||||||
case PhoneInterfaces.Lumia_Label:
|
|
||||||
DeviceMode = "Flash";
|
|
||||||
IsSwitchingInterface = true;
|
|
||||||
ModeSwitchProgressWrapper("First rebooting phone to Flash mode...", null);
|
|
||||||
LogFile.Log("First rebooting phone to Flash mode (then attempt Label mode)", LogType.FileAndConsole);
|
|
||||||
break;
|
|
||||||
case PhoneInterfaces.Lumia_MassStorage:
|
|
||||||
DeviceMode = "Flash";
|
|
||||||
IsSwitchingInterface = true;
|
|
||||||
ModeSwitchProgressWrapper("First rebooting phone to Flash mode...", null);
|
|
||||||
LogFile.Log("First rebooting phone to Flash mode (then attempt Mass Storage mode)", LogType.FileAndConsole);
|
|
||||||
break;
|
|
||||||
case PhoneInterfaces.Qualcomm_Download: // Only available in new Lumia's
|
|
||||||
DeviceMode = "Flash";
|
|
||||||
IsSwitchingInterface = true;
|
|
||||||
ModeSwitchProgressWrapper("First rebooting phone to Flash mode...", null);
|
|
||||||
LogFile.Log("First rebooting phone to Flash mode (then attempt Qualcomm Download mode", LogType.FileAndConsole);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Dictionary<string, object> Params = new();
|
|
||||||
Params.Add("DeviceMode", DeviceMode);
|
|
||||||
Params.Add("ResetMethod", "HwReset");
|
|
||||||
try
|
|
||||||
{
|
|
||||||
((NokiaPhoneModel)CurrentModel).ExecuteJsonMethodAsync("SetDeviceMode", Params);
|
|
||||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
|
||||||
}
|
|
||||||
catch (Exception Ex)
|
|
||||||
{
|
|
||||||
LogFile.LogException(Ex);
|
|
||||||
ModeSwitchErrorWrapper("Failed to switch to Qualcomm Download mode");
|
|
||||||
IsSwitchingInterface = false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PhoneInterfaces.Lumia_Flash:
|
|
||||||
case PhoneInterfaces.Lumia_Bootloader:
|
|
||||||
byte[] BootModeFlagCommand = new byte[] { 0x4E, 0x4F, 0x4B, 0x58, 0x46, 0x57, 0x00, 0x55, 0x42, 0x46, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 }; // NOKFW UBF
|
|
||||||
byte[] RebootCommand = new byte[] { 0x4E, 0x4F, 0x4B, 0x52 }; // NOKR
|
|
||||||
byte[] RebootCommandResult;
|
|
||||||
IsSwitchingInterface = true;
|
|
||||||
switch (TargetMode)
|
|
||||||
{
|
|
||||||
case null:
|
|
||||||
((NokiaFlashModel)CurrentModel).Shutdown();
|
|
||||||
ModeSwitchProgressWrapper("Please disconnect your device. Waiting...", null);
|
|
||||||
LogFile.Log("Please disconnect your device. Waiting...", LogType.FileAndConsole);
|
|
||||||
new Thread(() =>
|
|
||||||
{
|
|
||||||
PhoneNotifier.WaitForRemoval().Wait();
|
|
||||||
ModeSwitchSuccessWrapper();
|
|
||||||
}).Start();
|
|
||||||
break;
|
|
||||||
case PhoneInterfaces.Lumia_Normal:
|
|
||||||
((NokiaPhoneModel)CurrentModel).ExecuteRawVoidMethod(RebootCommand);
|
|
||||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
|
||||||
ModeSwitchProgressWrapper("Rebooting phone to Normal mode...", null);
|
|
||||||
LogFile.Log("Rebooting phone to Normal mode", LogType.FileAndConsole);
|
|
||||||
break;
|
|
||||||
case PhoneInterfaces.Lumia_Bootloader:
|
|
||||||
((NokiaPhoneModel)CurrentModel).ExecuteRawVoidMethod(RebootCommand);
|
|
||||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
|
||||||
ModeSwitchProgressWrapper("Rebooting phone to Bootloader mode...", null);
|
|
||||||
LogFile.Log("Rebooting phone to Bootloader mode", LogType.FileAndConsole);
|
|
||||||
break;
|
|
||||||
case PhoneInterfaces.Lumia_Label:
|
|
||||||
SwitchFromFlashToLabelMode();
|
|
||||||
break;
|
|
||||||
case PhoneInterfaces.Lumia_Flash: // attempt to boot from limited flash to full flash
|
|
||||||
byte[] RebootToFlashCommand = new byte[] { 0x4E, 0x4F, 0x4B, 0x53 }; // NOKS
|
|
||||||
((NokiaPhoneModel)CurrentModel).ExecuteRawVoidMethod(RebootToFlashCommand);
|
|
||||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
|
||||||
ModeSwitchProgressWrapper("Rebooting phone to Flash mode...", null);
|
|
||||||
LogFile.Log("Rebooting phone to Flash mode", LogType.FileAndConsole);
|
|
||||||
break;
|
|
||||||
case PhoneInterfaces.Lumia_MassStorage:
|
|
||||||
SwitchFromFlashToMassStorageMode();
|
|
||||||
break;
|
|
||||||
case PhoneInterfaces.Qualcomm_Download:
|
|
||||||
byte[] RebootToQualcommDownloadCommand = new byte[] { 0x4E, 0x4F, 0x4B, 0x58, 0x43, 0x42, 0x45 }; // NOKXCBE
|
|
||||||
RebootCommandResult = ((NokiaPhoneModel)CurrentModel).ExecuteRawMethod(RebootToQualcommDownloadCommand);
|
|
||||||
if (RebootCommandResult?.Length == 4) // This means fail: NOKU (unknow command)
|
|
||||||
{
|
|
||||||
IsSwitchingInterface = false;
|
|
||||||
ModeSwitchErrorWrapper("Failed to switch to Qualcomm Download mode");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
|
||||||
ModeSwitchProgressWrapper("Rebooting phone to Qualcomm Download mode...", null);
|
|
||||||
LogFile.Log("Rebooting phone to Qualcomm Download mode", LogType.FileAndConsole);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PhoneInterfaces.Lumia_MassStorage:
|
|
||||||
IsSwitchingInterface = true;
|
|
||||||
switch (TargetMode)
|
|
||||||
{
|
|
||||||
case PhoneInterfaces.Lumia_Normal:
|
|
||||||
((MassStorage)CurrentModel).Reboot();
|
|
||||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
|
||||||
ModeSwitchProgressWrapper("Rebooting phone to Normal mode...", null);
|
|
||||||
LogFile.Log("Rebooting phone to Normal mode", LogType.FileAndConsole);
|
|
||||||
break;
|
|
||||||
case PhoneInterfaces.Lumia_Label:
|
|
||||||
((MassStorage)CurrentModel).Reboot();
|
|
||||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrivedFromMassStorageMode;
|
|
||||||
ModeSwitchProgressWrapper("Rebooting phone to Label mode...", null);
|
|
||||||
LogFile.Log("Rebooting phone to Label mode...", LogType.FileAndConsole);
|
|
||||||
break;
|
|
||||||
case PhoneInterfaces.Lumia_Flash:
|
|
||||||
((MassStorage)CurrentModel).Reboot();
|
|
||||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrivedFromMassStorageMode;
|
|
||||||
ModeSwitchProgressWrapper("Rebooting phone to Flash mode...", null);
|
|
||||||
LogFile.Log("Rebooting phone to Flash mode...", LogType.FileAndConsole);
|
|
||||||
break;
|
|
||||||
case null:
|
|
||||||
((MassStorage)CurrentModel).Reboot();
|
|
||||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrivedFromMassStorageMode;
|
|
||||||
ModeSwitchProgressWrapper("First rebooting phone to Flash mode...", null);
|
|
||||||
LogFile.Log("First rebooting phone to Bootloader mode...", LogType.FileAndConsole);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PhoneInterfaces.Qualcomm_Download:
|
|
||||||
// TODO: don't know how to switch from Qualcomm Download mode to other mode
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void NewDeviceArrivedFromMassStorageMode(ArrivalEventArgs Args)
|
|
||||||
{
|
|
||||||
PhoneNotifier.NewDeviceArrived -= NewDeviceArrivedFromMassStorageMode;
|
|
||||||
|
|
||||||
CurrentModel = Args.NewModel;
|
|
||||||
CurrentMode = Args.NewInterface;
|
|
||||||
|
|
||||||
// After the mass storage mode reboot command, the phone must be in Bootloader mode.
|
|
||||||
// If it isn't, something unexpected happened and the phone can't be switched.
|
|
||||||
//
|
|
||||||
if (CurrentMode == PhoneInterfaces.Lumia_Bootloader)
|
|
||||||
{
|
|
||||||
Task.Run(async () =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await SwitchToWithStatus(PhoneNotifier, TargetMode, SetWorkingStatus, UpdateWorkingStatus);
|
|
||||||
ModeSwitchSuccessWrapper();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
switch (TargetMode)
|
|
||||||
{
|
|
||||||
case PhoneInterfaces.Lumia_Flash:
|
|
||||||
ModeSwitchErrorWrapper("Failed to switch to Flash mode");
|
|
||||||
break;
|
|
||||||
case PhoneInterfaces.Lumia_Label:
|
|
||||||
ModeSwitchErrorWrapper("Failed to switch to Label mode");
|
|
||||||
break;
|
|
||||||
case PhoneInterfaces.Lumia_Normal:
|
|
||||||
ModeSwitchErrorWrapper("Failed to switch to Normal mode");
|
|
||||||
break;
|
|
||||||
case null:
|
|
||||||
ModeSwitchSuccessWrapper();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (TargetMode)
|
|
||||||
{
|
|
||||||
case PhoneInterfaces.Lumia_Flash:
|
|
||||||
ModeSwitchErrorWrapper("Failed to switch to Flash mode");
|
|
||||||
break;
|
|
||||||
case PhoneInterfaces.Lumia_Label:
|
|
||||||
ModeSwitchErrorWrapper("Failed to switch to Label mode");
|
|
||||||
break;
|
|
||||||
case PhoneInterfaces.Lumia_Normal:
|
|
||||||
ModeSwitchErrorWrapper("Failed to switch to Normal mode");
|
|
||||||
break;
|
|
||||||
case null:
|
|
||||||
ModeSwitchErrorWrapper("Failed to shutdown");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void NewDeviceArrived(ArrivalEventArgs Args)
|
|
||||||
{
|
|
||||||
PhoneNotifier.NewDeviceArrived -= NewDeviceArrived;
|
|
||||||
|
|
||||||
CurrentModel = Args.NewModel;
|
|
||||||
CurrentMode = Args.NewInterface;
|
|
||||||
|
|
||||||
if ((CurrentMode == PhoneInterfaces.Lumia_Bootloader) && (TargetMode == PhoneInterfaces.Lumia_Flash))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Going from BootMgr to FlashApp
|
|
||||||
// SwitchToFlashAppContext() will only switch context. Phone will not charge.
|
|
||||||
// ResetPhoneToFlashMode() reboots to real flash app. Phone will charge. Works when in BootMgrApp, not when already in FlashApp.
|
|
||||||
|
|
||||||
((NokiaFlashModel)CurrentModel).ResetPhoneToFlashMode();
|
|
||||||
CurrentMode = PhoneInterfaces.Lumia_Flash;
|
|
||||||
PhoneNotifier.NotifyArrival();
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CurrentMode == TargetMode)
|
|
||||||
{
|
|
||||||
if (TargetMode == PhoneInterfaces.Lumia_Bootloader)
|
|
||||||
{
|
|
||||||
((NokiaFlashModel)CurrentModel).DisableRebootTimeOut();
|
|
||||||
}
|
|
||||||
|
|
||||||
ModeSwitchSuccessWrapper();
|
|
||||||
}
|
|
||||||
else if (!IsSwitching)
|
|
||||||
{
|
|
||||||
StartSwitch();
|
|
||||||
}
|
|
||||||
else if ((CurrentMode == PhoneInterfaces.Lumia_Bootloader) && (TargetMode == PhoneInterfaces.Lumia_Normal))
|
|
||||||
{
|
|
||||||
// Do nothing, because booting to Normal shortly goes into Flash mode too.
|
|
||||||
// Just wait to arrive in Normal mode;
|
|
||||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
|
||||||
}
|
|
||||||
else if ((CurrentMode == PhoneInterfaces.Lumia_Flash) && (TargetMode == PhoneInterfaces.Lumia_MassStorage))
|
|
||||||
{
|
|
||||||
SwitchFromFlashToMassStorageMode(Continuation: true);
|
|
||||||
}
|
|
||||||
else if ((CurrentMode == PhoneInterfaces.Lumia_Flash) && (TargetMode == PhoneInterfaces.Lumia_Label))
|
|
||||||
{
|
|
||||||
SwitchFromFlashToLabelMode(Continuation: true);
|
|
||||||
}
|
|
||||||
else if ((CurrentMode == PhoneInterfaces.Lumia_Flash) && (TargetMode == PhoneInterfaces.Qualcomm_Download))
|
|
||||||
{
|
|
||||||
byte[] RebootCommand = new byte[] { 0x4E, 0x4F, 0x4B, 0x52 };
|
|
||||||
byte[] RebootToQualcommDownloadCommand = new byte[] { 0x4E, 0x4F, 0x4B, 0x58, 0x43, 0x42, 0x45 }; // NOKXCBE
|
|
||||||
IsSwitchingInterface = true;
|
|
||||||
LogFile.Log("Sending command for rebooting to Emergency Download mode");
|
|
||||||
byte[] RebootCommandResult = ((NokiaPhoneModel)CurrentModel).ExecuteRawMethod(RebootToQualcommDownloadCommand);
|
|
||||||
if (RebootCommandResult?.Length >= 8)
|
|
||||||
{
|
|
||||||
int ResultCode = (RebootCommandResult[6] << 8) + RebootCommandResult[7];
|
|
||||||
LogFile.Log("Resultcode: 0x" + ResultCode.ToString("X4"));
|
|
||||||
}
|
|
||||||
if (RebootCommandResult?.Length == 4) // This means fail: NOKU (unknow command)
|
|
||||||
{
|
|
||||||
ModeSwitchErrorWrapper("Failed to switch to Qualcomm Download mode");
|
|
||||||
IsSwitchingInterface = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
|
||||||
ModeSwitchProgressWrapper("And now rebooting phone to Qualcomm Download mode...", null);
|
|
||||||
LogFile.Log("Rebooting phone to Qualcomm Download mode");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (TargetMode)
|
|
||||||
{
|
|
||||||
case PhoneInterfaces.Lumia_Normal:
|
|
||||||
ModeSwitchErrorWrapper("Failed to switch to Normal mode");
|
|
||||||
break;
|
|
||||||
case PhoneInterfaces.Lumia_Flash:
|
|
||||||
ModeSwitchErrorWrapper("Failed to switch to Flash mode");
|
|
||||||
break;
|
|
||||||
case PhoneInterfaces.Lumia_Label:
|
|
||||||
ModeSwitchErrorWrapper("Failed to switch to Label mode");
|
|
||||||
break;
|
|
||||||
case PhoneInterfaces.Lumia_MassStorage:
|
|
||||||
ModeSwitchErrorWrapper("Failed to switch to Mass Storage mode");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SwitchFromFlashToLabelMode(bool Continuation = false)
|
|
||||||
{
|
|
||||||
string ProgressText = Continuation ? "And now preparing to boot the phone to Label mode..." : "Preparing to boot the phone to Label mode...";
|
|
||||||
NokiaFlashModel FlashModel = (NokiaFlashModel)CurrentModel;
|
|
||||||
if (CurrentMode == PhoneInterfaces.Lumia_Bootloader)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
FlashModel.SwitchToFlashAppContext();
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
PhoneInfo Info = FlashModel.ReadPhoneInfo(ExtendedInfo: true);
|
|
||||||
|
|
||||||
if (Info.MmosOverUsbSupported)
|
|
||||||
{
|
|
||||||
new Thread(() =>
|
|
||||||
{
|
|
||||||
LogFile.BeginAction("SwitchToLabelMode");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ModeSwitchProgressWrapper(ProgressText, null);
|
|
||||||
string TempFolder = Environment.GetEnvironmentVariable("TEMP") + @"\WPInternals";
|
|
||||||
if (Info.Type == "RM-1152")
|
|
||||||
{
|
|
||||||
Info.Type = "RM-1151";
|
|
||||||
}
|
|
||||||
string ENOSWPackage = LumiaDownloadModel.SearchENOSW(Info.Type, Info.Firmware);
|
|
||||||
SetWorkingStatus("Downloading " + Info.Type + " Test Mode package...", MaxProgressValue: 100);
|
|
||||||
DownloadEntry downloadEntry = new(ENOSWPackage, TempFolder, null, null, null);
|
|
||||||
|
|
||||||
downloadEntry.PropertyChanged += (object sender, System.ComponentModel.PropertyChangedEventArgs e) =>
|
|
||||||
{
|
|
||||||
if (e.PropertyName == "Progress")
|
|
||||||
{
|
|
||||||
int progress = (sender as DownloadEntry)?.Progress ?? 0;
|
|
||||||
ulong.TryParse(progress.ToString(), out ulong progressret);
|
|
||||||
UpdateWorkingStatus(null, CurrentProgressValue: progressret);
|
|
||||||
|
|
||||||
if (progress == 100)
|
|
||||||
{
|
|
||||||
ModeSwitchProgressWrapper("Initializing Flash...", null);
|
|
||||||
|
|
||||||
string MMOSPath = TempFolder + "\\" + (sender as DownloadEntry)?.Name;
|
|
||||||
|
|
||||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
|
||||||
FileInfo info = new(MMOSPath);
|
|
||||||
uint length = uint.Parse(info.Length.ToString());
|
|
||||||
const int maximumbuffersize = 0x00240000;
|
|
||||||
uint totalcounts = (uint)Math.Truncate((decimal)length / maximumbuffersize);
|
|
||||||
|
|
||||||
SetWorkingStatus("Flashing Test Mode package...", MaxProgressValue: 100);
|
|
||||||
|
|
||||||
ProgressUpdater progressUpdater = new(totalcounts + 1, (int i, TimeSpan? time) => UpdateWorkingStatus(null, CurrentProgressValue: (ulong)i));
|
|
||||||
FlashModel.FlashMMOS(MMOSPath, progressUpdater);
|
|
||||||
|
|
||||||
SetWorkingStatus("And now booting phone to MMOS...", "If the phone stays on the lightning cog screen for a while, you may need to unplug and replug the phone to continue the boot process.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
catch (Exception Ex)
|
|
||||||
{
|
|
||||||
LogFile.LogException(Ex);
|
|
||||||
ModeSwitchErrorWrapper(Ex.Message);
|
|
||||||
}
|
|
||||||
|
|
||||||
LogFile.EndAction("SwitchToLabelMode");
|
|
||||||
}).Start();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
byte[] BootModeFlagCommand = new byte[] { 0x4E, 0x4F, 0x4B, 0x58, 0x46, 0x57, 0x00, 0x55, 0x42, 0x46, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 }; // NOKFW UBF
|
|
||||||
byte[] RebootCommand = new byte[] { 0x4E, 0x4F, 0x4B, 0x52 }; // NOKR
|
|
||||||
|
|
||||||
BootModeFlagCommand[0x0F] = 0x59;
|
|
||||||
((NokiaPhoneModel)CurrentModel).ExecuteRawMethod(BootModeFlagCommand);
|
|
||||||
((NokiaPhoneModel)CurrentModel).ExecuteRawVoidMethod(RebootCommand);
|
|
||||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
|
||||||
ModeSwitchProgressWrapper("Rebooting phone to Label mode", null);
|
|
||||||
LogFile.Log("Rebooting phone to Label mode", LogType.FileAndConsole);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SwitchFromFlashToMassStorageMode(bool Continuation = false)
|
|
||||||
{
|
|
||||||
string ProgressText = Continuation ? "And now rebooting phone to Mass Storage mode..." : "Rebooting phone to Mass Storage mode...";
|
|
||||||
NokiaFlashModel FlashModel = (NokiaFlashModel)CurrentModel;
|
|
||||||
if (CurrentMode == PhoneInterfaces.Lumia_Bootloader)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
FlashModel.SwitchToFlashAppContext();
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
PhoneInfo Info = FlashModel.ReadPhoneInfo(ExtendedInfo: false);
|
|
||||||
|
|
||||||
MassStorageWarning = null;
|
|
||||||
if (Info.FlashAppProtocolVersionMajor < 2)
|
|
||||||
{
|
|
||||||
MassStorageWarning = "Switching to Mass Storage mode should take about 10 seconds. The phone should be unlocked using an Engineering SBL3 to enable Mass Storage mode. When you unlocked the bootloader, but you did not use an Engineering SBL3, an attempt to boot to Mass Storage mode may result in an unresponsive state. Installing drivers for this interface may also cause to hang the PC. So when this switch is taking too long, you should reboot both the PC and the phone. To reboot the phone, you have to perform a soft-reset. Press and hold the volume-down-button and the power-button at the same time for at least 10 seconds. This will trigger a power-cycle and the phone will reboot. Once fully booted, the phone may show strange behavior, like complaining about mail-accounts, showing old text-messages, inability to load https-websites, etc. This is expected behavior, because the time-settings of the phone are incorrect. Just wait a few seconds for the phone to get a data-connection and have the date/time synced. After that the strange behavior will stop automatically and normal operation is resumed.";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MassStorageWarning = "When the screen of the phone is black for a while, it could be that the phone is already in Mass Storage Mode, but there is no drive-letter assigned. To resolve this issue, open Device Manager and manually assign a drive-letter to the MainOS partition of your phone, or open a command-prompt and type: diskpart automount enable.";
|
|
||||||
if (App.IsPnPEventLogMissing)
|
|
||||||
{
|
|
||||||
MassStorageWarning += " It is also possible that the phone is in Mass Storage mode, but the Mass Storage driver on this PC failed. Your PC does not have an eventlog to detect this misbehaviour. But in this case you will see a device with an exclamation mark in Device Manager and then you need to manually reset the phone by pressing and holding the power-button for at least 10 seconds until it vibrates and reboots. After that Windows Phone Internals will revert the changes. After the phone has rebooted to the OS, you can retry to unlock the bootloader.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsOldLumia = Info.FlashAppProtocolVersionMajor < 2;
|
|
||||||
bool IsNewLumia = Info.FlashAppProtocolVersionMajor >= 2;
|
|
||||||
bool IsUnlockedNew = false;
|
|
||||||
if (IsNewLumia)
|
|
||||||
{
|
|
||||||
GPT GPT = FlashModel.ReadGPT();
|
|
||||||
IsUnlockedNew = (GPT.GetPartition("IS_UNLOCKED") != null) || (GPT.GetPartition("BACKUP_EFIESP") != null) || (GPT.GetPartition("BACKUP_BS_NV") != null);
|
|
||||||
}
|
|
||||||
bool IsOriginalEngineeringLumia = !Info.IsBootloaderSecure && !IsUnlockedNew;
|
|
||||||
|
|
||||||
if (IsOldLumia || IsOriginalEngineeringLumia)
|
|
||||||
{
|
|
||||||
byte[] BootModeFlagCommand = new byte[] { 0x4E, 0x4F, 0x4B, 0x58, 0x46, 0x57, 0x00, 0x55, 0x42, 0x46, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 }; // NOKFW UBF
|
|
||||||
byte[] RebootCommand = new byte[] { 0x4E, 0x4F, 0x4B, 0x52 };
|
|
||||||
byte[] RebootToMassStorageCommand = new byte[] { 0x4E, 0x4F, 0x4B, 0x4D }; // NOKM
|
|
||||||
IsSwitchingInterface = true;
|
|
||||||
byte[] RebootCommandResult = ((NokiaPhoneModel)CurrentModel).ExecuteRawMethod(RebootToMassStorageCommand);
|
|
||||||
if (RebootCommandResult?.Length == 4) // This means fail: NOKU (unknown command)
|
|
||||||
{
|
|
||||||
BootModeFlagCommand[0x0F] = 0x4D;
|
|
||||||
byte[] BootFlagResult = ((NokiaPhoneModel)CurrentModel).ExecuteRawMethod(BootModeFlagCommand);
|
|
||||||
UInt16 ResultCode = BitConverter.ToUInt16(BootFlagResult, 6);
|
|
||||||
if (ResultCode == 0)
|
|
||||||
{
|
|
||||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
|
||||||
((NokiaPhoneModel)CurrentModel).ExecuteRawVoidMethod(RebootCommand);
|
|
||||||
ModeSwitchProgressWrapper(ProgressText, MassStorageWarning);
|
|
||||||
LogFile.Log("Rebooting phone to Mass Storage mode");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ModeSwitchErrorWrapper("Failed to switch to Mass Storage mode");
|
|
||||||
IsSwitchingInterface = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
|
||||||
ModeSwitchProgressWrapper(ProgressText, MassStorageWarning);
|
|
||||||
LogFile.Log("Rebooting phone to Mass Storage mode");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (IsUnlockedNew)
|
|
||||||
{
|
|
||||||
new Thread(async () =>
|
|
||||||
{
|
|
||||||
LogFile.BeginAction("SwitchToMassStorageMode");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Implementation of writing a partition with SecureBoot variable to the phone
|
|
||||||
ModeSwitchProgressWrapper(ProgressText, MassStorageWarning);
|
|
||||||
LogFile.Log("Preparing phone for Mass Storage Mode", LogType.FileAndConsole);
|
|
||||||
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
|
|
||||||
|
|
||||||
// Magic!
|
|
||||||
// The SBMSM resource is a compressed version of a raw NV-variable-partition.
|
|
||||||
// In this partition the SecureBoot variable is disabled and an extra variable is added which triggers Mass Storage Mode on next reboot.
|
|
||||||
// It overwrites the variable in a different NV-partition than where this variable is stored usually.
|
|
||||||
// This normally leads to endless-loops when the NV-variables are enumerated.
|
|
||||||
// But the partition contains an extra hack to break out the endless loops.
|
|
||||||
using (var stream = assembly.GetManifestResourceStream("WPinternals.SBMSM"))
|
|
||||||
{
|
|
||||||
using DecompressedStream dec = new(stream);
|
|
||||||
using MemoryStream SB = new(); // Must be a seekable stream!
|
|
||||||
dec.CopyTo(SB);
|
|
||||||
|
|
||||||
// We don't need to check for the BACKUP_BS_NV partition here,
|
|
||||||
// because the SecureBoot flag is disabled here.
|
|
||||||
// So either the NV was already backupped or already overwritten.
|
|
||||||
|
|
||||||
GPT GPT = FlashModel.ReadGPT();
|
|
||||||
Partition Target = GPT.GetPartition("UEFI_BS_NV");
|
|
||||||
|
|
||||||
// We've been reading the GPT, so we let the phone reset once more to be sure that memory maps are the same
|
|
||||||
WPinternalsStatus LastStatus = WPinternalsStatus.Undefined;
|
|
||||||
List<FlashPart> Parts = new();
|
|
||||||
FlashPart Part = new();
|
|
||||||
Part.StartSector = (uint)Target.FirstSector;
|
|
||||||
Part.Stream = SB;
|
|
||||||
Parts.Add(Part);
|
|
||||||
await LumiaV2UnlockBootViewModel.LumiaV2CustomFlash(PhoneNotifier, null, false, false, Parts, DoResetFirst: true, ClearFlashingStatusAtEnd: false, ShowProgress: false,
|
|
||||||
SetWorkingStatus: (m, s, v, a, st) =>
|
|
||||||
{
|
|
||||||
if (SetWorkingStatus != null)
|
|
||||||
{
|
|
||||||
if ((st == WPinternalsStatus.Scanning) || (st == WPinternalsStatus.WaitingForManualReset))
|
|
||||||
{
|
|
||||||
SetWorkingStatus(m, s, v, a, st);
|
|
||||||
}
|
|
||||||
else if ((LastStatus == WPinternalsStatus.Scanning) || (LastStatus == WPinternalsStatus.WaitingForManualReset))
|
|
||||||
{
|
|
||||||
SetWorkingStatus(ProgressText, MassStorageWarning);
|
|
||||||
}
|
|
||||||
|
|
||||||
LastStatus = st;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
UpdateWorkingStatus: (m, s, v, st) =>
|
|
||||||
{
|
|
||||||
if (UpdateWorkingStatus != null)
|
|
||||||
{
|
|
||||||
if ((st == WPinternalsStatus.Scanning) || (st == WPinternalsStatus.WaitingForManualReset))
|
|
||||||
{
|
|
||||||
UpdateWorkingStatus(m, s, v, st);
|
|
||||||
}
|
|
||||||
else if ((LastStatus == WPinternalsStatus.Scanning) || (LastStatus == WPinternalsStatus.WaitingForManualReset))
|
|
||||||
{
|
|
||||||
SetWorkingStatus(ProgressText, MassStorageWarning);
|
|
||||||
}
|
|
||||||
|
|
||||||
LastStatus = st;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PhoneNotifier.CurrentInterface == PhoneInterfaces.Lumia_BadMassStorage)
|
|
||||||
{
|
|
||||||
throw new WPinternalsException("Phone is in Mass Storage mode, but the driver on PC failed to start");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for bootloader
|
|
||||||
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_MassStorage)
|
|
||||||
{
|
|
||||||
LogFile.Log("Waiting for Mass Storage Mode (1)...", LogType.FileOnly);
|
|
||||||
await PhoneNotifier.WaitForArrival();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PhoneNotifier.CurrentInterface == PhoneInterfaces.Lumia_BadMassStorage)
|
|
||||||
{
|
|
||||||
throw new WPinternalsException("Phone is in Mass Storage mode, but the driver on PC failed to start");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for mass storage mode
|
|
||||||
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_MassStorage)
|
|
||||||
{
|
|
||||||
LogFile.Log("Waiting for Mass Storage Mode (2)...", LogType.FileOnly);
|
|
||||||
await PhoneNotifier.WaitForArrival();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PhoneNotifier.CurrentInterface == PhoneInterfaces.Lumia_BadMassStorage)
|
|
||||||
{
|
|
||||||
throw new WPinternalsException("Phone is in Mass Storage mode, but the driver on PC failed to start");
|
|
||||||
}
|
|
||||||
|
|
||||||
MassStorage Storage = null;
|
|
||||||
if (PhoneNotifier.CurrentModel is MassStorage)
|
|
||||||
{
|
|
||||||
Storage = (MassStorage)PhoneNotifier.CurrentModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Storage == null)
|
|
||||||
{
|
|
||||||
ModeSwitchErrorWrapper("Failed to switch to Mass Storage Mode");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ModeSwitchSuccessWrapper();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception Ex)
|
|
||||||
{
|
|
||||||
LogFile.LogException(Ex);
|
|
||||||
ModeSwitchErrorWrapper(Ex.Message);
|
|
||||||
}
|
|
||||||
|
|
||||||
LogFile.EndAction("SwitchToMassStorageMode");
|
|
||||||
}).Start();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ModeSwitchErrorWrapper("Bootloader was not unlocked. First unlock bootloader before you try to switch to Mass Storage Mode.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal async static Task<IDisposable> SwitchTo(PhoneNotifierViewModel Notifier, PhoneInterfaces? TargetMode, string RequestedVolumeForMassStorage = "MainOS")
|
|
||||||
{
|
|
||||||
return await SwitchToWithProgress(Notifier, TargetMode, null, RequestedVolumeForMassStorage);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal async static Task<IDisposable> SwitchToWithProgress(PhoneNotifierViewModel Notifier, PhoneInterfaces? TargetMode, ModeSwitchProgressHandler ModeSwitchProgress, string RequestedVolumeForMassStorage = "MainOS")
|
|
||||||
{
|
|
||||||
if (Notifier.CurrentInterface == TargetMode)
|
|
||||||
{
|
|
||||||
return Notifier.CurrentModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
IDisposable Result = null;
|
|
||||||
string LocalErrorMessage = null;
|
|
||||||
|
|
||||||
AsyncAutoResetEvent Event = new(false);
|
|
||||||
|
|
||||||
SwitchModeViewModel Switch = new(
|
|
||||||
Notifier,
|
|
||||||
TargetMode,
|
|
||||||
ModeSwitchProgress,
|
|
||||||
(string ErrorMessage) =>
|
|
||||||
{
|
|
||||||
LocalErrorMessage = ErrorMessage;
|
|
||||||
Event.Set();
|
|
||||||
},
|
|
||||||
(IDisposable NewModel, PhoneInterfaces NewInterface) =>
|
|
||||||
{
|
|
||||||
Result = NewModel;
|
|
||||||
Event.Set();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
await Event.WaitAsync(Timeout.InfiniteTimeSpan);
|
|
||||||
|
|
||||||
if (LocalErrorMessage != null)
|
|
||||||
{
|
|
||||||
throw new WPinternalsException(LocalErrorMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal async static Task<IDisposable> SwitchToWithStatus(PhoneNotifierViewModel Notifier, PhoneInterfaces? TargetMode, SetWorkingStatus SetWorkingStatus = null, UpdateWorkingStatus UpdateWorkingStatus = null, string RequestedVolumeForMassStorage = "MainOS")
|
|
||||||
{
|
|
||||||
if (Notifier.CurrentInterface == TargetMode)
|
|
||||||
{
|
|
||||||
return Notifier.CurrentModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
IDisposable Result = null;
|
|
||||||
string LocalErrorMessage = null;
|
|
||||||
|
|
||||||
AsyncAutoResetEvent Event = new(false);
|
|
||||||
|
|
||||||
SwitchModeViewModel Switch = new(
|
|
||||||
Notifier,
|
|
||||||
TargetMode,
|
|
||||||
null,
|
|
||||||
(string ErrorMessage) =>
|
|
||||||
{
|
|
||||||
LocalErrorMessage = ErrorMessage;
|
|
||||||
Event.Set();
|
|
||||||
},
|
|
||||||
(IDisposable NewModel, PhoneInterfaces NewInterface) =>
|
|
||||||
{
|
|
||||||
Result = NewModel;
|
|
||||||
Event.Set();
|
|
||||||
}, SetWorkingStatus, UpdateWorkingStatus
|
|
||||||
);
|
|
||||||
|
|
||||||
await Event.WaitAsync(Timeout.InfiniteTimeSpan);
|
|
||||||
|
|
||||||
if (LocalErrorMessage != null)
|
|
||||||
{
|
|
||||||
throw new WPinternalsException(LocalErrorMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,240 +0,0 @@
|
|||||||
<!--
|
|
||||||
Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
copy of this software and associated documentation files (the "Software"),
|
|
||||||
to deal in the Software without restriction, including without limitation
|
|
||||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
DEALINGS IN THE SOFTWARE.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<UserControl x:Class="WPinternals.LumiaDownloadView"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:local="clr-namespace:WPinternals"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
d:DesignWidth="700">
|
|
||||||
<UserControl.Resources>
|
|
||||||
<local:ObjectToVisibilityConverter x:Key="ObjectToVisibilityConverter" />
|
|
||||||
<local:DownloaderNameConvertor x:Key="DownloaderNameConvertor" />
|
|
||||||
<local:DownloaderSizeConvertor x:Key="DownloaderSizeConvertor" />
|
|
||||||
<local:DownloaderSpeedConvertor x:Key="DownloaderSpeedConvertor" />
|
|
||||||
<local:DownloaderTimeRemainingConvertor x:Key="DownloaderTimeRemainingConvertor" />
|
|
||||||
<Style x:Key="HeaderLeftAligned" TargetType="{x:Type GridViewColumnHeader}">
|
|
||||||
<Setter Property="HorizontalContentAlignment" Value="Left"></Setter>
|
|
||||||
<Setter Property="Padding" Value="6,0,0,0"></Setter>
|
|
||||||
</Style>
|
|
||||||
<Style x:Key="HeaderRightAligned" TargetType="{x:Type GridViewColumnHeader}">
|
|
||||||
<Setter Property="HorizontalContentAlignment" Value="Right"></Setter>
|
|
||||||
<Setter Property="Padding" Value="0,0,6,0"></Setter>
|
|
||||||
</Style>
|
|
||||||
<Style x:Key="ContentRightAligned" TargetType="ListViewItem">
|
|
||||||
<Setter Property="HorizontalContentAlignment" Value="Right" />
|
|
||||||
<Setter Property="Padding" Value="0,0,6,0" />
|
|
||||||
</Style>
|
|
||||||
</UserControl.Resources>
|
|
||||||
<StackPanel VerticalAlignment="Center">
|
|
||||||
<Border BorderThickness="1" BorderBrush="#FFD4D4D4" HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="0,0,0,20">
|
|
||||||
<StackPanel>
|
|
||||||
<local:FlowDocumentScrollViewerNoMouseWheel Grid.Column="1" Margin="20,0,20,0" VerticalScrollBarVisibility="Auto" >
|
|
||||||
<FlowDocument FontFamily="Segoe UI" FontSize="12" Loaded="Document_Loaded" TextAlignment="Left">
|
|
||||||
<FlowDocument.Resources>
|
|
||||||
<!-- This style is used to set the margins for all paragraphs in the FlowDocument to 0. -->
|
|
||||||
<Style TargetType="{x:Type Paragraph}">
|
|
||||||
<Setter Property="Margin" Value="0"/>
|
|
||||||
</Style>
|
|
||||||
<Style TargetType="{x:Type Section}">
|
|
||||||
<Setter Property="Margin" Value="0"/>
|
|
||||||
</Style>
|
|
||||||
</FlowDocument.Resources>
|
|
||||||
<local:Paragraph>
|
|
||||||
<Run Text="Download" FontSize="18" FontWeight="Bold" Foreground="#FF3753A6" />
|
|
||||||
<LineBreak />
|
|
||||||
<LineBreak />
|
|
||||||
<local:FolderPicker Caption="Download folder: " SelectionText="Select the destination location for the downloaded files..." Path="{Binding DownloadFolder, Mode=TwoWay}" AllowNull="False" HorizontalAlignment="Stretch" />
|
|
||||||
</local:Paragraph>
|
|
||||||
</FlowDocument>
|
|
||||||
</local:FlowDocumentScrollViewerNoMouseWheel>
|
|
||||||
<TextBlock Margin="36,0,36,6">Currently downloading:</TextBlock>
|
|
||||||
<ListView Grid.Row="1" ItemsSource="{Binding DownloadList}" Margin="36,0,36,24" MinHeight="66" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Visible" local:GridViewColumnResize.Enabled="True" >
|
|
||||||
<ListView.ItemContainerStyle>
|
|
||||||
<Style TargetType="ListViewItem">
|
|
||||||
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
|
||||||
</Style>
|
|
||||||
</ListView.ItemContainerStyle>
|
|
||||||
<ListView.View>
|
|
||||||
<GridView>
|
|
||||||
<GridViewColumn local:GridViewColumnResize.Width="*" Header="Name" DisplayMemberBinding="{Binding Name}" HeaderContainerStyle="{StaticResource HeaderLeftAligned}" />
|
|
||||||
<GridViewColumn Width="80" Header="Size" HeaderContainerStyle="{StaticResource HeaderRightAligned}" >
|
|
||||||
<GridViewColumn.CellTemplate>
|
|
||||||
<DataTemplate>
|
|
||||||
<TextBlock Style="{x:Null}" Text="{Binding Size, Converter={StaticResource DownloaderSizeConvertor}}" TextAlignment="Right" />
|
|
||||||
</DataTemplate>
|
|
||||||
</GridViewColumn.CellTemplate>
|
|
||||||
</GridViewColumn>
|
|
||||||
<GridViewColumn Width="75" Header="Time Left" HeaderContainerStyle="{StaticResource HeaderRightAligned}" >
|
|
||||||
<GridViewColumn.CellTemplate>
|
|
||||||
<DataTemplate>
|
|
||||||
<TextBlock Style="{x:Null}" Text="{Binding TimeLeft,Mode=OneWay,Converter={StaticResource DownloaderTimeRemainingConvertor}}" TextAlignment="Right" />
|
|
||||||
</DataTemplate>
|
|
||||||
</GridViewColumn.CellTemplate>
|
|
||||||
</GridViewColumn>
|
|
||||||
<GridViewColumn Width="75" Header="Speed" HeaderContainerStyle="{StaticResource HeaderRightAligned}" >
|
|
||||||
<GridViewColumn.CellTemplate>
|
|
||||||
<DataTemplate>
|
|
||||||
<TextBlock Style="{x:Null}" Text="{Binding Speed, Mode=OneWay,Converter={StaticResource DownloaderSpeedConvertor}}" TextAlignment="Right" />
|
|
||||||
</DataTemplate>
|
|
||||||
</GridViewColumn.CellTemplate>
|
|
||||||
</GridViewColumn>
|
|
||||||
<GridViewColumn Width="123" Header="Progress">
|
|
||||||
<GridViewColumn.CellTemplate>
|
|
||||||
<DataTemplate>
|
|
||||||
<ProgressBar Value="{Binding Progress, Mode=OneWay}" Width="120" Height="16" Maximum="100"></ProgressBar>
|
|
||||||
</DataTemplate>
|
|
||||||
</GridViewColumn.CellTemplate>
|
|
||||||
</GridViewColumn>
|
|
||||||
</GridView>
|
|
||||||
</ListView.View>
|
|
||||||
</ListView>
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
<Border BorderThickness="1" BorderBrush="#FFD4D4D4" HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="0,0,0,20">
|
|
||||||
<StackPanel>
|
|
||||||
<local:FlowDocumentScrollViewerNoMouseWheel Grid.Column="1" Margin="20,0,20,0" VerticalScrollBarVisibility="Auto" >
|
|
||||||
<FlowDocument FontFamily="Segoe UI" FontSize="12" Loaded="Document_Loaded" TextAlignment="Left">
|
|
||||||
<FlowDocument.Resources>
|
|
||||||
<!-- This style is used to set the margins for all paragraphs in the FlowDocument to 0. -->
|
|
||||||
<Style TargetType="{x:Type Paragraph}">
|
|
||||||
<Setter Property="Margin" Value="0"/>
|
|
||||||
</Style>
|
|
||||||
<Style TargetType="{x:Type Section}">
|
|
||||||
<Setter Property="Margin" Value="0"/>
|
|
||||||
</Style>
|
|
||||||
</FlowDocument.Resources>
|
|
||||||
<local:Paragraph>
|
|
||||||
<Run Text="Model" FontSize="18" FontWeight="Bold" Foreground="#FF3753A6" />
|
|
||||||
<LineBreak/>
|
|
||||||
<LineBreak/>
|
|
||||||
<Run Text="When you choose "Download all", Windows Phone Internals will download an FFU-file and emergency-files for your phone. When the FFU-file is downloaded, it will be analyzed. And if the OS-version is not a supported version, then Windows Phone Internals will start to download another FFU-file, which should have a supported OS-version. It will be for a different model, but Windows Phone Internals needs it extract some files from it." />
|
|
||||||
<LineBreak/>
|
|
||||||
<LineBreak/>
|
|
||||||
<Run Text="When you connect your phone, the search criteria will be detected automatically. For some older Lumia models this may not work when the phone is in Flash mode. To get the exact search criteria, you need to switch the phone to Normal mode first." />
|
|
||||||
<LineBreak/>
|
|
||||||
<LineBreak/>
|
|
||||||
<Run Text="In some cases the emergency files cannot be found and you will need to download the emergency files yourself. This " />
|
|
||||||
<Hyperlink NavigateUri="https://www.google.com/search?q=%22Lumia 650 emergency files%22">google search</Hyperlink>
|
|
||||||
<Run Text=" may yield some relevant results." />
|
|
||||||
<LineBreak/>
|
|
||||||
<LineBreak/>
|
|
||||||
<Run Text="For some older Lumia models the operatorcode search criterion doesn't work. Your search may not yield any results when use the Operatorcode search criterion. You should use the Productcode to find the files for your exact model." />
|
|
||||||
<LineBreak/>
|
|
||||||
</local:Paragraph>
|
|
||||||
</FlowDocument>
|
|
||||||
</local:FlowDocumentScrollViewerNoMouseWheel>
|
|
||||||
<Grid Margin="36,-6,36,0">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Grid Grid.Column="0">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="100" />
|
|
||||||
<ColumnDefinition Width="120" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition />
|
|
||||||
<RowDefinition />
|
|
||||||
<RowDefinition />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<TextBlock Grid.Column="0" Grid.Row="0">Producttype</TextBlock>
|
|
||||||
<TextBlock Grid.Column="0" Grid.Row="1">Productcode</TextBlock>
|
|
||||||
<TextBlock Grid.Column="0" Grid.Row="2">Operatorcode</TextBlock>
|
|
||||||
<TextBox Grid.Column="1" Grid.Row="0" Width="Auto" Margin="0,0,0,8" Text="{Binding ProductType, Mode=TwoWay}"/>
|
|
||||||
<TextBox Grid.Column="1" Grid.Row="1" Width="Auto" Margin="0,0,0,8" Text="{Binding ProductCode, Mode=TwoWay}"/>
|
|
||||||
<TextBox Grid.Column="1" Grid.Row="2" Width="Auto" Text="{Binding OperatorCode, Mode=TwoWay}"/>
|
|
||||||
</Grid>
|
|
||||||
<StackPanel Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Bottom" Orientation="Horizontal">
|
|
||||||
<Button Content="Search" Padding="0,5" Width="120" Margin="0,0,20,0" Command="{Binding Path=SearchCommand, Mode=OneWay}" IsDefault="True"/>
|
|
||||||
<Button Content="Download all" Padding="0,5" Width="120" Command="{Binding Path=DownloadAllCommand, Mode=OneWay}" />
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<TextBlock Margin="36,30,36,6">Search results:</TextBlock>
|
|
||||||
<ListView Grid.Row="1" Name="SearchResultsListView" ItemsSource="{Binding SearchResultList}" Margin="36,0,36,0" MinHeight="66" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Visible" local:GridViewColumnResize.Enabled="True">
|
|
||||||
<ListView.ItemContainerStyle>
|
|
||||||
<Style TargetType="{x:Type ListBoxItem}">
|
|
||||||
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
|
|
||||||
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
|
||||||
</Style>
|
|
||||||
</ListView.ItemContainerStyle>
|
|
||||||
<ListView.View>
|
|
||||||
<GridView>
|
|
||||||
<GridViewColumn local:GridViewColumnResize.Width="*" Header="Name" DisplayMemberBinding="{Binding Name}" HeaderContainerStyle="{StaticResource HeaderLeftAligned}" />
|
|
||||||
<GridViewColumn Width="80" Header="Size" HeaderContainerStyle="{StaticResource HeaderRightAligned}" >
|
|
||||||
<GridViewColumn.CellTemplate>
|
|
||||||
<DataTemplate>
|
|
||||||
<TextBlock Style="{x:Null}" Text="{Binding Size, Converter={StaticResource DownloaderSizeConvertor}}" TextAlignment="Right" />
|
|
||||||
</DataTemplate>
|
|
||||||
</GridViewColumn.CellTemplate>
|
|
||||||
</GridViewColumn>
|
|
||||||
</GridView>
|
|
||||||
</ListView.View>
|
|
||||||
</ListView>
|
|
||||||
<StackPanel Orientation="Horizontal" Width="Auto" Height="Auto" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,16,36,25">
|
|
||||||
<Button Command="{Binding Path=DownloadSelectedCommand, Mode=OneWay}" Content="Download selected" Width="Auto" Height="Auto" Padding="20,5" />
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
<Border BorderThickness="1" BorderBrush="#FFD4D4D4" HorizontalAlignment="Stretch" VerticalAlignment="Center">
|
|
||||||
<StackPanel>
|
|
||||||
<local:FlowDocumentScrollViewerNoMouseWheel Grid.Column="1" Margin="20,0,20,0" VerticalScrollBarVisibility="Auto">
|
|
||||||
<FlowDocument FontFamily="Segoe UI" FontSize="12" Loaded="Document_Loaded" TextAlignment="Left">
|
|
||||||
<FlowDocument.Resources>
|
|
||||||
<!-- This style is used to set the margins for all paragraphs in the FlowDocument to 0. -->
|
|
||||||
<Style TargetType="{x:Type Paragraph}">
|
|
||||||
<Setter Property="Margin" Value="0"/>
|
|
||||||
</Style>
|
|
||||||
<Style TargetType="{x:Type Section}">
|
|
||||||
<Setter Property="Margin" Value="0"/>
|
|
||||||
</Style>
|
|
||||||
</FlowDocument.Resources>
|
|
||||||
<local:Paragraph>
|
|
||||||
<Run Text="Repository" FontSize="18" FontWeight="Bold" Foreground="#FF3753A6" />
|
|
||||||
</local:Paragraph>
|
|
||||||
</FlowDocument>
|
|
||||||
</local:FlowDocumentScrollViewerNoMouseWheel>
|
|
||||||
<local:FlowDocumentScrollViewerNoMouseWheel Grid.Column="1" Margin="20,-15,20,0" VerticalScrollBarVisibility="Auto" Visibility="{Binding Path=LastStatusText, Converter={StaticResource ObjectToVisibilityConverter}}">
|
|
||||||
<FlowDocument FontFamily="Segoe UI" FontSize="12" Loaded="Document_Loaded" TextAlignment="Left">
|
|
||||||
<FlowDocument.Resources>
|
|
||||||
<!-- This style is used to set the margins for all paragraphs in the FlowDocument to 0. -->
|
|
||||||
<Style TargetType="{x:Type Paragraph}">
|
|
||||||
<Setter Property="Margin" Value="0"/>
|
|
||||||
</Style>
|
|
||||||
<Style TargetType="{x:Type Section}">
|
|
||||||
<Setter Property="Margin" Value="0"/>
|
|
||||||
</Style>
|
|
||||||
</FlowDocument.Resources>
|
|
||||||
<local:Paragraph>
|
|
||||||
<Run Text="{Binding Path=LastStatusText}" />
|
|
||||||
</local:Paragraph>
|
|
||||||
</FlowDocument>
|
|
||||||
</local:FlowDocumentScrollViewerNoMouseWheel>
|
|
||||||
<Button Height="30" Width="Auto" Content="Add existing FFU-file..." Padding="20,5,20,5" HorizontalAlignment="Right" Margin="0,0,36,20" Command="{Binding Path=AddFFUCommand}"/>
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
</StackPanel>
|
|
||||||
</UserControl>
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
copy of this software and associated documentation files (the "Software"),
|
copy of this software and associated documentation files (the "Software"),
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
// copy of this software and associated documentation files (the "Software"),
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
@@ -20,9 +20,10 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using WPinternals.HelperClasses;
|
||||||
|
using WPinternals.Config;
|
||||||
|
|
||||||
namespace WPinternals
|
namespace WPinternals
|
||||||
{
|
{
|
||||||
@@ -76,14 +77,14 @@ namespace WPinternals
|
|||||||
Registration.CheckExpiration();
|
Registration.CheckExpiration();
|
||||||
|
|
||||||
string PatchDefintionsXml;
|
string PatchDefintionsXml;
|
||||||
string PatchDefintionsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "PatchDefintions.xml");
|
string PatchDefintionsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets", "PatchDefintions.xml");
|
||||||
if (File.Exists(PatchDefintionsPath))
|
if (File.Exists(PatchDefintionsPath))
|
||||||
{
|
{
|
||||||
PatchDefintionsXml = File.ReadAllText(PatchDefintionsPath);
|
PatchDefintionsXml = File.ReadAllText(PatchDefintionsPath);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
using Stream stream = System.Reflection.Assembly.GetEntryAssembly().GetManifestResourceStream("WPinternals.PatchDefinitions.xml");
|
using Stream stream = System.Reflection.Assembly.GetEntryAssembly().GetManifestResourceStream("WPinternals.Assets.PatchDefinitions.xml");
|
||||||
using StreamReader sr = new(stream);
|
using StreamReader sr = new(stream);
|
||||||
PatchDefintionsXml = sr.ReadToEnd();
|
PatchDefintionsXml = sr.ReadToEnd();
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB |
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Copyright(c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
Copyright(c) 2018, Rene Lergner - @Heathcliff74xda
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
copy of this software and associated documentation files(the "Software"),
|
copy of this software and associated documentation files(the "Software"),
|
||||||
|
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 |
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
// copy of this software and associated documentation files (the "Software"),
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
@@ -26,6 +26,11 @@ using System.Linq;
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using WPinternals.Config;
|
||||||
|
using WPinternals.HelperClasses;
|
||||||
|
using WPinternals.Models.Lumia.NCSd;
|
||||||
|
using WPinternals.Models.UEFIApps.BootMgr;
|
||||||
|
using WPinternals.Models.UEFIApps.Flash;
|
||||||
|
|
||||||
namespace WPinternals
|
namespace WPinternals
|
||||||
{
|
{
|
||||||
@@ -83,18 +88,16 @@ namespace WPinternals
|
|||||||
{
|
{
|
||||||
FFU FFU = null;
|
FFU FFU = null;
|
||||||
PhoneNotifierViewModel Notifier;
|
PhoneNotifierViewModel Notifier;
|
||||||
NokiaFlashModel FlashModel;
|
LumiaFlashAppModel FlashModel;
|
||||||
NokiaPhoneModel NormalModel;
|
LumiaBootManagerAppModel BootMgrModel;
|
||||||
PhoneInfo Info;
|
NokiaCareSuiteModel NormalModel;
|
||||||
|
LumiaFlashAppPhoneInfo FlashInfo;
|
||||||
|
LumiaBootManagerPhoneInfo BootManagerInfo;
|
||||||
string ProductType;
|
string ProductType;
|
||||||
string ProductCode;
|
|
||||||
string OperatorCode;
|
|
||||||
string DownloadFolder;
|
string DownloadFolder;
|
||||||
string FFUFilePath;
|
string FFUFilePath;
|
||||||
string URL;
|
|
||||||
string[] URLs;
|
string[] URLs;
|
||||||
Uri URI;
|
Uri URI;
|
||||||
string FFUFileName;
|
|
||||||
string EmergencyFileName;
|
string EmergencyFileName;
|
||||||
string EmergencyFilePath;
|
string EmergencyFilePath;
|
||||||
string ProgrammerPath = "";
|
string ProgrammerPath = "";
|
||||||
@@ -114,7 +117,7 @@ namespace WPinternals
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (args[1].ToLower().TrimStart(new char[] { '-', '/' }))
|
switch (args[1].ToLower().TrimStart(['-', '/']))
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
case "test":
|
case "test":
|
||||||
@@ -152,8 +155,12 @@ namespace WPinternals
|
|||||||
? Convert.ToUInt64(args[2][2..], 16)
|
? Convert.ToUInt64(args[2][2..], 16)
|
||||||
: Convert.ToUInt64(args[2], 10);
|
: Convert.ToUInt64(args[2], 10);
|
||||||
}
|
}
|
||||||
catch
|
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("Bad start sector", LogType.ConsoleOnly);
|
LogFile.Log("Bad start sector", LogType.ConsoleOnly);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -181,24 +188,13 @@ namespace WPinternals
|
|||||||
{
|
{
|
||||||
Notifier = new PhoneNotifierViewModel();
|
Notifier = new PhoneNotifierViewModel();
|
||||||
UIContext.Send(s => Notifier.Start(), null);
|
UIContext.Send(s => Notifier.Start(), null);
|
||||||
|
await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Bootloader);
|
||||||
FlashModel = (NokiaFlashModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Bootloader); // This also works for Bootloader Spec A
|
GPT GPT = await LumiaUnlockBootloaderViewModel.ReadGPTFromFlashOrBootMgr(Notifier);
|
||||||
|
|
||||||
GPT GPT = FlashModel.ReadGPT(); // May throw NotSupportedException
|
|
||||||
foreach (Partition Partition in GPT.Partitions)
|
foreach (Partition Partition in GPT.Partitions)
|
||||||
{
|
{
|
||||||
LogFile.Log(Partition.Name.PadRight(20) + "0x" + Partition.FirstSector.ToString("X8") + " - 0x" + Partition.LastSector.ToString("X8") + " " + Partition.Volume, LogType.ConsoleOnly);
|
LogFile.Log(Partition.Name.PadRight(20) + "0x" + Partition.FirstSector.ToString("X8") + " - 0x" + Partition.LastSector.ToString("X8") + " " + Partition.Volume, LogType.ConsoleOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FlashModel.ReadPhoneInfo(false).FlashAppProtocolVersionMajor >= 2)
|
|
||||||
{
|
|
||||||
FlashModel.SwitchToFlashAppContext();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
|
||||||
}
|
|
||||||
|
|
||||||
Notifier.Stop();
|
Notifier.Stop();
|
||||||
}
|
}
|
||||||
catch (Exception Ex)
|
catch (Exception Ex)
|
||||||
@@ -221,11 +217,14 @@ namespace WPinternals
|
|||||||
{
|
{
|
||||||
Notifier = new PhoneNotifierViewModel();
|
Notifier = new PhoneNotifierViewModel();
|
||||||
UIContext.Send(s => Notifier.Start(), null);
|
UIContext.Send(s => Notifier.Start(), null);
|
||||||
FlashModel = (NokiaFlashModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Bootloader);
|
||||||
GPT GPT = FlashModel.ReadGPT(); // May throw NotSupportedException
|
GPT GPT = await LumiaUnlockBootloaderViewModel.ReadGPTFromFlashOrBootMgr(Notifier);
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(args[2]));
|
string DirPath = Path.GetDirectoryName(args[2]);
|
||||||
|
if (!string.IsNullOrEmpty(DirPath) && !Directory.Exists(DirPath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(DirPath);
|
||||||
|
}
|
||||||
GPT.WritePartitions(args[2]);
|
GPT.WritePartitions(args[2]);
|
||||||
FlashModel.SwitchToFlashAppContext();
|
|
||||||
Notifier.Stop();
|
Notifier.Stop();
|
||||||
}
|
}
|
||||||
catch (Exception Ex)
|
catch (Exception Ex)
|
||||||
@@ -237,6 +236,35 @@ namespace WPinternals
|
|||||||
LogFile.EndAction("BackupGPT");
|
LogFile.EndAction("BackupGPT");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "convertgpt":
|
||||||
|
if (args.Length < 4)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Wrong number of arguments. Usage: WPinternals.exe -ConvertGPT <Path to GPT-file> <Path to xml-file>");
|
||||||
|
}
|
||||||
|
|
||||||
|
LogFile.BeginAction("ConvertGPT");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using FileStream stream = File.OpenRead(args[2]);
|
||||||
|
byte[] GPTBuffer = new byte[34 * 0x200];
|
||||||
|
stream.Read(GPTBuffer, 0, 34 * 0x200);
|
||||||
|
GPT GPT = new(GPTBuffer);// May throw NotSupportedException
|
||||||
|
string DirPath = Path.GetDirectoryName(args[3]);
|
||||||
|
if (!string.IsNullOrEmpty(DirPath) && !Directory.Exists(DirPath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(DirPath);
|
||||||
|
}
|
||||||
|
GPT.WritePartitions(args[3]);
|
||||||
|
}
|
||||||
|
catch (Exception Ex)
|
||||||
|
{
|
||||||
|
LogFile.LogException(Ex);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogFile.EndAction("ConvertGPT");
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "restoregpt":
|
case "restoregpt":
|
||||||
if (args.Length < 3)
|
if (args.Length < 3)
|
||||||
{
|
{
|
||||||
@@ -248,14 +276,12 @@ namespace WPinternals
|
|||||||
{
|
{
|
||||||
Notifier = new PhoneNotifierViewModel();
|
Notifier = new PhoneNotifierViewModel();
|
||||||
UIContext.Send(s => Notifier.Start(), null);
|
UIContext.Send(s => Notifier.Start(), null);
|
||||||
FlashModel = (NokiaFlashModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
byte[] GptChunk = await LumiaUnlockBootloaderViewModel.GetGptChunkFromFlashOrBootMgr(Notifier, 0x20000);
|
||||||
byte[] GptChunk = LumiaUnlockBootloaderViewModel.GetGptChunk(FlashModel, 0x20000);
|
|
||||||
GPT GPT = new(GptChunk);
|
GPT GPT = new(GptChunk);
|
||||||
string Xml = File.ReadAllText(args[2]);
|
string Xml = File.ReadAllText(args[2]);
|
||||||
GPT.MergePartitions(Xml, false);
|
GPT.MergePartitions(Xml, false);
|
||||||
GPT.Rebuild();
|
GPT.Rebuild();
|
||||||
await LumiaV2UnlockBootViewModel.LumiaV2CustomFlash(Notifier, null, false, false, 0, GptChunk, true, true);
|
await LumiaV2UnlockBootViewModel.LumiaV2CustomFlash(Notifier, null, false, false, 0, GptChunk, true, true);
|
||||||
FlashModel.SwitchToFlashAppContext();
|
|
||||||
Notifier.Stop();
|
Notifier.Stop();
|
||||||
}
|
}
|
||||||
catch (Exception Ex)
|
catch (Exception Ex)
|
||||||
@@ -285,7 +311,10 @@ namespace WPinternals
|
|||||||
s = new FileStream(args[3], FileMode.Open, FileAccess.Read);
|
s = new FileStream(args[3], FileMode.Open, FileAccess.Read);
|
||||||
Archive = new ZipArchive(s);
|
Archive = new ZipArchive(s);
|
||||||
}
|
}
|
||||||
catch { }
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogFile.LogException(ex, LogType.FileOnly);
|
||||||
|
}
|
||||||
|
|
||||||
if (Archive == null)
|
if (Archive == null)
|
||||||
{
|
{
|
||||||
@@ -393,7 +422,11 @@ namespace WPinternals
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
string EfiPath = Path.Combine(args[3], Name);
|
string EfiPath = Path.Combine(args[3], Name);
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(EfiPath));
|
string DirPath = Path.GetDirectoryName(EfiPath);
|
||||||
|
if (!string.IsNullOrEmpty(DirPath) && !Directory.Exists(DirPath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(DirPath);
|
||||||
|
}
|
||||||
File.WriteAllBytes(EfiPath, EfiBinary);
|
File.WriteAllBytes(EfiPath, EfiBinary);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -512,9 +545,9 @@ namespace WPinternals
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
UIContext.Send(s => Notifier.Start(), null);
|
UIContext.Send(s => Notifier.Start(), null);
|
||||||
FlashModel = (NokiaFlashModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
FlashModel = (LumiaFlashAppModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||||
Info = FlashModel.ReadPhoneInfo();
|
FlashInfo = FlashModel.ReadPhoneInfo();
|
||||||
Info.Log(LogType.ConsoleOnly);
|
FlashInfo.Log(LogType.ConsoleOnly);
|
||||||
|
|
||||||
FFU ProfileFFU = null;
|
FFU ProfileFFU = null;
|
||||||
FFU CurrentFFU;
|
FFU CurrentFFU;
|
||||||
@@ -527,7 +560,7 @@ namespace WPinternals
|
|||||||
string PlatformID = CurrentFFU.PlatformID;
|
string PlatformID = CurrentFFU.PlatformID;
|
||||||
|
|
||||||
// Check if the current FFU matches the connected phone, so that the FFU can be used for profiling.
|
// Check if the current FFU matches the connected phone, so that the FFU can be used for profiling.
|
||||||
if (Info.PlatformID.StartsWith(PlatformID, StringComparison.OrdinalIgnoreCase))
|
if (FlashInfo.PlatformID.StartsWith(PlatformID, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
ProfileFFU = CurrentFFU;
|
ProfileFFU = CurrentFFU;
|
||||||
}
|
}
|
||||||
@@ -536,7 +569,7 @@ namespace WPinternals
|
|||||||
|
|
||||||
if (ProfileFFU == null)
|
if (ProfileFFU == null)
|
||||||
{
|
{
|
||||||
List<FFUEntry> FFUs = App.Config.FFURepository.Where(e => Info.PlatformID.StartsWith(e.PlatformID, StringComparison.OrdinalIgnoreCase) && e.Exists()).ToList();
|
List<FFUEntry> FFUs = App.Config.FFURepository.Where(e => FlashInfo.PlatformID.StartsWith(e.PlatformID, StringComparison.OrdinalIgnoreCase) && e.Exists()).ToList();
|
||||||
ProfileFFU = FFUs.Count > 0
|
ProfileFFU = FFUs.Count > 0
|
||||||
? new FFU(FFUs[0].Path)
|
? new FFU(FFUs[0].Path)
|
||||||
: throw new WPinternalsException("Profile FFU missing", "No profile FFU has been found in the repository for your device. You can add a profile FFU within the download section of the tool or by using the command line.");
|
: throw new WPinternalsException("Profile FFU missing", "No profile FFU has been found in the repository for your device. You can add a profile FFU within the download section of the tool or by using the command line.");
|
||||||
@@ -661,9 +694,9 @@ namespace WPinternals
|
|||||||
LogFile.Log("Command: Show phone info", LogType.FileAndConsole);
|
LogFile.Log("Command: Show phone info", LogType.FileAndConsole);
|
||||||
Notifier = new PhoneNotifierViewModel();
|
Notifier = new PhoneNotifierViewModel();
|
||||||
UIContext.Send(s => Notifier.Start(), null);
|
UIContext.Send(s => Notifier.Start(), null);
|
||||||
FlashModel = (NokiaFlashModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
FlashModel = (LumiaFlashAppModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||||
Info = FlashModel.ReadPhoneInfo();
|
FlashInfo = FlashModel.ReadPhoneInfo();
|
||||||
Info.Log(LogType.ConsoleOnly);
|
FlashInfo.Log(LogType.ConsoleOnly);
|
||||||
Notifier.Stop();
|
Notifier.Stop();
|
||||||
break;
|
break;
|
||||||
case "unlockbootloader":
|
case "unlockbootloader":
|
||||||
@@ -673,9 +706,9 @@ namespace WPinternals
|
|||||||
LogFile.Log("Command: Unlock Bootloader", LogType.FileAndConsole);
|
LogFile.Log("Command: Unlock Bootloader", LogType.FileAndConsole);
|
||||||
Notifier = new PhoneNotifierViewModel();
|
Notifier = new PhoneNotifierViewModel();
|
||||||
UIContext.Send(s => Notifier.Start(), null);
|
UIContext.Send(s => Notifier.Start(), null);
|
||||||
FlashModel = (NokiaFlashModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
FlashModel = (LumiaFlashAppModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||||
Info = FlashModel.ReadPhoneInfo();
|
FlashInfo = FlashModel.ReadPhoneInfo();
|
||||||
Info.Log(LogType.ConsoleOnly);
|
FlashInfo.Log(LogType.ConsoleOnly);
|
||||||
|
|
||||||
FFU ProfileFFU = null;
|
FFU ProfileFFU = null;
|
||||||
FFU SupportedFFU = null;
|
FFU SupportedFFU = null;
|
||||||
@@ -689,7 +722,7 @@ namespace WPinternals
|
|||||||
string PlatformID = CurrentFFU.PlatformID;
|
string PlatformID = CurrentFFU.PlatformID;
|
||||||
|
|
||||||
// Check if the current FFU matches the connected phone, so that the FFU can be used for profiling.
|
// Check if the current FFU matches the connected phone, so that the FFU can be used for profiling.
|
||||||
if (Info.PlatformID.StartsWith(PlatformID, StringComparison.OrdinalIgnoreCase))
|
if (FlashInfo.PlatformID.StartsWith(PlatformID, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
ProfileFFU = CurrentFFU;
|
ProfileFFU = CurrentFFU;
|
||||||
}
|
}
|
||||||
@@ -704,7 +737,7 @@ namespace WPinternals
|
|||||||
|
|
||||||
if (ProfileFFU == null)
|
if (ProfileFFU == null)
|
||||||
{
|
{
|
||||||
List<FFUEntry> FFUs = App.Config.FFURepository.Where(e => Info.PlatformID.StartsWith(e.PlatformID, StringComparison.OrdinalIgnoreCase) && e.Exists()).ToList();
|
List<FFUEntry> FFUs = App.Config.FFURepository.Where(e => FlashInfo.PlatformID.StartsWith(e.PlatformID, StringComparison.OrdinalIgnoreCase) && e.Exists()).ToList();
|
||||||
ProfileFFU = FFUs.Count > 0
|
ProfileFFU = FFUs.Count > 0
|
||||||
? new FFU(FFUs[0].Path)
|
? new FFU(FFUs[0].Path)
|
||||||
: throw new WPinternalsException("Profile FFU missing", "No profile FFU has been found in the repository for your device. You can add a profile FFU within the download section of the tool or by using the command line.");
|
: throw new WPinternalsException("Profile FFU missing", "No profile FFU has been found in the repository for your device. You can add a profile FFU within the download section of the tool or by using the command line.");
|
||||||
@@ -746,9 +779,9 @@ namespace WPinternals
|
|||||||
LogFile.Log("Custom ROM: " + CustomRomPath, LogType.FileAndConsole);
|
LogFile.Log("Custom ROM: " + CustomRomPath, LogType.FileAndConsole);
|
||||||
Notifier = new PhoneNotifierViewModel();
|
Notifier = new PhoneNotifierViewModel();
|
||||||
UIContext.Send(s => Notifier.Start(), null);
|
UIContext.Send(s => Notifier.Start(), null);
|
||||||
FlashModel = (NokiaFlashModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
FlashModel = (LumiaFlashAppModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||||
Info = FlashModel.ReadPhoneInfo();
|
FlashInfo = FlashModel.ReadPhoneInfo();
|
||||||
Info.Log(LogType.ConsoleOnly);
|
FlashInfo.Log(LogType.ConsoleOnly);
|
||||||
LogFile.Log("Preparing to flash Custom ROM", LogType.FileAndConsole);
|
LogFile.Log("Preparing to flash Custom ROM", LogType.FileAndConsole);
|
||||||
await LumiaV2UnlockBootViewModel.LumiaV2FlashArchive(Notifier, CustomRomPath);
|
await LumiaV2UnlockBootViewModel.LumiaV2FlashArchive(Notifier, CustomRomPath);
|
||||||
LogFile.Log("Custom ROM flashed successfully", LogType.FileAndConsole);
|
LogFile.Log("Custom ROM flashed successfully", LogType.FileAndConsole);
|
||||||
@@ -777,11 +810,11 @@ namespace WPinternals
|
|||||||
LogFile.Log("FFU file: " + FFUPath, LogType.FileAndConsole);
|
LogFile.Log("FFU file: " + FFUPath, LogType.FileAndConsole);
|
||||||
Notifier = new PhoneNotifierViewModel();
|
Notifier = new PhoneNotifierViewModel();
|
||||||
UIContext.Send(s => Notifier.Start(), null);
|
UIContext.Send(s => Notifier.Start(), null);
|
||||||
FlashModel = (NokiaFlashModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
FlashModel = (LumiaFlashAppModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||||
Info = FlashModel.ReadPhoneInfo();
|
FlashInfo = FlashModel.ReadPhoneInfo();
|
||||||
Info.Log(LogType.ConsoleOnly);
|
FlashInfo.Log(LogType.ConsoleOnly);
|
||||||
LogFile.Log("Flashing FFU...", LogType.FileAndConsole);
|
LogFile.Log("Flashing FFU...", LogType.FileAndConsole);
|
||||||
await Task.Run(() => FlashModel.FlashFFU(new FFU(FFUPath), true, (byte)(!Info.IsBootloaderSecure ? FlashOptions.SkipSignatureCheck : 0)));
|
await Task.Run(() => FlashModel.FlashFFU(new FFU(FFUPath), true, (byte)(!FlashInfo.IsBootloaderSecure ? FlashOptions.SkipSignatureCheck : 0)));
|
||||||
LogFile.Log("FFU flashed successfully", LogType.FileAndConsole);
|
LogFile.Log("FFU flashed successfully", LogType.FileAndConsole);
|
||||||
Notifier.Stop();
|
Notifier.Stop();
|
||||||
}
|
}
|
||||||
@@ -1234,680 +1267,6 @@ namespace WPinternals
|
|||||||
|
|
||||||
LogFile.Log("Root access enabled on image", LogType.FileAndConsole);
|
LogFile.Log("Root access enabled on image", LogType.FileAndConsole);
|
||||||
break;
|
break;
|
||||||
case "downloadffu":
|
|
||||||
LogFile.Log("Command: Download FFU", LogType.FileAndConsole);
|
|
||||||
Notifier = new PhoneNotifierViewModel();
|
|
||||||
UIContext.Send(s => Notifier.Start(), null);
|
|
||||||
if (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Normal)
|
|
||||||
{
|
|
||||||
NormalModel = (NokiaPhoneModel)Notifier.CurrentModel;
|
|
||||||
ProductCode = NormalModel.ExecuteJsonMethodAsString("ReadProductCode", "ProductCode");
|
|
||||||
}
|
|
||||||
else if ((Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) || (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Flash))
|
|
||||||
{
|
|
||||||
FlashModel = (NokiaFlashModel)Notifier.CurrentModel;
|
|
||||||
Info = FlashModel.ReadPhoneInfo();
|
|
||||||
ProductCode = Info.ProductCode;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NormalModel = (NokiaPhoneModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Normal);
|
|
||||||
ProductCode = NormalModel.ExecuteJsonMethodAsString("ReadProductCode", "ProductCode");
|
|
||||||
}
|
|
||||||
URL = LumiaDownloadModel.SearchFFU(null, ProductCode, null, out ProductType);
|
|
||||||
DownloadFolder = args.Length >= 3
|
|
||||||
? args[4]
|
|
||||||
: Environment.ExpandEnvironmentVariables("%ALLUSERSPROFILE%\\WPInternals\\Repository\\" + ProductType.ToUpper());
|
|
||||||
|
|
||||||
if (!Directory.Exists(DownloadFolder))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(DownloadFolder);
|
|
||||||
}
|
|
||||||
|
|
||||||
LogFile.Log("Download folder: " + DownloadFolder, LogType.FileAndConsole);
|
|
||||||
LogFile.Log("URL: " + URL, LogType.FileAndConsole);
|
|
||||||
URI = new Uri(URL);
|
|
||||||
FFUFileName = Path.GetFileName(URI.LocalPath);
|
|
||||||
LogFile.Log("File: " + FFUFileName, LogType.FileAndConsole);
|
|
||||||
FFUFilePath = Path.Combine(DownloadFolder, FFUFileName);
|
|
||||||
LogFile.Log("Downloading...", LogType.FileAndConsole);
|
|
||||||
using (System.Net.WebClient myWebClient = new())
|
|
||||||
{
|
|
||||||
await myWebClient.DownloadFileTaskAsync(URL, FFUFilePath);
|
|
||||||
}
|
|
||||||
LogFile.Log("Download finished", LogType.FileAndConsole);
|
|
||||||
App.Config.AddFfuToRepository(FFUFilePath);
|
|
||||||
Notifier.Stop();
|
|
||||||
break;
|
|
||||||
case "downloadffubyoperatorcode":
|
|
||||||
LogFile.Log("Command: Download FFU by Operator Code", LogType.FileAndConsole);
|
|
||||||
if (args.Length < 4)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Wrong number of arguments. Usage: WPinternals.exe -DownloadFFUbyOperatorCode <Product type> <Operator code> <Optional: Download folder>");
|
|
||||||
}
|
|
||||||
|
|
||||||
ProductType = args[2];
|
|
||||||
LogFile.Log("Product type: " + ProductType, LogType.FileAndConsole);
|
|
||||||
OperatorCode = args[3];
|
|
||||||
LogFile.Log("Operator code: " + OperatorCode, LogType.FileAndConsole);
|
|
||||||
DownloadFolder = args.Length >= 5
|
|
||||||
? args[4]
|
|
||||||
: Environment.ExpandEnvironmentVariables("%ALLUSERSPROFILE%\\WPInternals\\Repository\\" + ProductType.ToUpper());
|
|
||||||
|
|
||||||
if (!Directory.Exists(DownloadFolder))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(DownloadFolder);
|
|
||||||
}
|
|
||||||
|
|
||||||
LogFile.Log("Download folder: " + DownloadFolder, LogType.FileAndConsole);
|
|
||||||
URL = LumiaDownloadModel.SearchFFU(ProductType, null, OperatorCode);
|
|
||||||
LogFile.Log("URL: " + URL, LogType.FileAndConsole);
|
|
||||||
URI = new Uri(URL);
|
|
||||||
FFUFileName = Path.GetFileName(URI.LocalPath);
|
|
||||||
LogFile.Log("File: " + FFUFileName, LogType.FileAndConsole);
|
|
||||||
FFUFilePath = Path.Combine(DownloadFolder, FFUFileName);
|
|
||||||
LogFile.Log("Downloading...", LogType.FileAndConsole);
|
|
||||||
using (System.Net.WebClient myWebClient = new())
|
|
||||||
{
|
|
||||||
await myWebClient.DownloadFileTaskAsync(URL, FFUFilePath);
|
|
||||||
}
|
|
||||||
LogFile.Log("Download finished", LogType.FileAndConsole);
|
|
||||||
App.Config.AddFfuToRepository(FFUFilePath);
|
|
||||||
break;
|
|
||||||
case "downloadffubyproductcode":
|
|
||||||
LogFile.Log("Command: Download FFU by Product Code", LogType.FileAndConsole);
|
|
||||||
if (args.Length < 3)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Wrong number of arguments. Usage: WPinternals.exe -DownloadFFUbyProductCode <Product code> <Optional: Download folder>");
|
|
||||||
}
|
|
||||||
|
|
||||||
ProductCode = args[2];
|
|
||||||
LogFile.Log("Product code: " + ProductCode, LogType.FileAndConsole);
|
|
||||||
URL = LumiaDownloadModel.SearchFFU(null, ProductCode, null, out ProductType);
|
|
||||||
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);
|
|
||||||
LogFile.Log("URL: " + URL, LogType.FileAndConsole);
|
|
||||||
URI = new Uri(URL);
|
|
||||||
FFUFileName = Path.GetFileName(URI.LocalPath);
|
|
||||||
LogFile.Log("File: " + FFUFileName, LogType.FileAndConsole);
|
|
||||||
FFUFilePath = Path.Combine(DownloadFolder, FFUFileName);
|
|
||||||
LogFile.Log("Downloading...", LogType.FileAndConsole);
|
|
||||||
using (System.Net.WebClient myWebClient = new())
|
|
||||||
{
|
|
||||||
await myWebClient.DownloadFileTaskAsync(URL, FFUFilePath);
|
|
||||||
}
|
|
||||||
LogFile.Log("Download finished", LogType.FileAndConsole);
|
|
||||||
App.Config.AddFfuToRepository(FFUFilePath);
|
|
||||||
break;
|
|
||||||
case "downloadffubyproducttype":
|
|
||||||
LogFile.Log("Command: Download FFU by Product Type", LogType.FileAndConsole);
|
|
||||||
if (args.Length < 3)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Wrong number of arguments. Usage: WPinternals.exe -DownloadFFUbyProductType <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);
|
|
||||||
}
|
|
||||||
|
|
||||||
LogFile.Log("Download folder: " + DownloadFolder, LogType.FileAndConsole);
|
|
||||||
URL = LumiaDownloadModel.SearchFFU(ProductType, null, null);
|
|
||||||
LogFile.Log("URL: " + URL, LogType.FileAndConsole);
|
|
||||||
URI = new Uri(URL);
|
|
||||||
FFUFileName = Path.GetFileName(URI.LocalPath);
|
|
||||||
LogFile.Log("File: " + FFUFileName, LogType.FileAndConsole);
|
|
||||||
FFUFilePath = Path.Combine(DownloadFolder, FFUFileName);
|
|
||||||
LogFile.Log("Downloading...", LogType.FileAndConsole);
|
|
||||||
using (System.Net.WebClient myWebClient = new())
|
|
||||||
{
|
|
||||||
await myWebClient.DownloadFileTaskAsync(URL, FFUFilePath);
|
|
||||||
}
|
|
||||||
LogFile.Log("Download finished", LogType.FileAndConsole);
|
|
||||||
App.Config.AddFfuToRepository(FFUFilePath);
|
|
||||||
break;
|
|
||||||
case "searchffubyproducttype":
|
|
||||||
LogFile.Log("Command: Search FFU by Product Type", LogType.FileAndConsole);
|
|
||||||
if (args.Length < 3)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Wrong number of arguments. Usage: WPinternals.exe -SearchFFUbyProductType <Lumia model>");
|
|
||||||
}
|
|
||||||
|
|
||||||
ProductType = args[2];
|
|
||||||
LogFile.Log("Lumia model: " + ProductType, LogType.FileAndConsole);
|
|
||||||
URL = LumiaDownloadModel.SearchFFU(ProductType, null, null);
|
|
||||||
LogFile.Log("URL: " + URL, LogType.FileAndConsole);
|
|
||||||
URI = new Uri(URL);
|
|
||||||
FFUFileName = Path.GetFileName(URI.LocalPath);
|
|
||||||
LogFile.Log("File: " + FFUFileName, 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 = (NokiaPhoneModel)Notifier.CurrentModel;
|
|
||||||
ProductType = NormalModel.ExecuteJsonMethodAsString("ReadManufacturerModelName", "ManufacturerModelName");
|
|
||||||
if (ProductType.Contains('_'))
|
|
||||||
{
|
|
||||||
ProductType = ProductType.Substring(0, ProductType.IndexOf('_'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) || (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Flash))
|
|
||||||
{
|
|
||||||
FlashModel = (NokiaFlashModel)Notifier.CurrentModel;
|
|
||||||
Info = FlashModel.ReadPhoneInfo();
|
|
||||||
ProductType = Info.Type;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NormalModel = (NokiaPhoneModel)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 = (NokiaPhoneModel)Notifier.CurrentModel;
|
|
||||||
ProductCode = NormalModel.ExecuteJsonMethodAsString("ReadProductCode", "ProductCode");
|
|
||||||
}
|
|
||||||
else if ((Notifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) || (Notifier.CurrentInterface == PhoneInterfaces.Lumia_Flash))
|
|
||||||
{
|
|
||||||
FlashModel = (NokiaFlashModel)Notifier.CurrentModel;
|
|
||||||
Info = FlashModel.ReadPhoneInfo();
|
|
||||||
ProductCode = Info.ProductCode;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NormalModel = (NokiaPhoneModel)await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Normal);
|
|
||||||
ProductCode = NormalModel.ExecuteJsonMethodAsString("ReadProductCode", "ProductCode");
|
|
||||||
}
|
|
||||||
URL = LumiaDownloadModel.SearchFFU(null, ProductCode, null, out ProductType);
|
|
||||||
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);
|
|
||||||
LogFile.Log("URL: " + URL, LogType.FileAndConsole);
|
|
||||||
URI = new Uri(URL);
|
|
||||||
FFUFileName = Path.GetFileName(URI.LocalPath);
|
|
||||||
LogFile.Log("File: " + FFUFileName, LogType.FileAndConsole);
|
|
||||||
FFUFilePath = Path.Combine(DownloadFolder, FFUFileName);
|
|
||||||
LogFile.Log("Downloading...", LogType.FileAndConsole);
|
|
||||||
using (System.Net.WebClient myWebClient = new())
|
|
||||||
{
|
|
||||||
await myWebClient.DownloadFileTaskAsync(URL, FFUFilePath);
|
|
||||||
}
|
|
||||||
LogFile.Log("Download finished", LogType.FileAndConsole);
|
|
||||||
App.Config.AddFfuToRepository(FFUFilePath);
|
|
||||||
|
|
||||||
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)))
|
|
||||||
{
|
|
||||||
ProductType = "RM-1085";
|
|
||||||
|
|
||||||
URL = LumiaDownloadModel.SearchFFU(ProductType, null, 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);
|
|
||||||
LogFile.Log("URL: " + URL, LogType.FileAndConsole);
|
|
||||||
URI = new Uri(URL);
|
|
||||||
FFUFileName = Path.GetFileName(URI.LocalPath);
|
|
||||||
LogFile.Log("File: " + FFUFileName, LogType.FileAndConsole);
|
|
||||||
FFUFilePath = Path.Combine(DownloadFolder, FFUFileName);
|
|
||||||
LogFile.Log("Downloading...", LogType.FileAndConsole);
|
|
||||||
using (System.Net.WebClient myWebClient = new())
|
|
||||||
{
|
|
||||||
await myWebClient.DownloadFileTaskAsync(URL, FFUFilePath);
|
|
||||||
}
|
|
||||||
LogFile.Log("Download finished", LogType.FileAndConsole);
|
|
||||||
App.Config.AddFfuToRepository(FFUFilePath);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
LogFile.Log("Download folder: " + DownloadFolder, LogType.FileAndConsole);
|
|
||||||
URL = LumiaDownloadModel.SearchFFU(ProductType, null, null);
|
|
||||||
LogFile.Log("URL: " + URL, LogType.FileAndConsole);
|
|
||||||
URI = new Uri(URL);
|
|
||||||
FFUFileName = Path.GetFileName(URI.LocalPath);
|
|
||||||
LogFile.Log("File: " + FFUFileName, LogType.FileAndConsole);
|
|
||||||
FFUFilePath = Path.Combine(DownloadFolder, FFUFileName);
|
|
||||||
LogFile.Log("Downloading...", LogType.FileAndConsole);
|
|
||||||
using (System.Net.WebClient myWebClient = new())
|
|
||||||
{
|
|
||||||
await myWebClient.DownloadFileTaskAsync(URL, FFUFilePath);
|
|
||||||
}
|
|
||||||
LogFile.Log("Download finished", LogType.FileAndConsole);
|
|
||||||
App.Config.AddFfuToRepository(FFUFilePath);
|
|
||||||
|
|
||||||
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)))
|
|
||||||
{
|
|
||||||
ProductType = "RM-1085";
|
|
||||||
|
|
||||||
URL = LumiaDownloadModel.SearchFFU(ProductType, null, 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);
|
|
||||||
LogFile.Log("URL: " + URL, LogType.FileAndConsole);
|
|
||||||
URI = new Uri(URL);
|
|
||||||
FFUFileName = Path.GetFileName(URI.LocalPath);
|
|
||||||
LogFile.Log("File: " + FFUFileName, LogType.FileAndConsole);
|
|
||||||
FFUFilePath = Path.Combine(DownloadFolder, FFUFileName);
|
|
||||||
LogFile.Log("Downloading...", LogType.FileAndConsole);
|
|
||||||
using (System.Net.WebClient myWebClient = new())
|
|
||||||
{
|
|
||||||
await myWebClient.DownloadFileTaskAsync(URL, FFUFilePath);
|
|
||||||
}
|
|
||||||
LogFile.Log("Download finished", LogType.FileAndConsole);
|
|
||||||
App.Config.AddFfuToRepository(FFUFilePath);
|
|
||||||
|
|
||||||
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 "downloadallbyproductcode":
|
|
||||||
LogFile.Log("Command: Download all by Product Code", LogType.FileAndConsole);
|
|
||||||
if (args.Length < 3)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Wrong number of arguments. Usage: WPinternals.exe -DownloadAllByProductCode <Product code> <Optional: Download folder>");
|
|
||||||
}
|
|
||||||
|
|
||||||
ProductCode = args[2];
|
|
||||||
LogFile.Log("Product code: " + ProductCode, LogType.FileAndConsole);
|
|
||||||
URL = LumiaDownloadModel.SearchFFU(null, ProductCode, null, out ProductType);
|
|
||||||
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);
|
|
||||||
LogFile.Log("URL: " + URL, LogType.FileAndConsole);
|
|
||||||
URI = new Uri(URL);
|
|
||||||
FFUFileName = Path.GetFileName(URI.LocalPath);
|
|
||||||
LogFile.Log("File: " + FFUFileName, LogType.FileAndConsole);
|
|
||||||
FFUFilePath = Path.Combine(DownloadFolder, FFUFileName);
|
|
||||||
LogFile.Log("Downloading...", LogType.FileAndConsole);
|
|
||||||
using (System.Net.WebClient myWebClient = new())
|
|
||||||
{
|
|
||||||
await myWebClient.DownloadFileTaskAsync(URL, FFUFilePath);
|
|
||||||
}
|
|
||||||
LogFile.Log("Download finished", LogType.FileAndConsole);
|
|
||||||
App.Config.AddFfuToRepository(FFUFilePath);
|
|
||||||
|
|
||||||
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)))
|
|
||||||
{
|
|
||||||
ProductType = "RM-1085";
|
|
||||||
|
|
||||||
URL = LumiaDownloadModel.SearchFFU(ProductType, null, 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);
|
|
||||||
LogFile.Log("URL: " + URL, LogType.FileAndConsole);
|
|
||||||
URI = new Uri(URL);
|
|
||||||
FFUFileName = Path.GetFileName(URI.LocalPath);
|
|
||||||
LogFile.Log("File: " + FFUFileName, LogType.FileAndConsole);
|
|
||||||
FFUFilePath = Path.Combine(DownloadFolder, FFUFileName);
|
|
||||||
LogFile.Log("Downloading...", LogType.FileAndConsole);
|
|
||||||
using (System.Net.WebClient myWebClient = new())
|
|
||||||
{
|
|
||||||
await myWebClient.DownloadFileTaskAsync(URL, FFUFilePath);
|
|
||||||
}
|
|
||||||
LogFile.Log("Download finished", LogType.FileAndConsole);
|
|
||||||
App.Config.AddFfuToRepository(FFUFilePath);
|
|
||||||
|
|
||||||
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 "downloadallbyoperatorcode":
|
|
||||||
LogFile.Log("Command: Download FFU by Operator Code", LogType.FileAndConsole);
|
|
||||||
if (args.Length < 4)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Wrong number of arguments. Usage: WPinternals.exe -DownloadFFUbyOperatorCode <Product type> <Operator code> <Optional: Download folder>");
|
|
||||||
}
|
|
||||||
|
|
||||||
ProductType = args[2];
|
|
||||||
LogFile.Log("Product type: " + ProductType, LogType.FileAndConsole);
|
|
||||||
OperatorCode = args[3];
|
|
||||||
LogFile.Log("Operator code: " + OperatorCode, LogType.FileAndConsole);
|
|
||||||
DownloadFolder = args.Length >= 5
|
|
||||||
? args[4]
|
|
||||||
: Environment.ExpandEnvironmentVariables("%ALLUSERSPROFILE%\\WPInternals\\Repository\\" + ProductType.ToUpper());
|
|
||||||
|
|
||||||
if (!Directory.Exists(DownloadFolder))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(DownloadFolder);
|
|
||||||
}
|
|
||||||
|
|
||||||
LogFile.Log("Download folder: " + DownloadFolder, LogType.FileAndConsole);
|
|
||||||
URL = LumiaDownloadModel.SearchFFU(ProductType, null, OperatorCode);
|
|
||||||
LogFile.Log("URL: " + URL, LogType.FileAndConsole);
|
|
||||||
URI = new Uri(URL);
|
|
||||||
FFUFileName = Path.GetFileName(URI.LocalPath);
|
|
||||||
LogFile.Log("File: " + FFUFileName, LogType.FileAndConsole);
|
|
||||||
FFUFilePath = Path.Combine(DownloadFolder, FFUFileName);
|
|
||||||
LogFile.Log("Downloading...", LogType.FileAndConsole);
|
|
||||||
using (System.Net.WebClient myWebClient = new())
|
|
||||||
{
|
|
||||||
await myWebClient.DownloadFileTaskAsync(URL, FFUFilePath);
|
|
||||||
}
|
|
||||||
LogFile.Log("Download finished", LogType.FileAndConsole);
|
|
||||||
App.Config.AddFfuToRepository(FFUFilePath);
|
|
||||||
|
|
||||||
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)))
|
|
||||||
{
|
|
||||||
ProductType = "RM-1085";
|
|
||||||
|
|
||||||
URL = LumiaDownloadModel.SearchFFU(ProductType, null, null);
|
|
||||||
DownloadFolder = args.Length >= 5
|
|
||||||
? args[4]
|
|
||||||
: Environment.ExpandEnvironmentVariables("%ALLUSERSPROFILE%\\WPInternals\\Repository\\" + ProductType.ToUpper());
|
|
||||||
|
|
||||||
if (!Directory.Exists(DownloadFolder))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(DownloadFolder);
|
|
||||||
}
|
|
||||||
|
|
||||||
LogFile.Log("Download folder: " + DownloadFolder, LogType.FileAndConsole);
|
|
||||||
LogFile.Log("URL: " + URL, LogType.FileAndConsole);
|
|
||||||
URI = new Uri(URL);
|
|
||||||
FFUFileName = Path.GetFileName(URI.LocalPath);
|
|
||||||
LogFile.Log("File: " + FFUFileName, LogType.FileAndConsole);
|
|
||||||
FFUFilePath = Path.Combine(DownloadFolder, FFUFileName);
|
|
||||||
LogFile.Log("Downloading...", LogType.FileAndConsole);
|
|
||||||
using (System.Net.WebClient myWebClient = new())
|
|
||||||
{
|
|
||||||
await myWebClient.DownloadFileTaskAsync(URL, FFUFilePath);
|
|
||||||
}
|
|
||||||
LogFile.Log("Download finished", LogType.FileAndConsole);
|
|
||||||
App.Config.AddFfuToRepository(FFUFilePath);
|
|
||||||
|
|
||||||
if (!App.Config.FFURepository.Any(e => App.PatchEngine.PatchDefinitions.First(p => p.Name == "SecureBootHack-V2-EFIESP").TargetVersions.Any(v => v.Description == e.OSVersion)))
|
|
||||||
{
|
|
||||||
throw new WPinternalsException("Unable to find compatible FFU", "No donor-FFU has been found in the repository with a supported OS version. You can add a donor-FFU within the download section of the tool or by using the command line. A donor-FFU can be for a different device and a different CPU than your device. It is only used to gather Operating System specific binaries to be patched and used as part of the unlock process.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "rewritepartitionsfrommassstorage":
|
case "rewritepartitionsfrommassstorage":
|
||||||
if (args.Length < 2)
|
if (args.Length < 2)
|
||||||
{
|
{
|
||||||
@@ -1968,6 +1327,7 @@ namespace WPinternals
|
|||||||
LogFile.Log("WPinternals -ClearNV", LogType.ConsoleOnly);
|
LogFile.Log("WPinternals -ClearNV", LogType.ConsoleOnly);
|
||||||
LogFile.Log("WPinternals -ReadGPT", LogType.ConsoleOnly);
|
LogFile.Log("WPinternals -ReadGPT", LogType.ConsoleOnly);
|
||||||
LogFile.Log("WPinternals -BackupGPT <Path to xml-file>", LogType.ConsoleOnly);
|
LogFile.Log("WPinternals -BackupGPT <Path to xml-file>", LogType.ConsoleOnly);
|
||||||
|
LogFile.Log("WPinternals -ConvertGPT <Path to GPT-file> <Path to xml-file>", LogType.ConsoleOnly);
|
||||||
LogFile.Log("WPinternals -RestoreGPT <Path to xml-file>", LogType.ConsoleOnly);
|
LogFile.Log("WPinternals -RestoreGPT <Path to xml-file>", LogType.ConsoleOnly);
|
||||||
LogFile.Log("WPinternals -MergeGPT <Path to input-xml-file> <Path to input-xml-file>", LogType.ConsoleOnly);
|
LogFile.Log("WPinternals -MergeGPT <Path to input-xml-file> <Path to input-xml-file>", LogType.ConsoleOnly);
|
||||||
LogFile.Log(" <Optional: Path to output-xml-file>", LogType.ConsoleOnly);
|
LogFile.Log(" <Optional: Path to output-xml-file>", LogType.ConsoleOnly);
|
||||||
@@ -2055,12 +1415,18 @@ namespace WPinternals
|
|||||||
Microsoft.Win32.SafeHandles.SafeFileHandle safeFileHandle = new(stdHandle, true);
|
Microsoft.Win32.SafeHandles.SafeFileHandle safeFileHandle = new(stdHandle, true);
|
||||||
FileStream fileStream = new(safeFileHandle, FileAccess.Write);
|
FileStream fileStream = new(safeFileHandle, FileAccess.Write);
|
||||||
Encoding encoding = Encoding.GetEncoding(MY_CODE_PAGE);
|
Encoding encoding = Encoding.GetEncoding(MY_CODE_PAGE);
|
||||||
StreamWriter standardOutput = new(fileStream, encoding);
|
StreamWriter standardOutput = new(fileStream, encoding)
|
||||||
standardOutput.AutoFlush = true;
|
{
|
||||||
|
AutoFlush = true
|
||||||
|
};
|
||||||
Console.SetOut(standardOutput);
|
Console.SetOut(standardOutput);
|
||||||
}
|
}
|
||||||
catch
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using WPinternals.HelperClasses;
|
||||||
|
|
||||||
|
namespace WPinternals.Config
|
||||||
|
{
|
||||||
|
public class EmergencyFileEntry
|
||||||
|
{
|
||||||
|
public string Type;
|
||||||
|
|
||||||
|
[XmlIgnore]
|
||||||
|
public byte[] RKH;
|
||||||
|
[XmlElement(ElementName = "RKH")]
|
||||||
|
public string RKHAsString
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return RKH == null ? null : Converter.ConvertHexToString(RKH, "");
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
RKH = value == null ? null : Converter.ConvertStringToHex(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ProgrammerPath;
|
||||||
|
public string PayloadPath;
|
||||||
|
|
||||||
|
internal bool ProgrammerExists()
|
||||||
|
{
|
||||||
|
return File.Exists(ProgrammerPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool PayloadExists()
|
||||||
|
{
|
||||||
|
return File.Exists(PayloadPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
// 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.IO;
|
||||||
|
|
||||||
|
namespace WPinternals.Config
|
||||||
|
{
|
||||||
|
public class FFUEntry
|
||||||
|
{
|
||||||
|
public string PlatformID;
|
||||||
|
public string FirmwareVersion;
|
||||||
|
public string OSVersion;
|
||||||
|
public string Path;
|
||||||
|
|
||||||
|
internal bool Exists()
|
||||||
|
{
|
||||||
|
return File.Exists(Path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
// 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.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace WPinternals.Config
|
||||||
|
{
|
||||||
|
public class FlashProfile
|
||||||
|
{
|
||||||
|
public string Type;
|
||||||
|
public string PlatformID;
|
||||||
|
public string ProductCode;
|
||||||
|
public string PhoneFirmware;
|
||||||
|
public string FfuFirmware;
|
||||||
|
|
||||||
|
[XmlIgnore]
|
||||||
|
internal uint FillSize;
|
||||||
|
[XmlIgnore]
|
||||||
|
internal uint HeaderSize;
|
||||||
|
[XmlIgnore]
|
||||||
|
internal bool AssumeImageHeaderFallsInGap;
|
||||||
|
[XmlIgnore]
|
||||||
|
internal bool AllocateAsyncBuffersOnPhone;
|
||||||
|
|
||||||
|
[XmlElement(ElementName = "Profile")]
|
||||||
|
public string ProfileAsString
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
byte[] ValueBuffer = new byte[10];
|
||||||
|
ValueBuffer[0] = 1; // Profile version
|
||||||
|
ByteOperations.WriteUInt32(ValueBuffer, 1, FillSize);
|
||||||
|
ByteOperations.WriteUInt32(ValueBuffer, 5, HeaderSize);
|
||||||
|
if (AssumeImageHeaderFallsInGap)
|
||||||
|
{
|
||||||
|
ValueBuffer[9] |= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AllocateAsyncBuffersOnPhone)
|
||||||
|
{
|
||||||
|
ValueBuffer[9] |= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Convert.ToBase64String(ValueBuffer);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
byte[] ValueBuffer = Convert.FromBase64String(value);
|
||||||
|
byte Version = ValueBuffer[0];
|
||||||
|
FillSize = ByteOperations.ReadUInt32(ValueBuffer, 1);
|
||||||
|
HeaderSize = ByteOperations.ReadUInt32(ValueBuffer, 5);
|
||||||
|
AssumeImageHeaderFallsInGap = (ValueBuffer[9] & 1) != 0;
|
||||||
|
AllocateAsyncBuffersOnPhone = (ValueBuffer[9] & 2) != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace WPinternals.Config
|
||||||
|
{
|
||||||
|
internal static class Registration
|
||||||
|
{
|
||||||
|
#if PREVIEW
|
||||||
|
internal const bool IsPrerelease = true;
|
||||||
|
#else
|
||||||
|
internal const bool IsPrerelease = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
internal static readonly DateTime ExpirationDate = new(2027, 4, 1);
|
||||||
|
|
||||||
|
internal static void CheckExpiration()
|
||||||
|
{
|
||||||
|
#if PREVIEW
|
||||||
|
//if (IsPrerelease && (DateTime.Now >= ExpirationDate))
|
||||||
|
if (DateTime.Now >= ExpirationDate)
|
||||||
|
{
|
||||||
|
if (Environment.GetCommandLineArgs().Count() > 1)
|
||||||
|
{
|
||||||
|
Console.WriteLine("This prerelease version is expired!");
|
||||||
|
CommandLine.CloseConsole();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
MessageBox.Show("This prerelease version is expired!", "Windows Phone Internals", MessageBoxButton.OK, MessageBoxImage.Exclamation);
|
||||||
|
Environment.Exit(0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool IsRegistered()
|
||||||
|
{
|
||||||
|
bool Result = false;
|
||||||
|
if (App.Config.RegistrationName != null)
|
||||||
|
{
|
||||||
|
Result = CalcRegKey() == App.Config.RegistrationKey;
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string CalcRegKey()
|
||||||
|
{
|
||||||
|
string KeyBase = App.Config.RegistrationName;
|
||||||
|
if (Environment.MachineName == null)
|
||||||
|
{
|
||||||
|
KeyBase += "-Unknown";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KeyBase += "-" + Environment.MachineName;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] KeyBytes = System.Text.Encoding.UTF8.GetBytes(KeyBase);
|
||||||
|
SHA1Managed sha = new();
|
||||||
|
byte[] Key = sha.ComputeHash(KeyBytes);
|
||||||
|
return Convert.ToBase64String(Key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
// 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.IO;
|
||||||
|
|
||||||
|
namespace WPinternals.Config
|
||||||
|
{
|
||||||
|
public class SecWimEntry
|
||||||
|
{
|
||||||
|
public string FirmwareVersion;
|
||||||
|
public string Path;
|
||||||
|
|
||||||
|
internal bool Exists()
|
||||||
|
{
|
||||||
|
return File.Exists(Path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
// copy of this software and associated documentation files (the "Software"),
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
@@ -22,67 +22,11 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
|
using WPinternals.HelperClasses;
|
||||||
|
|
||||||
namespace WPinternals
|
namespace WPinternals.Config
|
||||||
{
|
{
|
||||||
internal static class Registration
|
|
||||||
{
|
|
||||||
#if PREVIEW
|
|
||||||
internal const bool IsPrerelease = true;
|
|
||||||
#else
|
|
||||||
internal const bool IsPrerelease = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
internal static readonly DateTime ExpirationDate = new(2019, 01, 06);
|
|
||||||
|
|
||||||
internal static void CheckExpiration()
|
|
||||||
{
|
|
||||||
#if PREVIEW
|
|
||||||
//if (IsPrerelease && (DateTime.Now >= ExpirationDate))
|
|
||||||
if (DateTime.Now >= ExpirationDate)
|
|
||||||
{
|
|
||||||
if (Environment.GetCommandLineArgs().Count() > 1)
|
|
||||||
{
|
|
||||||
Console.WriteLine("This prerelease version is expired!");
|
|
||||||
CommandLine.CloseConsole();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
MessageBox.Show("This prerelease version is expired!", "Windows Phone Internals", MessageBoxButton.OK, MessageBoxImage.Exclamation);
|
|
||||||
Environment.Exit(0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static bool IsRegistered()
|
|
||||||
{
|
|
||||||
bool Result = false;
|
|
||||||
if (App.Config.RegistrationName != null)
|
|
||||||
{
|
|
||||||
Result = CalcRegKey() == App.Config.RegistrationKey;
|
|
||||||
}
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static string CalcRegKey()
|
|
||||||
{
|
|
||||||
string KeyBase = App.Config.RegistrationName;
|
|
||||||
if (Environment.MachineName == null)
|
|
||||||
{
|
|
||||||
KeyBase += "-Unknown";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
KeyBase += "-" + Environment.MachineName;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] KeyBytes = System.Text.Encoding.UTF8.GetBytes(KeyBase);
|
|
||||||
SHA1Managed sha = new();
|
|
||||||
byte[] Key = sha.ComputeHash(KeyBytes);
|
|
||||||
return Convert.ToBase64String(Key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class WPinternalsConfig
|
public class WPinternalsConfig
|
||||||
{
|
{
|
||||||
@@ -121,7 +65,7 @@ namespace WPinternals
|
|||||||
FileWriter.Close();
|
FileWriter.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void SetProfile(string Type, string PlatformID, string ProductCode, string PhoneFirmware, string FfuFirmware, UInt32 FillSize, UInt32 HeaderSize, bool AssumeImageHeaderFallsInGap, bool AllocateAsyncBuffersOnPhone)
|
internal void SetProfile(string Type, string PlatformID, string ProductCode, string PhoneFirmware, string FfuFirmware, uint FillSize, uint HeaderSize, bool AssumeImageHeaderFallsInGap, bool AllocateAsyncBuffersOnPhone)
|
||||||
{
|
{
|
||||||
FlashProfile Profile = GetProfile(PlatformID, PhoneFirmware, FfuFirmware);
|
FlashProfile Profile = GetProfile(PlatformID, PhoneFirmware, FfuFirmware);
|
||||||
if (Profile == null)
|
if (Profile == null)
|
||||||
@@ -147,10 +91,10 @@ namespace WPinternals
|
|||||||
|
|
||||||
internal FlashProfile GetProfile(string PlatformID, string PhoneFirmware, string FfuFirmware = null)
|
internal FlashProfile GetProfile(string PlatformID, string PhoneFirmware, string FfuFirmware = null)
|
||||||
{
|
{
|
||||||
return FlashProfiles.Find(p => string.Equals(p.PlatformID, PlatformID, StringComparison.CurrentCultureIgnoreCase) && string.Equals(p.PhoneFirmware, PhoneFirmware, StringComparison.CurrentCultureIgnoreCase) && ((FfuFirmware == null) || string.Equals(p.FfuFirmware, FfuFirmware, StringComparison.CurrentCultureIgnoreCase)));
|
return FlashProfiles.Find(p => string.Equals(p.PlatformID, PlatformID, StringComparison.CurrentCultureIgnoreCase) && string.Equals(p.PhoneFirmware, PhoneFirmware, StringComparison.CurrentCultureIgnoreCase) && (FfuFirmware == null || string.Equals(p.FfuFirmware, FfuFirmware, StringComparison.CurrentCultureIgnoreCase)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<FlashProfile> FlashProfiles = new();
|
public List<FlashProfile> FlashProfiles = [];
|
||||||
|
|
||||||
internal void AddFfuToRepository(string FFUPath)
|
internal void AddFfuToRepository(string FFUPath)
|
||||||
{
|
{
|
||||||
@@ -167,7 +111,7 @@ namespace WPinternals
|
|||||||
|
|
||||||
internal void AddFfuToRepository(string FFUPath, string PlatformID, string FirmwareVersion, string OSVersion)
|
internal void AddFfuToRepository(string FFUPath, string PlatformID, string FirmwareVersion, string OSVersion)
|
||||||
{
|
{
|
||||||
FFUEntry Entry = FFURepository.Find(e => (e.PlatformID == PlatformID) && (e.FirmwareVersion == FirmwareVersion) && string.Equals(e.Path, FFUPath, StringComparison.CurrentCultureIgnoreCase));
|
FFUEntry Entry = FFURepository.Find(e => e.PlatformID == PlatformID && e.FirmwareVersion == FirmwareVersion && string.Equals(e.Path, FFUPath, StringComparison.CurrentCultureIgnoreCase));
|
||||||
if (Entry == null)
|
if (Entry == null)
|
||||||
{
|
{
|
||||||
LogFile.Log("Adding FFU to repository: " + FFUPath, LogType.FileAndConsole);
|
LogFile.Log("Adding FFU to repository: " + FFUPath, LogType.FileAndConsole);
|
||||||
@@ -217,14 +161,60 @@ namespace WPinternals
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<FFUEntry> FFURepository = new();
|
public List<FFUEntry> FFURepository = [];
|
||||||
|
|
||||||
public List<EmergencyFileEntry> EmergencyRepository = new();
|
internal void AddSecWimToRepository(string SecWimPath, string FirmwareVersion)
|
||||||
|
{
|
||||||
|
SecWimEntry Entry = SecWimRepository.Find(e => e.FirmwareVersion == FirmwareVersion && string.Equals(e.Path, SecWimPath, StringComparison.CurrentCultureIgnoreCase));
|
||||||
|
if (Entry == null)
|
||||||
|
{
|
||||||
|
LogFile.Log("Adding Secure WIM to repository: " + SecWimPath, LogType.FileAndConsole);
|
||||||
|
if (FirmwareVersion != null)
|
||||||
|
{
|
||||||
|
LogFile.Log("Firmware version: " + FirmwareVersion, LogType.FileAndConsole);
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry = new SecWimEntry
|
||||||
|
{
|
||||||
|
Path = SecWimPath,
|
||||||
|
FirmwareVersion = FirmwareVersion
|
||||||
|
};
|
||||||
|
SecWimRepository.Add(Entry);
|
||||||
|
WriteConfig();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogFile.Log("Secure WIM not added, because it was already present in the repository.", LogType.FileAndConsole);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void RemoveSecWimFromRepository(string SecWimPath)
|
||||||
|
{
|
||||||
|
int Count = 0;
|
||||||
|
SecWimRepository.Where(e => string.Equals(e.Path, SecWimPath, StringComparison.CurrentCultureIgnoreCase)).ToList().ForEach(e =>
|
||||||
|
{
|
||||||
|
Count++;
|
||||||
|
SecWimRepository.Remove(e);
|
||||||
|
});
|
||||||
|
if (Count == 0)
|
||||||
|
{
|
||||||
|
LogFile.Log("Secure WIM was not removed from repository because it was not present.", LogType.FileAndConsole);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogFile.Log("Removed Secure WIM from repository: " + SecWimPath, LogType.FileAndConsole);
|
||||||
|
WriteConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<SecWimEntry> SecWimRepository = [];
|
||||||
|
|
||||||
|
public List<EmergencyFileEntry> EmergencyRepository = [];
|
||||||
|
|
||||||
internal void AddEmergencyToRepository(string Type, string ProgrammerPath, string PayloadPath)
|
internal void AddEmergencyToRepository(string Type, string ProgrammerPath, string PayloadPath)
|
||||||
{
|
{
|
||||||
EmergencyFileEntry Entry = EmergencyRepository.Find(e => (e.Type == Type) && string.Equals(e.ProgrammerPath, ProgrammerPath, StringComparison.CurrentCultureIgnoreCase));
|
EmergencyFileEntry Entry = EmergencyRepository.Find(e => e.Type == Type && string.Equals(e.ProgrammerPath, ProgrammerPath, StringComparison.CurrentCultureIgnoreCase));
|
||||||
if ((Entry != null) && (PayloadPath != null) && (!string.Equals(Entry.PayloadPath, PayloadPath, StringComparison.CurrentCultureIgnoreCase)))
|
if (Entry != null && PayloadPath != null && !string.Equals(Entry.PayloadPath, PayloadPath, StringComparison.CurrentCultureIgnoreCase))
|
||||||
{
|
{
|
||||||
LogFile.Log("Updating emergency payload path in repository: " + PayloadPath, LogType.FileAndConsole);
|
LogFile.Log("Updating emergency payload path in repository: " + PayloadPath, LogType.FileAndConsole);
|
||||||
Entry.PayloadPath = PayloadPath;
|
Entry.PayloadPath = PayloadPath;
|
||||||
@@ -279,100 +269,4 @@ namespace WPinternals
|
|||||||
public string RegistrationTelegramID;
|
public string RegistrationTelegramID;
|
||||||
public string RegistrationKey;
|
public string RegistrationKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FlashProfile
|
|
||||||
{
|
|
||||||
public string Type;
|
|
||||||
public string PlatformID;
|
|
||||||
public string ProductCode;
|
|
||||||
public string PhoneFirmware;
|
|
||||||
public string FfuFirmware;
|
|
||||||
|
|
||||||
[XmlIgnore]
|
|
||||||
internal UInt32 FillSize;
|
|
||||||
[XmlIgnore]
|
|
||||||
internal UInt32 HeaderSize;
|
|
||||||
[XmlIgnore]
|
|
||||||
internal bool AssumeImageHeaderFallsInGap;
|
|
||||||
[XmlIgnore]
|
|
||||||
internal bool AllocateAsyncBuffersOnPhone;
|
|
||||||
|
|
||||||
[XmlElement(ElementName = "Profile")]
|
|
||||||
public string ProfileAsString
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
byte[] ValueBuffer = new byte[10];
|
|
||||||
ValueBuffer[0] = 1; // Profile version
|
|
||||||
ByteOperations.WriteUInt32(ValueBuffer, 1, FillSize);
|
|
||||||
ByteOperations.WriteUInt32(ValueBuffer, 5, HeaderSize);
|
|
||||||
if (AssumeImageHeaderFallsInGap)
|
|
||||||
{
|
|
||||||
ValueBuffer[9] |= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (AllocateAsyncBuffersOnPhone)
|
|
||||||
{
|
|
||||||
ValueBuffer[9] |= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Convert.ToBase64String(ValueBuffer);
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
byte[] ValueBuffer = Convert.FromBase64String(value);
|
|
||||||
byte Version = ValueBuffer[0];
|
|
||||||
FillSize = ByteOperations.ReadUInt32(ValueBuffer, 1);
|
|
||||||
HeaderSize = ByteOperations.ReadUInt32(ValueBuffer, 5);
|
|
||||||
AssumeImageHeaderFallsInGap = (ValueBuffer[9] & 1) != 0;
|
|
||||||
AllocateAsyncBuffersOnPhone = (ValueBuffer[9] & 2) != 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class FFUEntry
|
|
||||||
{
|
|
||||||
public string PlatformID;
|
|
||||||
public string FirmwareVersion;
|
|
||||||
public string OSVersion;
|
|
||||||
public string Path;
|
|
||||||
|
|
||||||
internal bool Exists()
|
|
||||||
{
|
|
||||||
return File.Exists(Path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class EmergencyFileEntry
|
|
||||||
{
|
|
||||||
public string Type;
|
|
||||||
|
|
||||||
[XmlIgnore]
|
|
||||||
public byte[] RKH;
|
|
||||||
[XmlElement(ElementName = "RKH")]
|
|
||||||
public string RKHAsString
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return RKH == null ? null : Converter.ConvertHexToString(RKH, "");
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
RKH = value == null ? null : Converter.ConvertStringToHex(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ProgrammerPath;
|
|
||||||
public string PayloadPath;
|
|
||||||
|
|
||||||
internal bool ProgrammerExists()
|
|
||||||
{
|
|
||||||
return File.Exists(ProgrammerPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal bool PayloadExists()
|
|
||||||
{
|
|
||||||
return File.Exists(PayloadPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
copy of this software and associated documentation files (the "Software"),
|
copy of this software and associated documentation files (the "Software"),
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
// copy of this software and associated documentation files (the "Software"),
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
@@ -24,6 +24,7 @@ using System.Globalization;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
using WPinternals.HelperClasses;
|
||||||
|
|
||||||
namespace WPinternals
|
namespace WPinternals
|
||||||
{
|
{
|
||||||
@@ -149,7 +150,7 @@ namespace WPinternals
|
|||||||
|
|
||||||
protected override Size MeasureOverride(Size availableSize)
|
protected override Size MeasureOverride(Size availableSize)
|
||||||
{
|
{
|
||||||
var resultSize = new Size(availableSize.Width, 0);
|
Size resultSize = new Size(availableSize.Width, 0);
|
||||||
|
|
||||||
#if NETCORE
|
#if NETCORE
|
||||||
FormattedText formatted = new FormattedText(
|
FormattedText formatted = new FormattedText(
|
||||||
@@ -316,13 +317,19 @@ namespace WPinternals
|
|||||||
{
|
{
|
||||||
filename = System.IO.Path.GetFileName(Text);
|
filename = System.IO.Path.GetFileName(Text);
|
||||||
}
|
}
|
||||||
catch { }
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogFile.LogException(ex, LogType.FileOnly);
|
||||||
|
}
|
||||||
string directory = "";
|
string directory = "";
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
directory = System.IO.Path.GetDirectoryName(Text);
|
directory = System.IO.Path.GetDirectoryName(Text);
|
||||||
}
|
}
|
||||||
catch { }
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogFile.LogException(ex, LogType.FileOnly);
|
||||||
|
}
|
||||||
FormattedText formatted;
|
FormattedText formatted;
|
||||||
bool widthOK = false;
|
bool widthOK = false;
|
||||||
bool changedWidth = false;
|
bool changedWidth = false;
|
||||||
@@ -423,9 +430,10 @@ namespace WPinternals
|
|||||||
|
|
||||||
if (SaveDialog)
|
if (SaveDialog)
|
||||||
{
|
{
|
||||||
Microsoft.Win32.SaveFileDialog savedlg = new();
|
Microsoft.Win32.SaveFileDialog savedlg = new()
|
||||||
|
{
|
||||||
savedlg.FileName = Path ?? DefaultFileName;
|
FileName = Path ?? DefaultFileName
|
||||||
|
};
|
||||||
|
|
||||||
// Show open file dialog box
|
// Show open file dialog box
|
||||||
result = savedlg.ShowDialog();
|
result = savedlg.ShowDialog();
|
||||||
@@ -440,9 +448,10 @@ namespace WPinternals
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Select file
|
// Select file
|
||||||
Microsoft.Win32.OpenFileDialog dlg = new();
|
Microsoft.Win32.OpenFileDialog dlg = new()
|
||||||
|
{
|
||||||
dlg.FileName = Path ?? DefaultFileName;
|
FileName = Path ?? DefaultFileName
|
||||||
|
};
|
||||||
|
|
||||||
// Show open file dialog box
|
// Show open file dialog box
|
||||||
result = dlg.ShowDialog();
|
result = dlg.ShowDialog();
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
// This class was found online.
|
||||||
|
// Original author is probably: Swizzy
|
||||||
|
// https://github.com/ttgxdinger/Random/blob/master/CPUKey%20Checker/CPUKey%20Checker/FolderSelectDialog.cs
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace WPinternals
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Wraps System.Windows.Forms.OpenFileDialog to make it present
|
||||||
|
/// a vista-style dialog.
|
||||||
|
/// </summary>
|
||||||
|
public class FolderSelectDialog
|
||||||
|
{
|
||||||
|
// Wrapped dialog
|
||||||
|
private readonly OpenFileDialog ofd = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default constructor
|
||||||
|
/// </summary>
|
||||||
|
public FolderSelectDialog()
|
||||||
|
{
|
||||||
|
ofd = new OpenFileDialog
|
||||||
|
{
|
||||||
|
Filter = "Folders|\n",
|
||||||
|
AddExtension = false,
|
||||||
|
CheckFileExists = false,
|
||||||
|
DereferenceLinks = true,
|
||||||
|
Multiselect = false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets/Sets the initial folder to be selected. A null value selects the current directory.
|
||||||
|
/// </summary>
|
||||||
|
public string InitialDirectory
|
||||||
|
{
|
||||||
|
get { return ofd.InitialDirectory; }
|
||||||
|
set { ofd.InitialDirectory = string.IsNullOrEmpty(value) ? Environment.CurrentDirectory : value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets/Sets the title to show in the dialog
|
||||||
|
/// </summary>
|
||||||
|
public string Title
|
||||||
|
{
|
||||||
|
get { return ofd.Title; }
|
||||||
|
set { ofd.Title = value ?? "Select a folder"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the selected folder
|
||||||
|
/// </summary>
|
||||||
|
public string FileName
|
||||||
|
{
|
||||||
|
get { return ofd.FileName; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shows the dialog
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if the user presses OK else false</returns>
|
||||||
|
public bool ShowDialog()
|
||||||
|
{
|
||||||
|
return ShowDialog(IntPtr.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shows the dialog
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hWndOwner">Handle of the control to be parent</param>
|
||||||
|
/// <returns>True if the user presses OK else false</returns>
|
||||||
|
public bool ShowDialog(IntPtr hWndOwner)
|
||||||
|
{
|
||||||
|
FolderBrowserDialog fbd = new FolderBrowserDialog
|
||||||
|
{
|
||||||
|
Description = this.Title,
|
||||||
|
SelectedPath = this.InitialDirectory,
|
||||||
|
ShowNewFolderButton = false
|
||||||
|
};
|
||||||
|
if (fbd.ShowDialog(new WindowWrapper(hWndOwner)) != DialogResult.OK)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ofd.FileName = fbd.SelectedPath;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates IWin32Window around an IntPtr
|
||||||
|
/// </summary>
|
||||||
|
public class WindowWrapper : IWin32Window
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handle">Handle to wrap</param>
|
||||||
|
public WindowWrapper(IntPtr handle)
|
||||||
|
{
|
||||||
|
Handle = handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Original ptr
|
||||||
|
/// </summary>
|
||||||
|
public IntPtr Handle { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// Some of the classes and functions in this file were found online.
|
||||||
|
// Where possible the original authors are referenced.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WPinternals.HelperClasses
|
||||||
|
{
|
||||||
|
internal class ArrivalEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
public PhoneInterfaces NewInterface;
|
||||||
|
public IDisposable NewModel;
|
||||||
|
|
||||||
|
public ArrivalEventArgs(PhoneInterfaces NewInterface, IDisposable NewModel)
|
||||||
|
: base()
|
||||||
|
{
|
||||||
|
this.NewInterface = NewInterface;
|
||||||
|
this.NewModel = NewModel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||