53 Commits
Author SHA1 Message Date
Gustave Monce a982c119fb Bump timebomb 2024-09-09 21:08:35 +02:00
Gustave Monce c6dee3fe33 workaround older phone fw issues when retrieving via json rpc and gpt get function failures 2024-09-01 16:49:36 +02:00
Gustave Monce 91961b0e7b fix issues with downloading files 2024-09-01 12:45:46 +02:00
Gustave Monce 29c6ab06d4 fix: Download issues with ENOSW 2024-09-01 10:38:47 +02:00
Gustave Monce b03b561724 fix a few TODOs 2024-08-31 23:17:34 +02:00
Gustave Monce 91f534a7c3 fix: Merge issues from previous commit 2024-08-31 21:58:23 +02:00
Gustave Monce f0f3268924 Split phone info structures for each app type 2024-08-31 21:52:20 +02:00
Gustave Monce c269cfe839 Enable downloading ENOSW via Download Page 2024-08-31 19:45:24 +02:00
Gustave Monce 7d8aad0e88 fix: Modern Flash App Label mode switching 2024-08-31 18:31:56 +02:00
Gustave Monce 310d0b97c5 fix: Mode change detection on specb
resolves a few issues but not all due to the combined app
2024-08-31 17:50:18 +02:00
Gustave Monce 8e50c46357 wip: Refactor FlashApp Logic to account for the 3 split app states 2024-08-31 16:39:44 +02:00
Gustave Monce e6555741b0 fix: PhoneInfo app handling + label parsing issues 2024-08-31 11:00:04 +02:00
Gustave Monce c21692491d fix: Log all silent exceptions 2024-08-30 21:43:30 +02:00
Gustave Monce 350b6e8f1e fix: add missing raise can execute changed for unlock v1 with supported ffu field 2024-08-30 20:42:52 +02:00
Gustave Monce 0101477830 fix: Handle empty flash part list
This is used to clear the red flashing status we need to handle this differently for spec A
2024-08-30 20:42:37 +02:00
Gustave Monce a6c017986b fix: Handle loaders with new lines at the top instead of intel hex style right at the start 2024-08-30 20:42:16 +02:00
Gustave Monce 0174fc8b30 QCParts: Check if signatures are available 2024-08-30 20:41:57 +02:00
Gustave Monce c6f6ef4429 Rework Qualcomm Partition to also work with modern day ed loaders 2024-08-27 10:08:47 +02:00
Gustave Monce ab0c35e879 fix: revert qualcomm partition code changes to account for older ed payloads 2024-08-27 09:55:52 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
676a95dd97 Bump System.Text.Json from 8.0.0 to 8.0.4 in /WPinternals (#74)
Bumps System.Text.Json from 8.0.0 to 8.0.4.

---
updated-dependencies:
- dependency-name: System.Text.Json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-13 14:53:12 +02:00
Gustave Monce 8981fd02e9 Enable Preview Build 2023-11-26 18:50:46 +01:00
Gustave Monce 16d3f95971 WPinternals v3.0 2023-11-26 18:39:49 +01:00
Gustave Monce 293c649edb Refactor Qualcomm Sahara and Qualcomm Firehose code 2023-11-26 18:37:14 +01:00
Gustave Monce 88efc77887 Cleanup Sahara Implementation 2023-11-26 18:08:50 +01:00
Gustave Monce dc6085f185 Sahara: Implement getting the RKH 2023-11-26 16:51:29 +01:00
Gustave Monce e2cbb9c6fc Alter the list of OS partitions 2023-11-26 14:19:05 +01:00
Gustave Monce 4b7b9621b4 Rebuild the Backup to Custom ROM zip functionality to handle more partitions and be more flexible 2023-11-26 14:04:13 +01:00
Gustave Monce 96c42a29b5 Adopt new C# syntax for array init 2023-11-26 14:03:46 +01:00
Gustave Monce 742c89b9bf CI: Use .NET 8 SDK 2023-11-26 13:09:49 +01:00
Gustave Monce dbd303fd07 Add new feature to generate a GPT xml file from a binary or backup 2023-11-26 13:08:33 +01:00
Gustave Monce 8d35be447a Project: Update to .NET 8 2023-11-26 12:25:14 +01:00
Gustave Monce 83c09bdc81 Improve RKH Reading from Qualcomm Images 2023-03-09 21:40:23 +01:00
Gustave MonceandGitHub 93a5064751 Merge pull request #47 from ungeskriptet/fix-typo 2022-12-23 09:31:24 +01:00
David Wronek ef6a962a01 Fix typo in MassStorageView 2022-12-19 20:35:47 +01:00
Gustave Monce d32788198d Project: Migrate to .NET 7 2022-11-11 02:26:45 -08:00
Gustave Monce 7798dd1c34 RKH: Fix an issue retrieving modern day RKH 2022-11-11 02:22:17 -08:00
Gustave Monce 57cd052d61 About: Show Build and Revision in the version field 2021-11-15 15:06:13 +01:00
Gustave Monce 5eb523530c Remove the Lumia 535 from the supported phone list 2021-11-15 14:53:34 +01:00
Gustave Monce 8a17b05398 Project: Update to .NET 6 2021-11-15 14:47:29 +01:00
Gustave Monce dc5ac1e7d4 CI: Make CI always fetch latest .NET 5 SDK 2021-08-26 09:09:47 +02:00
Gustave Monce 1d14d79fab Flash: Custom ROM: Fix incorrect unlocked check for EFIESP 2021-08-16 11:40:58 +02:00
Gustave Monce 846ea41883 Project: Add SDK 2021-08-14 11:24:02 +02:00
Gustave Monce 452393aaa7 Project: Add RootAccessTestUWP 2021-08-14 11:14:56 +02:00
Gustave Monce 17bc763761 Project: Move WPinternals code to a WPinternals folder 2021-08-14 11:04:37 +02:00
Gustave Monce 668a9b7fe2 Fix an issue with incorrect logging of secure boot state 2021-08-13 13:21:15 +02:00
Gustave Monce 8293c18406 Merge branch 'master' of https://github.com/ReneLergner/WPinternals 2021-08-12 17:43:45 +02:00
Gustave Monce 48fbfa77df Project: remove references to hijacked website/domain to prevent potential malicious activity due to us not controlling the domain anymore. 2021-08-12 17:43:38 +02:00
Gustave MonceandGitHub 709c91cec5 Create bug_report.yml 2021-08-12 08:59:16 +02:00
Gustave MonceandGitHub 611ad122f9 Create README.md 2021-08-12 08:52:54 +02:00
Gustave Monce d8fd0aa516 Fix more hyperlink issues 2021-08-12 08:37:20 +02:00
Gustave Monce 7f3c8b1777 Merge branch 'master' of https://github.com/ReneLergner/WPinternals 2021-08-12 08:32:27 +02:00
Gustave Monce 087457fa0d FIx an issue with hyperlinks 2021-08-12 08:31:36 +02:00
Gustave MonceandGitHub bb9f614e82 CI: Use .NET 5.0.9 SDK 2021-08-11 18:43:57 +02:00
285 changed files with 57282 additions and 48454 deletions
+60
View File
@@ -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.
+2 -2
View File
@@ -11,7 +11,7 @@ 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
@@ -20,7 +20,7 @@ jobs:
- name: Install .NET SDK - name: Install .NET SDK
uses: actions/setup-dotnet@v1 uses: actions/setup-dotnet@v1
with: with:
dotnet-version: "5.0.101" 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
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
+24
View File
@@ -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
+8
View File
@@ -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>
+100
View File
@@ -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();
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

+89
View File
@@ -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
}
}
}
+19
View File
@@ -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>
+65
View File
@@ -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"
});
}
}
}
}
+49
View File
@@ -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>
+169
View File
@@ -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)' &lt; '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>
+1818 -5
View File
File diff suppressed because it is too large Load Diff
@@ -1,64 +1,64 @@
// Common/CRC.cs // Common/CRC.cs
namespace SevenZip namespace SevenZip
{ {
internal class CRC internal class CRC
{ {
public static readonly uint[] Table; public static readonly uint[] Table;
static CRC() static CRC()
{ {
Table = new uint[256]; Table = new uint[256];
const uint kPoly = 0xEDB88320; const uint kPoly = 0xEDB88320;
for (uint i = 0; i < 256; i++) for (uint i = 0; i < 256; i++)
{ {
uint r = i; uint r = i;
for (int j = 0; j < 8; j++) for (int j = 0; j < 8; j++)
{ {
if ((r & 1) != 0) if ((r & 1) != 0)
{ {
r = (r >> 1) ^ kPoly; r = (r >> 1) ^ kPoly;
} }
else else
{ {
r >>= 1; r >>= 1;
} }
} }
Table[i] = r; Table[i] = r;
} }
} }
private uint _value = 0xFFFFFFFF; private uint _value = 0xFFFFFFFF;
public void Init() { _value = 0xFFFFFFFF; } public void Init() { _value = 0xFFFFFFFF; }
public void UpdateByte(byte b) public void UpdateByte(byte b)
{ {
_value = Table[((byte)_value) ^ b] ^ (_value >> 8); _value = Table[((byte)_value) ^ b] ^ (_value >> 8);
} }
public void Update(byte[] data, uint offset, uint size) public void Update(byte[] data, uint offset, uint size)
{ {
for (uint i = 0; i < size; i++) for (uint i = 0; i < size; i++)
{ {
_value = Table[((byte)_value) ^ data[offset + i]] ^ (_value >> 8); _value = Table[((byte)_value) ^ data[offset + i]] ^ (_value >> 8);
} }
} }
public uint GetDigest() { return _value ^ 0xFFFFFFFF; } public uint GetDigest() { return _value ^ 0xFFFFFFFF; }
private static uint CalculateDigest(byte[] data, uint offset, uint size) private static uint CalculateDigest(byte[] data, uint offset, uint size)
{ {
CRC crc = new(); CRC crc = new();
// crc.Init(); // crc.Init();
crc.Update(data, offset, size); crc.Update(data, offset, size);
return crc.GetDigest(); return crc.GetDigest();
} }
private static bool VerifyDigest(uint digest, byte[] data, uint offset, uint size) private static bool VerifyDigest(uint digest, byte[] data, uint offset, uint size)
{ {
return CalculateDigest(data, offset, size) == digest; return CalculateDigest(data, offset, size) == digest;
} }
} }
} }
@@ -1,325 +1,325 @@
// CommandLineParser.cs // CommandLineParser.cs
using System; using System;
using System.Collections; using System.Collections;
namespace SevenZip.CommandLineParser namespace SevenZip.CommandLineParser
{ {
public enum SwitchType public enum SwitchType
{ {
Simple, Simple,
PostMinus, PostMinus,
LimitedPostString, LimitedPostString,
UnLimitedPostString, UnLimitedPostString,
PostChar PostChar
} }
public class SwitchForm public class SwitchForm
{ {
public string IDString; public string IDString;
public SwitchType Type; public SwitchType Type;
public bool Multi; public bool Multi;
public int MinLen; public int MinLen;
public int MaxLen; public int MaxLen;
public string PostCharSet; public string PostCharSet;
public SwitchForm(string idString, SwitchType type, bool multi, public SwitchForm(string idString, SwitchType type, bool multi,
int minLen, int maxLen, string postCharSet) int minLen, int maxLen, string postCharSet)
{ {
IDString = idString; IDString = idString;
Type = type; Type = type;
Multi = multi; Multi = multi;
MinLen = minLen; MinLen = minLen;
MaxLen = maxLen; MaxLen = maxLen;
PostCharSet = postCharSet; PostCharSet = postCharSet;
} }
public SwitchForm(string idString, SwitchType type, bool multi, int minLen) : public SwitchForm(string idString, SwitchType type, bool multi, int minLen) :
this(idString, type, multi, minLen, 0, "") this(idString, type, multi, minLen, 0, "")
{ {
} }
public SwitchForm(string idString, SwitchType type, bool multi) : public SwitchForm(string idString, SwitchType type, bool multi) :
this(idString, type, multi, 0) this(idString, type, multi, 0)
{ {
} }
} }
public class SwitchResult public class SwitchResult
{ {
public bool ThereIs; public bool ThereIs;
public bool WithMinus; public bool WithMinus;
public ArrayList PostStrings = new(); public ArrayList PostStrings = new();
public int PostCharIndex; public int PostCharIndex;
public SwitchResult() public SwitchResult()
{ {
ThereIs = false; ThereIs = false;
} }
} }
public class Parser public class Parser
{ {
public ArrayList NonSwitchStrings = new(); public ArrayList NonSwitchStrings = new();
private readonly SwitchResult[] _switches; private readonly SwitchResult[] _switches;
public Parser(int numSwitches) public Parser(int numSwitches)
{ {
_switches = new SwitchResult[numSwitches]; _switches = new SwitchResult[numSwitches];
for (int i = 0; i < numSwitches; i++) for (int i = 0; i < numSwitches; i++)
{ {
_switches[i] = new SwitchResult(); _switches[i] = new SwitchResult();
} }
} }
private bool ParseString(string srcString, SwitchForm[] switchForms) private bool ParseString(string srcString, SwitchForm[] switchForms)
{ {
int len = srcString.Length; int len = srcString.Length;
if (len == 0) if (len == 0)
{ {
return false; return false;
} }
int pos = 0; int pos = 0;
if (!IsItSwitchChar(srcString[pos])) if (!IsItSwitchChar(srcString[pos]))
{ {
return false; return false;
} }
while (pos < len) while (pos < len)
{ {
if (IsItSwitchChar(srcString[pos])) if (IsItSwitchChar(srcString[pos]))
{ {
pos++; pos++;
} }
const int kNoLen = -1; const int kNoLen = -1;
int matchedSwitchIndex = 0; int matchedSwitchIndex = 0;
int maxLen = kNoLen; int maxLen = kNoLen;
for (int switchIndex = 0; switchIndex < _switches.Length; switchIndex++) for (int switchIndex = 0; switchIndex < _switches.Length; switchIndex++)
{ {
int switchLen = switchForms[switchIndex].IDString.Length; int switchLen = switchForms[switchIndex].IDString.Length;
if (switchLen <= maxLen || pos + switchLen > len) if (switchLen <= maxLen || pos + switchLen > len)
{ {
continue; continue;
} }
if (String.Compare(switchForms[switchIndex].IDString, 0, if (String.Compare(switchForms[switchIndex].IDString, 0,
srcString, pos, switchLen, true) == 0) srcString, pos, switchLen, true) == 0)
{ {
matchedSwitchIndex = switchIndex; matchedSwitchIndex = switchIndex;
maxLen = switchLen; maxLen = switchLen;
} }
} }
if (maxLen == kNoLen) if (maxLen == kNoLen)
{ {
throw new Exception("maxLen == kNoLen"); throw new Exception("maxLen == kNoLen");
} }
SwitchResult matchedSwitch = _switches[matchedSwitchIndex]; SwitchResult matchedSwitch = _switches[matchedSwitchIndex];
SwitchForm switchForm = switchForms[matchedSwitchIndex]; SwitchForm switchForm = switchForms[matchedSwitchIndex];
if ((!switchForm.Multi) && matchedSwitch.ThereIs) if ((!switchForm.Multi) && matchedSwitch.ThereIs)
{ {
throw new Exception("switch must be single"); throw new Exception("switch must be single");
} }
matchedSwitch.ThereIs = true; matchedSwitch.ThereIs = true;
pos += maxLen; pos += maxLen;
int tailSize = len - pos; int tailSize = len - pos;
SwitchType type = switchForm.Type; SwitchType type = switchForm.Type;
switch (type) switch (type)
{ {
case SwitchType.PostMinus: case SwitchType.PostMinus:
{ {
if (tailSize == 0) if (tailSize == 0)
{ {
matchedSwitch.WithMinus = false; matchedSwitch.WithMinus = false;
} }
else else
{ {
matchedSwitch.WithMinus = srcString[pos] == kSwitchMinus; matchedSwitch.WithMinus = srcString[pos] == kSwitchMinus;
if (matchedSwitch.WithMinus) if (matchedSwitch.WithMinus)
{ {
pos++; pos++;
} }
} }
break; break;
} }
case SwitchType.PostChar: case SwitchType.PostChar:
{ {
if (tailSize < switchForm.MinLen) if (tailSize < switchForm.MinLen)
{ {
throw new Exception("switch is not full"); throw new Exception("switch is not full");
} }
string charSet = switchForm.PostCharSet; string charSet = switchForm.PostCharSet;
const int kEmptyCharValue = -1; const int kEmptyCharValue = -1;
if (tailSize == 0) if (tailSize == 0)
{ {
matchedSwitch.PostCharIndex = kEmptyCharValue; matchedSwitch.PostCharIndex = kEmptyCharValue;
} }
else else
{ {
int index = charSet.IndexOf(srcString[pos]); int index = charSet.IndexOf(srcString[pos]);
if (index < 0) if (index < 0)
{ {
matchedSwitch.PostCharIndex = kEmptyCharValue; matchedSwitch.PostCharIndex = kEmptyCharValue;
} }
else else
{ {
matchedSwitch.PostCharIndex = index; matchedSwitch.PostCharIndex = index;
pos++; pos++;
} }
} }
break; break;
} }
case SwitchType.LimitedPostString: case SwitchType.LimitedPostString:
case SwitchType.UnLimitedPostString: case SwitchType.UnLimitedPostString:
{ {
int minLen = switchForm.MinLen; int minLen = switchForm.MinLen;
if (tailSize < minLen) if (tailSize < minLen)
{ {
throw new Exception("switch is not full"); throw new Exception("switch is not full");
} }
if (type == SwitchType.UnLimitedPostString) if (type == SwitchType.UnLimitedPostString)
{ {
matchedSwitch.PostStrings.Add(srcString[pos..]); matchedSwitch.PostStrings.Add(srcString[pos..]);
return true; return true;
} }
String stringSwitch = srcString.Substring(pos, minLen); String stringSwitch = srcString.Substring(pos, minLen);
pos += minLen; pos += minLen;
for (int i = minLen; i < switchForm.MaxLen && pos < len; i++, pos++) for (int i = minLen; i < switchForm.MaxLen && pos < len; i++, pos++)
{ {
char c = srcString[pos]; char c = srcString[pos];
if (IsItSwitchChar(c)) if (IsItSwitchChar(c))
{ {
break; break;
} }
stringSwitch += c; stringSwitch += c;
} }
matchedSwitch.PostStrings.Add(stringSwitch); matchedSwitch.PostStrings.Add(stringSwitch);
break; break;
} }
} }
} }
return true; return true;
} }
public void ParseStrings(SwitchForm[] switchForms, string[] commandStrings) public void ParseStrings(SwitchForm[] switchForms, string[] commandStrings)
{ {
int numCommandStrings = commandStrings.Length; int numCommandStrings = commandStrings.Length;
bool stopSwitch = false; bool stopSwitch = false;
for (int i = 0; i < numCommandStrings; i++) for (int i = 0; i < numCommandStrings; i++)
{ {
string s = commandStrings[i]; string s = commandStrings[i];
if (stopSwitch) if (stopSwitch)
{ {
NonSwitchStrings.Add(s); NonSwitchStrings.Add(s);
} }
else else
if (s == kStopSwitchParsing) if (s == kStopSwitchParsing)
{ {
stopSwitch = true; stopSwitch = true;
} }
else else
if (!ParseString(s, switchForms)) if (!ParseString(s, switchForms))
{ {
NonSwitchStrings.Add(s); NonSwitchStrings.Add(s);
} }
} }
} }
public SwitchResult this[int index] { get { return _switches[index]; } } public SwitchResult this[int index] { get { return _switches[index]; } }
public static int ParseCommand(CommandForm[] commandForms, string commandString, public static int ParseCommand(CommandForm[] commandForms, string commandString,
out string postString) out string postString)
{ {
for (int i = 0; i < commandForms.Length; i++) for (int i = 0; i < commandForms.Length; i++)
{ {
string id = commandForms[i].IDString; string id = commandForms[i].IDString;
if (commandForms[i].PostStringMode) if (commandForms[i].PostStringMode)
{ {
if (commandString.IndexOf(id) == 0) if (commandString.IndexOf(id) == 0)
{ {
postString = commandString[id.Length..]; postString = commandString[id.Length..];
return i; return i;
} }
} }
else else
if (commandString == id) if (commandString == id)
{ {
postString = ""; postString = "";
return i; return i;
} }
} }
postString = ""; postString = "";
return -1; return -1;
} }
private static bool ParseSubCharsCommand(int numForms, CommandSubCharsSet[] forms, private static bool ParseSubCharsCommand(int numForms, CommandSubCharsSet[] forms,
string commandString, ArrayList indices) string commandString, ArrayList indices)
{ {
indices.Clear(); indices.Clear();
int numUsedChars = 0; int numUsedChars = 0;
for (int i = 0; i < numForms; i++) for (int i = 0; i < numForms; i++)
{ {
CommandSubCharsSet charsSet = forms[i]; CommandSubCharsSet charsSet = forms[i];
int currentIndex = -1; int currentIndex = -1;
int len = charsSet.Chars.Length; int len = charsSet.Chars.Length;
for (int j = 0; j < len; j++) for (int j = 0; j < len; j++)
{ {
char c = charsSet.Chars[j]; char c = charsSet.Chars[j];
int newIndex = commandString.IndexOf(c); int newIndex = commandString.IndexOf(c);
if (newIndex >= 0) if (newIndex >= 0)
{ {
if (currentIndex >= 0) if (currentIndex >= 0)
{ {
return false; return false;
} }
if (commandString.IndexOf(c, newIndex + 1) >= 0) if (commandString.IndexOf(c, newIndex + 1) >= 0)
{ {
return false; return false;
} }
currentIndex = j; currentIndex = j;
numUsedChars++; numUsedChars++;
} }
} }
if (currentIndex == -1 && !charsSet.EmptyAllowed) if (currentIndex == -1 && !charsSet.EmptyAllowed)
{ {
return false; return false;
} }
indices.Add(currentIndex); indices.Add(currentIndex);
} }
return numUsedChars == commandString.Length; return numUsedChars == commandString.Length;
} }
private const char kSwitchID1 = '-'; private const char kSwitchID1 = '-';
private const char kSwitchID2 = '/'; private const char kSwitchID2 = '/';
private const char kSwitchMinus = '-'; private const char kSwitchMinus = '-';
private const string kStopSwitchParsing = "--"; private const string kStopSwitchParsing = "--";
private static bool IsItSwitchChar(char c) private static bool IsItSwitchChar(char c)
{ {
return c == kSwitchID1 || c == kSwitchID2; return c == kSwitchID1 || c == kSwitchID2;
} }
} }
public class CommandForm public class CommandForm
{ {
public string IDString = ""; public string IDString = "";
public bool PostStringMode = false; public bool PostStringMode = false;
public CommandForm(string idString, bool postStringMode) public CommandForm(string idString, bool postStringMode)
{ {
IDString = idString; IDString = idString;
PostStringMode = postStringMode; PostStringMode = postStringMode;
} }
} }
internal class CommandSubCharsSet internal class CommandSubCharsSet
{ {
public string Chars = ""; public string Chars = "";
public bool EmptyAllowed = false; public bool EmptyAllowed = false;
} }
} }
@@ -1,78 +1,78 @@
// InBuffer.cs // InBuffer.cs
namespace SevenZip.Buffer namespace SevenZip.Buffer
{ {
public class InBuffer public class InBuffer
{ {
private readonly byte[] m_Buffer; private readonly byte[] m_Buffer;
private uint m_Pos; private uint m_Pos;
private uint m_Limit; private uint m_Limit;
private readonly uint m_BufferSize; private readonly uint m_BufferSize;
private System.IO.Stream m_Stream; private System.IO.Stream m_Stream;
private bool m_StreamWasExhausted; private bool m_StreamWasExhausted;
private ulong m_ProcessedSize; private ulong m_ProcessedSize;
public InBuffer(uint bufferSize) public InBuffer(uint bufferSize)
{ {
m_Buffer = new byte[bufferSize]; m_Buffer = new byte[bufferSize];
m_BufferSize = bufferSize; m_BufferSize = bufferSize;
} }
public void Init(System.IO.Stream stream) public void Init(System.IO.Stream stream)
{ {
m_Stream = stream; m_Stream = stream;
m_ProcessedSize = 0; m_ProcessedSize = 0;
m_Limit = 0; m_Limit = 0;
m_Pos = 0; m_Pos = 0;
m_StreamWasExhausted = false; m_StreamWasExhausted = false;
} }
public bool ReadBlock() public bool ReadBlock()
{ {
if (m_StreamWasExhausted) if (m_StreamWasExhausted)
{ {
return false; return false;
} }
m_ProcessedSize += m_Pos; m_ProcessedSize += m_Pos;
int aNumProcessedBytes = m_Stream.Read(m_Buffer, 0, (int)m_BufferSize); int aNumProcessedBytes = m_Stream.Read(m_Buffer, 0, (int)m_BufferSize);
m_Pos = 0; m_Pos = 0;
m_Limit = (uint)aNumProcessedBytes; m_Limit = (uint)aNumProcessedBytes;
m_StreamWasExhausted = aNumProcessedBytes == 0; m_StreamWasExhausted = aNumProcessedBytes == 0;
return !m_StreamWasExhausted; return !m_StreamWasExhausted;
} }
public void ReleaseStream() public void ReleaseStream()
{ {
// m_Stream.Close(); // m_Stream.Close();
m_Stream = null; m_Stream = null;
} }
public bool ReadByte(byte b) // check it public bool ReadByte(byte b) // check it
{ {
if (m_Pos >= m_Limit && !ReadBlock()) if (m_Pos >= m_Limit && !ReadBlock())
{ {
return false; return false;
} }
b = m_Buffer[m_Pos++]; b = m_Buffer[m_Pos++];
return true; return true;
} }
public byte ReadByte() public byte ReadByte()
{ {
// return (byte)m_Stream.ReadByte(); // return (byte)m_Stream.ReadByte();
if (m_Pos >= m_Limit && !ReadBlock()) if (m_Pos >= m_Limit && !ReadBlock())
{ {
return 0xFF; return 0xFF;
} }
return m_Buffer[m_Pos++]; return m_Buffer[m_Pos++];
} }
public ulong GetProcessedSize() public ulong GetProcessedSize()
{ {
return m_ProcessedSize + m_Pos; return m_ProcessedSize + m_Pos;
} }
} }
} }
@@ -1,52 +1,52 @@
// OutBuffer.cs // OutBuffer.cs
namespace SevenZip.Buffer namespace SevenZip.Buffer
{ {
public class OutBuffer public class OutBuffer
{ {
private readonly byte[] m_Buffer; private readonly byte[] m_Buffer;
private uint m_Pos; private uint m_Pos;
private readonly uint m_BufferSize; private readonly uint m_BufferSize;
private System.IO.Stream m_Stream; private System.IO.Stream m_Stream;
private ulong m_ProcessedSize; private ulong m_ProcessedSize;
public OutBuffer(uint bufferSize) public OutBuffer(uint bufferSize)
{ {
m_Buffer = new byte[bufferSize]; m_Buffer = new byte[bufferSize];
m_BufferSize = bufferSize; m_BufferSize = bufferSize;
} }
public void SetStream(System.IO.Stream stream) { m_Stream = stream; } public void SetStream(System.IO.Stream stream) { m_Stream = stream; }
public void FlushStream() { m_Stream.Flush(); } public void FlushStream() { m_Stream.Flush(); }
public void CloseStream() { m_Stream.Close(); } public void CloseStream() { m_Stream.Close(); }
public void ReleaseStream() { m_Stream = null; } public void ReleaseStream() { m_Stream = null; }
public void Init() public void Init()
{ {
m_ProcessedSize = 0; m_ProcessedSize = 0;
m_Pos = 0; m_Pos = 0;
} }
public void WriteByte(byte b) public void WriteByte(byte b)
{ {
m_Buffer[m_Pos++] = b; m_Buffer[m_Pos++] = b;
if (m_Pos >= m_BufferSize) if (m_Pos >= m_BufferSize)
{ {
FlushData(); FlushData();
} }
} }
public void FlushData() public void FlushData()
{ {
if (m_Pos == 0) if (m_Pos == 0)
{ {
return; return;
} }
m_Stream.Write(m_Buffer, 0, (int)m_Pos); m_Stream.Write(m_Buffer, 0, (int)m_Pos);
m_Pos = 0; m_Pos = 0;
} }
public ulong GetProcessedSize() { return m_ProcessedSize + m_Pos; } public ulong GetProcessedSize() { return m_ProcessedSize + m_Pos; }
} }
} }
@@ -1,24 +1,24 @@
// IMatchFinder.cs // IMatchFinder.cs
using System; using System;
namespace SevenZip.Compression.LZ namespace SevenZip.Compression.LZ
{ {
internal interface IInWindowStream internal interface IInWindowStream
{ {
void SetStream(System.IO.Stream inStream); void SetStream(System.IO.Stream inStream);
void Init(); void Init();
void ReleaseStream(); void ReleaseStream();
Byte GetIndexByte(Int32 index); Byte GetIndexByte(Int32 index);
UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit); UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit);
UInt32 GetNumAvailableBytes(); UInt32 GetNumAvailableBytes();
} }
internal interface IMatchFinder : IInWindowStream internal interface IMatchFinder : IInWindowStream
{ {
void Create(UInt32 historySize, UInt32 keepAddBufferBefore, void Create(UInt32 historySize, UInt32 keepAddBufferBefore,
UInt32 matchMaxLen, UInt32 keepAddBufferAfter); UInt32 matchMaxLen, UInt32 keepAddBufferAfter);
UInt32 GetMatches(UInt32[] distances); UInt32 GetMatches(UInt32[] distances);
void Skip(UInt32 num); void Skip(UInt32 num);
} }
} }
@@ -1,408 +1,408 @@
// LzBinTree.cs // LzBinTree.cs
using System; using System;
namespace SevenZip.Compression.LZ namespace SevenZip.Compression.LZ
{ {
public class BinTree : InWindow, IMatchFinder public class BinTree : InWindow, IMatchFinder
{ {
private UInt32 _cyclicBufferPos; private UInt32 _cyclicBufferPos;
private UInt32 _cyclicBufferSize = 0; private UInt32 _cyclicBufferSize = 0;
private UInt32 _matchMaxLen; private UInt32 _matchMaxLen;
private UInt32[] _son; private UInt32[] _son;
private UInt32[] _hash; private UInt32[] _hash;
private UInt32 _cutValue = 0xFF; private UInt32 _cutValue = 0xFF;
private UInt32 _hashMask; private UInt32 _hashMask;
private UInt32 _hashSizeSum = 0; private UInt32 _hashSizeSum = 0;
private bool HASH_ARRAY = true; private bool HASH_ARRAY = true;
private const UInt32 kHash2Size = 1 << 10; private const UInt32 kHash2Size = 1 << 10;
private const UInt32 kHash3Size = 1 << 16; private const UInt32 kHash3Size = 1 << 16;
private const UInt32 kBT2HashSize = 1 << 16; private const UInt32 kBT2HashSize = 1 << 16;
private const UInt32 kStartMaxLen = 1; private const UInt32 kStartMaxLen = 1;
private const UInt32 kHash3Offset = kHash2Size; private const UInt32 kHash3Offset = kHash2Size;
private const UInt32 kEmptyHashValue = 0; private const UInt32 kEmptyHashValue = 0;
private const UInt32 kMaxValForNormalize = ((UInt32)1 << 31) - 1; private const UInt32 kMaxValForNormalize = ((UInt32)1 << 31) - 1;
private UInt32 kNumHashDirectBytes = 0; private UInt32 kNumHashDirectBytes = 0;
private UInt32 kMinMatchCheck = 4; private UInt32 kMinMatchCheck = 4;
private UInt32 kFixHashSize = kHash2Size + kHash3Size; private UInt32 kFixHashSize = kHash2Size + kHash3Size;
public void SetType(int numHashBytes) public void SetType(int numHashBytes)
{ {
HASH_ARRAY = numHashBytes > 2; HASH_ARRAY = numHashBytes > 2;
if (HASH_ARRAY) if (HASH_ARRAY)
{ {
kNumHashDirectBytes = 0; kNumHashDirectBytes = 0;
kMinMatchCheck = 4; kMinMatchCheck = 4;
kFixHashSize = kHash2Size + kHash3Size; kFixHashSize = kHash2Size + kHash3Size;
} }
else else
{ {
kNumHashDirectBytes = 2; kNumHashDirectBytes = 2;
kMinMatchCheck = 2 + 1; kMinMatchCheck = 2 + 1;
kFixHashSize = 0; kFixHashSize = 0;
} }
} }
public new void SetStream(System.IO.Stream stream) { base.SetStream(stream); } public new void SetStream(System.IO.Stream stream) { base.SetStream(stream); }
public new void ReleaseStream() { base.ReleaseStream(); } public new void ReleaseStream() { base.ReleaseStream(); }
public new void Init() public new void Init()
{ {
base.Init(); base.Init();
for (UInt32 i = 0; i < _hashSizeSum; i++) for (UInt32 i = 0; i < _hashSizeSum; i++)
{ {
_hash[i] = kEmptyHashValue; _hash[i] = kEmptyHashValue;
} }
_cyclicBufferPos = 0; _cyclicBufferPos = 0;
ReduceOffsets(-1); ReduceOffsets(-1);
} }
public new void MovePos() public new void MovePos()
{ {
if (++_cyclicBufferPos >= _cyclicBufferSize) if (++_cyclicBufferPos >= _cyclicBufferSize)
{ {
_cyclicBufferPos = 0; _cyclicBufferPos = 0;
} }
base.MovePos(); base.MovePos();
if (_pos == kMaxValForNormalize) if (_pos == kMaxValForNormalize)
{ {
Normalize(); Normalize();
} }
} }
public new Byte GetIndexByte(Int32 index) { return base.GetIndexByte(index); } public new Byte GetIndexByte(Int32 index) { return base.GetIndexByte(index); }
public new UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit) public new UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit)
{ return base.GetMatchLen(index, distance, limit); } { return base.GetMatchLen(index, distance, limit); }
public new UInt32 GetNumAvailableBytes() { return base.GetNumAvailableBytes(); } public new UInt32 GetNumAvailableBytes() { return base.GetNumAvailableBytes(); }
public void Create(UInt32 historySize, UInt32 keepAddBufferBefore, public void Create(UInt32 historySize, UInt32 keepAddBufferBefore,
UInt32 matchMaxLen, UInt32 keepAddBufferAfter) UInt32 matchMaxLen, UInt32 keepAddBufferAfter)
{ {
if (historySize > kMaxValForNormalize - 256) if (historySize > kMaxValForNormalize - 256)
{ {
throw new Exception(); throw new Exception();
} }
_cutValue = 16 + (matchMaxLen >> 1); _cutValue = 16 + (matchMaxLen >> 1);
UInt32 windowReservSize = ((historySize + keepAddBufferBefore + UInt32 windowReservSize = ((historySize + keepAddBufferBefore +
matchMaxLen + keepAddBufferAfter) / 2) + 256; matchMaxLen + keepAddBufferAfter) / 2) + 256;
Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, windowReservSize); Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, windowReservSize);
_matchMaxLen = matchMaxLen; _matchMaxLen = matchMaxLen;
UInt32 cyclicBufferSize = historySize + 1; UInt32 cyclicBufferSize = historySize + 1;
if (_cyclicBufferSize != cyclicBufferSize) if (_cyclicBufferSize != cyclicBufferSize)
{ {
_son = new UInt32[(_cyclicBufferSize = cyclicBufferSize) * 2]; _son = new UInt32[(_cyclicBufferSize = cyclicBufferSize) * 2];
} }
UInt32 hs = kBT2HashSize; UInt32 hs = kBT2HashSize;
if (HASH_ARRAY) if (HASH_ARRAY)
{ {
hs = historySize - 1; hs = historySize - 1;
hs |= hs >> 1; hs |= hs >> 1;
hs |= hs >> 2; hs |= hs >> 2;
hs |= hs >> 4; hs |= hs >> 4;
hs |= hs >> 8; hs |= hs >> 8;
hs >>= 1; hs >>= 1;
hs |= 0xFFFF; hs |= 0xFFFF;
if (hs > (1 << 24)) if (hs > (1 << 24))
{ {
hs >>= 1; hs >>= 1;
} }
_hashMask = hs; _hashMask = hs;
hs++; hs++;
hs += kFixHashSize; hs += kFixHashSize;
} }
if (hs != _hashSizeSum) if (hs != _hashSizeSum)
{ {
_hash = new UInt32[_hashSizeSum = hs]; _hash = new UInt32[_hashSizeSum = hs];
} }
} }
public UInt32 GetMatches(UInt32[] distances) public UInt32 GetMatches(UInt32[] distances)
{ {
UInt32 lenLimit; UInt32 lenLimit;
if (_pos + _matchMaxLen <= _streamPos) if (_pos + _matchMaxLen <= _streamPos)
{ {
lenLimit = _matchMaxLen; lenLimit = _matchMaxLen;
} }
else else
{ {
lenLimit = _streamPos - _pos; lenLimit = _streamPos - _pos;
if (lenLimit < kMinMatchCheck) if (lenLimit < kMinMatchCheck)
{ {
MovePos(); MovePos();
return 0; return 0;
} }
} }
UInt32 offset = 0; UInt32 offset = 0;
UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0; UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
UInt32 cur = _bufferOffset + _pos; UInt32 cur = _bufferOffset + _pos;
UInt32 maxLen = kStartMaxLen; // to avoid items for len < hashSize; UInt32 maxLen = kStartMaxLen; // to avoid items for len < hashSize;
UInt32 hashValue, hash2Value = 0, hash3Value = 0; UInt32 hashValue, hash2Value = 0, hash3Value = 0;
if (HASH_ARRAY) if (HASH_ARRAY)
{ {
UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1]; UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1];
hash2Value = temp & (kHash2Size - 1); hash2Value = temp & (kHash2Size - 1);
temp ^= (UInt32)_bufferBase[cur + 2] << 8; temp ^= (UInt32)_bufferBase[cur + 2] << 8;
hash3Value = temp & (kHash3Size - 1); hash3Value = temp & (kHash3Size - 1);
hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask; hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask;
} }
else else
{ {
hashValue = _bufferBase[cur] ^ ((UInt32)_bufferBase[cur + 1] << 8); hashValue = _bufferBase[cur] ^ ((UInt32)_bufferBase[cur + 1] << 8);
} }
UInt32 curMatch = _hash[kFixHashSize + hashValue]; UInt32 curMatch = _hash[kFixHashSize + hashValue];
if (HASH_ARRAY) if (HASH_ARRAY)
{ {
UInt32 curMatch2 = _hash[hash2Value]; UInt32 curMatch2 = _hash[hash2Value];
UInt32 curMatch3 = _hash[kHash3Offset + hash3Value]; UInt32 curMatch3 = _hash[kHash3Offset + hash3Value];
_hash[hash2Value] = _pos; _hash[hash2Value] = _pos;
_hash[kHash3Offset + hash3Value] = _pos; _hash[kHash3Offset + hash3Value] = _pos;
if (curMatch2 > matchMinPos && _bufferBase[_bufferOffset + curMatch2] == _bufferBase[cur]) if (curMatch2 > matchMinPos && _bufferBase[_bufferOffset + curMatch2] == _bufferBase[cur])
{ {
distances[offset++] = maxLen = 2; distances[offset++] = maxLen = 2;
distances[offset++] = _pos - curMatch2 - 1; distances[offset++] = _pos - curMatch2 - 1;
} }
if (curMatch3 > matchMinPos && _bufferBase[_bufferOffset + curMatch3] == _bufferBase[cur]) if (curMatch3 > matchMinPos && _bufferBase[_bufferOffset + curMatch3] == _bufferBase[cur])
{ {
if (curMatch3 == curMatch2) if (curMatch3 == curMatch2)
{ {
offset -= 2; offset -= 2;
} }
distances[offset++] = maxLen = 3; distances[offset++] = maxLen = 3;
distances[offset++] = _pos - curMatch3 - 1; distances[offset++] = _pos - curMatch3 - 1;
curMatch2 = curMatch3; curMatch2 = curMatch3;
} }
if (offset != 0 && curMatch2 == curMatch) if (offset != 0 && curMatch2 == curMatch)
{ {
offset -= 2; offset -= 2;
maxLen = kStartMaxLen; maxLen = kStartMaxLen;
} }
} }
_hash[kFixHashSize + hashValue] = _pos; _hash[kFixHashSize + hashValue] = _pos;
UInt32 ptr0 = (_cyclicBufferPos << 1) + 1; UInt32 ptr0 = (_cyclicBufferPos << 1) + 1;
UInt32 ptr1 = _cyclicBufferPos << 1; UInt32 ptr1 = _cyclicBufferPos << 1;
UInt32 len0, len1; UInt32 len0, len1;
len0 = len1 = kNumHashDirectBytes; len0 = len1 = kNumHashDirectBytes;
if (kNumHashDirectBytes != 0 && curMatch > matchMinPos) if (kNumHashDirectBytes != 0 && curMatch > matchMinPos)
{ {
if (_bufferBase[_bufferOffset + curMatch + kNumHashDirectBytes] != if (_bufferBase[_bufferOffset + curMatch + kNumHashDirectBytes] !=
_bufferBase[cur + kNumHashDirectBytes]) _bufferBase[cur + kNumHashDirectBytes])
{ {
distances[offset++] = maxLen = kNumHashDirectBytes; distances[offset++] = maxLen = kNumHashDirectBytes;
distances[offset++] = _pos - curMatch - 1; distances[offset++] = _pos - curMatch - 1;
} }
} }
UInt32 count = _cutValue; UInt32 count = _cutValue;
while (true) while (true)
{ {
if (curMatch <= matchMinPos || count-- == 0) if (curMatch <= matchMinPos || count-- == 0)
{ {
_son[ptr0] = _son[ptr1] = kEmptyHashValue; _son[ptr0] = _son[ptr1] = kEmptyHashValue;
break; break;
} }
UInt32 delta = _pos - curMatch; UInt32 delta = _pos - curMatch;
UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ? UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ?
(_cyclicBufferPos - delta) : (_cyclicBufferPos - delta) :
(_cyclicBufferPos - delta + _cyclicBufferSize)) << 1; (_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;
UInt32 pby1 = _bufferOffset + curMatch; UInt32 pby1 = _bufferOffset + curMatch;
UInt32 len = Math.Min(len0, len1); UInt32 len = Math.Min(len0, len1);
if (_bufferBase[pby1 + len] == _bufferBase[cur + len]) if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
{ {
while (++len != lenLimit) while (++len != lenLimit)
{ {
if (_bufferBase[pby1 + len] != _bufferBase[cur + len]) if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
{ {
break; break;
} }
} }
if (maxLen < len) if (maxLen < len)
{ {
distances[offset++] = maxLen = len; distances[offset++] = maxLen = len;
distances[offset++] = delta - 1; distances[offset++] = delta - 1;
if (len == lenLimit) if (len == lenLimit)
{ {
_son[ptr1] = _son[cyclicPos]; _son[ptr1] = _son[cyclicPos];
_son[ptr0] = _son[cyclicPos + 1]; _son[ptr0] = _son[cyclicPos + 1];
break; break;
} }
} }
} }
if (_bufferBase[pby1 + len] < _bufferBase[cur + len]) if (_bufferBase[pby1 + len] < _bufferBase[cur + len])
{ {
_son[ptr1] = curMatch; _son[ptr1] = curMatch;
ptr1 = cyclicPos + 1; ptr1 = cyclicPos + 1;
curMatch = _son[ptr1]; curMatch = _son[ptr1];
len1 = len; len1 = len;
} }
else else
{ {
_son[ptr0] = curMatch; _son[ptr0] = curMatch;
ptr0 = cyclicPos; ptr0 = cyclicPos;
curMatch = _son[ptr0]; curMatch = _son[ptr0];
len0 = len; len0 = len;
} }
} }
MovePos(); MovePos();
return offset; return offset;
} }
public void Skip(UInt32 num) public void Skip(UInt32 num)
{ {
do do
{ {
UInt32 lenLimit; UInt32 lenLimit;
if (_pos + _matchMaxLen <= _streamPos) if (_pos + _matchMaxLen <= _streamPos)
{ {
lenLimit = _matchMaxLen; lenLimit = _matchMaxLen;
} }
else else
{ {
lenLimit = _streamPos - _pos; lenLimit = _streamPos - _pos;
if (lenLimit < kMinMatchCheck) if (lenLimit < kMinMatchCheck)
{ {
MovePos(); MovePos();
continue; continue;
} }
} }
UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0; UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
UInt32 cur = _bufferOffset + _pos; UInt32 cur = _bufferOffset + _pos;
UInt32 hashValue; UInt32 hashValue;
if (HASH_ARRAY) if (HASH_ARRAY)
{ {
UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1]; UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1];
UInt32 hash2Value = temp & (kHash2Size - 1); UInt32 hash2Value = temp & (kHash2Size - 1);
_hash[hash2Value] = _pos; _hash[hash2Value] = _pos;
temp ^= (UInt32)_bufferBase[cur + 2] << 8; temp ^= (UInt32)_bufferBase[cur + 2] << 8;
UInt32 hash3Value = temp & (kHash3Size - 1); UInt32 hash3Value = temp & (kHash3Size - 1);
_hash[kHash3Offset + hash3Value] = _pos; _hash[kHash3Offset + hash3Value] = _pos;
hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask; hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask;
} }
else else
{ {
hashValue = _bufferBase[cur] ^ ((UInt32)_bufferBase[cur + 1] << 8); hashValue = _bufferBase[cur] ^ ((UInt32)_bufferBase[cur + 1] << 8);
} }
UInt32 curMatch = _hash[kFixHashSize + hashValue]; UInt32 curMatch = _hash[kFixHashSize + hashValue];
_hash[kFixHashSize + hashValue] = _pos; _hash[kFixHashSize + hashValue] = _pos;
UInt32 ptr0 = (_cyclicBufferPos << 1) + 1; UInt32 ptr0 = (_cyclicBufferPos << 1) + 1;
UInt32 ptr1 = _cyclicBufferPos << 1; UInt32 ptr1 = _cyclicBufferPos << 1;
UInt32 len0, len1; UInt32 len0, len1;
len0 = len1 = kNumHashDirectBytes; len0 = len1 = kNumHashDirectBytes;
UInt32 count = _cutValue; UInt32 count = _cutValue;
while (true) while (true)
{ {
if (curMatch <= matchMinPos || count-- == 0) if (curMatch <= matchMinPos || count-- == 0)
{ {
_son[ptr0] = _son[ptr1] = kEmptyHashValue; _son[ptr0] = _son[ptr1] = kEmptyHashValue;
break; break;
} }
UInt32 delta = _pos - curMatch; UInt32 delta = _pos - curMatch;
UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ? UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ?
(_cyclicBufferPos - delta) : (_cyclicBufferPos - delta) :
(_cyclicBufferPos - delta + _cyclicBufferSize)) << 1; (_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;
UInt32 pby1 = _bufferOffset + curMatch; UInt32 pby1 = _bufferOffset + curMatch;
UInt32 len = Math.Min(len0, len1); UInt32 len = Math.Min(len0, len1);
if (_bufferBase[pby1 + len] == _bufferBase[cur + len]) if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
{ {
while (++len != lenLimit) while (++len != lenLimit)
{ {
if (_bufferBase[pby1 + len] != _bufferBase[cur + len]) if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
{ {
break; break;
} }
} }
if (len == lenLimit) if (len == lenLimit)
{ {
_son[ptr1] = _son[cyclicPos]; _son[ptr1] = _son[cyclicPos];
_son[ptr0] = _son[cyclicPos + 1]; _son[ptr0] = _son[cyclicPos + 1];
break; break;
} }
} }
if (_bufferBase[pby1 + len] < _bufferBase[cur + len]) if (_bufferBase[pby1 + len] < _bufferBase[cur + len])
{ {
_son[ptr1] = curMatch; _son[ptr1] = curMatch;
ptr1 = cyclicPos + 1; ptr1 = cyclicPos + 1;
curMatch = _son[ptr1]; curMatch = _son[ptr1];
len1 = len; len1 = len;
} }
else else
{ {
_son[ptr0] = curMatch; _son[ptr0] = curMatch;
ptr0 = cyclicPos; ptr0 = cyclicPos;
curMatch = _son[ptr0]; curMatch = _son[ptr0];
len0 = len; len0 = len;
} }
} }
MovePos(); MovePos();
} }
while (--num != 0); while (--num != 0);
} }
private void NormalizeLinks(UInt32[] items, UInt32 numItems, UInt32 subValue) private void NormalizeLinks(UInt32[] items, UInt32 numItems, UInt32 subValue)
{ {
for (UInt32 i = 0; i < numItems; i++) for (UInt32 i = 0; i < numItems; i++)
{ {
UInt32 value = items[i]; UInt32 value = items[i];
if (value <= subValue) if (value <= subValue)
{ {
value = kEmptyHashValue; value = kEmptyHashValue;
} }
else else
{ {
value -= subValue; value -= subValue;
} }
items[i] = value; items[i] = value;
} }
} }
private void Normalize() private void Normalize()
{ {
UInt32 subValue = _pos - _cyclicBufferSize; UInt32 subValue = _pos - _cyclicBufferSize;
NormalizeLinks(_son, _cyclicBufferSize * 2, subValue); NormalizeLinks(_son, _cyclicBufferSize * 2, subValue);
NormalizeLinks(_hash, _hashSizeSum, subValue); NormalizeLinks(_hash, _hashSizeSum, subValue);
ReduceOffsets((Int32)subValue); ReduceOffsets((Int32)subValue);
} }
public void SetCutValue(UInt32 cutValue) { _cutValue = cutValue; } public void SetCutValue(UInt32 cutValue) { _cutValue = cutValue; }
} }
} }
@@ -1,155 +1,155 @@
// LzInWindow.cs // LzInWindow.cs
using System; using System;
namespace SevenZip.Compression.LZ namespace SevenZip.Compression.LZ
{ {
public class InWindow public class InWindow
{ {
public Byte[] _bufferBase = null; // pointer to buffer with data public Byte[] _bufferBase = null; // pointer to buffer with data
private System.IO.Stream _stream; private System.IO.Stream _stream;
private UInt32 _posLimit; // offset (from _buffer) of first byte when new block reading must be done private UInt32 _posLimit; // offset (from _buffer) of first byte when new block reading must be done
private bool _streamEndWasReached; // if (true) then _streamPos shows real end of stream private bool _streamEndWasReached; // if (true) then _streamPos shows real end of stream
private UInt32 _pointerToLastSafePosition; private UInt32 _pointerToLastSafePosition;
public UInt32 _bufferOffset; public UInt32 _bufferOffset;
public UInt32 _blockSize; // Size of Allocated memory block public UInt32 _blockSize; // Size of Allocated memory block
public UInt32 _pos; // offset (from _buffer) of curent byte public UInt32 _pos; // offset (from _buffer) of curent byte
private UInt32 _keepSizeBefore; // how many BYTEs must be kept in buffer before _pos private UInt32 _keepSizeBefore; // how many BYTEs must be kept in buffer before _pos
private UInt32 _keepSizeAfter; // how many BYTEs must be kept buffer after _pos private UInt32 _keepSizeAfter; // how many BYTEs must be kept buffer after _pos
public UInt32 _streamPos; // offset (from _buffer) of first not read byte from Stream public UInt32 _streamPos; // offset (from _buffer) of first not read byte from Stream
public void MoveBlock() public void MoveBlock()
{ {
UInt32 offset = _bufferOffset + _pos - _keepSizeBefore; UInt32 offset = _bufferOffset + _pos - _keepSizeBefore;
// we need one additional byte, since MovePos moves on 1 byte. // we need one additional byte, since MovePos moves on 1 byte.
if (offset > 0) if (offset > 0)
{ {
offset--; offset--;
} }
UInt32 numBytes = _bufferOffset + _streamPos - offset; UInt32 numBytes = _bufferOffset + _streamPos - offset;
// check negative offset ???? // check negative offset ????
for (UInt32 i = 0; i < numBytes; i++) for (UInt32 i = 0; i < numBytes; i++)
{ {
_bufferBase[i] = _bufferBase[offset + i]; _bufferBase[i] = _bufferBase[offset + i];
} }
_bufferOffset -= offset; _bufferOffset -= offset;
} }
public virtual void ReadBlock() public virtual void ReadBlock()
{ {
if (_streamEndWasReached) if (_streamEndWasReached)
{ {
return; return;
} }
while (true) while (true)
{ {
int size = (int)(0 - _bufferOffset + _blockSize - _streamPos); int size = (int)(0 - _bufferOffset + _blockSize - _streamPos);
if (size == 0) if (size == 0)
{ {
return; return;
} }
int numReadBytes = _stream.Read(_bufferBase, (int)(_bufferOffset + _streamPos), size); int numReadBytes = _stream.Read(_bufferBase, (int)(_bufferOffset + _streamPos), size);
if (numReadBytes == 0) if (numReadBytes == 0)
{ {
_posLimit = _streamPos; _posLimit = _streamPos;
UInt32 pointerToPostion = _bufferOffset + _posLimit; UInt32 pointerToPostion = _bufferOffset + _posLimit;
if (pointerToPostion > _pointerToLastSafePosition) if (pointerToPostion > _pointerToLastSafePosition)
{ {
_posLimit = _pointerToLastSafePosition - _bufferOffset; _posLimit = _pointerToLastSafePosition - _bufferOffset;
} }
_streamEndWasReached = true; _streamEndWasReached = true;
return; return;
} }
_streamPos += (UInt32)numReadBytes; _streamPos += (UInt32)numReadBytes;
if (_streamPos >= _pos + _keepSizeAfter) if (_streamPos >= _pos + _keepSizeAfter)
{ {
_posLimit = _streamPos - _keepSizeAfter; _posLimit = _streamPos - _keepSizeAfter;
} }
} }
} }
private void Free() { _bufferBase = null; } private void Free() { _bufferBase = null; }
public void Create(UInt32 keepSizeBefore, UInt32 keepSizeAfter, UInt32 keepSizeReserv) public void Create(UInt32 keepSizeBefore, UInt32 keepSizeAfter, UInt32 keepSizeReserv)
{ {
_keepSizeBefore = keepSizeBefore; _keepSizeBefore = keepSizeBefore;
_keepSizeAfter = keepSizeAfter; _keepSizeAfter = keepSizeAfter;
UInt32 blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv; UInt32 blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv;
if (_bufferBase == null || _blockSize != blockSize) if (_bufferBase == null || _blockSize != blockSize)
{ {
Free(); Free();
_blockSize = blockSize; _blockSize = blockSize;
_bufferBase = new Byte[_blockSize]; _bufferBase = new Byte[_blockSize];
} }
_pointerToLastSafePosition = _blockSize - keepSizeAfter; _pointerToLastSafePosition = _blockSize - keepSizeAfter;
} }
public void SetStream(System.IO.Stream stream) { _stream = stream; } public void SetStream(System.IO.Stream stream) { _stream = stream; }
public void ReleaseStream() { _stream = null; } public void ReleaseStream() { _stream = null; }
public void Init() public void Init()
{ {
_bufferOffset = 0; _bufferOffset = 0;
_pos = 0; _pos = 0;
_streamPos = 0; _streamPos = 0;
_streamEndWasReached = false; _streamEndWasReached = false;
ReadBlock(); ReadBlock();
} }
public void MovePos() public void MovePos()
{ {
_pos++; _pos++;
if (_pos > _posLimit) if (_pos > _posLimit)
{ {
UInt32 pointerToPostion = _bufferOffset + _pos; UInt32 pointerToPostion = _bufferOffset + _pos;
if (pointerToPostion > _pointerToLastSafePosition) if (pointerToPostion > _pointerToLastSafePosition)
{ {
MoveBlock(); MoveBlock();
} }
ReadBlock(); ReadBlock();
} }
} }
public Byte GetIndexByte(Int32 index) { return _bufferBase[_bufferOffset + _pos + index]; } public Byte GetIndexByte(Int32 index) { return _bufferBase[_bufferOffset + _pos + index]; }
// index + limit have not to exceed _keepSizeAfter; // index + limit have not to exceed _keepSizeAfter;
public UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit) public UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit)
{ {
if (_streamEndWasReached && _pos + index + limit > _streamPos) if (_streamEndWasReached && _pos + index + limit > _streamPos)
{ {
limit = _streamPos - (UInt32)(_pos + index); limit = _streamPos - (UInt32)(_pos + index);
} }
distance++; distance++;
// Byte *pby = _buffer + (size_t)_pos + index; // Byte *pby = _buffer + (size_t)_pos + index;
UInt32 pby = _bufferOffset + _pos + (UInt32)index; UInt32 pby = _bufferOffset + _pos + (UInt32)index;
UInt32 i; UInt32 i;
for (i = 0; i < limit && _bufferBase[pby + i] == _bufferBase[pby + i - distance]; i++) for (i = 0; i < limit && _bufferBase[pby + i] == _bufferBase[pby + i - distance]; i++)
{ {
} }
return i; return i;
} }
public UInt32 GetNumAvailableBytes() { return _streamPos - _pos; } public UInt32 GetNumAvailableBytes() { return _streamPos - _pos; }
public void ReduceOffsets(Int32 subValue) public void ReduceOffsets(Int32 subValue)
{ {
_bufferOffset += (UInt32)subValue; _bufferOffset += (UInt32)subValue;
_posLimit -= (UInt32)subValue; _posLimit -= (UInt32)subValue;
_pos -= (UInt32)subValue; _pos -= (UInt32)subValue;
_streamPos -= (UInt32)subValue; _streamPos -= (UInt32)subValue;
} }
} }
} }
@@ -1,137 +1,137 @@
// LzOutWindow.cs // LzOutWindow.cs
namespace SevenZip.Compression.LZ namespace SevenZip.Compression.LZ
{ {
public class OutWindow public class OutWindow
{ {
private byte[] _buffer = null; private byte[] _buffer = null;
private uint _pos; private uint _pos;
private uint _windowSize = 0; private uint _windowSize = 0;
private uint _streamPos; private uint _streamPos;
private System.IO.Stream _stream; private System.IO.Stream _stream;
public uint TrainSize = 0; public uint TrainSize = 0;
public void Create(uint windowSize) public void Create(uint windowSize)
{ {
if (_windowSize != windowSize) if (_windowSize != windowSize)
{ {
// System.GC.Collect(); // System.GC.Collect();
_buffer = new byte[windowSize]; _buffer = new byte[windowSize];
} }
_windowSize = windowSize; _windowSize = windowSize;
_pos = 0; _pos = 0;
_streamPos = 0; _streamPos = 0;
} }
public void Init(System.IO.Stream stream, bool solid) public void Init(System.IO.Stream stream, bool solid)
{ {
ReleaseStream(); ReleaseStream();
_stream = stream; _stream = stream;
if (!solid) if (!solid)
{ {
_streamPos = 0; _streamPos = 0;
_pos = 0; _pos = 0;
TrainSize = 0; TrainSize = 0;
} }
} }
public bool Train(System.IO.Stream stream) public bool Train(System.IO.Stream stream)
{ {
long len = stream.Length; long len = stream.Length;
uint size = (len < _windowSize) ? (uint)len : _windowSize; uint size = (len < _windowSize) ? (uint)len : _windowSize;
TrainSize = size; TrainSize = size;
stream.Position = len - size; stream.Position = len - size;
_streamPos = _pos = 0; _streamPos = _pos = 0;
while (size > 0) while (size > 0)
{ {
uint curSize = _windowSize - _pos; uint curSize = _windowSize - _pos;
if (size < curSize) if (size < curSize)
{ {
curSize = size; curSize = size;
} }
int numReadBytes = stream.Read(_buffer, (int)_pos, (int)curSize); int numReadBytes = stream.Read(_buffer, (int)_pos, (int)curSize);
if (numReadBytes == 0) if (numReadBytes == 0)
{ {
return false; return false;
} }
size -= (uint)numReadBytes; size -= (uint)numReadBytes;
_pos += (uint)numReadBytes; _pos += (uint)numReadBytes;
_streamPos += (uint)numReadBytes; _streamPos += (uint)numReadBytes;
if (_pos == _windowSize) if (_pos == _windowSize)
{ {
_streamPos = _pos = 0; _streamPos = _pos = 0;
} }
} }
return true; return true;
} }
public void ReleaseStream() public void ReleaseStream()
{ {
Flush(); Flush();
_stream = null; _stream = null;
} }
public void Flush() public void Flush()
{ {
uint size = _pos - _streamPos; uint size = _pos - _streamPos;
if (size == 0) if (size == 0)
{ {
return; return;
} }
_stream.Write(_buffer, (int)_streamPos, (int)size); _stream.Write(_buffer, (int)_streamPos, (int)size);
if (_pos >= _windowSize) if (_pos >= _windowSize)
{ {
_pos = 0; _pos = 0;
} }
_streamPos = _pos; _streamPos = _pos;
} }
public void CopyBlock(uint distance, uint len) public void CopyBlock(uint distance, uint len)
{ {
uint pos = _pos - distance - 1; uint pos = _pos - distance - 1;
if (pos >= _windowSize) if (pos >= _windowSize)
{ {
pos += _windowSize; pos += _windowSize;
} }
for (; len > 0; len--) for (; len > 0; len--)
{ {
if (pos >= _windowSize) if (pos >= _windowSize)
{ {
pos = 0; pos = 0;
} }
_buffer[_pos++] = _buffer[pos++]; _buffer[_pos++] = _buffer[pos++];
if (_pos >= _windowSize) if (_pos >= _windowSize)
{ {
Flush(); Flush();
} }
} }
} }
public void PutByte(byte b) public void PutByte(byte b)
{ {
_buffer[_pos++] = b; _buffer[_pos++] = b;
if (_pos >= _windowSize) if (_pos >= _windowSize)
{ {
Flush(); Flush();
} }
} }
public byte GetByte(uint distance) public byte GetByte(uint distance)
{ {
uint pos = _pos - distance - 1; uint pos = _pos - distance - 1;
if (pos >= _windowSize) if (pos >= _windowSize)
{ {
pos += _windowSize; pos += _windowSize;
} }
return _buffer[pos]; return _buffer[pos];
} }
} }
} }
@@ -1,88 +1,88 @@
// LzmaBase.cs // LzmaBase.cs
namespace SevenZip.Compression.LZMA namespace SevenZip.Compression.LZMA
{ {
internal abstract class Base internal abstract class Base
{ {
public const uint kNumRepDistances = 4; public const uint kNumRepDistances = 4;
public const uint kNumStates = 12; public const uint kNumStates = 12;
// static byte []kLiteralNextStates = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; // static byte []kLiteralNextStates = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5};
// static byte []kMatchNextStates = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; // static byte []kMatchNextStates = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
// static byte []kRepNextStates = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; // static byte []kRepNextStates = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
// static byte []kShortRepNextStates = {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; // static byte []kShortRepNextStates = {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
public struct State public struct State
{ {
public uint Index; public uint Index;
public void Init() { Index = 0; } public void Init() { Index = 0; }
public void UpdateChar() public void UpdateChar()
{ {
if (Index < 4) if (Index < 4)
{ {
Index = 0; Index = 0;
} }
else if (Index < 10) else if (Index < 10)
{ {
Index -= 3; Index -= 3;
} }
else else
{ {
Index -= 6; Index -= 6;
} }
} }
public void UpdateMatch() { Index = (uint)(Index < 7 ? 7 : 10); } public void UpdateMatch() { Index = (uint)(Index < 7 ? 7 : 10); }
public void UpdateRep() { Index = (uint)(Index < 7 ? 8 : 11); } public void UpdateRep() { Index = (uint)(Index < 7 ? 8 : 11); }
public void UpdateShortRep() { Index = (uint)(Index < 7 ? 9 : 11); } public void UpdateShortRep() { Index = (uint)(Index < 7 ? 9 : 11); }
public bool IsCharState() { return Index < 7; } public bool IsCharState() { return Index < 7; }
} }
public const int kNumPosSlotBits = 6; public const int kNumPosSlotBits = 6;
public const int kDicLogSizeMin = 0; public const int kDicLogSizeMin = 0;
// public const int kDicLogSizeMax = 30; // public const int kDicLogSizeMax = 30;
// public const uint kDistTableSizeMax = kDicLogSizeMax * 2; // public const uint kDistTableSizeMax = kDicLogSizeMax * 2;
public const int kNumLenToPosStatesBits = 2; // it's for speed optimization public const int kNumLenToPosStatesBits = 2; // it's for speed optimization
public const uint kNumLenToPosStates = 1 << kNumLenToPosStatesBits; public const uint kNumLenToPosStates = 1 << kNumLenToPosStatesBits;
public const uint kMatchMinLen = 2; public const uint kMatchMinLen = 2;
public static uint GetLenToPosState(uint len) public static uint GetLenToPosState(uint len)
{ {
len -= kMatchMinLen; len -= kMatchMinLen;
if (len < kNumLenToPosStates) if (len < kNumLenToPosStates)
{ {
return len; return len;
} }
return kNumLenToPosStates - 1; return kNumLenToPosStates - 1;
} }
public const int kNumAlignBits = 4; public const int kNumAlignBits = 4;
public const uint kAlignTableSize = 1 << kNumAlignBits; public const uint kAlignTableSize = 1 << kNumAlignBits;
public const uint kAlignMask = kAlignTableSize - 1; public const uint kAlignMask = kAlignTableSize - 1;
public const uint kStartPosModelIndex = 4; public const uint kStartPosModelIndex = 4;
public const uint kEndPosModelIndex = 14; public const uint kEndPosModelIndex = 14;
public const uint kNumPosModels = kEndPosModelIndex - kStartPosModelIndex; public const uint kNumPosModels = kEndPosModelIndex - kStartPosModelIndex;
public const uint kNumFullDistances = 1 << ((int)kEndPosModelIndex / 2); public const uint kNumFullDistances = 1 << ((int)kEndPosModelIndex / 2);
public const uint kNumLitPosStatesBitsEncodingMax = 4; public const uint kNumLitPosStatesBitsEncodingMax = 4;
public const uint kNumLitContextBitsMax = 8; public const uint kNumLitContextBitsMax = 8;
public const int kNumPosStatesBitsMax = 4; public const int kNumPosStatesBitsMax = 4;
public const uint kNumPosStatesMax = 1 << kNumPosStatesBitsMax; public const uint kNumPosStatesMax = 1 << kNumPosStatesBitsMax;
public const int kNumPosStatesBitsEncodingMax = 4; public const int kNumPosStatesBitsEncodingMax = 4;
public const uint kNumPosStatesEncodingMax = 1 << kNumPosStatesBitsEncodingMax; public const uint kNumPosStatesEncodingMax = 1 << kNumPosStatesBitsEncodingMax;
public const int kNumLowLenBits = 3; public const int kNumLowLenBits = 3;
public const int kNumMidLenBits = 3; public const int kNumMidLenBits = 3;
public const int kNumHighLenBits = 8; public const int kNumHighLenBits = 8;
public const uint kNumLowLenSymbols = 1 << kNumLowLenBits; public const uint kNumLowLenSymbols = 1 << kNumLowLenBits;
public const uint kNumMidLenSymbols = 1 << kNumMidLenBits; public const uint kNumMidLenSymbols = 1 << kNumMidLenBits;
public const uint kNumLenSymbols = kNumLowLenSymbols + kNumMidLenSymbols + public const uint kNumLenSymbols = kNumLowLenSymbols + kNumMidLenSymbols +
(1 << kNumHighLenBits); (1 << kNumHighLenBits);
public const uint kMatchMaxLen = kMatchMinLen + kNumLenSymbols - 1; public const uint kMatchMaxLen = kMatchMinLen + kNumLenSymbols - 1;
} }
} }
@@ -1,465 +1,465 @@
// LzmaDecoder.cs // LzmaDecoder.cs
using System; using System;
namespace SevenZip.Compression.LZMA namespace SevenZip.Compression.LZMA
{ {
using RangeCoder; using RangeCoder;
using System.Threading; using System.Threading;
public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream
{ {
private class LenDecoder private class LenDecoder
{ {
private BitDecoder m_Choice = new(); private BitDecoder m_Choice = new();
private BitDecoder m_Choice2 = new(); private BitDecoder m_Choice2 = new();
private readonly BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[Base.kNumPosStatesMax]; private readonly BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
private readonly BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[Base.kNumPosStatesMax]; private readonly BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
private readonly BitTreeDecoder m_HighCoder = new(Base.kNumHighLenBits); private readonly BitTreeDecoder m_HighCoder = new(Base.kNumHighLenBits);
private uint m_NumPosStates = 0; private uint m_NumPosStates = 0;
public void Create(uint numPosStates) public void Create(uint numPosStates)
{ {
for (uint posState = m_NumPosStates; posState < numPosStates; posState++) for (uint posState = m_NumPosStates; posState < numPosStates; posState++)
{ {
m_LowCoder[posState] = new BitTreeDecoder(Base.kNumLowLenBits); m_LowCoder[posState] = new BitTreeDecoder(Base.kNumLowLenBits);
m_MidCoder[posState] = new BitTreeDecoder(Base.kNumMidLenBits); m_MidCoder[posState] = new BitTreeDecoder(Base.kNumMidLenBits);
} }
m_NumPosStates = numPosStates; m_NumPosStates = numPosStates;
} }
public void Init() public void Init()
{ {
m_Choice.Init(); m_Choice.Init();
for (uint posState = 0; posState < m_NumPosStates; posState++) for (uint posState = 0; posState < m_NumPosStates; posState++)
{ {
m_LowCoder[posState].Init(); m_LowCoder[posState].Init();
m_MidCoder[posState].Init(); m_MidCoder[posState].Init();
} }
m_Choice2.Init(); m_Choice2.Init();
m_HighCoder.Init(); m_HighCoder.Init();
} }
public uint Decode(RangeCoder.Decoder rangeDecoder, uint posState) public uint Decode(RangeCoder.Decoder rangeDecoder, uint posState)
{ {
if (m_Choice.Decode(rangeDecoder) == 0) if (m_Choice.Decode(rangeDecoder) == 0)
{ {
return m_LowCoder[posState].Decode(rangeDecoder); return m_LowCoder[posState].Decode(rangeDecoder);
} }
else else
{ {
uint symbol = Base.kNumLowLenSymbols; uint symbol = Base.kNumLowLenSymbols;
if (m_Choice2.Decode(rangeDecoder) == 0) if (m_Choice2.Decode(rangeDecoder) == 0)
{ {
symbol += m_MidCoder[posState].Decode(rangeDecoder); symbol += m_MidCoder[posState].Decode(rangeDecoder);
} }
else else
{ {
symbol += Base.kNumMidLenSymbols; symbol += Base.kNumMidLenSymbols;
symbol += m_HighCoder.Decode(rangeDecoder); symbol += m_HighCoder.Decode(rangeDecoder);
} }
return symbol; return symbol;
} }
} }
} }
private class LiteralDecoder private class LiteralDecoder
{ {
private struct Decoder2 private struct Decoder2
{ {
private BitDecoder[] m_Decoders; private BitDecoder[] m_Decoders;
public void Create() { m_Decoders = new BitDecoder[0x300]; } public void Create() { m_Decoders = new BitDecoder[0x300]; }
public void Init() { for (int i = 0; i < 0x300; i++) public void Init() { for (int i = 0; i < 0x300; i++)
{ {
m_Decoders[i].Init(); m_Decoders[i].Init();
} }
} }
public byte DecodeNormal(RangeCoder.Decoder rangeDecoder) public byte DecodeNormal(RangeCoder.Decoder rangeDecoder)
{ {
uint symbol = 1; uint symbol = 1;
do do
{ {
symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder); symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder);
} }
while (symbol < 0x100); while (symbol < 0x100);
return (byte)symbol; return (byte)symbol;
} }
public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, byte matchByte) public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, byte matchByte)
{ {
uint symbol = 1; uint symbol = 1;
do do
{ {
uint matchBit = (uint)(matchByte >> 7) & 1; uint matchBit = (uint)(matchByte >> 7) & 1;
matchByte <<= 1; matchByte <<= 1;
uint bit = m_Decoders[((1 + matchBit) << 8) + symbol].Decode(rangeDecoder); uint bit = m_Decoders[((1 + matchBit) << 8) + symbol].Decode(rangeDecoder);
symbol = (symbol << 1) | bit; symbol = (symbol << 1) | bit;
if (matchBit != bit) if (matchBit != bit)
{ {
while (symbol < 0x100) while (symbol < 0x100)
{ {
symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder); symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder);
} }
break; break;
} }
} }
while (symbol < 0x100); while (symbol < 0x100);
return (byte)symbol; return (byte)symbol;
} }
} }
private Decoder2[] m_Coders; private Decoder2[] m_Coders;
private int m_NumPrevBits; private int m_NumPrevBits;
private int m_NumPosBits; private int m_NumPosBits;
private uint m_PosMask; private uint m_PosMask;
public void Create(int numPosBits, int numPrevBits) public void Create(int numPosBits, int numPrevBits)
{ {
if (m_Coders != null && m_NumPrevBits == numPrevBits && if (m_Coders != null && m_NumPrevBits == numPrevBits &&
m_NumPosBits == numPosBits) m_NumPosBits == numPosBits)
{ {
return; return;
} }
m_NumPosBits = numPosBits; m_NumPosBits = numPosBits;
m_PosMask = ((uint)1 << numPosBits) - 1; m_PosMask = ((uint)1 << numPosBits) - 1;
m_NumPrevBits = numPrevBits; m_NumPrevBits = numPrevBits;
uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits); uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
m_Coders = new Decoder2[numStates]; m_Coders = new Decoder2[numStates];
for (uint i = 0; i < numStates; i++) for (uint i = 0; i < numStates; i++)
{ {
m_Coders[i].Create(); m_Coders[i].Create();
} }
} }
public void Init() public void Init()
{ {
uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits); uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
for (uint i = 0; i < numStates; i++) for (uint i = 0; i < numStates; i++)
{ {
m_Coders[i].Init(); m_Coders[i].Init();
} }
} }
private uint GetState(uint pos, byte prevByte) private uint GetState(uint pos, byte prevByte)
{ return ((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> (8 - m_NumPrevBits)); } { return ((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> (8 - m_NumPrevBits)); }
public byte DecodeNormal(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte) public byte DecodeNormal(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte)
{ return m_Coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); } { return m_Coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); }
public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte, byte matchByte) public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte, byte matchByte)
{ return m_Coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); } { return m_Coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); }
}; };
private readonly LZ.OutWindow m_OutWindow = new(); private readonly LZ.OutWindow m_OutWindow = new();
private readonly RangeCoder.Decoder m_RangeDecoder = new(); private readonly RangeCoder.Decoder m_RangeDecoder = new();
private readonly BitDecoder[] m_IsMatchDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax]; private readonly BitDecoder[] m_IsMatchDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
private readonly BitDecoder[] m_IsRepDecoders = new BitDecoder[Base.kNumStates]; private readonly BitDecoder[] m_IsRepDecoders = new BitDecoder[Base.kNumStates];
private readonly BitDecoder[] m_IsRepG0Decoders = new BitDecoder[Base.kNumStates]; private readonly BitDecoder[] m_IsRepG0Decoders = new BitDecoder[Base.kNumStates];
private readonly BitDecoder[] m_IsRepG1Decoders = new BitDecoder[Base.kNumStates]; private readonly BitDecoder[] m_IsRepG1Decoders = new BitDecoder[Base.kNumStates];
private readonly BitDecoder[] m_IsRepG2Decoders = new BitDecoder[Base.kNumStates]; private readonly BitDecoder[] m_IsRepG2Decoders = new BitDecoder[Base.kNumStates];
private readonly BitDecoder[] m_IsRep0LongDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax]; private readonly BitDecoder[] m_IsRep0LongDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
private readonly BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[Base.kNumLenToPosStates]; private readonly BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[Base.kNumLenToPosStates];
private readonly BitDecoder[] m_PosDecoders = new BitDecoder[Base.kNumFullDistances - Base.kEndPosModelIndex]; private readonly BitDecoder[] m_PosDecoders = new BitDecoder[Base.kNumFullDistances - Base.kEndPosModelIndex];
private readonly BitTreeDecoder m_PosAlignDecoder = new(Base.kNumAlignBits); private readonly BitTreeDecoder m_PosAlignDecoder = new(Base.kNumAlignBits);
private readonly LenDecoder m_LenDecoder = new(); private readonly LenDecoder m_LenDecoder = new();
private readonly LenDecoder m_RepLenDecoder = new(); private readonly LenDecoder m_RepLenDecoder = new();
private readonly LiteralDecoder m_LiteralDecoder = new(); private readonly LiteralDecoder m_LiteralDecoder = new();
private uint m_DictionarySize; private uint m_DictionarySize;
private uint m_DictionarySizeCheck; private uint m_DictionarySizeCheck;
private uint m_PosStateMask; private uint m_PosStateMask;
public Decoder() public Decoder()
{ {
m_DictionarySize = 0xFFFFFFFF; m_DictionarySize = 0xFFFFFFFF;
for (int i = 0; i < Base.kNumLenToPosStates; i++) for (int i = 0; i < Base.kNumLenToPosStates; i++)
{ {
m_PosSlotDecoder[i] = new BitTreeDecoder(Base.kNumPosSlotBits); m_PosSlotDecoder[i] = new BitTreeDecoder(Base.kNumPosSlotBits);
} }
} }
private void SetDictionarySize(uint dictionarySize) private void SetDictionarySize(uint dictionarySize)
{ {
if (m_DictionarySize != dictionarySize) if (m_DictionarySize != dictionarySize)
{ {
m_DictionarySize = dictionarySize; m_DictionarySize = dictionarySize;
m_DictionarySizeCheck = Math.Max(m_DictionarySize, 1); m_DictionarySizeCheck = Math.Max(m_DictionarySize, 1);
uint blockSize = Math.Max(m_DictionarySizeCheck, 1 << 12); uint blockSize = Math.Max(m_DictionarySizeCheck, 1 << 12);
m_OutWindow.Create(blockSize); m_OutWindow.Create(blockSize);
} }
} }
private void SetLiteralProperties(int lp, int lc) private void SetLiteralProperties(int lp, int lc)
{ {
if (lp > 8) if (lp > 8)
{ {
throw new InvalidParamException(); throw new InvalidParamException();
} }
if (lc > 8) if (lc > 8)
{ {
throw new InvalidParamException(); throw new InvalidParamException();
} }
m_LiteralDecoder.Create(lp, lc); m_LiteralDecoder.Create(lp, lc);
} }
private void SetPosBitsProperties(int pb) private void SetPosBitsProperties(int pb)
{ {
if (pb > Base.kNumPosStatesBitsMax) if (pb > Base.kNumPosStatesBitsMax)
{ {
throw new InvalidParamException(); throw new InvalidParamException();
} }
uint numPosStates = (uint)1 << pb; uint numPosStates = (uint)1 << pb;
m_LenDecoder.Create(numPosStates); m_LenDecoder.Create(numPosStates);
m_RepLenDecoder.Create(numPosStates); m_RepLenDecoder.Create(numPosStates);
m_PosStateMask = numPosStates - 1; m_PosStateMask = numPosStates - 1;
} }
private bool _solid = false; private bool _solid = false;
private void Init(System.IO.Stream inStream, System.IO.Stream outStream) private void Init(System.IO.Stream inStream, System.IO.Stream outStream)
{ {
m_RangeDecoder.Init(inStream); m_RangeDecoder.Init(inStream);
m_OutWindow.Init(outStream, _solid); m_OutWindow.Init(outStream, _solid);
uint i; uint i;
for (i = 0; i < Base.kNumStates; i++) for (i = 0; i < Base.kNumStates; i++)
{ {
for (uint j = 0; j <= m_PosStateMask; j++) for (uint j = 0; j <= m_PosStateMask; j++)
{ {
uint index = (i << Base.kNumPosStatesBitsMax) + j; uint index = (i << Base.kNumPosStatesBitsMax) + j;
m_IsMatchDecoders[index].Init(); m_IsMatchDecoders[index].Init();
m_IsRep0LongDecoders[index].Init(); m_IsRep0LongDecoders[index].Init();
} }
m_IsRepDecoders[i].Init(); m_IsRepDecoders[i].Init();
m_IsRepG0Decoders[i].Init(); m_IsRepG0Decoders[i].Init();
m_IsRepG1Decoders[i].Init(); m_IsRepG1Decoders[i].Init();
m_IsRepG2Decoders[i].Init(); m_IsRepG2Decoders[i].Init();
} }
m_LiteralDecoder.Init(); m_LiteralDecoder.Init();
for (i = 0; i < Base.kNumLenToPosStates; i++) for (i = 0; i < Base.kNumLenToPosStates; i++)
{ {
m_PosSlotDecoder[i].Init(); m_PosSlotDecoder[i].Init();
} }
// m_PosSpecDecoder.Init(); // m_PosSpecDecoder.Init();
for (i = 0; i < Base.kNumFullDistances - Base.kEndPosModelIndex; i++) for (i = 0; i < Base.kNumFullDistances - Base.kEndPosModelIndex; i++)
{ {
m_PosDecoders[i].Init(); m_PosDecoders[i].Init();
} }
m_LenDecoder.Init(); m_LenDecoder.Init();
m_RepLenDecoder.Init(); m_RepLenDecoder.Init();
m_PosAlignDecoder.Init(); m_PosAlignDecoder.Init();
} }
public void Code(System.IO.Stream inStream, System.IO.Stream outStream, public void Code(System.IO.Stream inStream, System.IO.Stream outStream,
Int64 inSize, Int64 outSize, ICodeProgress progress, CancellationToken? token = null) Int64 inSize, Int64 outSize, ICodeProgress progress, CancellationToken? token = null)
{ {
Init(inStream, outStream); Init(inStream, outStream);
Base.State state = new(); Base.State state = new();
state.Init(); state.Init();
uint rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0; uint rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0;
UInt64 nowPos64 = 0; UInt64 nowPos64 = 0;
UInt64 outSize64 = (UInt64)outSize; UInt64 outSize64 = (UInt64)outSize;
if (nowPos64 < outSize64) if (nowPos64 < outSize64)
{ {
if (m_IsMatchDecoders[state.Index << Base.kNumPosStatesBitsMax].Decode(m_RangeDecoder) != 0) if (m_IsMatchDecoders[state.Index << Base.kNumPosStatesBitsMax].Decode(m_RangeDecoder) != 0)
{ {
throw new DataErrorException(); throw new DataErrorException();
} }
state.UpdateChar(); state.UpdateChar();
byte b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, 0, 0); byte b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, 0, 0);
m_OutWindow.PutByte(b); m_OutWindow.PutByte(b);
nowPos64++; nowPos64++;
} }
try try
{ {
while (nowPos64 < outSize64) while (nowPos64 < outSize64)
{ {
token?.ThrowIfCancellationRequested(); token?.ThrowIfCancellationRequested();
// UInt64 next = Math.Min(nowPos64 + (1 << 18), outSize64); // UInt64 next = Math.Min(nowPos64 + (1 << 18), outSize64);
// while(nowPos64 < next) // while(nowPos64 < next)
{ {
uint posState = (uint)nowPos64 & m_PosStateMask; uint posState = (uint)nowPos64 & m_PosStateMask;
if (m_IsMatchDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0) if (m_IsMatchDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0)
{ {
byte b; byte b;
byte prevByte = m_OutWindow.GetByte(0); byte prevByte = m_OutWindow.GetByte(0);
b = !state.IsCharState() b = !state.IsCharState()
? m_LiteralDecoder.DecodeWithMatchByte(m_RangeDecoder, ? m_LiteralDecoder.DecodeWithMatchByte(m_RangeDecoder,
(uint)nowPos64, prevByte, m_OutWindow.GetByte(rep0)) (uint)nowPos64, prevByte, m_OutWindow.GetByte(rep0))
: m_LiteralDecoder.DecodeNormal(m_RangeDecoder, (uint)nowPos64, prevByte); : m_LiteralDecoder.DecodeNormal(m_RangeDecoder, (uint)nowPos64, prevByte);
m_OutWindow.PutByte(b); m_OutWindow.PutByte(b);
state.UpdateChar(); state.UpdateChar();
nowPos64++; nowPos64++;
} }
else else
{ {
uint len; uint len;
if (m_IsRepDecoders[state.Index].Decode(m_RangeDecoder) == 1) if (m_IsRepDecoders[state.Index].Decode(m_RangeDecoder) == 1)
{ {
if (m_IsRepG0Decoders[state.Index].Decode(m_RangeDecoder) == 0) if (m_IsRepG0Decoders[state.Index].Decode(m_RangeDecoder) == 0)
{ {
if (m_IsRep0LongDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0) if (m_IsRep0LongDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0)
{ {
state.UpdateShortRep(); state.UpdateShortRep();
m_OutWindow.PutByte(m_OutWindow.GetByte(rep0)); m_OutWindow.PutByte(m_OutWindow.GetByte(rep0));
nowPos64++; nowPos64++;
continue; continue;
} }
} }
else else
{ {
UInt32 distance; UInt32 distance;
if (m_IsRepG1Decoders[state.Index].Decode(m_RangeDecoder) == 0) if (m_IsRepG1Decoders[state.Index].Decode(m_RangeDecoder) == 0)
{ {
distance = rep1; distance = rep1;
} }
else else
{ {
if (m_IsRepG2Decoders[state.Index].Decode(m_RangeDecoder) == 0) if (m_IsRepG2Decoders[state.Index].Decode(m_RangeDecoder) == 0)
{ {
distance = rep2; distance = rep2;
} }
else else
{ {
distance = rep3; distance = rep3;
rep3 = rep2; rep3 = rep2;
} }
rep2 = rep1; rep2 = rep1;
} }
rep1 = rep0; rep1 = rep0;
rep0 = distance; rep0 = distance;
} }
len = m_RepLenDecoder.Decode(m_RangeDecoder, posState) + Base.kMatchMinLen; len = m_RepLenDecoder.Decode(m_RangeDecoder, posState) + Base.kMatchMinLen;
state.UpdateRep(); state.UpdateRep();
} }
else else
{ {
rep3 = rep2; rep3 = rep2;
rep2 = rep1; rep2 = rep1;
rep1 = rep0; rep1 = rep0;
len = Base.kMatchMinLen + m_LenDecoder.Decode(m_RangeDecoder, posState); len = Base.kMatchMinLen + m_LenDecoder.Decode(m_RangeDecoder, posState);
state.UpdateMatch(); state.UpdateMatch();
uint posSlot = m_PosSlotDecoder[Base.GetLenToPosState(len)].Decode(m_RangeDecoder); uint posSlot = m_PosSlotDecoder[Base.GetLenToPosState(len)].Decode(m_RangeDecoder);
if (posSlot >= Base.kStartPosModelIndex) if (posSlot >= Base.kStartPosModelIndex)
{ {
int numDirectBits = (int)((posSlot >> 1) - 1); int numDirectBits = (int)((posSlot >> 1) - 1);
rep0 = (2 | (posSlot & 1)) << numDirectBits; rep0 = (2 | (posSlot & 1)) << numDirectBits;
if (posSlot < Base.kEndPosModelIndex) if (posSlot < Base.kEndPosModelIndex)
{ {
rep0 += BitTreeDecoder.ReverseDecode(m_PosDecoders, rep0 += BitTreeDecoder.ReverseDecode(m_PosDecoders,
rep0 - posSlot - 1, m_RangeDecoder, numDirectBits); rep0 - posSlot - 1, m_RangeDecoder, numDirectBits);
} }
else else
{ {
rep0 += m_RangeDecoder.DecodeDirectBits( rep0 += m_RangeDecoder.DecodeDirectBits(
numDirectBits - Base.kNumAlignBits) << Base.kNumAlignBits; numDirectBits - Base.kNumAlignBits) << Base.kNumAlignBits;
rep0 += m_PosAlignDecoder.ReverseDecode(m_RangeDecoder); rep0 += m_PosAlignDecoder.ReverseDecode(m_RangeDecoder);
} }
} }
else else
{ {
rep0 = posSlot; rep0 = posSlot;
} }
} }
if (rep0 >= m_OutWindow.TrainSize + nowPos64 || rep0 >= m_DictionarySizeCheck) if (rep0 >= m_OutWindow.TrainSize + nowPos64 || rep0 >= m_DictionarySizeCheck)
{ {
if (rep0 == 0xFFFFFFFF) if (rep0 == 0xFFFFFFFF)
{ {
break; break;
} }
throw new DataErrorException(); throw new DataErrorException();
} }
m_OutWindow.CopyBlock(rep0, len); m_OutWindow.CopyBlock(rep0, len);
nowPos64 += len; nowPos64 += len;
} }
} }
} }
} }
catch (OperationCanceledException) catch (OperationCanceledException)
{ {
} }
m_OutWindow.Flush(); m_OutWindow.Flush();
m_OutWindow.ReleaseStream(); m_OutWindow.ReleaseStream();
m_RangeDecoder.ReleaseStream(); m_RangeDecoder.ReleaseStream();
} }
public void SetDecoderProperties(byte[] properties) public void SetDecoderProperties(byte[] properties)
{ {
if (properties.Length < 5) if (properties.Length < 5)
{ {
throw new InvalidParamException(); throw new InvalidParamException();
} }
int lc = properties[0] % 9; int lc = properties[0] % 9;
int remainder = properties[0] / 9; int remainder = properties[0] / 9;
int lp = remainder % 5; int lp = remainder % 5;
int pb = remainder / 5; int pb = remainder / 5;
if (pb > Base.kNumPosStatesBitsMax) if (pb > Base.kNumPosStatesBitsMax)
{ {
throw new InvalidParamException(); throw new InvalidParamException();
} }
UInt32 dictionarySize = 0; UInt32 dictionarySize = 0;
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
dictionarySize += ((UInt32)properties[1 + i]) << (i * 8); dictionarySize += ((UInt32)properties[1 + i]) << (i * 8);
} }
SetDictionarySize(dictionarySize); SetDictionarySize(dictionarySize);
SetLiteralProperties(lp, lc); SetLiteralProperties(lp, lc);
SetPosBitsProperties(pb); SetPosBitsProperties(pb);
} }
public bool Train(System.IO.Stream stream) public bool Train(System.IO.Stream stream)
{ {
_solid = true; _solid = true;
return m_OutWindow.Train(stream); return m_OutWindow.Train(stream);
} }
/* /*
public override bool CanRead { get { return true; }} public override bool CanRead { get { return true; }}
public override bool CanWrite { get { return true; }} public override bool CanWrite { get { return true; }}
public override bool CanSeek { get { return true; }} public override bool CanSeek { get { return true; }}
public override long Length { get { return 0; }} public override long Length { get { return 0; }}
public override long Position public override long Position
{ {
get { return 0; } get { return 0; }
set { } set { }
} }
public override void Flush() { } public override void Flush() { }
public override int Read(byte[] buffer, int offset, int count) public override int Read(byte[] buffer, int offset, int count)
{ {
return 0; return 0;
} }
public override void Write(byte[] buffer, int offset, int count) public override void Write(byte[] buffer, int offset, int count)
{ {
} }
public override long Seek(long offset, System.IO.SeekOrigin origin) public override long Seek(long offset, System.IO.SeekOrigin origin)
{ {
return 0; return 0;
} }
public override void SetLength(long value) {} public override void SetLength(long value) {}
*/ */
} }
} }
File diff suppressed because it is too large Load Diff
@@ -1,243 +1,243 @@
using System; using System;
namespace SevenZip.Compression.RangeCoder namespace SevenZip.Compression.RangeCoder
{ {
internal class Encoder internal class Encoder
{ {
public const uint kTopValue = 1 << 24; public const uint kTopValue = 1 << 24;
private System.IO.Stream Stream; private System.IO.Stream Stream;
public UInt64 Low; public UInt64 Low;
public uint Range; public uint Range;
private uint _cacheSize; private uint _cacheSize;
private byte _cache; private byte _cache;
private long StartPosition; private long StartPosition;
public void SetStream(System.IO.Stream stream) public void SetStream(System.IO.Stream stream)
{ {
Stream = stream; Stream = stream;
} }
public void ReleaseStream() public void ReleaseStream()
{ {
Stream = null; Stream = null;
} }
public void Init() public void Init()
{ {
StartPosition = Stream.Position; StartPosition = Stream.Position;
Low = 0; Low = 0;
Range = 0xFFFFFFFF; Range = 0xFFFFFFFF;
_cacheSize = 1; _cacheSize = 1;
_cache = 0; _cache = 0;
} }
public void FlushData() public void FlushData()
{ {
for (int i = 0; i < 5; i++) for (int i = 0; i < 5; i++)
{ {
ShiftLow(); ShiftLow();
} }
} }
public void FlushStream() public void FlushStream()
{ {
Stream.Flush(); Stream.Flush();
} }
public void CloseStream() public void CloseStream()
{ {
Stream.Close(); Stream.Close();
} }
public void Encode(uint start, uint size, uint total) public void Encode(uint start, uint size, uint total)
{ {
Low += start * (Range /= total); Low += start * (Range /= total);
Range *= size; Range *= size;
while (Range < kTopValue) while (Range < kTopValue)
{ {
Range <<= 8; Range <<= 8;
ShiftLow(); ShiftLow();
} }
} }
public void ShiftLow() public void ShiftLow()
{ {
if ((uint)Low < 0xFF000000 || (uint)(Low >> 32) == 1) if ((uint)Low < 0xFF000000 || (uint)(Low >> 32) == 1)
{ {
byte temp = _cache; byte temp = _cache;
do do
{ {
Stream.WriteByte((byte)(temp + (Low >> 32))); Stream.WriteByte((byte)(temp + (Low >> 32)));
temp = 0xFF; temp = 0xFF;
} }
while (--_cacheSize != 0); while (--_cacheSize != 0);
_cache = (byte)(((uint)Low) >> 24); _cache = (byte)(((uint)Low) >> 24);
} }
_cacheSize++; _cacheSize++;
Low = ((uint)Low) << 8; Low = ((uint)Low) << 8;
} }
public void EncodeDirectBits(uint v, int numTotalBits) public void EncodeDirectBits(uint v, int numTotalBits)
{ {
for (int i = numTotalBits - 1; i >= 0; i--) for (int i = numTotalBits - 1; i >= 0; i--)
{ {
Range >>= 1; Range >>= 1;
if (((v >> i) & 1) == 1) if (((v >> i) & 1) == 1)
{ {
Low += Range; Low += Range;
} }
if (Range < kTopValue) if (Range < kTopValue)
{ {
Range <<= 8; Range <<= 8;
ShiftLow(); ShiftLow();
} }
} }
} }
public void EncodeBit(uint size0, int numTotalBits, uint symbol) public void EncodeBit(uint size0, int numTotalBits, uint symbol)
{ {
uint newBound = (Range >> numTotalBits) * size0; uint newBound = (Range >> numTotalBits) * size0;
if (symbol == 0) if (symbol == 0)
{ {
Range = newBound; Range = newBound;
} }
else else
{ {
Low += newBound; Low += newBound;
Range -= newBound; Range -= newBound;
} }
while (Range < kTopValue) while (Range < kTopValue)
{ {
Range <<= 8; Range <<= 8;
ShiftLow(); ShiftLow();
} }
} }
public long GetProcessedSizeAdd() public long GetProcessedSizeAdd()
{ {
return _cacheSize + return _cacheSize +
Stream.Position - StartPosition + 4; Stream.Position - StartPosition + 4;
// (long)Stream.GetProcessedSize(); // (long)Stream.GetProcessedSize();
} }
} }
internal class Decoder internal class Decoder
{ {
public const uint kTopValue = 1 << 24; public const uint kTopValue = 1 << 24;
public uint Range; public uint Range;
public uint Code; public uint Code;
// public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16); // public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16);
public System.IO.Stream Stream; public System.IO.Stream Stream;
public void Init(System.IO.Stream stream) public void Init(System.IO.Stream stream)
{ {
// Stream.Init(stream); // Stream.Init(stream);
Stream = stream; Stream = stream;
Code = 0; Code = 0;
Range = 0xFFFFFFFF; Range = 0xFFFFFFFF;
for (int i = 0; i < 5; i++) for (int i = 0; i < 5; i++)
{ {
Code = (Code << 8) | (byte)Stream.ReadByte(); Code = (Code << 8) | (byte)Stream.ReadByte();
} }
} }
public void ReleaseStream() public void ReleaseStream()
{ {
// Stream.ReleaseStream(); // Stream.ReleaseStream();
Stream = null; Stream = null;
} }
public void CloseStream() public void CloseStream()
{ {
Stream.Close(); Stream.Close();
} }
public void Normalize() public void Normalize()
{ {
while (Range < kTopValue) while (Range < kTopValue)
{ {
Code = (Code << 8) | (byte)Stream.ReadByte(); Code = (Code << 8) | (byte)Stream.ReadByte();
Range <<= 8; Range <<= 8;
} }
} }
public void Normalize2() public void Normalize2()
{ {
if (Range < kTopValue) if (Range < kTopValue)
{ {
Code = (Code << 8) | (byte)Stream.ReadByte(); Code = (Code << 8) | (byte)Stream.ReadByte();
Range <<= 8; Range <<= 8;
} }
} }
public uint GetThreshold(uint total) public uint GetThreshold(uint total)
{ {
return Code / (Range /= total); return Code / (Range /= total);
} }
public void Decode(uint start, uint size, uint total) public void Decode(uint start, uint size, uint total)
{ {
Code -= start * Range; Code -= start * Range;
Range *= size; Range *= size;
Normalize(); Normalize();
} }
public uint DecodeDirectBits(int numTotalBits) public uint DecodeDirectBits(int numTotalBits)
{ {
uint range = Range; uint range = Range;
uint code = Code; uint code = Code;
uint result = 0; uint result = 0;
for (int i = numTotalBits; i > 0; i--) for (int i = numTotalBits; i > 0; i--)
{ {
range >>= 1; range >>= 1;
/* /*
result <<= 1; result <<= 1;
if (code >= range) if (code >= range)
{ {
code -= range; code -= range;
result |= 1; result |= 1;
} }
*/ */
uint t = (code - range) >> 31; uint t = (code - range) >> 31;
code -= range & (t - 1); code -= range & (t - 1);
result = (result << 1) | (1 - t); result = (result << 1) | (1 - t);
if (range < kTopValue) if (range < kTopValue)
{ {
code = (code << 8) | (byte)Stream.ReadByte(); code = (code << 8) | (byte)Stream.ReadByte();
range <<= 8; range <<= 8;
} }
} }
Range = range; Range = range;
Code = code; Code = code;
return result; return result;
} }
public uint DecodeBit(uint size0, int numTotalBits) public uint DecodeBit(uint size0, int numTotalBits)
{ {
uint newBound = (Range >> numTotalBits) * size0; uint newBound = (Range >> numTotalBits) * size0;
uint symbol; uint symbol;
if (Code < newBound) if (Code < newBound)
{ {
symbol = 0; symbol = 0;
Range = newBound; Range = newBound;
} }
else else
{ {
symbol = 1; symbol = 1;
Code -= newBound; Code -= newBound;
Range -= newBound; Range -= newBound;
} }
Normalize(); Normalize();
return symbol; return symbol;
} }
// ulong GetProcessedSize() {return Stream.GetProcessedSize(); } // ulong GetProcessedSize() {return Stream.GetProcessedSize(); }
} }
} }
@@ -1,127 +1,127 @@
using System; using System;
namespace SevenZip.Compression.RangeCoder namespace SevenZip.Compression.RangeCoder
{ {
internal struct BitEncoder internal struct BitEncoder
{ {
public const int kNumBitModelTotalBits = 11; public const int kNumBitModelTotalBits = 11;
public const uint kBitModelTotal = 1 << kNumBitModelTotalBits; public const uint kBitModelTotal = 1 << kNumBitModelTotalBits;
private const int kNumMoveBits = 5; private const int kNumMoveBits = 5;
private const int kNumMoveReducingBits = 2; private const int kNumMoveReducingBits = 2;
public const int kNumBitPriceShiftBits = 6; public const int kNumBitPriceShiftBits = 6;
private uint Prob; private uint Prob;
public void Init() { Prob = kBitModelTotal >> 1; } public void Init() { Prob = kBitModelTotal >> 1; }
public void UpdateModel(uint symbol) public void UpdateModel(uint symbol)
{ {
if (symbol == 0) if (symbol == 0)
{ {
Prob += (kBitModelTotal - Prob) >> kNumMoveBits; Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
} }
else else
{ {
Prob -= Prob >> kNumMoveBits; Prob -= Prob >> kNumMoveBits;
} }
} }
public void Encode(Encoder encoder, uint symbol) public void Encode(Encoder encoder, uint symbol)
{ {
// encoder.EncodeBit(Prob, kNumBitModelTotalBits, symbol); // encoder.EncodeBit(Prob, kNumBitModelTotalBits, symbol);
// UpdateModel(symbol); // UpdateModel(symbol);
uint newBound = (encoder.Range >> kNumBitModelTotalBits) * Prob; uint newBound = (encoder.Range >> kNumBitModelTotalBits) * Prob;
if (symbol == 0) if (symbol == 0)
{ {
encoder.Range = newBound; encoder.Range = newBound;
Prob += (kBitModelTotal - Prob) >> kNumMoveBits; Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
} }
else else
{ {
encoder.Low += newBound; encoder.Low += newBound;
encoder.Range -= newBound; encoder.Range -= newBound;
Prob -= Prob >> kNumMoveBits; Prob -= Prob >> kNumMoveBits;
} }
if (encoder.Range < Encoder.kTopValue) if (encoder.Range < Encoder.kTopValue)
{ {
encoder.Range <<= 8; encoder.Range <<= 8;
encoder.ShiftLow(); encoder.ShiftLow();
} }
} }
private static readonly UInt32[] ProbPrices = new UInt32[kBitModelTotal >> kNumMoveReducingBits]; private static readonly UInt32[] ProbPrices = new UInt32[kBitModelTotal >> kNumMoveReducingBits];
static BitEncoder() static BitEncoder()
{ {
const int kNumBits = kNumBitModelTotalBits - kNumMoveReducingBits; const int kNumBits = kNumBitModelTotalBits - kNumMoveReducingBits;
for (int i = kNumBits - 1; i >= 0; i--) for (int i = kNumBits - 1; i >= 0; i--)
{ {
UInt32 start = (UInt32)1 << (kNumBits - i - 1); UInt32 start = (UInt32)1 << (kNumBits - i - 1);
UInt32 end = (UInt32)1 << (kNumBits - i); UInt32 end = (UInt32)1 << (kNumBits - i);
for (UInt32 j = start; j < end; j++) for (UInt32 j = start; j < end; j++)
{ {
ProbPrices[j] = ((UInt32)i << kNumBitPriceShiftBits) + ProbPrices[j] = ((UInt32)i << kNumBitPriceShiftBits) +
(((end - j) << kNumBitPriceShiftBits) >> (kNumBits - i - 1)); (((end - j) << kNumBitPriceShiftBits) >> (kNumBits - i - 1));
} }
} }
} }
public uint GetPrice(uint symbol) public uint GetPrice(uint symbol)
{ {
return ProbPrices[(((Prob - symbol) ^ (-(int)symbol)) & (kBitModelTotal - 1)) >> kNumMoveReducingBits]; return ProbPrices[(((Prob - symbol) ^ (-(int)symbol)) & (kBitModelTotal - 1)) >> kNumMoveReducingBits];
} }
public uint GetPrice0() { return ProbPrices[Prob >> kNumMoveReducingBits]; } public uint GetPrice0() { return ProbPrices[Prob >> kNumMoveReducingBits]; }
public uint GetPrice1() { return ProbPrices[(kBitModelTotal - Prob) >> kNumMoveReducingBits]; } public uint GetPrice1() { return ProbPrices[(kBitModelTotal - Prob) >> kNumMoveReducingBits]; }
} }
internal struct BitDecoder internal struct BitDecoder
{ {
public const int kNumBitModelTotalBits = 11; public const int kNumBitModelTotalBits = 11;
public const uint kBitModelTotal = 1 << kNumBitModelTotalBits; public const uint kBitModelTotal = 1 << kNumBitModelTotalBits;
private const int kNumMoveBits = 5; private const int kNumMoveBits = 5;
private uint Prob; private uint Prob;
public void UpdateModel(int numMoveBits, uint symbol) public void UpdateModel(int numMoveBits, uint symbol)
{ {
if (symbol == 0) if (symbol == 0)
{ {
Prob += (kBitModelTotal - Prob) >> numMoveBits; Prob += (kBitModelTotal - Prob) >> numMoveBits;
} }
else else
{ {
Prob -= Prob >> numMoveBits; Prob -= Prob >> numMoveBits;
} }
} }
public void Init() { Prob = kBitModelTotal >> 1; } public void Init() { Prob = kBitModelTotal >> 1; }
public uint Decode(Decoder rangeDecoder) public uint Decode(Decoder rangeDecoder)
{ {
uint newBound = (rangeDecoder.Range >> kNumBitModelTotalBits) * Prob; uint newBound = (rangeDecoder.Range >> kNumBitModelTotalBits) * Prob;
if (rangeDecoder.Code < newBound) if (rangeDecoder.Code < newBound)
{ {
rangeDecoder.Range = newBound; rangeDecoder.Range = newBound;
Prob += (kBitModelTotal - Prob) >> kNumMoveBits; Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
if (rangeDecoder.Range < Decoder.kTopValue) if (rangeDecoder.Range < Decoder.kTopValue)
{ {
rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte(); rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
rangeDecoder.Range <<= 8; rangeDecoder.Range <<= 8;
} }
return 0; return 0;
} }
else else
{ {
rangeDecoder.Range -= newBound; rangeDecoder.Range -= newBound;
rangeDecoder.Code -= newBound; rangeDecoder.Code -= newBound;
Prob -= Prob >> kNumMoveBits; Prob -= Prob >> kNumMoveBits;
if (rangeDecoder.Range < Decoder.kTopValue) if (rangeDecoder.Range < Decoder.kTopValue)
{ {
rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte(); rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
rangeDecoder.Range <<= 8; rangeDecoder.Range <<= 8;
} }
return 1; return 1;
} }
} }
} }
} }
@@ -1,164 +1,164 @@
using System; using System;
namespace SevenZip.Compression.RangeCoder namespace SevenZip.Compression.RangeCoder
{ {
internal struct BitTreeEncoder internal struct BitTreeEncoder
{ {
private readonly BitEncoder[] Models; private readonly BitEncoder[] Models;
private readonly int NumBitLevels; private readonly int NumBitLevels;
public BitTreeEncoder(int numBitLevels) public BitTreeEncoder(int numBitLevels)
{ {
NumBitLevels = numBitLevels; NumBitLevels = numBitLevels;
Models = new BitEncoder[1 << numBitLevels]; Models = new BitEncoder[1 << numBitLevels];
} }
public void Init() public void Init()
{ {
for (uint i = 1; i < (1 << NumBitLevels); i++) for (uint i = 1; i < (1 << NumBitLevels); i++)
{ {
Models[i].Init(); Models[i].Init();
} }
} }
public void Encode(Encoder rangeEncoder, UInt32 symbol) public void Encode(Encoder rangeEncoder, UInt32 symbol)
{ {
UInt32 m = 1; UInt32 m = 1;
for (int bitIndex = NumBitLevels; bitIndex > 0;) for (int bitIndex = NumBitLevels; bitIndex > 0;)
{ {
bitIndex--; bitIndex--;
UInt32 bit = (symbol >> bitIndex) & 1; UInt32 bit = (symbol >> bitIndex) & 1;
Models[m].Encode(rangeEncoder, bit); Models[m].Encode(rangeEncoder, bit);
m = (m << 1) | bit; m = (m << 1) | bit;
} }
} }
public void ReverseEncode(Encoder rangeEncoder, UInt32 symbol) public void ReverseEncode(Encoder rangeEncoder, UInt32 symbol)
{ {
UInt32 m = 1; UInt32 m = 1;
for (UInt32 i = 0; i < NumBitLevels; i++) for (UInt32 i = 0; i < NumBitLevels; i++)
{ {
UInt32 bit = symbol & 1; UInt32 bit = symbol & 1;
Models[m].Encode(rangeEncoder, bit); Models[m].Encode(rangeEncoder, bit);
m = (m << 1) | bit; m = (m << 1) | bit;
symbol >>= 1; symbol >>= 1;
} }
} }
public UInt32 GetPrice(UInt32 symbol) public UInt32 GetPrice(UInt32 symbol)
{ {
UInt32 price = 0; UInt32 price = 0;
UInt32 m = 1; UInt32 m = 1;
for (int bitIndex = NumBitLevels; bitIndex > 0;) for (int bitIndex = NumBitLevels; bitIndex > 0;)
{ {
bitIndex--; bitIndex--;
UInt32 bit = (symbol >> bitIndex) & 1; UInt32 bit = (symbol >> bitIndex) & 1;
price += Models[m].GetPrice(bit); price += Models[m].GetPrice(bit);
m = (m << 1) + bit; m = (m << 1) + bit;
} }
return price; return price;
} }
public UInt32 ReverseGetPrice(UInt32 symbol) public UInt32 ReverseGetPrice(UInt32 symbol)
{ {
UInt32 price = 0; UInt32 price = 0;
UInt32 m = 1; UInt32 m = 1;
for (int i = NumBitLevels; i > 0; i--) for (int i = NumBitLevels; i > 0; i--)
{ {
UInt32 bit = symbol & 1; UInt32 bit = symbol & 1;
symbol >>= 1; symbol >>= 1;
price += Models[m].GetPrice(bit); price += Models[m].GetPrice(bit);
m = (m << 1) | bit; m = (m << 1) | bit;
} }
return price; return price;
} }
public static UInt32 ReverseGetPrice(BitEncoder[] Models, UInt32 startIndex, public static UInt32 ReverseGetPrice(BitEncoder[] Models, UInt32 startIndex,
int NumBitLevels, UInt32 symbol) int NumBitLevels, UInt32 symbol)
{ {
UInt32 price = 0; UInt32 price = 0;
UInt32 m = 1; UInt32 m = 1;
for (int i = NumBitLevels; i > 0; i--) for (int i = NumBitLevels; i > 0; i--)
{ {
UInt32 bit = symbol & 1; UInt32 bit = symbol & 1;
symbol >>= 1; symbol >>= 1;
price += Models[startIndex + m].GetPrice(bit); price += Models[startIndex + m].GetPrice(bit);
m = (m << 1) | bit; m = (m << 1) | bit;
} }
return price; return price;
} }
public static void ReverseEncode(BitEncoder[] Models, UInt32 startIndex, public static void ReverseEncode(BitEncoder[] Models, UInt32 startIndex,
Encoder rangeEncoder, int NumBitLevels, UInt32 symbol) Encoder rangeEncoder, int NumBitLevels, UInt32 symbol)
{ {
UInt32 m = 1; UInt32 m = 1;
for (int i = 0; i < NumBitLevels; i++) for (int i = 0; i < NumBitLevels; i++)
{ {
UInt32 bit = symbol & 1; UInt32 bit = symbol & 1;
Models[startIndex + m].Encode(rangeEncoder, bit); Models[startIndex + m].Encode(rangeEncoder, bit);
m = (m << 1) | bit; m = (m << 1) | bit;
symbol >>= 1; symbol >>= 1;
} }
} }
} }
internal struct BitTreeDecoder internal struct BitTreeDecoder
{ {
private readonly BitDecoder[] Models; private readonly BitDecoder[] Models;
private readonly int NumBitLevels; private readonly int NumBitLevels;
public BitTreeDecoder(int numBitLevels) public BitTreeDecoder(int numBitLevels)
{ {
NumBitLevels = numBitLevels; NumBitLevels = numBitLevels;
Models = new BitDecoder[1 << numBitLevels]; Models = new BitDecoder[1 << numBitLevels];
} }
public void Init() public void Init()
{ {
for (uint i = 1; i < (1 << NumBitLevels); i++) for (uint i = 1; i < (1 << NumBitLevels); i++)
{ {
Models[i].Init(); Models[i].Init();
} }
} }
public uint Decode(Decoder rangeDecoder) public uint Decode(Decoder rangeDecoder)
{ {
uint m = 1; uint m = 1;
for (int bitIndex = NumBitLevels; bitIndex > 0; bitIndex--) for (int bitIndex = NumBitLevels; bitIndex > 0; bitIndex--)
{ {
m = (m << 1) + Models[m].Decode(rangeDecoder); m = (m << 1) + Models[m].Decode(rangeDecoder);
} }
return m - ((uint)1 << NumBitLevels); return m - ((uint)1 << NumBitLevels);
} }
public uint ReverseDecode(Decoder rangeDecoder) public uint ReverseDecode(Decoder rangeDecoder)
{ {
uint m = 1; uint m = 1;
uint symbol = 0; uint symbol = 0;
for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++) for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
{ {
uint bit = Models[m].Decode(rangeDecoder); uint bit = Models[m].Decode(rangeDecoder);
m <<= 1; m <<= 1;
m += bit; m += bit;
symbol |= bit << bitIndex; symbol |= bit << bitIndex;
} }
return symbol; return symbol;
} }
public static uint ReverseDecode(BitDecoder[] Models, UInt32 startIndex, public static uint ReverseDecode(BitDecoder[] Models, UInt32 startIndex,
Decoder rangeDecoder, int NumBitLevels) Decoder rangeDecoder, int NumBitLevels)
{ {
uint m = 1; uint m = 1;
uint symbol = 0; uint symbol = 0;
for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++) for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
{ {
uint bit = Models[startIndex + m].Decode(rangeDecoder); uint bit = Models[startIndex + m].Decode(rangeDecoder);
m <<= 1; m <<= 1;
m += bit; m += bit;
symbol |= bit << bitIndex; symbol |= bit << bitIndex;
} }
return symbol; return symbol;
} }
} }
} }
+173 -173
View File
@@ -1,173 +1,173 @@
// ICoder.h // ICoder.h
using System; using System;
using System.Threading; using System.Threading;
namespace SevenZip namespace SevenZip
{ {
/// <summary> /// <summary>
/// The exception that is thrown when an error in input stream occurs during decoding. /// The exception that is thrown when an error in input stream occurs during decoding.
/// </summary> /// </summary>
internal class DataErrorException : ApplicationException internal class DataErrorException : ApplicationException
{ {
public DataErrorException() : base("Data Error") { } public DataErrorException() : base("Data Error") { }
public DataErrorException(string message) : base(message) public DataErrorException(string message) : base(message)
{ {
} }
public DataErrorException(string message, Exception innerException) : base(message, innerException) public DataErrorException(string message, Exception innerException) : base(message, innerException)
{ {
} }
} }
/// <summary> /// <summary>
/// The exception that is thrown when the value of an argument is outside the allowable range. /// The exception that is thrown when the value of an argument is outside the allowable range.
/// </summary> /// </summary>
internal class InvalidParamException : ApplicationException internal class InvalidParamException : ApplicationException
{ {
public InvalidParamException() : base("Invalid Parameter") { } public InvalidParamException() : base("Invalid Parameter") { }
public InvalidParamException(string message) : base(message) public InvalidParamException(string message) : base(message)
{ {
} }
public InvalidParamException(string message, Exception innerException) : base(message, innerException) public InvalidParamException(string message, Exception innerException) : base(message, innerException)
{ {
} }
} }
public interface ICodeProgress public interface ICodeProgress
{ {
/// <summary> /// <summary>
/// Callback progress. /// Callback progress.
/// </summary> /// </summary>
/// <param name="inSize"> /// <param name="inSize">
/// input size. -1 if unknown. /// input size. -1 if unknown.
/// </param> /// </param>
/// <param name="outSize"> /// <param name="outSize">
/// output size. -1 if unknown. /// output size. -1 if unknown.
/// </param> /// </param>
void SetProgress(Int64 inSize, Int64 outSize); void SetProgress(Int64 inSize, Int64 outSize);
}; };
public interface ICoder public interface ICoder
{ {
/// <summary> /// <summary>
/// Codes streams. /// Codes streams.
/// </summary> /// </summary>
/// <param name="inStream"> /// <param name="inStream">
/// input Stream. /// input Stream.
/// </param> /// </param>
/// <param name="outStream"> /// <param name="outStream">
/// output Stream. /// output Stream.
/// </param> /// </param>
/// <param name="inSize"> /// <param name="inSize">
/// input Size. -1 if unknown. /// input Size. -1 if unknown.
/// </param> /// </param>
/// <param name="outSize"> /// <param name="outSize">
/// output Size. -1 if unknown. /// output Size. -1 if unknown.
/// </param> /// </param>
/// <param name="progress"> /// <param name="progress">
/// callback progress reference. /// callback progress reference.
/// </param> /// </param>
/// <exception cref="DataErrorException"> /// <exception cref="DataErrorException">
/// if input stream is not valid /// if input stream is not valid
/// </exception> /// </exception>
void Code(System.IO.Stream inStream, System.IO.Stream outStream, void Code(System.IO.Stream inStream, System.IO.Stream outStream,
Int64 inSize, Int64 outSize, ICodeProgress progress, CancellationToken? token = null); Int64 inSize, Int64 outSize, ICodeProgress progress, CancellationToken? token = null);
}; };
/* /*
public interface ICoder2 public interface ICoder2
{ {
void Code(ISequentialInStream []inStreams, void Code(ISequentialInStream []inStreams,
const UInt64 []inSizes, const UInt64 []inSizes,
ISequentialOutStream []outStreams, ISequentialOutStream []outStreams,
UInt64 []outSizes, UInt64 []outSizes,
ICodeProgress progress); ICodeProgress progress);
}; };
*/ */
/// <summary> /// <summary>
/// Provides the fields that represent properties idenitifiers for compressing. /// Provides the fields that represent properties idenitifiers for compressing.
/// </summary> /// </summary>
public enum CoderPropID public enum CoderPropID
{ {
/// <summary> /// <summary>
/// Specifies default property. /// Specifies default property.
/// </summary> /// </summary>
DefaultProp = 0, DefaultProp = 0,
/// <summary> /// <summary>
/// Specifies size of dictionary. /// Specifies size of dictionary.
/// </summary> /// </summary>
DictionarySize, DictionarySize,
/// <summary> /// <summary>
/// Specifies size of memory for PPM*. /// Specifies size of memory for PPM*.
/// </summary> /// </summary>
UsedMemorySize, UsedMemorySize,
/// <summary> /// <summary>
/// Specifies order for PPM methods. /// Specifies order for PPM methods.
/// </summary> /// </summary>
Order, Order,
/// <summary> /// <summary>
/// Specifies Block Size. /// Specifies Block Size.
/// </summary> /// </summary>
BlockSize, BlockSize,
/// <summary> /// <summary>
/// Specifies number of postion state bits for LZMA (0 <= x <= 4). /// Specifies number of postion state bits for LZMA (0 <= x <= 4).
/// </summary> /// </summary>
PosStateBits, PosStateBits,
/// <summary> /// <summary>
/// Specifies number of literal context bits for LZMA (0 <= x <= 8). /// Specifies number of literal context bits for LZMA (0 <= x <= 8).
/// </summary> /// </summary>
LitContextBits, LitContextBits,
/// <summary> /// <summary>
/// Specifies number of literal position bits for LZMA (0 <= x <= 4). /// Specifies number of literal position bits for LZMA (0 <= x <= 4).
/// </summary> /// </summary>
LitPosBits, LitPosBits,
/// <summary> /// <summary>
/// Specifies number of fast bytes for LZ*. /// Specifies number of fast bytes for LZ*.
/// </summary> /// </summary>
NumFastBytes, NumFastBytes,
/// <summary> /// <summary>
/// Specifies match finder. LZMA: "BT2", "BT4" or "BT4B". /// Specifies match finder. LZMA: "BT2", "BT4" or "BT4B".
/// </summary> /// </summary>
MatchFinder, MatchFinder,
/// <summary> /// <summary>
/// Specifies the number of match finder cyckes. /// Specifies the number of match finder cyckes.
/// </summary> /// </summary>
MatchFinderCycles, MatchFinderCycles,
/// <summary> /// <summary>
/// Specifies number of passes. /// Specifies number of passes.
/// </summary> /// </summary>
NumPasses, NumPasses,
/// <summary> /// <summary>
/// Specifies number of algorithm. /// Specifies number of algorithm.
/// </summary> /// </summary>
Algorithm, Algorithm,
/// <summary> /// <summary>
/// Specifies the number of threads. /// Specifies the number of threads.
/// </summary> /// </summary>
NumThreads, NumThreads,
/// <summary> /// <summary>
/// Specifies mode with end marker. /// Specifies mode with end marker.
/// </summary> /// </summary>
EndMarker EndMarker
}; };
public interface ISetCoderProperties public interface ISetCoderProperties
{ {
void SetCoderProperties(CoderPropID[] propIDs, object[] properties); void SetCoderProperties(CoderPropID[] propIDs, object[] properties);
}; };
public interface IWriteCoderProperties public interface IWriteCoderProperties
{ {
void WriteCoderProperties(System.IO.Stream outStream); void WriteCoderProperties(System.IO.Stream outStream);
} }
public interface ISetDecoderProperties public interface ISetDecoderProperties
{ {
void SetDecoderProperties(byte[] properties); void SetDecoderProperties(byte[] properties);
} }
} }
+112 -112
View File
@@ -1,112 +1,112 @@
<!-- <!--
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"),
to deal in the Software without restriction, including without limitation to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense, the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the 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: Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software. all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 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 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
--> -->
<Application x:Class="WPinternals.App" <Application x:Class="WPinternals.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Views\StartupWindow.xaml" StartupUri="Views\StartupWindow.xaml"
xmlns:ComponentModel="clr-namespace:System.ComponentModel;assembly=PresentationFramework" xmlns:ComponentModel="clr-namespace:System.ComponentModel;assembly=PresentationFramework"
> >
<Application.Resources> <Application.Resources>
<Style TargetType="{x:Type UserControl}"> <Style TargetType="{x:Type UserControl}">
<Style.Triggers> <Style.Triggers>
<Trigger Property="ComponentModel:DesignerProperties.IsInDesignMode" <Trigger Property="ComponentModel:DesignerProperties.IsInDesignMode"
Value="true"> Value="true">
<Setter Property="Background" <Setter Property="Background"
Value="White" /> Value="White" />
</Trigger> </Trigger>
</Style.Triggers> </Style.Triggers>
</Style> </Style>
<ControlTemplate x:Key="TopicExpanderTemplate" TargetType="{x:Type Expander}"> <ControlTemplate x:Key="TopicExpanderTemplate" TargetType="{x:Type Expander}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="3" SnapsToDevicePixels="True"> <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="3" SnapsToDevicePixels="True">
<DockPanel> <DockPanel>
<ToggleButton x:Name="HeaderSite" ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" DockPanel.Dock="Top" Foreground="{TemplateBinding Foreground}" FontWeight="{TemplateBinding FontWeight}" FontStyle="{TemplateBinding FontStyle}" FontStretch="{TemplateBinding FontStretch}" FontSize="{TemplateBinding FontSize}" FontFamily="{TemplateBinding FontFamily}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Margin="1" MinWidth="0" MinHeight="0" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"> <ToggleButton x:Name="HeaderSite" ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" DockPanel.Dock="Top" Foreground="{TemplateBinding Foreground}" FontWeight="{TemplateBinding FontWeight}" FontStyle="{TemplateBinding FontStyle}" FontStretch="{TemplateBinding FontStretch}" FontSize="{TemplateBinding FontSize}" FontFamily="{TemplateBinding FontFamily}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Margin="1" MinWidth="0" MinHeight="0" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}">
<ToggleButton.FocusVisualStyle> <ToggleButton.FocusVisualStyle>
<Style> <Style>
<Setter Property="Control.Template"> <Setter Property="Control.Template">
<Setter.Value> <Setter.Value>
<ControlTemplate> <ControlTemplate>
<Border> <Border>
<Rectangle Margin="0" SnapsToDevicePixels="True" Stroke="Black" StrokeThickness="1" StrokeDashArray="1 2"/> <Rectangle Margin="0" SnapsToDevicePixels="True" Stroke="Black" StrokeThickness="1" StrokeDashArray="1 2"/>
</Border> </Border>
</ControlTemplate> </ControlTemplate>
</Setter.Value> </Setter.Value>
</Setter> </Setter>
</Style> </Style>
</ToggleButton.FocusVisualStyle> </ToggleButton.FocusVisualStyle>
<ToggleButton.Style> <ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}"> <Style TargetType="{x:Type ToggleButton}">
<Setter Property="Template"> <Setter Property="Template">
<Setter.Value> <Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}"> <ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Padding="{TemplateBinding Padding}"> <Border Padding="{TemplateBinding Padding}">
<Grid Background="Transparent" SnapsToDevicePixels="False"> <Grid Background="Transparent" SnapsToDevicePixels="False">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
<ColumnDefinition Width="19"/> <ColumnDefinition Width="19"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Ellipse x:Name="circle" Fill="White" HorizontalAlignment="Center" Height="19" Stroke="#FF333333" VerticalAlignment="Center" Width="19" Grid.Column="1" /> <Ellipse x:Name="circle" Fill="White" HorizontalAlignment="Center" Height="19" Stroke="#FF333333" VerticalAlignment="Center" Width="19" Grid.Column="1" />
<Path x:Name="arrow" Data="M1,1.5L4.5,5 8,1.5" HorizontalAlignment="Center" SnapsToDevicePixels="False" Stroke="#FF333333" StrokeThickness="2" VerticalAlignment="Center" Grid.Column="1" /> <Path x:Name="arrow" Data="M1,1.5L4.5,5 8,1.5" HorizontalAlignment="Center" SnapsToDevicePixels="False" Stroke="#FF333333" StrokeThickness="2" VerticalAlignment="Center" Grid.Column="1" />
<ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Grid.Column="0" ContentStringFormat="{TemplateBinding ContentStringFormat}" HorizontalAlignment="Left" Margin="0,0,0,0" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Center" TextBlock.FontSize="18" TextBlock.FontWeight="Bold" TextBlock.Foreground="#FF3753A6"/> <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Grid.Column="0" ContentStringFormat="{TemplateBinding ContentStringFormat}" HorizontalAlignment="Left" Margin="0,0,0,0" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Center" TextBlock.FontSize="18" TextBlock.FontWeight="Bold" TextBlock.Foreground="#FF3753A6"/>
</Grid> </Grid>
</Border> </Border>
<ControlTemplate.Triggers> <ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True"> <Trigger Property="IsChecked" Value="True">
<Setter Property="Data" TargetName="arrow" Value="M1,4.5L4.5,1 8,4.5"/> <Setter Property="Data" TargetName="arrow" Value="M1,4.5L4.5,1 8,4.5"/>
</Trigger> </Trigger>
<Trigger Property="IsMouseOver" Value="True"> <Trigger Property="IsMouseOver" Value="True">
<Setter Property="Stroke" TargetName="circle" Value="#FF5593FF"/> <Setter Property="Stroke" TargetName="circle" Value="#FF5593FF"/>
<Setter Property="Fill" TargetName="circle" Value="#FFF3F9FF"/> <Setter Property="Fill" TargetName="circle" Value="#FFF3F9FF"/>
<Setter Property="Stroke" TargetName="arrow" Value="Black"/> <Setter Property="Stroke" TargetName="arrow" Value="Black"/>
</Trigger> </Trigger>
<Trigger Property="IsPressed" Value="True"> <Trigger Property="IsPressed" Value="True">
<Setter Property="Stroke" TargetName="circle" Value="#FF3C77DD"/> <Setter Property="Stroke" TargetName="circle" Value="#FF3C77DD"/>
<Setter Property="StrokeThickness" TargetName="circle" Value="1.5"/> <Setter Property="StrokeThickness" TargetName="circle" Value="1.5"/>
<Setter Property="Fill" TargetName="circle" Value="#FFD9ECFF"/> <Setter Property="Fill" TargetName="circle" Value="#FFD9ECFF"/>
<Setter Property="Stroke" TargetName="arrow" Value="Black"/> <Setter Property="Stroke" TargetName="arrow" Value="Black"/>
</Trigger> </Trigger>
<Trigger Property="IsEnabled" Value="False"> <Trigger Property="IsEnabled" Value="False">
<Setter Property="Stroke" TargetName="circle" Value="#FFBCBCBC"/> <Setter Property="Stroke" TargetName="circle" Value="#FFBCBCBC"/>
<Setter Property="Fill" TargetName="circle" Value="#FFE6E6E6"/> <Setter Property="Fill" TargetName="circle" Value="#FFE6E6E6"/>
<Setter Property="Stroke" TargetName="arrow" Value="#FF707070"/> <Setter Property="Stroke" TargetName="arrow" Value="#FF707070"/>
</Trigger> </Trigger>
</ControlTemplate.Triggers> </ControlTemplate.Triggers>
</ControlTemplate> </ControlTemplate>
</Setter.Value> </Setter.Value>
</Setter> </Setter>
</Style> </Style>
</ToggleButton.Style> </ToggleButton.Style>
</ToggleButton> </ToggleButton>
<ContentPresenter x:Name="ExpandSite" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" DockPanel.Dock="Bottom" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" Visibility="Collapsed" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> <ContentPresenter x:Name="ExpandSite" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" DockPanel.Dock="Bottom" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" Visibility="Collapsed" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</DockPanel> </DockPanel>
</Border> </Border>
<ControlTemplate.Triggers> <ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="True"> <Trigger Property="IsExpanded" Value="True">
<Setter Property="Visibility" TargetName="ExpandSite" Value="Visible"/> <Setter Property="Visibility" TargetName="ExpandSite" Value="Visible"/>
</Trigger> </Trigger>
<Trigger Property="IsEnabled" Value="False"> <Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/> <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger> </Trigger>
</ControlTemplate.Triggers> </ControlTemplate.Triggers>
</ControlTemplate> </ControlTemplate>
</Application.Resources> </Application.Resources>
</Application> </Application>
+103 -103
View File
@@ -1,103 +1,103 @@
// 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"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // 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: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // 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 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Windows; using System.Windows;
namespace WPinternals namespace WPinternals
{ {
/// <summary> /// <summary>
/// Interaction logic for App.xaml /// Interaction logic for App.xaml
/// </summary> /// </summary>
public partial class App : Application public partial class App : Application
{ {
internal static Action NavigateToGettingStarted; internal static Action NavigateToGettingStarted;
internal static Action NavigateToUnlockBoot; internal static Action NavigateToUnlockBoot;
internal static PatchEngine PatchEngine; internal static PatchEngine PatchEngine;
internal static WPinternalsConfig Config; internal static WPinternalsConfig Config;
internal static Mutex mutex = new(false, "Global\\WPinternalsRunning"); internal static Mutex mutex = new(false, "Global\\WPinternalsRunning");
internal static DownloadsViewModel DownloadManager; internal static DownloadsViewModel DownloadManager;
internal static bool InterruptBoot = false; internal static bool InterruptBoot = false;
internal static bool IsPnPEventLogMissing = true; internal static bool IsPnPEventLogMissing = true;
public App() public App()
: base() : base()
{ {
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
#if NETCORE #if NETCORE
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
#endif #endif
if (Environment.GetCommandLineArgs().Length > 1) if (Environment.GetCommandLineArgs().Length > 1)
{ {
CommandLine.OpenConsole(); CommandLine.OpenConsole();
} }
try try
{ {
if (!mutex.WaitOne(0, false)) if (!mutex.WaitOne(0, false))
{ {
if (Environment.GetCommandLineArgs().Length > 1) if (Environment.GetCommandLineArgs().Length > 1)
{ {
Console.WriteLine("Windows Phone Internals is already running"); Console.WriteLine("Windows Phone Internals is already running");
CommandLine.CloseConsole(); CommandLine.CloseConsole();
} }
else else
{ {
MessageBox.Show("Windows Phone Internals is already running.", "Windows Phone Internals", MessageBoxButton.OK, MessageBoxImage.Exclamation); MessageBox.Show("Windows Phone Internals is already running.", "Windows Phone Internals", MessageBoxButton.OK, MessageBoxImage.Exclamation);
} }
Environment.Exit(0); Environment.Exit(0);
} }
} }
catch (AbandonedMutexException) { } catch (AbandonedMutexException) { }
Registration.CheckExpiration(); Registration.CheckExpiration();
string PatchDefintionsXml; string PatchDefintionsXml;
string PatchDefintionsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "PatchDefintions.xml"); string PatchDefintionsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "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.PatchDefinitions.xml");
using StreamReader sr = new(stream); using StreamReader sr = new(stream);
PatchDefintionsXml = sr.ReadToEnd(); PatchDefintionsXml = sr.ReadToEnd();
} }
PatchEngine = new PatchEngine(PatchDefintionsXml); PatchEngine = new PatchEngine(PatchDefintionsXml);
Config = WPinternalsConfig.ReadConfig(); Config = WPinternalsConfig.ReadConfig();
} }
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{ {
if (e.ExceptionObject is Exception) if (e.ExceptionObject is Exception)
{ {
LogFile.LogException(e.ExceptionObject as Exception); LogFile.LogException(e.ExceptionObject as Exception);
} }
} }
} }
} }
File diff suppressed because it is too large Load Diff
@@ -68,7 +68,7 @@ namespace DiscUtils.Internal
result.Add(func(sVal)); result.Add(func(sVal));
} }
return result.ToArray(); return [.. result];
} }
/// <summary> /// <summary>
@@ -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)
@@ -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>
@@ -1275,7 +1275,7 @@ namespace DiscUtils.Fat
List<string> dirs = new(); List<string> dirs = new();
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>
@@ -1311,7 +1311,7 @@ namespace DiscUtils.Fat
List<string> results = new(); List<string> results = new();
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,41 +1,41 @@
<!-- <!--
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"),
to deal in the Software without restriction, including without limitation to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense, the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the 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: Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software. all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 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 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
--> -->
<UserControl <UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WPinternals" x:Class="WPinternals.FilePickerBase" xmlns:local="clr-namespace:WPinternals" x:Class="WPinternals.FilePickerBase"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="100" d:DesignWidth="300" d:DesignHeight="100" d:DesignWidth="300"
x:Name="FilePickerControlName" x:Name="FilePickerControlName"
SizeChanged="SizeChangedHandler" Loaded="LoadedHandler" SizeChanged="SizeChangedHandler" Loaded="LoadedHandler"
> >
<Grid> <Grid>
<TextBlock x:Name="CaptionTextBlock" HorizontalAlignment="Left" Text=""/> <TextBlock x:Name="CaptionTextBlock" HorizontalAlignment="Left" Text=""/>
<TextBlock x:Name="PathTextBlock" FontWeight="Bold" HorizontalAlignment="Left" Text="Path here"/> <TextBlock x:Name="PathTextBlock" FontWeight="Bold" HorizontalAlignment="Left" Text="Path here"/>
<TextBlock x:Name="SelectLink" Margin="150,0,0,0" HorizontalAlignment="Left"><Hyperlink NavigateUri="Select" Click="SelectLink_Click"><TextBlock Text="{Binding Path=SelectionText, ElementName=FilePickerControlName}"/></Hyperlink></TextBlock> <TextBlock x:Name="SelectLink" Margin="150,0,0,0" HorizontalAlignment="Left"><Hyperlink NavigateUri="Select" Click="SelectLink_Click"><TextBlock Text="{Binding Path=SelectionText, ElementName=FilePickerControlName}"/></Hyperlink></TextBlock>
<TextBlock x:Name="ChangeLink" Margin="210,0,0,0" HorizontalAlignment="Left"><Hyperlink NavigateUri="Change" Click="ChangeLink_Click">Change</Hyperlink></TextBlock> <TextBlock x:Name="ChangeLink" Margin="210,0,0,0" HorizontalAlignment="Left"><Hyperlink NavigateUri="Change" Click="ChangeLink_Click">Change</Hyperlink></TextBlock>
<TextBlock x:Name="ClearLink" Margin="260,0,0,0" HorizontalAlignment="Left"><Hyperlink NavigateUri="Clear" Click="ClearLink_Click">Clear</Hyperlink></TextBlock> <TextBlock x:Name="ClearLink" Margin="260,0,0,0" HorizontalAlignment="Left"><Hyperlink NavigateUri="Clear" Click="ClearLink_Click">Clear</Hyperlink></TextBlock>
</Grid> </Grid>
</UserControl> </UserControl>
File diff suppressed because it is too large Load Diff
@@ -1,120 +1,120 @@
// This class was found online. // This class was found online.
// Original author is probably: Swizzy // Original author is probably: Swizzy
// https://github.com/ttgxdinger/Random/blob/master/CPUKey%20Checker/CPUKey%20Checker/FolderSelectDialog.cs // https://github.com/ttgxdinger/Random/blob/master/CPUKey%20Checker/CPUKey%20Checker/FolderSelectDialog.cs
using System; using System;
using System.Windows.Forms; using System.Windows.Forms;
namespace WPinternals namespace WPinternals
{ {
/// <summary> /// <summary>
/// Wraps System.Windows.Forms.OpenFileDialog to make it present /// Wraps System.Windows.Forms.OpenFileDialog to make it present
/// a vista-style dialog. /// a vista-style dialog.
/// </summary> /// </summary>
public class FolderSelectDialog public class FolderSelectDialog
{ {
// Wrapped dialog // Wrapped dialog
private readonly OpenFileDialog ofd = null; private readonly OpenFileDialog ofd = null;
/// <summary> /// <summary>
/// Default constructor /// Default constructor
/// </summary> /// </summary>
public FolderSelectDialog() public FolderSelectDialog()
{ {
ofd = new OpenFileDialog ofd = new OpenFileDialog
{ {
Filter = "Folders|\n", Filter = "Folders|\n",
AddExtension = false, AddExtension = false,
CheckFileExists = false, CheckFileExists = false,
DereferenceLinks = true, DereferenceLinks = true,
Multiselect = false Multiselect = false
}; };
} }
#region Properties #region Properties
/// <summary> /// <summary>
/// Gets/Sets the initial folder to be selected. A null value selects the current directory. /// Gets/Sets the initial folder to be selected. A null value selects the current directory.
/// </summary> /// </summary>
public string InitialDirectory public string InitialDirectory
{ {
get { return ofd.InitialDirectory; } get { return ofd.InitialDirectory; }
set { ofd.InitialDirectory = string.IsNullOrEmpty(value) ? Environment.CurrentDirectory : value; } set { ofd.InitialDirectory = string.IsNullOrEmpty(value) ? Environment.CurrentDirectory : value; }
} }
/// <summary> /// <summary>
/// Gets/Sets the title to show in the dialog /// Gets/Sets the title to show in the dialog
/// </summary> /// </summary>
public string Title public string Title
{ {
get { return ofd.Title; } get { return ofd.Title; }
set { ofd.Title = value ?? "Select a folder"; } set { ofd.Title = value ?? "Select a folder"; }
} }
/// <summary> /// <summary>
/// Gets the selected folder /// Gets the selected folder
/// </summary> /// </summary>
public string FileName public string FileName
{ {
get { return ofd.FileName; } get { return ofd.FileName; }
} }
#endregion #endregion
#region Methods #region Methods
/// <summary> /// <summary>
/// Shows the dialog /// Shows the dialog
/// </summary> /// </summary>
/// <returns>True if the user presses OK else false</returns> /// <returns>True if the user presses OK else false</returns>
public bool ShowDialog() public bool ShowDialog()
{ {
return ShowDialog(IntPtr.Zero); return ShowDialog(IntPtr.Zero);
} }
/// <summary> /// <summary>
/// Shows the dialog /// Shows the dialog
/// </summary> /// </summary>
/// <param name="hWndOwner">Handle of the control to be parent</param> /// <param name="hWndOwner">Handle of the control to be parent</param>
/// <returns>True if the user presses OK else false</returns> /// <returns>True if the user presses OK else false</returns>
public bool ShowDialog(IntPtr hWndOwner) public bool ShowDialog(IntPtr hWndOwner)
{ {
var fbd = new FolderBrowserDialog var fbd = new FolderBrowserDialog
{ {
Description = this.Title, Description = this.Title,
SelectedPath = this.InitialDirectory, SelectedPath = this.InitialDirectory,
ShowNewFolderButton = false ShowNewFolderButton = false
}; };
if (fbd.ShowDialog(new WindowWrapper(hWndOwner)) != DialogResult.OK) if (fbd.ShowDialog(new WindowWrapper(hWndOwner)) != DialogResult.OK)
{ {
return false; return false;
} }
ofd.FileName = fbd.SelectedPath; ofd.FileName = fbd.SelectedPath;
return true; return true;
} }
#endregion #endregion
} }
/// <summary> /// <summary>
/// Creates IWin32Window around an IntPtr /// Creates IWin32Window around an IntPtr
/// </summary> /// </summary>
public class WindowWrapper : IWin32Window public class WindowWrapper : IWin32Window
{ {
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
/// <param name="handle">Handle to wrap</param> /// <param name="handle">Handle to wrap</param>
public WindowWrapper(IntPtr handle) public WindowWrapper(IntPtr handle)
{ {
Handle = handle; Handle = handle;
} }
/// <summary> /// <summary>
/// Original ptr /// Original ptr
/// </summary> /// </summary>
public IntPtr Handle { get; } public IntPtr Handle { get; }
} }
} }
File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 75 KiB

@@ -1,401 +1,401 @@
// 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"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // 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: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // 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 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
// These functions assume same endianness for the CPU architecture and the raw data it reads from or writes to. // These functions assume same endianness for the CPU architecture and the raw data it reads from or writes to.
using System; using System;
using System.IO; using System.IO;
namespace WPinternals namespace WPinternals
{ {
internal static class ByteOperations internal static class ByteOperations
{ {
internal static string ReadAsciiString(byte[] ByteArray, UInt32 Offset, UInt32 Length) internal static string ReadAsciiString(byte[] ByteArray, UInt32 Offset, UInt32 Length)
{ {
byte[] Bytes = new byte[Length]; byte[] Bytes = new byte[Length];
Buffer.BlockCopy(ByteArray, (int)Offset, Bytes, 0, (int)Length); Buffer.BlockCopy(ByteArray, (int)Offset, Bytes, 0, (int)Length);
return System.Text.Encoding.ASCII.GetString(Bytes); return System.Text.Encoding.ASCII.GetString(Bytes);
} }
internal static string ReadUnicodeString(byte[] ByteArray, UInt32 Offset, UInt32 Length) internal static string ReadUnicodeString(byte[] ByteArray, UInt32 Offset, UInt32 Length)
{ {
byte[] Bytes = new byte[Length]; byte[] Bytes = new byte[Length];
Buffer.BlockCopy(ByteArray, (int)Offset, Bytes, 0, (int)Length); Buffer.BlockCopy(ByteArray, (int)Offset, Bytes, 0, (int)Length);
return System.Text.Encoding.Unicode.GetString(Bytes); return System.Text.Encoding.Unicode.GetString(Bytes);
} }
internal static void WriteAsciiString(byte[] ByteArray, UInt32 Offset, string Text, UInt32? MaxBufferLength = null) internal static void WriteAsciiString(byte[] ByteArray, UInt32 Offset, string Text, UInt32? MaxBufferLength = null)
{ {
if (MaxBufferLength != null) if (MaxBufferLength != null)
{ {
Array.Clear(ByteArray, (int)Offset, (int)MaxBufferLength); Array.Clear(ByteArray, (int)Offset, (int)MaxBufferLength);
} }
byte[] TextBytes = System.Text.Encoding.ASCII.GetBytes(Text); byte[] TextBytes = System.Text.Encoding.ASCII.GetBytes(Text);
int WriteLength = TextBytes.Length; int WriteLength = TextBytes.Length;
if (WriteLength > MaxBufferLength) if (WriteLength > MaxBufferLength)
{ {
WriteLength = (int)MaxBufferLength; WriteLength = (int)MaxBufferLength;
} }
Buffer.BlockCopy(TextBytes, 0, ByteArray, (int)Offset, WriteLength); Buffer.BlockCopy(TextBytes, 0, ByteArray, (int)Offset, WriteLength);
} }
internal static void WriteUnicodeString(byte[] ByteArray, UInt32 Offset, string Text, UInt32? MaxBufferLength = null) internal static void WriteUnicodeString(byte[] ByteArray, UInt32 Offset, string Text, UInt32? MaxBufferLength = null)
{ {
if (MaxBufferLength != null) if (MaxBufferLength != null)
{ {
Array.Clear(ByteArray, (int)Offset, (int)MaxBufferLength); Array.Clear(ByteArray, (int)Offset, (int)MaxBufferLength);
} }
byte[] TextBytes = System.Text.Encoding.Unicode.GetBytes(Text); byte[] TextBytes = System.Text.Encoding.Unicode.GetBytes(Text);
int WriteLength = TextBytes.Length; int WriteLength = TextBytes.Length;
if (WriteLength > MaxBufferLength) if (WriteLength > MaxBufferLength)
{ {
WriteLength = (int)MaxBufferLength; WriteLength = (int)MaxBufferLength;
} }
Buffer.BlockCopy(TextBytes, 0, ByteArray, (int)Offset, WriteLength); Buffer.BlockCopy(TextBytes, 0, ByteArray, (int)Offset, WriteLength);
} }
internal static UInt32 ReadUInt32(byte[] ByteArray, UInt32 Offset) internal static UInt32 ReadUInt32(byte[] ByteArray, UInt32 Offset)
{ {
return BitConverter.ToUInt32(ByteArray, (int)Offset); return BitConverter.ToUInt32(ByteArray, (int)Offset);
} }
internal static void WriteUInt32(byte[] ByteArray, UInt32 Offset, UInt32 Value) internal static void WriteUInt32(byte[] ByteArray, UInt32 Offset, UInt32 Value)
{ {
Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 4); Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 4);
} }
internal static Int32 ReadInt32(byte[] ByteArray, UInt32 Offset) internal static Int32 ReadInt32(byte[] ByteArray, UInt32 Offset)
{ {
return BitConverter.ToInt32(ByteArray, (int)Offset); return BitConverter.ToInt32(ByteArray, (int)Offset);
} }
internal static void WriteInt32(byte[] ByteArray, UInt32 Offset, Int32 Value) internal static void WriteInt32(byte[] ByteArray, UInt32 Offset, Int32 Value)
{ {
Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 4); Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 4);
} }
internal static UInt16 ReadUInt16(byte[] ByteArray, UInt32 Offset) internal static UInt16 ReadUInt16(byte[] ByteArray, UInt32 Offset)
{ {
return BitConverter.ToUInt16(ByteArray, (int)Offset); return BitConverter.ToUInt16(ByteArray, (int)Offset);
} }
internal static void WriteUInt16(byte[] ByteArray, UInt32 Offset, UInt16 Value) internal static void WriteUInt16(byte[] ByteArray, UInt32 Offset, UInt16 Value)
{ {
Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 2); Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 2);
} }
internal static Int16 ReadInt16(byte[] ByteArray, UInt32 Offset) internal static Int16 ReadInt16(byte[] ByteArray, UInt32 Offset)
{ {
return BitConverter.ToInt16(ByteArray, (int)Offset); return BitConverter.ToInt16(ByteArray, (int)Offset);
} }
internal static void WriteInt16(byte[] ByteArray, UInt32 Offset, Int16 Value) internal static void WriteInt16(byte[] ByteArray, UInt32 Offset, Int16 Value)
{ {
Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 2); Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 2);
} }
internal static byte ReadUInt8(byte[] ByteArray, UInt32 Offset) internal static byte ReadUInt8(byte[] ByteArray, UInt32 Offset)
{ {
return ByteArray[Offset]; return ByteArray[Offset];
} }
internal static void WriteUInt8(byte[] ByteArray, UInt32 Offset, byte Value) internal static void WriteUInt8(byte[] ByteArray, UInt32 Offset, byte Value)
{ {
ByteArray[Offset] = Value; ByteArray[Offset] = Value;
} }
internal static UInt32 ReadUInt24(byte[] ByteArray, UInt32 Offset) internal static UInt32 ReadUInt24(byte[] ByteArray, UInt32 Offset)
{ {
return (UInt32)(ByteArray[Offset] + (ByteArray[Offset + 1] << 8) + (ByteArray[Offset + 2] << 16)); return (UInt32)(ByteArray[Offset] + (ByteArray[Offset + 1] << 8) + (ByteArray[Offset + 2] << 16));
} }
internal static void WriteUInt24(byte[] ByteArray, UInt32 Offset, UInt32 Value) internal static void WriteUInt24(byte[] ByteArray, UInt32 Offset, UInt32 Value)
{ {
Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 3); Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 3);
} }
internal static UInt64 ReadUInt64(byte[] ByteArray, UInt32 Offset) internal static UInt64 ReadUInt64(byte[] ByteArray, UInt32 Offset)
{ {
return BitConverter.ToUInt64(ByteArray, (int)Offset); return BitConverter.ToUInt64(ByteArray, (int)Offset);
} }
internal static void WriteUInt64(byte[] ByteArray, UInt32 Offset, UInt64 Value) internal static void WriteUInt64(byte[] ByteArray, UInt32 Offset, UInt64 Value)
{ {
Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 8); Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 8);
} }
internal static Guid ReadGuid(byte[] ByteArray, UInt32 Offset) internal static Guid ReadGuid(byte[] ByteArray, UInt32 Offset)
{ {
byte[] GuidBuffer = new byte[0x10]; byte[] GuidBuffer = new byte[0x10];
Buffer.BlockCopy(ByteArray, (int)Offset, GuidBuffer, 0, 0x10); Buffer.BlockCopy(ByteArray, (int)Offset, GuidBuffer, 0, 0x10);
return new Guid(GuidBuffer); return new Guid(GuidBuffer);
} }
internal static void WriteGuid(byte[] ByteArray, UInt32 Offset, Guid Value) internal static void WriteGuid(byte[] ByteArray, UInt32 Offset, Guid Value)
{ {
Buffer.BlockCopy(Value.ToByteArray(), 0, ByteArray, (int)Offset, 0x10); Buffer.BlockCopy(Value.ToByteArray(), 0, ByteArray, (int)Offset, 0x10);
} }
internal static UInt32 Align(UInt32 Base, UInt32 Offset, UInt32 Alignment) internal static UInt32 Align(UInt32 Base, UInt32 Offset, UInt32 Alignment)
{ {
if (((Offset - Base) % Alignment) == 0) if (((Offset - Base) % Alignment) == 0)
{ {
return Offset; return Offset;
} }
else else
{ {
return ((((Offset - Base) / Alignment) + 1) * Alignment) + Base; return ((((Offset - Base) / Alignment) + 1) * Alignment) + Base;
} }
} }
internal static UInt32? FindPatternInFile(string FileName, byte[] Pattern, byte[] Mask, out byte[] OutPattern) internal static UInt32? FindPatternInFile(string FileName, byte[] Pattern, byte[] Mask, out byte[] OutPattern)
{ {
// The mask is optional. // The mask is optional.
// In the mask 0x00 means the value must match, and 0xFF means that this position is a wildcard. // In the mask 0x00 means the value must match, and 0xFF means that this position is a wildcard.
UInt32? Result = null; UInt32? Result = null;
FileStream Stream = new(FileName, FileMode.Open, FileAccess.Read); FileStream Stream = new(FileName, FileMode.Open, FileAccess.Read);
byte[] Buffer = new byte[0x10000 + Pattern.Length - 1]; byte[] Buffer = new byte[0x10000 + Pattern.Length - 1];
UInt32 BufferReadPosition = 0; // Position in buffer where file-chunk is being read. UInt32 BufferReadPosition = 0; // Position in buffer where file-chunk is being read.
UInt32 BytesInBuffer = 0; UInt32 BytesInBuffer = 0;
UInt32 BytesRead; UInt32 BytesRead;
UInt32 SearchPositionFile = 0; UInt32 SearchPositionFile = 0;
UInt32 SearchPositionBuffer = 0; UInt32 SearchPositionBuffer = 0;
UInt32 BufferFileOffset = 0; // Offset in file where data from buffer is located. UInt32 BufferFileOffset = 0; // Offset in file where data from buffer is located.
bool Match = false; bool Match = false;
int i; int i;
OutPattern = null; OutPattern = null;
while (SearchPositionFile <= (Stream.Length - Pattern.Length)) while (SearchPositionFile <= (Stream.Length - Pattern.Length))
{ {
if ((SearchPositionBuffer + Pattern.Length) > BytesInBuffer) if ((SearchPositionBuffer + Pattern.Length) > BytesInBuffer)
{ {
// Need to read next chunk // Need to read next chunk
if ((BytesInBuffer - SearchPositionBuffer) > 0) if ((BytesInBuffer - SearchPositionBuffer) > 0)
{ {
System.Buffer.BlockCopy(Buffer, (int)SearchPositionBuffer, Buffer, 0, (int)(BytesInBuffer - SearchPositionBuffer)); System.Buffer.BlockCopy(Buffer, (int)SearchPositionBuffer, Buffer, 0, (int)(BytesInBuffer - SearchPositionBuffer));
} }
BufferReadPosition = BytesInBuffer - SearchPositionBuffer; BufferReadPosition = BytesInBuffer - SearchPositionBuffer;
BytesInBuffer -= SearchPositionBuffer; BytesInBuffer -= SearchPositionBuffer;
BufferFileOffset += SearchPositionBuffer; BufferFileOffset += SearchPositionBuffer;
SearchPositionBuffer = 0; SearchPositionBuffer = 0;
BytesRead = (UInt32)Stream.Read(Buffer, (int)BufferReadPosition, Buffer.Length - (int)BufferReadPosition); BytesRead = (UInt32)Stream.Read(Buffer, (int)BufferReadPosition, Buffer.Length - (int)BufferReadPosition);
BytesInBuffer += BytesRead; BytesInBuffer += BytesRead;
} }
Match = true; Match = true;
for (i = 0; i < Pattern.Length; i++) for (i = 0; i < Pattern.Length; i++)
{ {
if (Buffer[SearchPositionBuffer + i] != Pattern[i]) if (Buffer[SearchPositionBuffer + i] != Pattern[i])
{ {
if ((Mask == null) || (Mask[i] == 0)) if ((Mask == null) || (Mask[i] == 0))
{ {
Match = false; Match = false;
break; break;
} }
} }
} }
if (Match) if (Match)
{ {
Result = SearchPositionFile; Result = SearchPositionFile;
OutPattern = new byte[Pattern.Length]; OutPattern = new byte[Pattern.Length];
System.Buffer.BlockCopy(Buffer, (int)SearchPositionBuffer, OutPattern, 0, Pattern.Length); System.Buffer.BlockCopy(Buffer, (int)SearchPositionBuffer, OutPattern, 0, Pattern.Length);
break; break;
} }
SearchPositionBuffer++; SearchPositionBuffer++;
SearchPositionFile++; SearchPositionFile++;
} }
Stream.Close(); Stream.Close();
return Result; return Result;
} }
internal static UInt32? FindAscii(byte[] SourceBuffer, string Pattern) internal static UInt32? FindAscii(byte[] SourceBuffer, string Pattern)
{ {
return FindPattern(SourceBuffer, System.Text.Encoding.ASCII.GetBytes(Pattern), null, null); return FindPattern(SourceBuffer, System.Text.Encoding.ASCII.GetBytes(Pattern), null, null);
} }
internal static UInt32? FindUnicode(byte[] SourceBuffer, string Pattern) internal static UInt32? FindUnicode(byte[] SourceBuffer, string Pattern)
{ {
return FindPattern(SourceBuffer, System.Text.Encoding.Unicode.GetBytes(Pattern), null, null); return FindPattern(SourceBuffer, System.Text.Encoding.Unicode.GetBytes(Pattern), null, null);
} }
internal static UInt32? FindUint(byte[] SourceBuffer, UInt32 Pattern) internal static UInt32? FindUint(byte[] SourceBuffer, UInt32 Pattern)
{ {
return FindPattern(SourceBuffer, BitConverter.GetBytes(Pattern), null, null); return FindPattern(SourceBuffer, BitConverter.GetBytes(Pattern), null, null);
} }
internal static UInt32? FindPattern(byte[] SourceBuffer, byte[] Pattern, byte[] Mask, byte[] OutPattern) internal static UInt32? FindPattern(byte[] SourceBuffer, byte[] Pattern, byte[] Mask, byte[] OutPattern)
{ {
return FindPattern(SourceBuffer, 0, null, Pattern, Mask, OutPattern); return FindPattern(SourceBuffer, 0, null, Pattern, Mask, OutPattern);
} }
internal static bool Compare(byte[] Array1, byte[] Array2) internal static bool Compare(byte[] Array1, byte[] Array2)
{ {
return System.Collections.StructuralComparisons.StructuralEqualityComparer.Equals(Array1, Array2); return System.Collections.StructuralComparisons.StructuralEqualityComparer.Equals(Array1, Array2);
} }
internal static UInt32? FindPattern(byte[] SourceBuffer, uint SourceOffset, uint? SourceSize, byte[] Pattern, byte[] Mask, byte[] OutPattern) internal static UInt32? FindPattern(byte[] SourceBuffer, uint SourceOffset, uint? SourceSize, byte[] Pattern, byte[] Mask, byte[] OutPattern)
{ {
// The mask is optional. // The mask is optional.
// In the mask 0x00 means the value must match, and 0xFF means that this position is a wildcard. // In the mask 0x00 means the value must match, and 0xFF means that this position is a wildcard.
UInt32? Result = null; UInt32? Result = null;
UInt32 SearchPosition = SourceOffset; UInt32 SearchPosition = SourceOffset;
bool Match = false; bool Match = false;
int i; int i;
while ((SearchPosition <= (SourceBuffer.Length - Pattern.Length)) && ((SourceSize == null) || (SearchPosition <= (SourceOffset + SourceSize - Pattern.Length)))) while ((SearchPosition <= (SourceBuffer.Length - Pattern.Length)) && ((SourceSize == null) || (SearchPosition <= (SourceOffset + SourceSize - Pattern.Length))))
{ {
Match = true; Match = true;
for (i = 0; i < Pattern.Length; i++) for (i = 0; i < Pattern.Length; i++)
{ {
if (SourceBuffer[SearchPosition + i] != Pattern[i]) if (SourceBuffer[SearchPosition + i] != Pattern[i])
{ {
if ((Mask == null) || (Mask[i] == 0)) if ((Mask == null) || (Mask[i] == 0))
{ {
Match = false; Match = false;
break; break;
} }
} }
} }
if (Match) if (Match)
{ {
Result = SearchPosition; Result = SearchPosition;
if (OutPattern != null) if (OutPattern != null)
{ {
Buffer.BlockCopy(SourceBuffer, (int)SearchPosition, OutPattern, 0, Pattern.Length); Buffer.BlockCopy(SourceBuffer, (int)SearchPosition, OutPattern, 0, Pattern.Length);
} }
break; break;
} }
SearchPosition++; SearchPosition++;
} }
return Result; return Result;
} }
internal static byte CalculateChecksum8(byte[] Buffer, UInt32 Offset, UInt32 Size) internal static byte CalculateChecksum8(byte[] Buffer, UInt32 Offset, UInt32 Size)
{ {
byte Checksum = 0; byte Checksum = 0;
for (UInt32 i = Offset; i < (Offset + Size); i++) for (UInt32 i = Offset; i < (Offset + Size); i++)
{ {
Checksum += Buffer[i]; Checksum += Buffer[i];
} }
return (byte)(0x100 - Checksum); return (byte)(0x100 - Checksum);
} }
internal static UInt16 CalculateChecksum16(byte[] Buffer, UInt32 Offset, UInt32 Size) internal static UInt16 CalculateChecksum16(byte[] Buffer, UInt32 Offset, UInt32 Size)
{ {
UInt16 Checksum = 0; UInt16 Checksum = 0;
for (UInt32 i = Offset; i < (Offset + Size - 1); i += 2) for (UInt32 i = Offset; i < (Offset + Size - 1); i += 2)
{ {
Checksum += BitConverter.ToUInt16(Buffer, (int)i); Checksum += BitConverter.ToUInt16(Buffer, (int)i);
} }
return (UInt16)(0x10000 - Checksum); return (UInt16)(0x10000 - Checksum);
} }
private static readonly UInt32[] CRC32Table = new UInt32[] { private static readonly UInt32[] CRC32Table = [
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
}; ];
internal static UInt32 CRC32(byte[] Input, UInt32 Offset, UInt32 Length) internal static UInt32 CRC32(byte[] Input, UInt32 Offset, UInt32 Length)
{ {
if ((Input == null) || ((Offset + Length) > Input.Length)) if ((Input == null) || ((Offset + Length) > Input.Length))
{ {
throw new ArgumentException(); throw new ArgumentException();
} }
unchecked unchecked
{ {
uint crc = (uint)(((uint)0) ^ (-1)); uint crc = (uint)(((uint)0) ^ (-1));
for (var i = Offset; i < (Offset + Length); i++) for (var i = Offset; i < (Offset + Length); i++)
{ {
crc = (crc >> 8) ^ CRC32Table[(crc ^ Input[i]) & 0xFF]; crc = (crc >> 8) ^ CRC32Table[(crc ^ Input[i]) & 0xFF];
} }
crc = (uint)(crc ^ (-1)); crc = (uint)(crc ^ (-1));
return crc; return crc;
} }
} }
} }
} }
+487 -487
View File
@@ -1,487 +1,487 @@
// 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"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // 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: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // 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 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
namespace WPinternals namespace WPinternals
{ {
internal class FFU internal class FFU
{ {
internal int ChunkSize; internal int ChunkSize;
internal string Path; internal string Path;
internal byte[] SecurityHeader; internal byte[] SecurityHeader;
internal byte[] ImageHeader; internal byte[] ImageHeader;
internal byte[] StoreHeader; internal byte[] StoreHeader;
private readonly int?[] ChunkIndexes; private readonly int?[] ChunkIndexes;
private FileStream FFUFile = null; private FileStream FFUFile = null;
private int FileOpenCount = 0; private int FileOpenCount = 0;
internal string PlatformID; internal string PlatformID;
internal GPT GPT; internal GPT GPT;
internal UInt64 TotalSize; internal UInt64 TotalSize;
internal UInt64 HeaderSize; internal UInt64 HeaderSize;
internal UInt64 PayloadSize; internal UInt64 PayloadSize;
internal UInt64 TotalChunkCount; internal UInt64 TotalChunkCount;
internal FFU(string Path) internal FFU(string Path)
{ {
this.Path = Path; this.Path = Path;
try try
{ {
OpenFile(); OpenFile();
// Read Security Header // Read Security Header
byte[] ShortSecurityHeader = new byte[0x20]; byte[] ShortSecurityHeader = new byte[0x20];
FFUFile.Read(ShortSecurityHeader, 0, 0x20); FFUFile.Read(ShortSecurityHeader, 0, 0x20);
if (ByteOperations.ReadAsciiString(ShortSecurityHeader, 0x04, 0x0C) != "SignedImage ") if (ByteOperations.ReadAsciiString(ShortSecurityHeader, 0x04, 0x0C) != "SignedImage ")
{ {
throw new BadImageFormatException(); throw new BadImageFormatException();
} }
ChunkSize = ByteOperations.ReadInt32(ShortSecurityHeader, 0x10) * 1024; ChunkSize = ByteOperations.ReadInt32(ShortSecurityHeader, 0x10) * 1024;
UInt32 SecurityHeaderSize = ByteOperations.ReadUInt32(ShortSecurityHeader, 0x00); UInt32 SecurityHeaderSize = ByteOperations.ReadUInt32(ShortSecurityHeader, 0x00);
UInt32 CatalogSize = ByteOperations.ReadUInt32(ShortSecurityHeader, 0x18); UInt32 CatalogSize = ByteOperations.ReadUInt32(ShortSecurityHeader, 0x18);
UInt32 HashTableSize = ByteOperations.ReadUInt32(ShortSecurityHeader, 0x1C); UInt32 HashTableSize = ByteOperations.ReadUInt32(ShortSecurityHeader, 0x1C);
SecurityHeader = new byte[RoundUpToChunks(SecurityHeaderSize + CatalogSize + HashTableSize)]; SecurityHeader = new byte[RoundUpToChunks(SecurityHeaderSize + CatalogSize + HashTableSize)];
FFUFile.Seek(0, SeekOrigin.Begin); FFUFile.Seek(0, SeekOrigin.Begin);
FFUFile.Read(SecurityHeader, 0, SecurityHeader.Length); FFUFile.Read(SecurityHeader, 0, SecurityHeader.Length);
// Read Image Header // Read Image Header
byte[] ShortImageHeader = new byte[0x1C]; byte[] ShortImageHeader = new byte[0x1C];
FFUFile.Read(ShortImageHeader, 0, 0x1C); FFUFile.Read(ShortImageHeader, 0, 0x1C);
if (ByteOperations.ReadAsciiString(ShortImageHeader, 0x04, 0x0C) != "ImageFlash ") if (ByteOperations.ReadAsciiString(ShortImageHeader, 0x04, 0x0C) != "ImageFlash ")
{ {
throw new BadImageFormatException(); throw new BadImageFormatException();
} }
UInt32 ImageHeaderSize = ByteOperations.ReadUInt32(ShortImageHeader, 0x00); UInt32 ImageHeaderSize = ByteOperations.ReadUInt32(ShortImageHeader, 0x00);
UInt32 ManifestSize = ByteOperations.ReadUInt32(ShortImageHeader, 0x10); UInt32 ManifestSize = ByteOperations.ReadUInt32(ShortImageHeader, 0x10);
ImageHeader = new byte[RoundUpToChunks(ImageHeaderSize + ManifestSize)]; ImageHeader = new byte[RoundUpToChunks(ImageHeaderSize + ManifestSize)];
FFUFile.Seek(SecurityHeader.Length, SeekOrigin.Begin); FFUFile.Seek(SecurityHeader.Length, SeekOrigin.Begin);
FFUFile.Read(ImageHeader, 0, ImageHeader.Length); FFUFile.Read(ImageHeader, 0, ImageHeader.Length);
// Read Store Header // Read Store Header
byte[] ShortStoreHeader = new byte[248]; byte[] ShortStoreHeader = new byte[248];
FFUFile.Read(ShortStoreHeader, 0, 248); FFUFile.Read(ShortStoreHeader, 0, 248);
PlatformID = ByteOperations.ReadAsciiString(ShortStoreHeader, 0x0C, 192).TrimEnd(new char[] { (char)0, ' ' }); PlatformID = ByteOperations.ReadAsciiString(ShortStoreHeader, 0x0C, 192).TrimEnd([(char)0, ' ']);
int WriteDescriptorCount = ByteOperations.ReadInt32(ShortStoreHeader, 208); int WriteDescriptorCount = ByteOperations.ReadInt32(ShortStoreHeader, 208);
UInt32 WriteDescriptorLength = ByteOperations.ReadUInt32(ShortStoreHeader, 212); UInt32 WriteDescriptorLength = ByteOperations.ReadUInt32(ShortStoreHeader, 212);
UInt32 ValidateDescriptorLength = ByteOperations.ReadUInt32(ShortStoreHeader, 220); UInt32 ValidateDescriptorLength = ByteOperations.ReadUInt32(ShortStoreHeader, 220);
StoreHeader = new byte[RoundUpToChunks(248 + WriteDescriptorLength + ValidateDescriptorLength)]; StoreHeader = new byte[RoundUpToChunks(248 + WriteDescriptorLength + ValidateDescriptorLength)];
FFUFile.Seek(SecurityHeader.Length + ImageHeader.Length, SeekOrigin.Begin); FFUFile.Seek(SecurityHeader.Length + ImageHeader.Length, SeekOrigin.Begin);
FFUFile.Read(StoreHeader, 0, StoreHeader.Length); FFUFile.Read(StoreHeader, 0, StoreHeader.Length);
// Parse Chunk Indexes // Parse Chunk Indexes
int HighestChunkIndex = 0; int HighestChunkIndex = 0;
UInt32 LocationCount; UInt32 LocationCount;
int ChunkIndex; int ChunkIndex;
int ChunkCount; int ChunkCount;
int DiskAccessMethod; int DiskAccessMethod;
UInt32 WriteDescriptorEntryOffset = 248 + ValidateDescriptorLength; UInt32 WriteDescriptorEntryOffset = 248 + ValidateDescriptorLength;
int FFUChunkIndex = 0; int FFUChunkIndex = 0;
for (int i = 0; i < WriteDescriptorCount; i++) for (int i = 0; i < WriteDescriptorCount; i++)
{ {
LocationCount = ByteOperations.ReadUInt32(StoreHeader, WriteDescriptorEntryOffset + 0x00); LocationCount = ByteOperations.ReadUInt32(StoreHeader, WriteDescriptorEntryOffset + 0x00);
ChunkCount = ByteOperations.ReadInt32(StoreHeader, WriteDescriptorEntryOffset + 0x04); ChunkCount = ByteOperations.ReadInt32(StoreHeader, WriteDescriptorEntryOffset + 0x04);
for (int j = 0; j < LocationCount; j++) for (int j = 0; j < LocationCount; j++)
{ {
DiskAccessMethod = ByteOperations.ReadInt32(StoreHeader, (UInt32)(WriteDescriptorEntryOffset + 0x08 + (j * 0x08))); DiskAccessMethod = ByteOperations.ReadInt32(StoreHeader, (UInt32)(WriteDescriptorEntryOffset + 0x08 + (j * 0x08)));
ChunkIndex = ByteOperations.ReadInt32(StoreHeader, (UInt32)(WriteDescriptorEntryOffset + 0x0C + (j * 0x08))); ChunkIndex = ByteOperations.ReadInt32(StoreHeader, (UInt32)(WriteDescriptorEntryOffset + 0x0C + (j * 0x08)));
if (DiskAccessMethod == 0 && (ChunkIndex + ChunkCount - 1) > HighestChunkIndex) // 0 = From begin, 2 = From end. We ignore chunks at end of disk. These contain secondairy GPT. if (DiskAccessMethod == 0 && (ChunkIndex + ChunkCount - 1) > HighestChunkIndex) // 0 = From begin, 2 = From end. We ignore chunks at end of disk. These contain secondairy GPT.
{ {
HighestChunkIndex = ChunkIndex + ChunkCount - 1; HighestChunkIndex = ChunkIndex + ChunkCount - 1;
} }
} }
WriteDescriptorEntryOffset += 8 + (LocationCount * 0x08); WriteDescriptorEntryOffset += 8 + (LocationCount * 0x08);
FFUChunkIndex += ChunkCount; FFUChunkIndex += ChunkCount;
} }
ChunkIndexes = new int?[HighestChunkIndex + 1]; ChunkIndexes = new int?[HighestChunkIndex + 1];
WriteDescriptorEntryOffset = 248 + ValidateDescriptorLength; WriteDescriptorEntryOffset = 248 + ValidateDescriptorLength;
FFUChunkIndex = 0; FFUChunkIndex = 0;
for (int i = 0; i < WriteDescriptorCount; i++) for (int i = 0; i < WriteDescriptorCount; i++)
{ {
LocationCount = ByteOperations.ReadUInt32(StoreHeader, WriteDescriptorEntryOffset + 0x00); LocationCount = ByteOperations.ReadUInt32(StoreHeader, WriteDescriptorEntryOffset + 0x00);
ChunkCount = ByteOperations.ReadInt32(StoreHeader, WriteDescriptorEntryOffset + 0x04); ChunkCount = ByteOperations.ReadInt32(StoreHeader, WriteDescriptorEntryOffset + 0x04);
for (int j = 0; j < LocationCount; j++) for (int j = 0; j < LocationCount; j++)
{ {
DiskAccessMethod = ByteOperations.ReadInt32(StoreHeader, (UInt32)(WriteDescriptorEntryOffset + 0x08 + (j * 0x08))); DiskAccessMethod = ByteOperations.ReadInt32(StoreHeader, (UInt32)(WriteDescriptorEntryOffset + 0x08 + (j * 0x08)));
ChunkIndex = ByteOperations.ReadInt32(StoreHeader, (UInt32)(WriteDescriptorEntryOffset + 0x0C + (j * 0x08))); ChunkIndex = ByteOperations.ReadInt32(StoreHeader, (UInt32)(WriteDescriptorEntryOffset + 0x0C + (j * 0x08)));
if (DiskAccessMethod == 0) // 0 = From begin, 2 = From end. We ignore chunks at end of disk. These contain secondairy GPT. if (DiskAccessMethod == 0) // 0 = From begin, 2 = From end. We ignore chunks at end of disk. These contain secondairy GPT.
{ {
for (int k = 0; k < ChunkCount; k++) for (int k = 0; k < ChunkCount; k++)
{ {
ChunkIndexes[ChunkIndex + k] = FFUChunkIndex + k; ChunkIndexes[ChunkIndex + k] = FFUChunkIndex + k;
} }
} }
} }
WriteDescriptorEntryOffset += 8 + (LocationCount * 0x08); WriteDescriptorEntryOffset += 8 + (LocationCount * 0x08);
FFUChunkIndex += ChunkCount; FFUChunkIndex += ChunkCount;
} }
byte[] GPTBuffer = GetSectors(0x01, 0x21); byte[] GPTBuffer = GetSectors(0x01, 0x21);
GPT = new GPT(GPTBuffer); GPT = new GPT(GPTBuffer);
HeaderSize = (UInt64)(SecurityHeader.Length + ImageHeader.Length + StoreHeader.Length); HeaderSize = (UInt64)(SecurityHeader.Length + ImageHeader.Length + StoreHeader.Length);
TotalChunkCount = (UInt64)FFUChunkIndex; TotalChunkCount = (UInt64)FFUChunkIndex;
PayloadSize = TotalChunkCount * (UInt64)ChunkSize; PayloadSize = TotalChunkCount * (UInt64)ChunkSize;
TotalSize = HeaderSize + PayloadSize; TotalSize = HeaderSize + PayloadSize;
if (TotalSize != (UInt64)FFUFile.Length) if (TotalSize != (UInt64)FFUFile.Length)
{ {
throw new WPinternalsException("Bad FFU file", "Bad FFU file: " + Path + "." + Environment.NewLine + "Expected size: " + TotalSize.ToString() + ". Actual size: " + FFUFile.Length + "."); throw new WPinternalsException("Bad FFU file", "Bad FFU file: " + Path + "." + Environment.NewLine + "Expected size: " + TotalSize.ToString() + ". Actual size: " + FFUFile.Length + ".");
} }
} }
catch (WPinternalsException) catch (WPinternalsException)
{ {
throw; throw;
} }
catch (Exception Ex) catch (Exception Ex)
{ {
throw new WPinternalsException("Bad FFU file", "Bad FFU file: " + Path + "." + Environment.NewLine + Ex.Message, Ex); throw new WPinternalsException("Bad FFU file", "Bad FFU file: " + Path + "." + Environment.NewLine + Ex.Message, Ex);
} }
finally finally
{ {
CloseFile(); CloseFile();
} }
} }
internal static bool IsFFU(string FileName) internal static bool IsFFU(string FileName)
{ {
bool Result = false; bool Result = false;
FileStream FFUFile = new(FileName, FileMode.Open, FileAccess.Read); FileStream FFUFile = new(FileName, FileMode.Open, FileAccess.Read);
byte[] Signature = new byte[0x10]; byte[] Signature = new byte[0x10];
FFUFile.Read(Signature, 0, 0x10); FFUFile.Read(Signature, 0, 0x10);
Result = ByteOperations.ReadAsciiString(Signature, 0x04, 0x0C) == "SignedImage "; Result = ByteOperations.ReadAsciiString(Signature, 0x04, 0x0C) == "SignedImage ";
FFUFile.Close(); FFUFile.Close();
return Result; return Result;
} }
private void OpenFile() private void OpenFile()
{ {
if (FFUFile == null) if (FFUFile == null)
{ {
FFUFile = new FileStream(Path, FileMode.Open, FileAccess.Read); FFUFile = new FileStream(Path, FileMode.Open, FileAccess.Read);
FileOpenCount = 0; FileOpenCount = 0;
} }
FileOpenCount++; FileOpenCount++;
} }
private void CloseFile() private void CloseFile()
{ {
FileOpenCount--; FileOpenCount--;
if (FileOpenCount == 0) if (FileOpenCount == 0)
{ {
FFUFile.Close(); FFUFile.Close();
FFUFile = null; FFUFile = null;
} }
} }
private void FileSeek(long Position) private void FileSeek(long Position)
{ {
// https://social.msdn.microsoft.com/Forums/vstudio/en-US/2e67ca57-3556-4275-accd-58b7df30d424/unnecessary-filestreamseek-and-setting-filestreamposition-has-huge-effect-on-performance?forum=csharpgeneral // https://social.msdn.microsoft.com/Forums/vstudio/en-US/2e67ca57-3556-4275-accd-58b7df30d424/unnecessary-filestreamseek-and-setting-filestreamposition-has-huge-effect-on-performance?forum=csharpgeneral
if (FFUFile != null && FFUFile.Position != Position) if (FFUFile != null && FFUFile.Position != Position)
{ {
FFUFile.Seek(Position, SeekOrigin.Begin); FFUFile.Seek(Position, SeekOrigin.Begin);
} }
} }
internal UInt32 RoundUpToChunks(UInt32 Size) internal UInt32 RoundUpToChunks(UInt32 Size)
{ {
if ((Size % ChunkSize) > 0) if ((Size % ChunkSize) > 0)
{ {
return (UInt32)(((Size / ChunkSize) + 1) * ChunkSize); return (UInt32)(((Size / ChunkSize) + 1) * ChunkSize);
} }
else else
{ {
return Size; return Size;
} }
} }
internal UInt32 RoundDownToChunks(UInt32 Size) internal UInt32 RoundDownToChunks(UInt32 Size)
{ {
if ((Size % ChunkSize) > 0) if ((Size % ChunkSize) > 0)
{ {
return (UInt32)(Size / ChunkSize * ChunkSize); return (UInt32)(Size / ChunkSize * ChunkSize);
} }
else else
{ {
return Size; return Size;
} }
} }
internal byte[] GetSectors(int StartSector, int SectorCount) internal byte[] GetSectors(int StartSector, int SectorCount)
{ {
int FirstChunk = GetChunkIndexFromSectorIndex(StartSector); int FirstChunk = GetChunkIndexFromSectorIndex(StartSector);
int LastChunk = GetChunkIndexFromSectorIndex(StartSector + SectorCount - 1); int LastChunk = GetChunkIndexFromSectorIndex(StartSector + SectorCount - 1);
byte[] Buffer = new byte[ChunkSize]; byte[] Buffer = new byte[ChunkSize];
OpenFile(); OpenFile();
byte[] Result = new byte[SectorCount * 0x200]; byte[] Result = new byte[SectorCount * 0x200];
int ResultOffset = 0; int ResultOffset = 0;
for (int j = FirstChunk; j <= LastChunk; j++) for (int j = FirstChunk; j <= LastChunk; j++)
{ {
GetChunk(Buffer, j); GetChunk(Buffer, j);
int FirstSector = 0; int FirstSector = 0;
int LastSector = (ChunkSize / 0x200) - 1; int LastSector = (ChunkSize / 0x200) - 1;
if (j == FirstChunk) if (j == FirstChunk)
{ {
FirstSector = GetSectorNumberInChunkFromSectorIndex(StartSector); FirstSector = GetSectorNumberInChunkFromSectorIndex(StartSector);
} }
if (j == LastChunk) if (j == LastChunk)
{ {
LastSector = GetSectorNumberInChunkFromSectorIndex(StartSector + SectorCount - 1); LastSector = GetSectorNumberInChunkFromSectorIndex(StartSector + SectorCount - 1);
} }
int Offset = FirstSector * 0x200; int Offset = FirstSector * 0x200;
int Size = (LastSector - FirstSector + 1) * 0x200; int Size = (LastSector - FirstSector + 1) * 0x200;
System.Buffer.BlockCopy(Buffer, Offset, Result, ResultOffset, Size); System.Buffer.BlockCopy(Buffer, Offset, Result, ResultOffset, Size);
ResultOffset += Size; ResultOffset += Size;
} }
CloseFile(); CloseFile();
return Result; return Result;
} }
internal byte[] GetPartition(string Name) internal byte[] GetPartition(string Name)
{ {
Partition Target = GPT.Partitions.Find(p => string.Equals(p.Name, Name, StringComparison.CurrentCultureIgnoreCase)); Partition Target = GPT.Partitions.Find(p => string.Equals(p.Name, Name, StringComparison.CurrentCultureIgnoreCase));
if (Target == null) if (Target == null)
{ {
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
return GetSectors((int)Target.FirstSector, (int)(Target.LastSector - Target.FirstSector + 1)); return GetSectors((int)Target.FirstSector, (int)(Target.LastSector - Target.FirstSector + 1));
} }
internal void WritePartition(string Name, string FilePath, bool Compress = false) internal void WritePartition(string Name, string FilePath, bool Compress = false)
{ {
WritePartition(Name, FilePath, null, null, Compress); WritePartition(Name, FilePath, null, null, Compress);
} }
internal void WritePartition(string Name, string FilePath, Action<int, TimeSpan?> ProgressUpdateCallback, bool Compress = false) internal void WritePartition(string Name, string FilePath, Action<int, TimeSpan?> ProgressUpdateCallback, bool Compress = false)
{ {
WritePartition(Name, FilePath, ProgressUpdateCallback, null, Compress); WritePartition(Name, FilePath, ProgressUpdateCallback, null, Compress);
} }
internal void WritePartition(string Name, string FilePath, ProgressUpdater UpdaterPerSector, bool Compress = false) internal void WritePartition(string Name, string FilePath, ProgressUpdater UpdaterPerSector, bool Compress = false)
{ {
WritePartition(Name, FilePath, null, UpdaterPerSector, Compress); WritePartition(Name, FilePath, null, UpdaterPerSector, Compress);
} }
private void WritePartition(string Name, string FilePath, Action<int, TimeSpan?> ProgressUpdateCallback, ProgressUpdater UpdaterPerSector, bool Compress = false) private void WritePartition(string Name, string FilePath, Action<int, TimeSpan?> ProgressUpdateCallback, ProgressUpdater UpdaterPerSector, bool Compress = false)
{ {
Partition Target = GPT.Partitions.Find(p => string.Equals(p.Name, Name, StringComparison.CurrentCultureIgnoreCase)); Partition Target = GPT.Partitions.Find(p => string.Equals(p.Name, Name, StringComparison.CurrentCultureIgnoreCase));
if (Target == null) if (Target == null)
{ {
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
int FirstChunk = GetChunkIndexFromSectorIndex((int)Target.FirstSector); int FirstChunk = GetChunkIndexFromSectorIndex((int)Target.FirstSector);
int LastChunk = GetChunkIndexFromSectorIndex((int)Target.LastSector); int LastChunk = GetChunkIndexFromSectorIndex((int)Target.LastSector);
ProgressUpdater Updater = UpdaterPerSector; ProgressUpdater Updater = UpdaterPerSector;
if ((Updater == null) && (ProgressUpdateCallback != null)) if ((Updater == null) && (ProgressUpdateCallback != null))
{ {
Updater = new ProgressUpdater(Target.LastSector - Target.FirstSector + 1, ProgressUpdateCallback); Updater = new ProgressUpdater(Target.LastSector - Target.FirstSector + 1, ProgressUpdateCallback);
} }
byte[] Buffer = new byte[ChunkSize]; byte[] Buffer = new byte[ChunkSize];
OpenFile(); OpenFile();
FileStream OutputFile = new(FilePath, FileMode.Create, FileAccess.Write); FileStream OutputFile = new(FilePath, FileMode.Create, FileAccess.Write);
Stream OutStream = OutputFile; Stream OutStream = OutputFile;
// We use gzip compression // We use gzip compression
// //
// LZMA is about 60 times slower (compression is twice as good, but compressed size is already really small, so it doesnt matter much) // LZMA is about 60 times slower (compression is twice as good, but compressed size is already really small, so it doesnt matter much)
// OutStream = new LZMACompressionStream(OutputFile, System.IO.Compression.CompressionMode.Compress, false); // OutStream = new LZMACompressionStream(OutputFile, System.IO.Compression.CompressionMode.Compress, false);
// //
// DeflateStream is a raw compression stream without recognizable header // DeflateStream is a raw compression stream without recognizable header
// Deflate has almost no performance penalty // Deflate has almost no performance penalty
// OutStream = new DeflateStream(OutputFile, CompressionLevel.Optimal, false); // OutStream = new DeflateStream(OutputFile, CompressionLevel.Optimal, false);
// //
// GZip can be recognized. It always starts with 1F 8B 08 (1F 8B is the magic value, 08 is the Deflate compression method) // GZip can be recognized. It always starts with 1F 8B 08 (1F 8B is the magic value, 08 is the Deflate compression method)
// With GZip compression, dump time goes from 1m to 1m37s. So that doesnt matter much. // With GZip compression, dump time goes from 1m to 1m37s. So that doesnt matter much.
if (Compress) if (Compress)
{ {
OutStream = new CompressedStream(OutputFile, (Target.LastSector - Target.FirstSector + 1) * 0x200); OutStream = new CompressedStream(OutputFile, (Target.LastSector - Target.FirstSector + 1) * 0x200);
} }
for (int j = FirstChunk; j <= LastChunk; j++) for (int j = FirstChunk; j <= LastChunk; j++)
{ {
GetChunk(Buffer, j); GetChunk(Buffer, j);
int FirstSector = 0; int FirstSector = 0;
int LastSector = (ChunkSize / 0x200) - 1; int LastSector = (ChunkSize / 0x200) - 1;
if (j == FirstChunk) if (j == FirstChunk)
{ {
FirstSector = GetSectorNumberInChunkFromSectorIndex((int)Target.FirstSector); FirstSector = GetSectorNumberInChunkFromSectorIndex((int)Target.FirstSector);
} }
if (j == LastChunk) if (j == LastChunk)
{ {
LastSector = GetSectorNumberInChunkFromSectorIndex((int)Target.LastSector); LastSector = GetSectorNumberInChunkFromSectorIndex((int)Target.LastSector);
} }
int Offset = FirstSector * 0x200; int Offset = FirstSector * 0x200;
int Size = (LastSector - FirstSector + 1) * 0x200; int Size = (LastSector - FirstSector + 1) * 0x200;
OutStream.Write(Buffer, Offset, Size); OutStream.Write(Buffer, Offset, Size);
Updater?.IncreaseProgress((UInt64)(ChunkSize / 0x200)); Updater?.IncreaseProgress((UInt64)(ChunkSize / 0x200));
} }
OutStream.Close(); OutStream.Close();
CloseFile(); CloseFile();
} }
private byte[] GetChunk(int ChunkIndex) private byte[] GetChunk(int ChunkIndex)
{ {
long BaseOffset = (long)SecurityHeader.Length + ImageHeader.Length + StoreHeader.Length; long BaseOffset = (long)SecurityHeader.Length + ImageHeader.Length + StoreHeader.Length;
if (ChunkIndexes[ChunkIndex] == null) if (ChunkIndexes[ChunkIndex] == null)
{ {
return new byte[ChunkSize]; return new byte[ChunkSize];
} }
else else
{ {
OpenFile(); OpenFile();
FileSeek(BaseOffset + ((long)ChunkIndexes[ChunkIndex] * ChunkSize)); FileSeek(BaseOffset + ((long)ChunkIndexes[ChunkIndex] * ChunkSize));
byte[] Chunk = new byte[ChunkSize]; byte[] Chunk = new byte[ChunkSize];
FFUFile.Read(Chunk, 0, ChunkSize); FFUFile.Read(Chunk, 0, ChunkSize);
CloseFile(); CloseFile();
return Chunk; return Chunk;
} }
} }
private void GetChunk(byte[] Chunk, int ChunkIndex) private void GetChunk(byte[] Chunk, int ChunkIndex)
{ {
long BaseOffset = SecurityHeader.Length + ImageHeader.Length + StoreHeader.Length; long BaseOffset = SecurityHeader.Length + ImageHeader.Length + StoreHeader.Length;
if (ChunkIndexes[ChunkIndex] == null) if (ChunkIndexes[ChunkIndex] == null)
{ {
Array.Clear(Chunk, 0, ChunkSize); Array.Clear(Chunk, 0, ChunkSize);
} }
else else
{ {
OpenFile(); OpenFile();
FileSeek(BaseOffset + ((long)ChunkIndexes[ChunkIndex] * ChunkSize)); FileSeek(BaseOffset + ((long)ChunkIndexes[ChunkIndex] * ChunkSize));
FFUFile.Read(Chunk, 0, ChunkSize); FFUFile.Read(Chunk, 0, ChunkSize);
CloseFile(); CloseFile();
} }
} }
private int GetChunkIndexFromSectorIndex(int SectorIndex) private int GetChunkIndexFromSectorIndex(int SectorIndex)
{ {
int SectorsPerChunk = ChunkSize / 0x200; int SectorsPerChunk = ChunkSize / 0x200;
return SectorIndex / SectorsPerChunk; return SectorIndex / SectorsPerChunk;
} }
private int GetSectorNumberInChunkFromSectorIndex(int SectorIndex) private int GetSectorNumberInChunkFromSectorIndex(int SectorIndex)
{ {
int SectorsPerChunk = ChunkSize / 0x200; int SectorsPerChunk = ChunkSize / 0x200;
return SectorIndex % SectorsPerChunk; return SectorIndex % SectorsPerChunk;
} }
internal bool IsPartitionPresentInFFU(string PartitionName) internal bool IsPartitionPresentInFFU(string PartitionName)
{ {
Partition Target = GPT.GetPartition(PartitionName); Partition Target = GPT.GetPartition(PartitionName);
if (Target == null) if (Target == null)
{ {
throw new InvalidOperationException("Partitionname is not found!"); throw new InvalidOperationException("Partitionname is not found!");
} }
int ChunkIndex = GetChunkIndexFromSectorIndex((int)Target.FirstSector); int ChunkIndex = GetChunkIndexFromSectorIndex((int)Target.FirstSector);
return ChunkIndexes[ChunkIndex] != null; return ChunkIndexes[ChunkIndex] != null;
} }
private int GetChunkIndexFromSectorIndex(ulong p) private int GetChunkIndexFromSectorIndex(ulong p)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
internal string GetFirmwareVersion() internal string GetFirmwareVersion()
{ {
string Result = null; string Result = null;
Partition Plat = GPT.GetPartition("PLAT"); Partition Plat = GPT.GetPartition("PLAT");
if (Plat != null) if (Plat != null)
{ {
byte[] Data = GetPartition("PLAT"); byte[] Data = GetPartition("PLAT");
uint? Offset = ByteOperations.FindAscii(Data, "SWVERSION="); uint? Offset = ByteOperations.FindAscii(Data, "SWVERSION=");
if (Offset != null) if (Offset != null)
{ {
uint Start = (uint)Offset + 10; uint Start = (uint)Offset + 10;
uint Length = (uint)ByteOperations.FindPattern(Data, Start, 0x100, new byte[] { 0x00 }, null, null) - Start; uint Length = (uint)ByteOperations.FindPattern(Data, Start, 0x100, [0x00], null, null) - Start;
uint? Offset0D = ByteOperations.FindPattern(Data, Start, 0x100, new byte[] { 0x0D }, null, null); uint? Offset0D = ByteOperations.FindPattern(Data, Start, 0x100, [0x0D], null, null);
if ((Offset0D != null) && (Offset0D < (Start + Length))) if ((Offset0D != null) && (Offset0D < (Start + Length)))
{ {
Length = (uint)Offset0D - Start; Length = (uint)Offset0D - Start;
} }
Result = ByteOperations.ReadAsciiString(Data, Start, Length); Result = ByteOperations.ReadAsciiString(Data, Start, Length);
} }
} }
return Result; return Result;
} }
internal string GetOSVersion() internal string GetOSVersion()
{ {
byte[] efiesp = GetPartition("EFIESP"); byte[] efiesp = GetPartition("EFIESP");
MemoryStream s = new(efiesp); MemoryStream s = new(efiesp);
DiscUtils.Fat.FatFileSystem fs = new(s); DiscUtils.Fat.FatFileSystem fs = new(s);
Stream mss = fs.OpenFile(@"\Windows\System32\Boot\mobilestartup.efi", FileMode.Open, FileAccess.Read); Stream mss = fs.OpenFile(@"\Windows\System32\Boot\mobilestartup.efi", FileMode.Open, FileAccess.Read);
MemoryStream msms = new(); MemoryStream msms = new();
mss.CopyTo(msms); mss.CopyTo(msms);
byte[] mobilestartup = msms.ToArray(); byte[] mobilestartup = msms.ToArray();
Version OSVersion = PE.GetProductVersion(mobilestartup); Version OSVersion = PE.GetProductVersion(mobilestartup);
s.Close(); s.Close();
return OSVersion.ToString(); return OSVersion.ToString();
} }
} }
} }
+29
View File
@@ -0,0 +1,29 @@
// 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.
namespace WPinternals
{
internal enum FlashAppType
{
BootManager = 1,
FlashApp = 2,
PhoneInfoApp = 3
};
}
+30
View File
@@ -0,0 +1,30 @@
// 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.
namespace WPinternals
{
internal class FlashVersion
{
public int ApplicationMajor;
public int ApplicationMinor;
public int ProtocolMajor;
public int ProtocolMinor;
}
}
File diff suppressed because it is too large Load Diff
+312 -312
View File
@@ -1,312 +1,312 @@
// 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"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // 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: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // 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 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
// SevenZip LZMA SDK: http://www.7-zip.org/download.html // SevenZip LZMA SDK: http://www.7-zip.org/download.html
// Usage: http://stackoverflow.com/questions/7646328/how-to-use-the-7z-sdk-to-compress-and-decompress-a-file // Usage: http://stackoverflow.com/questions/7646328/how-to-use-the-7z-sdk-to-compress-and-decompress-a-file
using SevenZip; using SevenZip;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
namespace WPinternals namespace WPinternals
{ {
internal static class LZMA internal static class LZMA
{ {
internal static byte[] Decompress(byte[] Input, UInt32 Offset, UInt32 InputSize) internal static byte[] Decompress(byte[] Input, UInt32 Offset, UInt32 InputSize)
{ {
byte[] Properties = new byte[5]; byte[] Properties = new byte[5];
Buffer.BlockCopy(Input, (int)Offset, Properties, 0, 5); Buffer.BlockCopy(Input, (int)Offset, Properties, 0, 5);
UInt64 OutputSize = ByteOperations.ReadUInt64(Input, Offset + 5); UInt64 OutputSize = ByteOperations.ReadUInt64(Input, Offset + 5);
SevenZip.Compression.LZMA.Decoder Coder = new(); SevenZip.Compression.LZMA.Decoder Coder = new();
Coder.SetDecoderProperties(Properties); Coder.SetDecoderProperties(Properties);
MemoryStream InStream = new(Input, (int)Offset + 0x0D, (int)InputSize - 0x0D); MemoryStream InStream = new(Input, (int)Offset + 0x0D, (int)InputSize - 0x0D);
byte[] Output = new byte[OutputSize]; byte[] Output = new byte[OutputSize];
MemoryStream OutStream = new(Output, true); MemoryStream OutStream = new(Output, true);
Coder.Code(InStream, OutStream, (Int64)InputSize - 0x0D, (Int64)OutputSize, null); Coder.Code(InStream, OutStream, (Int64)InputSize - 0x0D, (Int64)OutputSize, null);
OutStream.Flush(); OutStream.Flush();
OutStream.Close(); OutStream.Close();
InStream.Close(); InStream.Close();
return Output; return Output;
} }
internal static byte[] Compress(byte[] Input, UInt32 Offset, UInt32 InputSize) internal static byte[] Compress(byte[] Input, UInt32 Offset, UInt32 InputSize)
{ {
SevenZip.Compression.LZMA.Encoder Coder = new(); SevenZip.Compression.LZMA.Encoder Coder = new();
MemoryStream InStream = new(Input, (int)Offset, (int)InputSize); MemoryStream InStream = new(Input, (int)Offset, (int)InputSize);
MemoryStream OutStream = new(); MemoryStream OutStream = new();
// Write the encoder properties // Write the encoder properties
Coder.WriteCoderProperties(OutStream); Coder.WriteCoderProperties(OutStream);
// Write the decompressed file size // Write the decompressed file size
OutStream.Write(BitConverter.GetBytes(InStream.Length), 0, 8); OutStream.Write(BitConverter.GetBytes(InStream.Length), 0, 8);
// Encode the file // Encode the file
Coder.Code(InStream, OutStream, InputSize, -1, null); Coder.Code(InStream, OutStream, InputSize, -1, null);
byte[] Output = new byte[OutStream.Length]; byte[] Output = new byte[OutStream.Length];
Buffer.BlockCopy(OutStream.GetBuffer(), 0, Output, 0, (int)OutStream.Length); Buffer.BlockCopy(OutStream.GetBuffer(), 0, Output, 0, (int)OutStream.Length);
OutStream.Flush(); OutStream.Flush();
OutStream.Close(); OutStream.Close();
InStream.Close(); InStream.Close();
return Output; return Output;
} }
} }
public class LZMACompressionStream : Stream public class LZMACompressionStream : Stream
{ {
private readonly SevenZip.Compression.LZMA.Encoder Encoder = null; private readonly SevenZip.Compression.LZMA.Encoder Encoder = null;
private readonly SevenZip.Compression.LZMA.Decoder Decoder = null; private readonly SevenZip.Compression.LZMA.Decoder Decoder = null;
private readonly PumpStream BufferStream; private readonly PumpStream BufferStream;
private readonly Stream stream; private readonly Stream stream;
private readonly bool LeaveOpen; private readonly bool LeaveOpen;
private readonly Thread WorkThread; private readonly Thread WorkThread;
private readonly CancellationTokenSource source; private readonly CancellationTokenSource source;
private readonly CancellationToken token; private readonly CancellationToken token;
public LZMACompressionStream(Stream stream, CompressionMode mode, bool LeaveOpen, int DictionarySize, int PosStateBits, public LZMACompressionStream(Stream stream, CompressionMode mode, bool LeaveOpen, int DictionarySize, int PosStateBits,
int LitContextBits, int LitPosBits, int Algorithm, int NumFastBytes, string MatchFinder, bool EndMarker) int LitContextBits, int LitPosBits, int Algorithm, int NumFastBytes, string MatchFinder, bool EndMarker)
{ {
this.stream = stream; this.stream = stream;
this.LeaveOpen = LeaveOpen; this.LeaveOpen = LeaveOpen;
BufferStream = new PumpStream(); BufferStream = new PumpStream();
source = new CancellationTokenSource(); source = new CancellationTokenSource();
token = source.Token; token = source.Token;
if (mode == CompressionMode.Compress) if (mode == CompressionMode.Compress)
{ {
Encoder = new SevenZip.Compression.LZMA.Encoder(); Encoder = new SevenZip.Compression.LZMA.Encoder();
if (DictionarySize != 0) if (DictionarySize != 0)
{ {
Encoder.SetCoderProperties( Encoder.SetCoderProperties(
new CoderPropID[8] {CoderPropID.DictionarySize, CoderPropID.PosStateBits, CoderPropID.LitContextBits, [CoderPropID.DictionarySize, CoderPropID.PosStateBits, CoderPropID.LitContextBits,
CoderPropID.LitPosBits, CoderPropID.Algorithm, CoderPropID.NumFastBytes, CoderPropID.MatchFinder, CoderPropID.EndMarker}, CoderPropID.LitPosBits, CoderPropID.Algorithm, CoderPropID.NumFastBytes, CoderPropID.MatchFinder, CoderPropID.EndMarker],
new object[8] { DictionarySize, PosStateBits, LitContextBits, LitPosBits, Algorithm, NumFastBytes, MatchFinder, EndMarker }); [DictionarySize, PosStateBits, LitContextBits, LitPosBits, Algorithm, NumFastBytes, MatchFinder, EndMarker]);
} }
Encoder.WriteCoderProperties(stream); Encoder.WriteCoderProperties(stream);
WorkThread = new Thread(new ThreadStart(Encode)); WorkThread = new Thread(new ThreadStart(Encode));
} }
else else
{ {
byte[] DecoderProperties = new byte[5]; byte[] DecoderProperties = new byte[5];
stream.Read(DecoderProperties, 0, 5); stream.Read(DecoderProperties, 0, 5);
Decoder = new SevenZip.Compression.LZMA.Decoder(); Decoder = new SevenZip.Compression.LZMA.Decoder();
Decoder.SetDecoderProperties(DecoderProperties); Decoder.SetDecoderProperties(DecoderProperties);
WorkThread = new Thread(new ThreadStart(Decode)); WorkThread = new Thread(new ThreadStart(Decode));
} }
WorkThread.Start(); WorkThread.Start();
} }
public LZMACompressionStream(Stream stream, CompressionMode mode, bool LeaveOpen) public LZMACompressionStream(Stream stream, CompressionMode mode, bool LeaveOpen)
: this(stream, mode, LeaveOpen, 0, 0, 0, 0, 0, 0, null, false) : this(stream, mode, LeaveOpen, 0, 0, 0, 0, 0, 0, null, false)
{ {
} }
private void Encode() private void Encode()
{ {
Encoder.Code(BufferStream, stream, -1, -1, null, token); Encoder.Code(BufferStream, stream, -1, -1, null, token);
if (!LeaveOpen) if (!LeaveOpen)
{ {
stream.Close(); stream.Close();
} }
} }
private void Decode() private void Decode()
{ {
Decoder.Code(stream, BufferStream, -1, -1, null, token); Decoder.Code(stream, BufferStream, -1, -1, null, token);
BufferStream.Close(); BufferStream.Close();
if (!LeaveOpen) if (!LeaveOpen)
{ {
stream.Close(); stream.Close();
} }
} }
public override void Close() public override void Close()
{ {
if (Encoder != null) if (Encoder != null)
{ {
BufferStream.Close(); BufferStream.Close();
} }
else if (WorkThread.IsAlive) else if (WorkThread.IsAlive)
{ {
source?.Cancel(); source?.Cancel();
WorkThread.Join(); WorkThread.Join();
} }
} }
public override int Read(byte[] buffer, int offset, int count) public override int Read(byte[] buffer, int offset, int count)
{ {
return BufferStream.Read(buffer, offset, count); return BufferStream.Read(buffer, offset, count);
} }
public override void Write(byte[] buffer, int offset, int count) public override void Write(byte[] buffer, int offset, int count)
{ {
BufferStream.Write(buffer, offset, count); BufferStream.Write(buffer, offset, count);
} }
public override bool CanRead { get { return Decoder != null; } } public override bool CanRead { get { return Decoder != null; } }
public override bool CanSeek { get { return false; } } public override bool CanSeek { get { return false; } }
public override bool CanWrite { get { return Encoder != null; } } public override bool CanWrite { get { return Encoder != null; } }
public override void Flush() { } public override void Flush() { }
public override long Length { get { return 0; } } public override long Length { get { return 0; } }
public override long Position { get { return 0; } set { } } public override long Position { get { return 0; } set { } }
public override long Seek(long offset, SeekOrigin origin) { return 0; } public override long Seek(long offset, SeekOrigin origin) { return 0; }
public override void SetLength(long value) { } public override void SetLength(long value) { }
} }
public class PumpStream : Stream public class PumpStream : Stream
{ {
private readonly Queue<byte[]> BufferQueue; private readonly Queue<byte[]> BufferQueue;
private int BufferOffset; private int BufferOffset;
private readonly long MaxBufferSize; private readonly long MaxBufferSize;
private long BufferSize; private long BufferSize;
private bool Closed; private bool Closed;
private bool EOF; private bool EOF;
public PumpStream(long MaxBufferSize, int ReadTimeout, int WriteTimeout) public PumpStream(long MaxBufferSize, int ReadTimeout, int WriteTimeout)
{ {
this.MaxBufferSize = MaxBufferSize; this.MaxBufferSize = MaxBufferSize;
this.ReadTimeout = ReadTimeout; this.ReadTimeout = ReadTimeout;
this.WriteTimeout = WriteTimeout; this.WriteTimeout = WriteTimeout;
BufferQueue = new Queue<byte[]>(); BufferQueue = new Queue<byte[]>();
BufferOffset = 0; BufferOffset = 0;
BufferSize = 0; BufferSize = 0;
Closed = false; Closed = false;
EOF = false; EOF = false;
} }
public PumpStream() public PumpStream()
: this(16777216, Timeout.Infinite, Timeout.Infinite) : this(16777216, Timeout.Infinite, Timeout.Infinite)
{ {
} }
public new void Dispose() public new void Dispose()
{ {
BufferQueue.Clear(); BufferQueue.Clear();
} }
public override void Close() public override void Close()
{ {
Closed = true; Closed = true;
lock (BufferQueue) lock (BufferQueue)
{ {
Monitor.Pulse(BufferQueue); Monitor.Pulse(BufferQueue);
} }
} }
public override int Read(byte[] buffer, int offset, int count) public override int Read(byte[] buffer, int offset, int count)
{ {
int BytesRead = 0; int BytesRead = 0;
lock (BufferQueue) lock (BufferQueue)
{ {
while (BytesRead < count && !EOF) while (BytesRead < count && !EOF)
{ {
if (BufferQueue.Count > 0) if (BufferQueue.Count > 0)
{ {
byte[] b = BufferQueue.Peek(); byte[] b = BufferQueue.Peek();
if ((b.Length - BufferOffset) <= (count - BytesRead)) if ((b.Length - BufferOffset) <= (count - BytesRead))
{ {
Array.Copy(b, BufferOffset, buffer, offset + BytesRead, b.Length - BufferOffset); Array.Copy(b, BufferOffset, buffer, offset + BytesRead, b.Length - BufferOffset);
BufferQueue.Dequeue(); BufferQueue.Dequeue();
BufferSize -= b.Length; BufferSize -= b.Length;
Monitor.Pulse(BufferQueue); Monitor.Pulse(BufferQueue);
BytesRead += b.Length - BufferOffset; BytesRead += b.Length - BufferOffset;
BufferOffset = 0; BufferOffset = 0;
} }
else else
{ {
Array.Copy(b, BufferOffset, buffer, offset + BytesRead, count - BytesRead); Array.Copy(b, BufferOffset, buffer, offset + BytesRead, count - BytesRead);
BufferOffset += count - BytesRead; BufferOffset += count - BytesRead;
BytesRead += count - BytesRead; BytesRead += count - BytesRead;
} }
} }
else else
{ {
if (!Closed) if (!Closed)
{ {
if (!Monitor.Wait(BufferQueue, ReadTimeout)) if (!Monitor.Wait(BufferQueue, ReadTimeout))
{ {
throw new IOException("Could not read from stream: Timeout expired waiting for data to be written."); throw new IOException("Could not read from stream: Timeout expired waiting for data to be written.");
} }
} }
else else
{ {
EOF = true; EOF = true;
} }
} }
} }
} }
return BytesRead; return BytesRead;
} }
public override void Write(byte[] buffer, int offset, int count) public override void Write(byte[] buffer, int offset, int count)
{ {
lock (BufferQueue) lock (BufferQueue)
{ {
while (BufferSize >= MaxBufferSize) while (BufferSize >= MaxBufferSize)
{ {
if (!Monitor.Wait(BufferQueue, WriteTimeout)) if (!Monitor.Wait(BufferQueue, WriteTimeout))
{ {
throw new IOException("Could not write to stream: Timeout expired waiting for data to be read."); throw new IOException("Could not write to stream: Timeout expired waiting for data to be read.");
} }
} }
byte[] b = new byte[count]; byte[] b = new byte[count];
Array.Copy(buffer, offset, b, 0, count); Array.Copy(buffer, offset, b, 0, count);
BufferQueue.Enqueue(b); BufferQueue.Enqueue(b);
BufferSize += b.Length; BufferSize += b.Length;
Monitor.Pulse(BufferQueue); Monitor.Pulse(BufferQueue);
} }
} }
public override int ReadTimeout { get; set; } public override int ReadTimeout { get; set; }
public override int WriteTimeout { get; set; } public override int WriteTimeout { get; set; }
public override bool CanRead { get { return true; } } public override bool CanRead { get { return true; } }
public override bool CanSeek { get { return false; } } public override bool CanSeek { get { return false; } }
public override bool CanWrite { get { return true; } } public override bool CanWrite { get { return true; } }
public override void Flush() { } public override void Flush() { }
public override long Length { get { return 0; } } public override long Length { get { return 0; } }
public override long Position { get { return 0; } set { } } public override long Position { get { return 0; } set { } }
public override long Seek(long offset, SeekOrigin origin) { return 0; } public override long Seek(long offset, SeekOrigin origin) { return 0; }
public override void SetLength(long value) { } public override void SetLength(long value) { }
} }
} }
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,302 +1,302 @@
// 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"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // 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: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // 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 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using Microsoft.Win32.SafeHandles; using Microsoft.Win32.SafeHandles;
using System; using System;
using System.Runtime.ConstrainedExecution; using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Security; using System.Security;
namespace WPinternals namespace WPinternals
{ {
[Flags] [Flags]
internal enum TokenAccessLevels internal enum TokenAccessLevels
{ {
AssignPrimary = 0x00000001, AssignPrimary = 0x00000001,
Duplicate = 0x00000002, Duplicate = 0x00000002,
Impersonate = 0x00000004, Impersonate = 0x00000004,
Query = 0x00000008, Query = 0x00000008,
QuerySource = 0x00000010, QuerySource = 0x00000010,
AdjustPrivileges = 0x00000020, AdjustPrivileges = 0x00000020,
AdjustGroups = 0x00000040, AdjustGroups = 0x00000040,
AdjustDefault = 0x00000080, AdjustDefault = 0x00000080,
AdjustSessionId = 0x00000100, AdjustSessionId = 0x00000100,
Read = 0x00020000 | Query, Read = 0x00020000 | Query,
Write = 0x00020000 | AdjustPrivileges | AdjustGroups | AdjustDefault, Write = 0x00020000 | AdjustPrivileges | AdjustGroups | AdjustDefault,
AllAccess = 0x000F0000 | AllAccess = 0x000F0000 |
AssignPrimary | AssignPrimary |
Duplicate | Duplicate |
Impersonate | Impersonate |
Query | Query |
QuerySource | QuerySource |
AdjustPrivileges | AdjustPrivileges |
AdjustGroups | AdjustGroups |
AdjustDefault | AdjustDefault |
AdjustSessionId, AdjustSessionId,
MaximumAllowed = 0x02000000 MaximumAllowed = 0x02000000
} }
internal enum SecurityImpersonationLevel internal enum SecurityImpersonationLevel
{ {
Anonymous = 0, Anonymous = 0,
Identification = 1, Identification = 1,
Impersonation = 2, Impersonation = 2,
Delegation = 3, Delegation = 3,
} }
internal enum TokenType internal enum TokenType
{ {
Primary = 1, Primary = 1,
Impersonation = 2, Impersonation = 2,
} }
internal enum EMoveMethod : uint internal enum EMoveMethod : uint
{ {
Begin = 0, Begin = 0,
Current = 1, Current = 1,
End = 2 End = 2
} }
internal sealed class NativeMethods internal sealed class NativeMethods
{ {
internal const uint SE_PRIVILEGE_DISABLED = 0x00000000; internal const uint SE_PRIVILEGE_DISABLED = 0x00000000;
internal const uint SE_PRIVILEGE_ENABLED = 0x00000002; internal const uint SE_PRIVILEGE_ENABLED = 0x00000002;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct LUID internal struct LUID
{ {
internal uint LowPart; internal uint LowPart;
internal uint HighPart; internal uint HighPart;
} }
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct LUID_AND_ATTRIBUTES internal struct LUID_AND_ATTRIBUTES
{ {
internal LUID Luid; internal LUID Luid;
internal uint Attributes; internal uint Attributes;
} }
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct TOKEN_PRIVILEGE internal struct TOKEN_PRIVILEGE
{ {
internal uint PrivilegeCount; internal uint PrivilegeCount;
internal LUID_AND_ATTRIBUTES Privilege; internal LUID_AND_ATTRIBUTES Privilege;
} }
internal const string ADVAPI32 = "advapi32.dll"; internal const string ADVAPI32 = "advapi32.dll";
internal const string KERNEL32 = "kernel32.dll"; internal const string KERNEL32 = "kernel32.dll";
internal const int ERROR_SUCCESS = 0x0; internal const int ERROR_SUCCESS = 0x0;
internal const int ERROR_ACCESS_DENIED = 0x5; internal const int ERROR_ACCESS_DENIED = 0x5;
internal const int ERROR_NOT_ENOUGH_MEMORY = 0x8; internal const int ERROR_NOT_ENOUGH_MEMORY = 0x8;
internal const int ERROR_NO_TOKEN = 0x3f0; internal const int ERROR_NO_TOKEN = 0x3f0;
internal const int ERROR_NOT_ALL_ASSIGNED = 0x514; internal const int ERROR_NOT_ALL_ASSIGNED = 0x514;
internal const int ERROR_NO_SUCH_PRIVILEGE = 0x521; internal const int ERROR_NO_SUCH_PRIVILEGE = 0x521;
internal const int ERROR_CANT_OPEN_ANONYMOUS = 0x543; internal const int ERROR_CANT_OPEN_ANONYMOUS = 0x543;
[DllImport( [DllImport(
KERNEL32, KERNEL32,
SetLastError = true)] SetLastError = true)]
internal static extern bool CloseHandle(IntPtr handle); internal static extern bool CloseHandle(IntPtr handle);
[DllImport( [DllImport(
ADVAPI32, ADVAPI32,
CharSet = CharSet.Unicode, CharSet = CharSet.Unicode,
SetLastError = true)] SetLastError = true)]
internal static extern bool AdjustTokenPrivileges( internal static extern bool AdjustTokenPrivileges(
[In] SafeTokenHandle TokenHandle, [In] SafeTokenHandle TokenHandle,
[In] bool DisableAllPrivileges, [In] bool DisableAllPrivileges,
[In] ref TOKEN_PRIVILEGE NewState, [In] ref TOKEN_PRIVILEGE NewState,
[In] uint BufferLength, [In] uint BufferLength,
[In, Out] ref TOKEN_PRIVILEGE PreviousState, [In, Out] ref TOKEN_PRIVILEGE PreviousState,
[In, Out] ref uint ReturnLength); [In, Out] ref uint ReturnLength);
[DllImport( [DllImport(
ADVAPI32, ADVAPI32,
CharSet = CharSet.Auto, CharSet = CharSet.Auto,
SetLastError = true)] SetLastError = true)]
internal static extern internal static extern
bool RevertToSelf(); bool RevertToSelf();
[DllImport( [DllImport(
ADVAPI32, ADVAPI32,
EntryPoint = "LookupPrivilegeValueW", EntryPoint = "LookupPrivilegeValueW",
CharSet = CharSet.Auto, CharSet = CharSet.Auto,
SetLastError = true)] SetLastError = true)]
internal static extern internal static extern
bool LookupPrivilegeValue( bool LookupPrivilegeValue(
[In] string lpSystemName, [In] string lpSystemName,
[In] string lpName, [In] string lpName,
[In, Out] ref LUID Luid); [In, Out] ref LUID Luid);
[DllImport( [DllImport(
KERNEL32, KERNEL32,
CharSet = CharSet.Auto, CharSet = CharSet.Auto,
SetLastError = true)] SetLastError = true)]
internal static extern internal static extern
IntPtr GetCurrentProcess(); IntPtr GetCurrentProcess();
[DllImport( [DllImport(
KERNEL32, KERNEL32,
CharSet = CharSet.Auto, CharSet = CharSet.Auto,
SetLastError = true)] SetLastError = true)]
internal static extern internal static extern
IntPtr GetCurrentThread(); IntPtr GetCurrentThread();
[DllImport( [DllImport(
ADVAPI32, ADVAPI32,
CharSet = CharSet.Unicode, CharSet = CharSet.Unicode,
SetLastError = true)] SetLastError = true)]
internal static extern internal static extern
bool OpenProcessToken( bool OpenProcessToken(
[In] IntPtr ProcessToken, [In] IntPtr ProcessToken,
[In] TokenAccessLevels DesiredAccess, [In] TokenAccessLevels DesiredAccess,
[In, Out] ref SafeTokenHandle TokenHandle); [In, Out] ref SafeTokenHandle TokenHandle);
[DllImport [DllImport
(ADVAPI32, (ADVAPI32,
CharSet = CharSet.Unicode, CharSet = CharSet.Unicode,
SetLastError = true)] SetLastError = true)]
internal static extern internal static extern
bool OpenThreadToken( bool OpenThreadToken(
[In] IntPtr ThreadToken, [In] IntPtr ThreadToken,
[In] TokenAccessLevels DesiredAccess, [In] TokenAccessLevels DesiredAccess,
[In] bool OpenAsSelf, [In] bool OpenAsSelf,
[In, Out] ref SafeTokenHandle TokenHandle); [In, Out] ref SafeTokenHandle TokenHandle);
[DllImport [DllImport
(ADVAPI32, (ADVAPI32,
CharSet = CharSet.Unicode, CharSet = CharSet.Unicode,
SetLastError = true)] SetLastError = true)]
internal static extern internal static extern
bool DuplicateTokenEx( bool DuplicateTokenEx(
[In] SafeTokenHandle ExistingToken, [In] SafeTokenHandle ExistingToken,
[In] TokenAccessLevels DesiredAccess, [In] TokenAccessLevels DesiredAccess,
[In] IntPtr TokenAttributes, [In] IntPtr TokenAttributes,
[In] SecurityImpersonationLevel ImpersonationLevel, [In] SecurityImpersonationLevel ImpersonationLevel,
[In] TokenType TokenType, [In] TokenType TokenType,
[In, Out] ref SafeTokenHandle NewToken); [In, Out] ref SafeTokenHandle NewToken);
[DllImport [DllImport
(ADVAPI32, (ADVAPI32,
CharSet = CharSet.Unicode, CharSet = CharSet.Unicode,
SetLastError = true)] SetLastError = true)]
internal static extern internal static extern
bool SetThreadToken( bool SetThreadToken(
[In] IntPtr Thread, [In] IntPtr Thread,
[In] SafeTokenHandle Token); [In] SafeTokenHandle Token);
internal const uint FILE_SHARE_READ = 0x00000001; internal const uint FILE_SHARE_READ = 0x00000001;
internal const uint FILE_SHARE_WRITE = 0x00000002; internal const uint FILE_SHARE_WRITE = 0x00000002;
internal const uint FILE_SHARE_DELETE = 0x00000004; internal const uint FILE_SHARE_DELETE = 0x00000004;
internal const uint OPEN_EXISTING = 3; internal const uint OPEN_EXISTING = 3;
internal const uint GENERIC_READ = 0x80000000; internal const uint GENERIC_READ = 0x80000000;
internal const uint GENERIC_WRITE = 0x40000000; internal const uint GENERIC_WRITE = 0x40000000;
internal const uint FILE_FLAG_WRITE_THROUGH = 0x80000000; internal const uint FILE_FLAG_WRITE_THROUGH = 0x80000000;
internal const uint FILE_FLAG_NO_BUFFERING = 0x20000000; internal const uint FILE_FLAG_NO_BUFFERING = 0x20000000;
internal const uint FILE_READ_ATTRIBUTES = 0x0080; internal const uint FILE_READ_ATTRIBUTES = 0x0080;
internal const uint FILE_WRITE_ATTRIBUTES = 0x0100; internal const uint FILE_WRITE_ATTRIBUTES = 0x0100;
internal const uint ERROR_INSUFFICIENT_BUFFER = 122; internal const uint ERROR_INSUFFICIENT_BUFFER = 122;
internal const uint FILE_BEGIN = 0; internal const uint FILE_BEGIN = 0;
internal const uint FSCTL_LOCK_VOLUME = 0x00090018; internal const uint FSCTL_LOCK_VOLUME = 0x00090018;
internal const uint FSCTL_DISMOUNT_VOLUME = 0x00090020; internal const uint FSCTL_DISMOUNT_VOLUME = 0x00090020;
internal const uint FSCTL_UNLOCK_VOLUME = 0x00090022; internal const uint FSCTL_UNLOCK_VOLUME = 0x00090022;
internal const uint IOCTL_STORAGE_EJECT_MEDIA = 0x2D4808; internal const uint IOCTL_STORAGE_EJECT_MEDIA = 0x2D4808;
internal const uint IOCTL_STORAGE_LOAD_MEDIA = 0x2D480C; internal const uint IOCTL_STORAGE_LOAD_MEDIA = 0x2D480C;
internal const Int32 INVALID_HANDLE_VALUE = -1; internal const Int32 INVALID_HANDLE_VALUE = -1;
internal const Int32 FILE_ATTRIBUTE_NORMAL = 1; internal const Int32 FILE_ATTRIBUTE_NORMAL = 1;
[DllImport("kernel32.dll", SetLastError = true)] [DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool WriteFile(IntPtr hFile, byte[] lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, IntPtr lpOverlapped); internal static extern bool WriteFile(IntPtr hFile, byte[] lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, IntPtr lpOverlapped);
[DllImport("kernel32.dll", SetLastError = true)] [DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped); internal static extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern uint SetFilePointer( internal static extern uint SetFilePointer(
[In] IntPtr hFile, [In] IntPtr hFile,
[In] int lDistanceToMove, [In] int lDistanceToMove,
[In, Out] ref int lpDistanceToMoveHigh, [In, Out] ref int lpDistanceToMoveHigh,
[In] EMoveMethod dwMoveMethod); [In] EMoveMethod dwMoveMethod);
[DllImport("kernel32.dll", SetLastError = true)] [DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr CreateFile( internal static extern IntPtr CreateFile(
string lpFileName, string lpFileName,
uint dwDesiredAccess, uint dwDesiredAccess,
uint dwShareMode, uint dwShareMode,
IntPtr lpSecurityAttributes, IntPtr lpSecurityAttributes,
uint dwCreationDisposition, uint dwCreationDisposition,
uint dwFlagsAndAttributes, uint dwFlagsAndAttributes,
IntPtr hTemplateFile); IntPtr hTemplateFile);
[DllImport("Kernel32.dll", SetLastError = false, CharSet = CharSet.Auto)] [DllImport("Kernel32.dll", SetLastError = false, CharSet = CharSet.Auto)]
public static extern bool DeviceIoControl( public static extern bool DeviceIoControl(
IntPtr hDevice, IntPtr hDevice,
uint IoControlCode, uint IoControlCode,
[In] object InBuffer, [In] object InBuffer,
uint nInBufferSize, uint nInBufferSize,
[Out] object OutBuffer, [Out] object OutBuffer,
uint nOutBufferSize, uint nOutBufferSize,
ref uint pBytesReturned, ref uint pBytesReturned,
IntPtr Overlapped IntPtr Overlapped
); );
[DllImport("kernel32.dll", SetLastError = true)] [DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FlushFileBuffers(IntPtr hFile); public static extern bool FlushFileBuffers(IntPtr hFile);
static NativeMethods() static NativeMethods()
{ {
} }
} }
internal sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid internal sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
{ {
private SafeTokenHandle() : base(true) { } private SafeTokenHandle() : base(true) { }
// 0 is an Invalid Handle // 0 is an Invalid Handle
internal SafeTokenHandle(IntPtr handle) internal SafeTokenHandle(IntPtr handle)
: base(true) : base(true)
{ {
SetHandle(handle); SetHandle(handle);
} }
internal static SafeTokenHandle InvalidHandle internal static SafeTokenHandle InvalidHandle
{ {
get { return new SafeTokenHandle(IntPtr.Zero); } get { return new SafeTokenHandle(IntPtr.Zero); }
} }
[DllImport(NativeMethods.KERNEL32, SetLastError = true), [DllImport(NativeMethods.KERNEL32, SetLastError = true),
SuppressUnmanagedCodeSecurity] SuppressUnmanagedCodeSecurity]
private static extern bool CloseHandle(IntPtr handle); private static extern bool CloseHandle(IntPtr handle);
override protected bool ReleaseHandle() override protected bool ReleaseHandle()
{ {
return CloseHandle(handle); return CloseHandle(handle);
} }
} }
} }
@@ -1,412 +1,426 @@
// 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"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // 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: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // 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 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using MadWizard.WinUSBNet; using MadWizard.WinUSBNet;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.Json; using System.Text.Json;
namespace WPinternals namespace WPinternals
{ {
internal class NokiaPhoneModel : IDisposable internal class NokiaPhoneModel : IDisposable
{ {
protected bool Disposed = false; protected bool Disposed = false;
private readonly USBDevice Device = null; private readonly USBDevice Device = null;
private int MessageId = 0; private int MessageId = 0;
private readonly object UsbLock = new(); private readonly object UsbLock = new();
public NokiaPhoneModel(string DevicePath) public NokiaPhoneModel(string DevicePath)
{ {
// Mass Storage device is not WinUSB // Mass Storage device is not WinUSB
try try
{ {
Device = new USBDevice(DevicePath); Device = new USBDevice(DevicePath);
} }
catch { } catch (Exception ex)
} {
LogFile.LogException(ex, LogType.FileOnly);
private JsonElement? ExecuteJsonMethodAsJsonToken(string JsonMethod, Dictionary<string, object> Params, string ResultElement) }
{ }
byte[] Buffer;
int Length; private JsonElement? ExecuteJsonMethodAsJsonToken(string JsonMethod, Dictionary<string, object> Params, string ResultElement)
{
lock (UsbLock) byte[] Buffer;
{ int Length;
const string jsonrpc = "2.0";
int id = MessageId++; lock (UsbLock)
string method = JsonMethod; {
Dictionary<string, object> @params = new(); const string jsonrpc = "2.0";
if (Params != null) int id = MessageId++;
{ string method = JsonMethod;
foreach (KeyValuePair<string, object> Param in Params) Dictionary<string, object> @params = new();
{ if (Params != null)
if (Param.Value is byte[] v) {
{ foreach (KeyValuePair<string, object> Param in Params)
@params.Add(Param.Key, v.Select(b => (int)b).ToArray()); // convert to int-array {
} if (Param.Value is byte[] v)
else {
{ @params.Add(Param.Key, v.Select(b => (int)b).ToArray()); // convert to int-array
@params.Add(Param.Key, Param.Value); }
} else
} {
} @params.Add(Param.Key, Param.Value);
@params.Add("MessageVersion", 0); }
string Request = JsonSerializer.Serialize(new { jsonrpc, id, method, @params }); }
Device.OutputPipe.Write(System.Text.Encoding.ASCII.GetBytes(Request)); }
@params.Add("MessageVersion", 0);
Buffer = new byte[0x10000]; string Request = JsonSerializer.Serialize(new { jsonrpc, id, method, @params });
Length = Device.InputPipe.Read(Buffer); Device.OutputPipe.Write(System.Text.Encoding.ASCII.GetBytes(Request));
}
Buffer = new byte[0x10000];
JsonDocument ResultMessage = JsonDocument.Parse(System.Text.Encoding.ASCII.GetString(Buffer, 0, Length)); Length = Device.InputPipe.Read(Buffer);
}
try
{ JsonDocument ResultMessage = JsonDocument.Parse(System.Text.Encoding.ASCII.GetString(Buffer, 0, Length));
JsonElement? ResultToken = ResultMessage.RootElement.GetProperty("result");
if ((ResultToken == null) || (ResultElement == null)) try
{ {
return null; JsonElement? ResultToken = ResultMessage.RootElement.GetProperty("result");
} if ((ResultToken == null) || (ResultElement == null))
{
return ResultToken.Value.GetProperty(ResultElement); return null;
} }
catch
{ return ResultToken.Value.GetProperty(ResultElement);
return null; }
} catch
} {
return null;
public void ExecuteJsonMethod(string JsonMethod, Dictionary<string, object> Params) }
{ }
_ = ExecuteJsonMethodAsJsonToken(JsonMethod, Params, null);
} public void ExecuteJsonMethod(string JsonMethod, Dictionary<string, object> Params)
{
public string ExecuteJsonMethodAsString(string JsonMethod, Dictionary<string, object> Params, string ResultElement) _ = ExecuteJsonMethodAsJsonToken(JsonMethod, Params, null);
{ }
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, Params, ResultElement);
if (Token == null) public string ExecuteJsonMethodAsString(string JsonMethod, Dictionary<string, object> Params, string ResultElement)
{ {
return null; JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, Params, ResultElement);
} if (Token == null)
{
return Token.Value.GetString(); return null;
} }
public string ExecuteJsonMethodAsString(string JsonMethod, string ResultElement) return Token.Value.GetString();
{ }
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, null, ResultElement);
if (Token == null) public string ExecuteJsonMethodAsString(string JsonMethod, string ResultElement)
{ {
return null; JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, null, ResultElement);
} if (Token == null)
{
return Token.Value.GetString(); return null;
} }
public int ExecuteJsonMethodAsInteger(string JsonMethod, Dictionary<string, object> Params, string ResultElement) return Token.Value.GetString();
{ }
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, Params, ResultElement);
if (Token == null) public int ExecuteJsonMethodAsInteger(string JsonMethod, Dictionary<string, object> Params, string ResultElement)
{ {
return 0; JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, Params, ResultElement);
} if (Token == null)
{
return Token.Value.GetInt32(); return 0;
} }
public int ExecuteJsonMethodAsInteger(string JsonMethod, string ResultElement) return Token.Value.GetInt32();
{ }
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, null, ResultElement);
if (Token == null) public int ExecuteJsonMethodAsInteger(string JsonMethod, string ResultElement)
{ {
return 0; JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, null, ResultElement);
} if (Token == null)
{
return Token.Value.GetInt32(); return 0;
} }
public byte[] ExecuteJsonMethodAsBytes(string JsonMethod, Dictionary<string, object> Params, string ResultElement) return Token.Value.GetInt32();
{ }
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, Params, ResultElement);
if (Token == null) public byte[] ExecuteJsonMethodAsBytes(string JsonMethod, Dictionary<string, object> Params, string ResultElement)
{ {
return null; JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, Params, ResultElement);
} if (Token == null)
{
return Token.Value.EnumerateArray().Select(x => x.GetByte()).ToArray(); return null;
} }
public byte[] ExecuteJsonMethodAsBytes(string JsonMethod, string ResultElement) return Token.Value.EnumerateArray().Select(x => x.GetByte()).ToArray();
{ }
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, null, ResultElement);
if (Token == null) public byte[] ExecuteJsonMethodAsBytes(string JsonMethod, string ResultElement)
{ {
return null; JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, null, ResultElement);
} if (Token == null)
{
return Token.Value.EnumerateArray().Select(x => x.GetByte()).ToArray(); return null;
} }
public bool? ExecuteJsonMethodAsBoolean(string JsonMethod, string ResultElement) return Token.Value.EnumerateArray().Select(x => x.GetByte()).ToArray();
{ }
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, null, ResultElement);
if (Token == null) public bool? ExecuteJsonMethodAsBoolean(string JsonMethod, string ResultElement)
{ {
return null; JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, null, ResultElement);
} if (Token == null)
{
return Token.Value.GetBoolean(); return null;
} }
public void ExecuteJsonMethodAsync(string JsonMethod, Dictionary<string, object> Params) if (Token.Value.ValueKind == JsonValueKind.String)
{ {
lock (UsbLock) return Token.Value.GetString().Equals("true", StringComparison.InvariantCultureIgnoreCase);
{ }
const string jsonrpc = "2.0";
int id = MessageId++; return Token.Value.GetBoolean();
string method = JsonMethod; }
Dictionary<string, object> @params = new();
if (Params != null) public void ExecuteJsonMethodAsync(string JsonMethod, Dictionary<string, object> Params)
{ {
foreach (KeyValuePair<string, object> Param in Params) lock (UsbLock)
{ {
if (Param.Value is byte[] v) const string jsonrpc = "2.0";
{ int id = MessageId++;
@params.Add(Param.Key, v.Select(b => (int)b).ToArray()); // convert to int-array string method = JsonMethod;
} Dictionary<string, object> @params = new();
else if (Params != null)
{ {
@params.Add(Param.Key, Param.Value); foreach (KeyValuePair<string, object> Param in Params)
} {
} if (Param.Value is byte[] v)
} {
@params.Add("MessageVersion", 0); @params.Add(Param.Key, v.Select(b => (int)b).ToArray()); // convert to int-array
string Request = JsonSerializer.Serialize(new { jsonrpc, id, method, @params }); }
else
byte[] OutBuffer = System.Text.Encoding.ASCII.GetBytes(Request); {
Device.OutputPipe.BeginWrite(OutBuffer, 0, OutBuffer.Length, (AsyncResultWrite) => Device.OutputPipe.EndWrite(AsyncResultWrite), null); @params.Add(Param.Key, Param.Value);
} }
} }
}
public void ExecuteJsonMethodAsync(string JsonMethod) @params.Add("MessageVersion", 0);
{ string Request = JsonSerializer.Serialize(new { jsonrpc, id, method, @params });
ExecuteJsonMethod(JsonMethod, null);
} byte[] OutBuffer = System.Text.Encoding.ASCII.GetBytes(Request);
Device.OutputPipe.BeginWrite(OutBuffer, 0, OutBuffer.Length, (AsyncResultWrite) => Device.OutputPipe.EndWrite(AsyncResultWrite), null);
public delegate void JsonMethodCallbackString(object State, string Result); }
}
public void ExecuteJsonMethodAsStringAsync(string JsonMethod, Dictionary<string, object> Params, string ResultElement, object State, JsonMethodCallbackString Callback)
{ public void ExecuteJsonMethodAsync(string JsonMethod)
ExecuteJsonMethodAsTokenAsync(JsonMethod, Params, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetRawText())); {
} ExecuteJsonMethod(JsonMethod, null);
}
public void ExecuteJsonMethodAsStringAsync(string JsonMethod, string ResultElement, object State, JsonMethodCallbackString Callback)
{ public delegate void JsonMethodCallbackString(object State, string Result);
ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetRawText()));
} public void ExecuteJsonMethodAsStringAsync(string JsonMethod, Dictionary<string, object> Params, string ResultElement, object State, JsonMethodCallbackString Callback)
{
public delegate void JsonMethodCallbackBoolean(object State, bool Result); ExecuteJsonMethodAsTokenAsync(JsonMethod, Params, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetRawText()));
}
public void ExecuteJsonMethodAsBooleanAsync(string JsonMethod, Dictionary<string, object> Params, string ResultElement, object State, JsonMethodCallbackBoolean Callback)
{ public void ExecuteJsonMethodAsStringAsync(string JsonMethod, string ResultElement, object State, JsonMethodCallbackString Callback)
ExecuteJsonMethodAsTokenAsync(JsonMethod, Params, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetBoolean())); {
} ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetRawText()));
}
public void ExecuteJsonMethodAsBooleanAsync(string JsonMethod, string ResultElement, object State, JsonMethodCallbackBoolean Callback)
{ public delegate void JsonMethodCallbackBoolean(object State, bool Result);
ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetBoolean()));
} public void ExecuteJsonMethodAsBooleanAsync(string JsonMethod, Dictionary<string, object> Params, string ResultElement, object State, JsonMethodCallbackBoolean Callback)
{
public delegate void JsonMethodCallbackBytes(object State, byte[] Result); ExecuteJsonMethodAsTokenAsync(JsonMethod, Params, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetBoolean()));
}
public void ExecuteJsonMethodAsBytesAsync(string JsonMethod, Dictionary<string, object> Params, string ResultElement, object State, JsonMethodCallbackBytes Callback)
{ public void ExecuteJsonMethodAsBooleanAsync(string JsonMethod, string ResultElement, object State, JsonMethodCallbackBoolean Callback)
ExecuteJsonMethodAsTokenAsync(JsonMethod, Params, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.EnumerateArray().Select(x => x.GetByte()).ToArray())); {
} ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetBoolean()));
}
public void ExecuteJsonMethodAsBytesAsync(string JsonMethod, string ResultElement, object State, JsonMethodCallbackBytes Callback)
{ public delegate void JsonMethodCallbackBytes(object State, byte[] Result);
ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.EnumerateArray().Select(x => x.GetByte()).ToArray()));
} public void ExecuteJsonMethodAsBytesAsync(string JsonMethod, Dictionary<string, object> Params, string ResultElement, object State, JsonMethodCallbackBytes Callback)
{
public delegate void JsonMethodCallbackInteger(object State, int Result); ExecuteJsonMethodAsTokenAsync(JsonMethod, Params, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.EnumerateArray().Select(x => x.GetByte()).ToArray()));
}
public void ExecuteJsonMethodAsIntegerAsync(string JsonMethod, Dictionary<string, object> Params, string ResultElement, object State, JsonMethodCallbackInteger Callback)
{ public void ExecuteJsonMethodAsBytesAsync(string JsonMethod, string ResultElement, object State, JsonMethodCallbackBytes Callback)
ExecuteJsonMethodAsTokenAsync(JsonMethod, Params, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetInt32())); {
} ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.EnumerateArray().Select(x => x.GetByte()).ToArray()));
}
public void ExecuteJsonMethodAsIntegerAsync(string JsonMethod, string ResultElement, object State, JsonMethodCallbackInteger Callback)
{ public delegate void JsonMethodCallbackInteger(object State, int Result);
ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetInt32()));
} public void ExecuteJsonMethodAsIntegerAsync(string JsonMethod, Dictionary<string, object> Params, string ResultElement, object State, JsonMethodCallbackInteger Callback)
{
public delegate void JsonMethodCallbackToken(object State, JsonElement? Result); ExecuteJsonMethodAsTokenAsync(JsonMethod, Params, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetInt32()));
}
public void ExecuteJsonMethodAsTokenAsync(string JsonMethod, Dictionary<string, object> Params, string ResultElement, object State, JsonMethodCallbackToken Callback)
{ public void ExecuteJsonMethodAsIntegerAsync(string JsonMethod, string ResultElement, object State, JsonMethodCallbackInteger Callback)
byte[] Buffer; {
int Length; ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetInt32()));
}
lock (UsbLock)
{ public delegate void JsonMethodCallbackToken(object State, JsonElement? Result);
const string jsonrpc = "2.0";
int id = MessageId++; public void ExecuteJsonMethodAsTokenAsync(string JsonMethod, Dictionary<string, object> Params, string ResultElement, object State, JsonMethodCallbackToken Callback)
string method = JsonMethod; {
Dictionary<string, object> @params = new(); byte[] Buffer;
if (Params != null) int Length;
{
foreach (KeyValuePair<string, object> Param in Params) lock (UsbLock)
{ {
if (Param.Value is byte[] v) const string jsonrpc = "2.0";
{ int id = MessageId++;
@params.Add(Param.Key, v.Select(b => (int)b).ToArray()); // convert to int-array string method = JsonMethod;
} Dictionary<string, object> @params = new();
else if (Params != null)
{ {
@params.Add(Param.Key, Param.Value); foreach (KeyValuePair<string, object> Param in Params)
} {
} if (Param.Value is byte[] v)
} {
@params.Add("MessageVersion", 0); @params.Add(Param.Key, v.Select(b => (int)b).ToArray()); // convert to int-array
string Request = JsonSerializer.Serialize(new { jsonrpc, id, method, @params }); }
else
byte[] OutBuffer = System.Text.Encoding.ASCII.GetBytes(Request); {
Device.OutputPipe.BeginWrite(OutBuffer, 0, OutBuffer.Length, (AsyncResultWrite) => @params.Add(Param.Key, Param.Value);
{ }
Device.OutputPipe.EndWrite(AsyncResultWrite); }
Buffer = new byte[0x10000]; }
Device.InputPipe.BeginRead(Buffer, 0, 0x10000, (AsyncResultRead) => @params.Add("MessageVersion", 0);
{ string Request = JsonSerializer.Serialize(new { jsonrpc, id, method, @params });
Length = Device.InputPipe.EndRead(AsyncResultRead);
byte[] OutBuffer = System.Text.Encoding.ASCII.GetBytes(Request);
JsonDocument ResultMessage = JsonDocument.Parse(System.Text.Encoding.ASCII.GetString(Buffer, 0, Length)); Device.OutputPipe.BeginWrite(OutBuffer, 0, OutBuffer.Length, (AsyncResultWrite) =>
{
JsonElement? ResultToken = ResultMessage.RootElement.GetProperty("result"); Device.OutputPipe.EndWrite(AsyncResultWrite);
if ((ResultToken == null) || (ResultElement == null)) Buffer = new byte[0x10000];
{ Device.InputPipe.BeginRead(Buffer, 0, 0x10000, (AsyncResultRead) =>
Callback(AsyncResultRead.AsyncState, null); {
} Length = Device.InputPipe.EndRead(AsyncResultRead);
Callback(AsyncResultRead.AsyncState, ResultToken.Value.GetProperty(ResultElement)); JsonDocument ResultMessage = JsonDocument.Parse(System.Text.Encoding.ASCII.GetString(Buffer, 0, Length));
}, AsyncResultWrite.AsyncState);
}, State); JsonElement? ResultToken = ResultMessage.RootElement.GetProperty("result");
} if ((ResultToken == null) || (ResultElement == null))
} {
Callback(AsyncResultRead.AsyncState, null);
public void ExecuteJsonMethodAsTokenAsync(string JsonMethod, string ResultElement, object State, JsonMethodCallbackToken Callback) }
{
ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, Callback); Callback(AsyncResultRead.AsyncState, ResultToken.Value.GetProperty(ResultElement));
} }, AsyncResultWrite.AsyncState);
}, State);
public byte[] ExecuteRawMethod(byte[] RawMethod) }
{ }
return ExecuteRawMethod(RawMethod, RawMethod.Length);
} public void ExecuteJsonMethodAsTokenAsync(string JsonMethod, string ResultElement, object State, JsonMethodCallbackToken Callback)
{
public byte[] ExecuteRawMethod(byte[] RawMethod, int Length) ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, Callback);
{ }
byte[] Buffer = new byte[0x8000]; // Should be at least 0x4408 for receiving the GPT packet.
byte[] Result = null; public byte[] ExecuteRawMethod(byte[] RawMethod)
lock (UsbLock) {
{ return ExecuteRawMethod(RawMethod, RawMethod.Length);
Device.OutputPipe.Write(RawMethod, 0, Length); }
try
{ public byte[] ExecuteRawMethod(byte[] RawMethod, int Length)
int OutputLength = Device.InputPipe.Read(Buffer); {
Result = new byte[OutputLength]; byte[] Buffer = new byte[0x8000]; // Should be at least 0x4408 for receiving the GPT packet.
System.Buffer.BlockCopy(Buffer, 0, Result, 0, OutputLength); byte[] Result = null;
} lock (UsbLock)
catch { } // Reboot command looses connection {
} Device.OutputPipe.Write(RawMethod, 0, Length);
return Result; try
} {
int OutputLength = Device.InputPipe.Read(Buffer);
public void ExecuteRawVoidMethod(byte[] RawMethod) Result = new byte[OutputLength];
{ System.Buffer.BlockCopy(Buffer, 0, Result, 0, OutputLength);
ExecuteRawVoidMethod(RawMethod, RawMethod.Length); }
} catch (Exception ex) // Reboot command looses connection
{
public void ExecuteRawVoidMethod(byte[] RawMethod, int Length) LogFile.LogException(ex, LogType.FileOnly);
{ }
lock (UsbLock) }
{ return Result;
Device.OutputPipe.Write(RawMethod, 0, Length); }
}
} public void ExecuteRawVoidMethod(byte[] RawMethod)
{
public void ResetDevice() ExecuteRawVoidMethod(RawMethod, RawMethod.Length);
{ }
try
{ public void ExecuteRawVoidMethod(byte[] RawMethod, int Length)
foreach (var pipe in Device.Pipes) {
{ lock (UsbLock)
pipe.Abort(); {
pipe.Reset(); Device.OutputPipe.Write(RawMethod, 0, Length);
} }
} }
catch { }
} public void ResetDevice()
{
/// <summary> try
/// Disposes the UsbDevice including all unmanaged WinUSB handles. This function {
/// should be called when the UsbDevice object is no longer in use, otherwise foreach (var pipe in Device.Pipes)
/// unmanaged handles will remain open until the garbage collector finalizes the {
/// object. pipe.Abort();
/// </summary> pipe.Reset();
public void Dispose() }
{ }
Dispose(true); catch (Exception ex)
GC.SuppressFinalize(this); {
} LogFile.LogException(ex, LogType.FileOnly);
}
/// <summary> }
/// Finalizer for the UsbDevice. Disposes all unmanaged handles.
/// </summary> /// <summary>
~NokiaPhoneModel() /// Disposes the UsbDevice including all unmanaged WinUSB handles. This function
{ /// should be called when the UsbDevice object is no longer in use, otherwise
Dispose(false); /// unmanaged handles will remain open until the garbage collector finalizes the
} /// object.
/// </summary>
/// <summary> public void Dispose()
/// Disposes the object {
/// </summary> Dispose(true);
/// <param name="disposing">Indicates wether Dispose was called manually (true) or by GC.SuppressFinalize(this);
/// the garbage collector (false) via the destructor.</param> }
protected virtual void Dispose(bool disposing)
{ /// <summary>
if (Disposed) /// Finalizer for the UsbDevice. Disposes all unmanaged handles.
{ /// </summary>
return; ~NokiaPhoneModel()
} {
Dispose(false);
if (disposing) }
{
Device?.Dispose(); /// <summary>
} /// Disposes the object
/// </summary>
// Clean unmanaged resources here. /// <param name="disposing">Indicates wether Dispose was called manually (true) or by
// (none currently) /// the garbage collector (false) via the destructor.</param>
protected virtual void Dispose(bool disposing)
Disposed = true; {
} if (Disposed)
} {
} return;
}
if (disposing)
{
Device?.Dispose();
}
// Clean unmanaged resources here.
// (none currently)
Disposed = true;
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,42 @@
// 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;
namespace WPinternals
{
internal class CommonPhoneInfo
{
public PhoneInfoState State = PhoneInfoState.Empty;
public FlashAppType App;
public byte VersionMajor;
public byte VersionMinor;
public byte ProtocolVersionMajor;
public byte ProtocolVersionMinor;
internal void Log(LogType Type)
{
LogFile.Log($"App: {VersionMajor}.{VersionMinor}", Type);
LogFile.Log($"Protocol: {ProtocolVersionMajor}.{ProtocolVersionMinor}", Type);
}
}
}
@@ -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;
namespace WPinternals
{
internal class LumiaBootManagerPhoneInfo
{
public PhoneInfoState State = PhoneInfoState.Empty;
public FlashAppType App;
public byte FlashAppVersionMajor;
public byte FlashAppVersionMinor;
public byte FlashAppProtocolVersionMajor;
public byte FlashAppProtocolVersionMinor;
public byte BootManagerVersionMajor;
public byte BootManagerVersionMinor;
public byte BootManagerProtocolVersionMajor;
public byte BootManagerProtocolVersionMinor;
public UInt32 TransferSize;
public bool MmosOverUsbSupported;
internal void Log(LogType Type)
{
switch (App)
{
case FlashAppType.BootManager:
LogFile.Log($"Bootmanager: {BootManagerVersionMajor}.{BootManagerVersionMinor}", Type);
LogFile.Log($"Bootmanager protocol: {BootManagerProtocolVersionMajor}.{BootManagerProtocolVersionMinor}", Type);
LogFile.Log($"Flash app: {FlashAppVersionMajor}.{FlashAppVersionMinor}", Type);
LogFile.Log($"Flash protocol: {FlashAppProtocolVersionMajor}.{FlashAppProtocolVersionMinor}", Type);
LogFile.Log($"Flash app: {FlashAppVersionMajor}.{FlashAppVersionMinor}", Type);
LogFile.Log($"Flash protocol: {FlashAppProtocolVersionMajor}.{FlashAppProtocolVersionMinor}", Type);
break;
}
}
}
}
@@ -0,0 +1,96 @@
// 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;
namespace WPinternals
{
internal class LumiaFlashAppPhoneInfo
{
public PhoneInfoState State = PhoneInfoState.Empty;
public string Firmware; // Extended info
public byte[] RKH; // Extended info
public FlashAppType App;
public byte FlashAppVersionMajor;
public byte FlashAppVersionMinor;
public byte FlashAppProtocolVersionMajor;
public byte FlashAppProtocolVersionMinor;
public UInt32 TransferSize;
public bool MmosOverUsbSupported;
public UInt32 SdCardSizeInSectors;
public UInt32 WriteBufferSize;
public UInt32 EmmcSizeInSectors;
public string PlatformID;
public UInt16 SecureFfuSupportedProtocolMask;
public bool AsyncSupport;
public bool PlatformSecureBootEnabled;
public bool SecureFfuEnabled;
public bool JtagDisabled;
public bool RdcPresent;
public bool Authenticated;
public bool UefiSecureBootEnabled;
public bool SecondaryHardwareKeyPresent;
public bool IsBootloaderSecure;
internal void Log(LogType Type)
{
if (State == PhoneInfoState.Extended)
{
if (RKH != null)
{
LogFile.Log($"Root key hash: {Converter.ConvertHexToString(RKH, "")}", Type);
}
if (Firmware?.Length > 0)
{
LogFile.Log($"Firmware version: {Firmware}", Type);
}
}
switch (App)
{
case FlashAppType.FlashApp:
LogFile.Log($"Flash app: {FlashAppVersionMajor}.{FlashAppVersionMinor}", Type);
LogFile.Log($"Flash protocol: {FlashAppProtocolVersionMajor}.{FlashAppProtocolVersionMinor}", Type);
break;
}
LogFile.Log($"SecureBoot: {((!PlatformSecureBootEnabled || !UefiSecureBootEnabled) ? "Disabled" : "Enabled")} (Platform Secure Boot: {(PlatformSecureBootEnabled ? "Enabled" : "Disabled")}, UEFI Secure Boot: {(UefiSecureBootEnabled ? "Enabled" : "Disabled")})", Type);
if ((Type == LogType.ConsoleOnly) || (Type == LogType.FileAndConsole))
{
LogFile.Log($"Flash app security: {(!IsBootloaderSecure ? "Disabled" : "Enabled")}", LogType.ConsoleOnly);
}
if ((Type == LogType.FileOnly) || (Type == LogType.FileAndConsole))
{
LogFile.Log($"Flash app security: {(!IsBootloaderSecure ? "Disabled" : "Enabled")} (FFU security: {(SecureFfuEnabled ? "Enabled" : "Disabled")}, RDC: {(RdcPresent ? "Present" : "Not found")}, Authenticated: {(Authenticated ? "True" : "False")})", LogType.FileOnly);
}
LogFile.Log($"JTAG: {(JtagDisabled ? "Disabled" : "Enabled")}", Type);
}
}
}
@@ -0,0 +1,69 @@
// 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;
namespace WPinternals
{
internal class LumiaPhoneInfoAppPhoneInfo
{
public PhoneInfoState State = PhoneInfoState.Empty;
public string Type; // Extended info
public string ProductCode; // Extended info
public string Imei; // Extended info
public FlashAppType App;
public byte PhoneInfoAppVersionMajor;
public byte PhoneInfoAppVersionMinor;
public byte PhoneInfoAppProtocolVersionMajor;
public byte PhoneInfoAppProtocolVersionMinor;
internal void Log(LogType Type)
{
if (State == PhoneInfoState.Extended)
{
if (this.Type != null)
{
LogFile.Log($"Phone type: {this.Type}", Type);
}
if (ProductCode != null)
{
LogFile.Log($"Product code: {ProductCode}", Type);
}
if (Type != LogType.ConsoleOnly && (Imei != null))
{
LogFile.Log($"IMEI: {Imei}", LogType.FileOnly);
}
}
switch (App)
{
case FlashAppType.PhoneInfoApp:
LogFile.Log($"Phone info app: {PhoneInfoAppVersionMajor}.{PhoneInfoAppVersionMinor}", Type);
LogFile.Log($"Phone info protocol: {PhoneInfoAppProtocolVersionMajor}.{PhoneInfoAppProtocolVersionMinor}", Type);
break;
}
}
}
}
+29
View File
@@ -0,0 +1,29 @@
// 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.
namespace WPinternals
{
internal enum PhoneInfoState
{
Empty,
Basic,
Extended
};
}
File diff suppressed because it is too large Load Diff
@@ -1,145 +1,145 @@
// 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"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // 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: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // 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 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
namespace WPinternals namespace WPinternals
{ {
internal class QualcommDownload internal class QualcommDownload
{ {
private readonly QualcommSerial Serial; private readonly QualcommSerial Serial;
public QualcommDownload(QualcommSerial Serial) public QualcommDownload(QualcommSerial Serial)
{ {
this.Serial = Serial; this.Serial = Serial;
} }
public bool IsAlive() public bool IsAlive()
{ {
try try
{ {
Serial.SendCommand(new byte[] { 0x06 }, new byte[] { 0x02 }); Serial.SendCommand([0x06], [0x02]);
return true; return true;
} }
catch catch
{ {
return false; return false;
} }
} }
public void SendToPhoneMemory(UInt32 Address, Stream Data, UInt32 Length = UInt32.MaxValue) public void SendToPhoneMemory(UInt32 Address, Stream Data, UInt32 Length = UInt32.MaxValue)
{ {
long Remaining = Length > (Data.Length - Data.Position) ? Data.Length - Data.Position : Length; long Remaining = Length > (Data.Length - Data.Position) ? Data.Length - Data.Position : Length;
UInt32 CurrentLength; UInt32 CurrentLength;
byte[] Buffer = new byte[0x107]; byte[] Buffer = new byte[0x107];
Buffer[0] = 0x0F; Buffer[0] = 0x0F;
System.Buffer.BlockCopy(BitConverter.GetBytes((UInt16)0x100).Reverse().ToArray(), 0, Buffer, 5, 2); // Length is in Big Endian System.Buffer.BlockCopy(BitConverter.GetBytes((UInt16)0x100).Reverse().ToArray(), 0, Buffer, 5, 2); // Length is in Big Endian
UInt32 CurrentAddress = Address; UInt32 CurrentAddress = Address;
while (Remaining > 0) while (Remaining > 0)
{ {
System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentAddress).Reverse().ToArray(), 0, Buffer, 1, 4); // Address is in Big Endian System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentAddress).Reverse().ToArray(), 0, Buffer, 1, 4); // Address is in Big Endian
CurrentLength = Remaining >= 0x100 ? 0x100 : (UInt32)Remaining; CurrentLength = Remaining >= 0x100 ? 0x100 : (UInt32)Remaining;
CurrentLength = (UInt32)Data.Read(Buffer, 7, (int)CurrentLength); CurrentLength = (UInt32)Data.Read(Buffer, 7, (int)CurrentLength);
Serial.SendCommand(Buffer, new byte[] { 0x02 }); Serial.SendCommand(Buffer, [0x02]);
CurrentAddress += CurrentLength; CurrentAddress += CurrentLength;
Remaining -= CurrentLength; Remaining -= CurrentLength;
} }
} }
public void SendToPhoneMemory(UInt32 Address, byte[] Data, UInt32 Offset = 0, UInt32 Length = UInt32.MaxValue) public void SendToPhoneMemory(UInt32 Address, byte[] Data, UInt32 Offset = 0, UInt32 Length = UInt32.MaxValue)
{ {
long Remaining; long Remaining;
if (Offset > (Data.Length - 1)) if (Offset > (Data.Length - 1))
{ {
throw new ArgumentException("Wrong offset"); throw new ArgumentException("Wrong offset");
} }
Remaining = Length > (Data.Length - Offset) ? Data.Length - Offset : Length; Remaining = Length > (Data.Length - Offset) ? Data.Length - Offset : Length;
UInt32 CurrentLength; UInt32 CurrentLength;
UInt32 CurrentOffset = Offset; UInt32 CurrentOffset = Offset;
byte[] Buffer = new byte[0x107]; byte[] Buffer = new byte[0x107];
UInt32 CurrentAddress = Address; UInt32 CurrentAddress = Address;
byte[] CurrentBytes; byte[] CurrentBytes;
while (Remaining > 0) while (Remaining > 0)
{ {
if (Remaining >= 0x100) if (Remaining >= 0x100)
{ {
CurrentLength = 0x100; CurrentLength = 0x100;
CurrentBytes = Buffer; CurrentBytes = Buffer;
} }
else else
{ {
CurrentLength = (UInt32)Remaining; CurrentLength = (UInt32)Remaining;
CurrentBytes = new byte[CurrentLength + 7]; CurrentBytes = new byte[CurrentLength + 7];
} }
CurrentBytes[0] = 0x0F; CurrentBytes[0] = 0x0F;
System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentAddress).Reverse().ToArray(), 0, CurrentBytes, 1, 4); // Address is in Big Endian System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentAddress).Reverse().ToArray(), 0, CurrentBytes, 1, 4); // Address is in Big Endian
System.Buffer.BlockCopy(BitConverter.GetBytes((UInt16)CurrentLength).Reverse().ToArray(), 0, CurrentBytes, 5, 2); // Length is in Big Endian System.Buffer.BlockCopy(BitConverter.GetBytes((UInt16)CurrentLength).Reverse().ToArray(), 0, CurrentBytes, 5, 2); // Length is in Big Endian
System.Buffer.BlockCopy(Data, (int)CurrentOffset, CurrentBytes, 7, (int)CurrentLength); System.Buffer.BlockCopy(Data, (int)CurrentOffset, CurrentBytes, 7, (int)CurrentLength);
Serial.SendCommand(CurrentBytes, new byte[] { 0x02 }); Serial.SendCommand(CurrentBytes, [0x02]);
CurrentAddress += CurrentLength; CurrentAddress += CurrentLength;
CurrentOffset += CurrentLength; CurrentOffset += CurrentLength;
Remaining -= CurrentLength; Remaining -= CurrentLength;
} }
} }
public void StartBootloader(UInt32 Address) public void StartBootloader(UInt32 Address)
{ {
byte[] Buffer = new byte[5]; byte[] Buffer = new byte[5];
Buffer[0] = 0x05; Buffer[0] = 0x05;
System.Buffer.BlockCopy(BitConverter.GetBytes(Address).Reverse().ToArray(), 0, Buffer, 1, 4); // Address is in Big Endian System.Buffer.BlockCopy(BitConverter.GetBytes(Address).Reverse().ToArray(), 0, Buffer, 1, 4); // Address is in Big Endian
Serial.SendCommand(Buffer, new byte[] { 0x02 }); Serial.SendCommand(Buffer, [0x02]);
} }
// Reset interface. Interface becomes unresponsive. // Reset interface. Interface becomes unresponsive.
public void Reset() public void Reset()
{ {
Serial.SendCommand(new byte[] { 0x0A }, new byte[] { 0x02 }); Serial.SendCommand([0x0A], [0x02]);
} }
// This also resets interface. This does not actually reboot the phone. The interface becomes unresponsive. // This also resets interface. This does not actually reboot the phone. The interface becomes unresponsive.
public void Shutdown() public void Shutdown()
{ {
Serial.SendCommand(new byte[] { 0x0E }, new byte[] { 0x02 }); Serial.SendCommand([0x0E], [0x02]);
} }
// This command only works on 9008 interface. // This command only works on 9008 interface.
public byte[] GetRKH() public byte[] GetRKH()
{ {
byte[] Response = Serial.SendCommand(new byte[] { 0x18 }, new byte[] { 0x18, 0x01, 0x00 }); byte[] Response = Serial.SendCommand([0x18], [0x18, 0x01, 0x00]);
byte[] Result = new byte[0x20]; byte[] Result = new byte[0x20];
Buffer.BlockCopy(Response, 3, Result, 0, 0x20); Buffer.BlockCopy(Response, 3, Result, 0, 0x20);
return Result; return Result;
} }
public void CloseSerial() public void CloseSerial()
{ {
Serial.Close(); Serial.Close();
} }
} }
} }
@@ -1,600 +1,388 @@
// 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"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // 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: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // 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 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections; using System.Collections;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace WPinternals namespace WPinternals
{ {
internal enum SaharaMode : uint internal class QualcommFirehose
{ {
ImageTransferPending = 0x00, private readonly QualcommSerial Serial;
ImagetransferComplete = 0x01,
MemoryDebug = 0x02, public QualcommFirehose(QualcommSerial Serial)
Command = 0x03 {
} this.Serial = Serial;
}
internal delegate void ReadyHandler();
public bool ConnectToProgrammer(byte[] PacketFromPcToProgrammer)
internal class QualcommSahara {
{ // Behaviour of old firehose:
private readonly QualcommSerial Serial; // Takes about 20 ms to be started.
// Then PC has to start talking to the phone.
public QualcommSahara(QualcommSerial Serial) // Behaviour of new firehose:
{ // After 2000 ms the firehose starts talking to the PC
Serial.EncodeCommands = false; //
Serial.DecodeResponses = false; // For the duration of 2.5 seconds we will send Hello packages
this.Serial = Serial; // And also wait for incoming messages
} // An incoming message can be a response to our outgoing Hello packet (read incoming until "response value")
// Or it can be an incoming Hello-packet from the programmer (always 2 packets, starting with "Chip serial num")
public bool SendImage(string Path) // Sending the hello-packet can succeed immediately, or it can timeout.
{ // When sending succeeds, an answer should be incoming immediately to complete the handshake.
bool Result = true; // When an incoming Hello was received, the phone still expects to receive another Hello.
LogFile.Log("Sending programmer: " + Path, LogType.FileOnly); int HelloSendCount = 0;
bool HandshakeCompleted = false;
int Step = 0; string Incoming;
UInt32 Offset = 0; do
UInt32 Length = 0; {
Serial.SetTimeOut(200);
byte[] ImageBuffer = null; HelloSendCount++;
try try
{ {
Step = 1; LogFile.Log("Send Hello to programmer (" + HelloSendCount.ToString() + ")", LogType.FileOnly);
byte[] Hello = Serial.GetResponse(new byte[] { 0x01, 0x00, 0x00, 0x00 }); Serial.SendData(PacketFromPcToProgrammer);
LogFile.Log("Hello packet accepted", LogType.FileOnly);
// Incoming Hello packet: }
// 00000001 = Hello command id catch
// xxxxxxxx = Length {
// xxxxxxxx = Protocol version LogFile.Log("Hello packet not accepted", LogType.FileOnly);
// xxxxxxxx = Supported version }
// xxxxxxxx = Max packet length
// xxxxxxxx = Expected mode try
// 6 dwords reserved space {
LogFile.Log("Protocol: 0x" + ByteOperations.ReadUInt32(Hello, 0x08).ToString("X8"), LogType.FileOnly); Serial.SetTimeOut(500);
LogFile.Log("Supported: 0x" + ByteOperations.ReadUInt32(Hello, 0x0C).ToString("X8"), LogType.FileOnly); Incoming = Encoding.ASCII.GetString(Serial.GetResponse(null));
LogFile.Log("MaxLength: 0x" + ByteOperations.ReadUInt32(Hello, 0x10).ToString("X8"), LogType.FileOnly); LogFile.Log("In: " + Incoming, LogType.FileOnly);
LogFile.Log("Mode: 0x" + ByteOperations.ReadUInt32(Hello, 0x14).ToString("X8"), LogType.FileOnly); Serial.SetTimeOut(200);
if (Incoming.Contains("Chip serial num"))
// Packet: {
// 00000002 = Hello response command id Incoming = Encoding.ASCII.GetString(Serial.GetResponse(null));
// 00000030 = Length LogFile.Log("In: " + Incoming, LogType.FileOnly);
// 00000002 = Protocol version LogFile.Log("Incoming Hello-packets received", LogType.FileOnly);
// 00000001 = Supported version }
// 00000000 = Status OK
// 00000000 = Mode while (Incoming.IndexOf("response value") < 0)
// rest is reserved space {
Step = 2; Incoming = Encoding.ASCII.GetString(Serial.GetResponse(null));
byte[] HelloResponse = new byte[] { LogFile.Log("In: " + Incoming, LogType.FileOnly);
0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, }
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 LogFile.Log("Incoming Hello-response received", LogType.FileOnly);
};
Serial.SendData(HelloResponse); if (!Incoming.Contains("Failed to authenticate Digital Signature."))
{
Step = 3; HandshakeCompleted = true;
using FileStream FileStream = new(Path, FileMode.Open, FileAccess.Read); }
while (true) else
{ {
Step = 4; LogFile.Log("Programmer failed to authenticate Digital Signature", LogType.FileOnly);
byte[] ReadDataRequest = Serial.GetResponse(null); }
UInt32 ResponseID = ByteOperations.ReadUInt32(ReadDataRequest, 0); }
if (ResponseID == 4) catch (Exception ex)
{ {
break; LogFile.LogException(ex, LogType.FileOnly);
} }
}
if (ResponseID != 3) while (!HandshakeCompleted && (HelloSendCount < 6));
{
Step = 5; return HandshakeCompleted;
throw new BadConnectionException(); }
}
public bool ConnectToProgrammerInTestMode()
Offset = ByteOperations.ReadUInt32(ReadDataRequest, 0x0C); {
Length = ByteOperations.ReadUInt32(ReadDataRequest, 0x10); byte[] HelloPacketFromPcToProgrammer = new byte[0x20C];
if ((ImageBuffer == null) || (ImageBuffer.Length != Length)) ByteOperations.WriteUInt32(HelloPacketFromPcToProgrammer, 0, 0x57503730);
{ ByteOperations.WriteUInt32(HelloPacketFromPcToProgrammer, 0x28, 0x57503730);
ImageBuffer = new byte[Length]; ByteOperations.WriteUInt32(HelloPacketFromPcToProgrammer, 0x208, 0x57503730);
} ByteOperations.WriteUInt16(HelloPacketFromPcToProgrammer, 0x48, 0x4445);
if (FileStream.Position != Offset) bool HandshakeCompleted = ConnectToProgrammer(HelloPacketFromPcToProgrammer);
{
FileStream.Seek(Offset, SeekOrigin.Begin); if (HandshakeCompleted)
} {
LogFile.Log("Handshake completed with programmer in testmode", LogType.FileOnly);
Step = 6; }
FileStream.Read(ImageBuffer, 0, (int)Length); else
{
Step = 7; LogFile.Log("Handshake with programmer failed", LogType.FileOnly);
Serial.SendData(ImageBuffer); }
}
} return HandshakeCompleted;
catch (Exception Ex) }
{
LogFile.LogException(Ex, LogType.FileAndConsole, Step.ToString() + " 0x" + Offset.ToString("X8") + " 0x" + Length.ToString("X8")); public async Task<bool> Reset()
Result = false; {
} bool Connected = await Task.Run(() => ConnectToProgrammerInTestMode());
if (!Connected)
if (Result) {
{ return false;
LogFile.Log("Programmer loaded into phone memory", LogType.FileOnly); }
}
LogFile.Log("Rebooting phone", LogType.FileAndConsole);
return Result; const string Command03 = "<?xml version=\"1.0\" ?><data><power value=\"reset\"/></data>";
} LogFile.Log("Out: " + Command03, LogType.FileOnly);
Serial.SendData(Encoding.ASCII.GetBytes(Command03));
public bool Handshake()
{ string Incoming;
bool Result = true; do
{
try Incoming = Encoding.ASCII.GetString(Serial.GetResponse(null));
{ LogFile.Log("In: " + Incoming, LogType.FileOnly);
byte[] Hello = Serial.GetResponse(new byte[] { 0x01, 0x00, 0x00, 0x00 }); }
while (Incoming.IndexOf("response value") < 0);
// Incoming Hello packet:
// 00000001 = Hello command id // Workaround for problem
// xxxxxxxx = Length // SerialPort is sometimes not disposed correctly when the device is already removed.
// xxxxxxxx = Protocol version // So explicitly dispose here
// xxxxxxxx = Supported version Serial.Close();
// xxxxxxxx = Max packet length
// xxxxxxxx = Expected mode return true;
// 6 dwords reserved space }
LogFile.Log("Protocol: 0x" + ByteOperations.ReadUInt32(Hello, 0x08).ToString("X8"), LogType.FileOnly);
LogFile.Log("Supported: 0x" + ByteOperations.ReadUInt32(Hello, 0x0C).ToString("X8"), LogType.FileOnly); public bool SendEdPayload(string ProgrammerPath, string PayloadPath)
LogFile.Log("MaxLength: 0x" + ByteOperations.ReadUInt32(Hello, 0x10).ToString("X8"), LogType.FileOnly); {
LogFile.Log("Mode: 0x" + ByteOperations.ReadUInt32(Hello, 0x14).ToString("X8"), LogType.FileOnly); // First, let's read the Emergency Download payload header and verify its validity
FileStream PayloadStream = File.OpenRead(PayloadPath);
byte[] HelloResponse = new byte[] {
0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, byte[] ValidReferencePayloadHeader = [0x45, 0x6D, 0x65, 0x72, 0x67, 0x65, 0x6E, 0x63, 0x79, 0x20, 0x50, 0x61, 0x79, 0x6C, 0x6F, 0x61, 0x64];
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 byte[] PayloadHeader = new byte[17];
}; PayloadStream.Read(PayloadHeader, 0, 17);
byte[] Ready = Serial.SendCommand(HelloResponse, new byte[] { 0x03, 0x00, 0x00, 0x00 }); bool IsValidEdPayloadImage = StructuralComparisons.StructuralEqualityComparer.Equals(PayloadHeader, ValidReferencePayloadHeader);
} if (!IsValidEdPayloadImage)
catch {
{ return false;
Result = false; }
}
// Now let's read the information block
return Result; PayloadStream.Seek(0x64, SeekOrigin.Begin);
} byte[] PayloadInformationBlock = new byte[0x64];
public void ResetSahara() PayloadStream.Read(PayloadInformationBlock, 0, 0x64);
{ string buildtime = Encoding.ASCII.GetString(PayloadInformationBlock).Trim('\0');
Serial.SendCommand(new byte[] { 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00 }, new byte[] { 0x08, 0x00, 0x00, 0x00 });
} PayloadStream.Read(PayloadInformationBlock, 0, 0x64);
string builddate = Encoding.ASCII.GetString(PayloadInformationBlock).Trim('\0');
public bool ConnectToProgrammer(byte[] PacketFromPcToProgrammer)
{ PayloadStream.Read(PayloadInformationBlock, 0, 0x64);
// Behaviour of old firehose: string version = Encoding.ASCII.GetString(PayloadInformationBlock).Trim('\0');
// Takes about 20 ms to be started.
// Then PC has to start talking to the phone. PayloadInformationBlock = new byte[0x670];
// Behaviour of new firehose: PayloadStream.Read(PayloadInformationBlock, 0, 0x670);
// After 2000 ms the firehose starts talking to the PC string Info = Encoding.ASCII.GetString(PayloadInformationBlock).Trim('\0');
//
// For the duration of 2.5 seconds we will send Hello packages // Print some information about the payload
// And also wait for incoming messages LogFile.Log("Emerency flasher version 0.1", LogType.FileAndConsole);
// An incoming message can be a response to our outgoing Hello packet (read incoming until "response value") LogFile.Log("Programmer information:", LogType.FileAndConsole);
// Or it can be an incoming Hello-packet from the programmer (always 2 packets, starting with "Chip serial num") LogFile.Log("Build time: " + buildtime, LogType.FileAndConsole);
// Sending the hello-packet can succeed immediately, or it can timeout. LogFile.Log("Build date: " + builddate, LogType.FileAndConsole);
// When sending succeeds, an answer should be incoming immediately to complete the handshake. LogFile.Log("Version: " + version, LogType.FileAndConsole);
// When an incoming Hello was received, the phone still expects to receive another Hello. LogFile.Log("Info: " + Info, LogType.FileAndConsole);
int HelloSendCount = 0; // Wait a few seconds before sending commands
bool HandshakeCompleted = false; LogFile.Log("Waiting...", LogType.FileAndConsole);
string Incoming; Thread.Sleep(2000);
do LogFile.Log("Waiting...OK", LogType.FileAndConsole);
{
Serial.SetTimeOut(200); bool Terminated = false;
HelloSendCount++; bool Connected = false;
try bool ProgrammerRawMode = false;
{
LogFile.Log("Send Hello to programmer (" + HelloSendCount.ToString() + ")", LogType.FileOnly); string Incoming;
Serial.SendData(PacketFromPcToProgrammer);
LogFile.Log("Hello packet accepted", LogType.FileOnly); while (!Terminated)
} {
catch PayloadInformationBlock = new byte[0x200];
{ PayloadStream.Read(PayloadInformationBlock, 0, 0x200);
LogFile.Log("Hello packet not accepted", LogType.FileOnly); string ProgrammerCommand = Encoding.ASCII.GetString(PayloadInformationBlock.Skip(0xC).ToArray()).Trim('\0');
}
LogFile.Log(ProgrammerCommand, LogType.FileAndConsole);
try
{ byte[] PacketFromPcToProgrammer = [];
Serial.SetTimeOut(500); byte[] temp = new byte[0x200];
Incoming = Encoding.ASCII.GetString(Serial.GetResponse(null));
LogFile.Log("In: " + Incoming, LogType.FileOnly); while (true)
Serial.SetTimeOut(200); {
if (Incoming.Contains("Chip serial num")) if (PayloadStream.Position == PayloadStream.Length)
{ {
Incoming = Encoding.ASCII.GetString(Serial.GetResponse(null)); Terminated = true;
LogFile.Log("In: " + Incoming, LogType.FileOnly); break;
LogFile.Log("Incoming Hello-packets received", LogType.FileOnly); }
}
PayloadStream.Read(temp, 0, 0x200);
while (Incoming.IndexOf("response value") < 0)
{ if (temp[12] == 77 && temp[13] == 83 && temp[14] == 71 && temp[15] == 95)
Incoming = Encoding.ASCII.GetString(Serial.GetResponse(null)); {
LogFile.Log("In: " + Incoming, LogType.FileOnly); PayloadStream.Seek(-0x200, SeekOrigin.Current);
} break;
}
LogFile.Log("Incoming Hello-response received", LogType.FileOnly);
PacketFromPcToProgrammer = [.. PacketFromPcToProgrammer, .. temp];
if (!Incoming.Contains("Failed to authenticate Digital Signature.")) }
{
HandshakeCompleted = true; bool ExpectingReplyFromProgrammer = false;
}
else if (ProgrammerCommand.Contains("XML"))
{ {
LogFile.Log("Programmer failed to authenticate Digital Signature", LogType.FileOnly); string Outgoing = Encoding.ASCII.GetString(PacketFromPcToProgrammer).Trim('\0');
} PacketFromPcToProgrammer = Encoding.ASCII.GetBytes(Outgoing);
} LogFile.Log("Out: " + Outgoing, LogType.FileAndConsole);
catch { } }
}
while (!HandshakeCompleted && (HelloSendCount < 6)); if (!ProgrammerCommand.Contains("RAW_DATA") && !ProgrammerRawMode)
{
return HandshakeCompleted; ExpectingReplyFromProgrammer = true;
} }
public bool ConnectToProgrammerInTestMode() if (ProgrammerCommand.Contains("LAST") && ProgrammerRawMode)
{ {
byte[] HelloPacketFromPcToProgrammer = new byte[0x20C]; ExpectingReplyFromProgrammer = true;
ByteOperations.WriteUInt32(HelloPacketFromPcToProgrammer, 0, 0x57503730); }
ByteOperations.WriteUInt32(HelloPacketFromPcToProgrammer, 0x28, 0x57503730);
ByteOperations.WriteUInt32(HelloPacketFromPcToProgrammer, 0x208, 0x57503730); if (ProgrammerCommand.Contains("DATA_ALL") && ProgrammerRawMode)
ByteOperations.WriteUInt16(HelloPacketFromPcToProgrammer, 0x48, 0x4445); {
ExpectingReplyFromProgrammer = true;
bool HandshakeCompleted = ConnectToProgrammer(HelloPacketFromPcToProgrammer); }
if (HandshakeCompleted) if (ProgrammerCommand.Contains("RAW_DATA") && !ProgrammerRawMode)
{ {
LogFile.Log("Handshake completed with programmer in testmode", LogType.FileOnly); LogFile.Log("Phone is not in raw mode ON, leaving...", LogType.FileAndConsole);
}
else // Workaround for problem
{ // SerialPort is sometimes not disposed correctly when the device is already removed.
LogFile.Log("Handshake with programmer failed", LogType.FileOnly); // So explicitly dispose here
} Serial.Close();
return HandshakeCompleted; LogFile.Log("Phone has been emergency flashed unsuccessfully!", LogType.FileAndConsole);
} PayloadStream.Dispose();
public async Task<bool> Reset(string ProgrammerPath) return false;
{ }
bool SendImageResult = await Task.Run(() => SendImage(ProgrammerPath));
if (!SendImageResult) if (!ProgrammerCommand.Contains("RAW_DATA") && ProgrammerRawMode)
{ {
return false; LogFile.Log("Phone is not in raw mode ON, leaving...", LogType.FileAndConsole);
}
// Workaround for problem
await Task.Run(() => StartProgrammer()); // SerialPort is sometimes not disposed correctly when the device is already removed.
// So explicitly dispose here
bool Connected = await Task.Run(() => ConnectToProgrammerInTestMode()); Serial.Close();
if (!Connected)
{ LogFile.Log("Phone has been emergency flashed unsuccessfully!", LogType.FileAndConsole);
return false; PayloadStream.Dispose();
}
return false;
LogFile.Log("Rebooting phone", LogType.FileAndConsole); }
const string Command03 = "<?xml version=\"1.0\" ?><data><power value=\"reset\"/></data>";
LogFile.Log("Out: " + Command03, LogType.FileOnly); if (Connected)
Serial.SendData(Encoding.ASCII.GetBytes(Command03)); {
Serial.SendData(PacketFromPcToProgrammer);
string Incoming; }
do
{ if (ExpectingReplyFromProgrammer)
Incoming = Encoding.ASCII.GetString(Serial.GetResponse(null)); {
LogFile.Log("In: " + Incoming, LogType.FileOnly); if (!Connected)
} {
while (Incoming.IndexOf("response value") < 0); Connected = ConnectToProgrammer(PacketFromPcToProgrammer);
// Workaround for problem if (Connected)
// SerialPort is sometimes not disposed correctly when the device is already removed. {
// So explicitly dispose here LogFile.Log("Handshake completed with programmer in validated image programming (VIP) mode", LogType.FileAndConsole);
Serial.Close(); }
else
return true; {
} LogFile.Log("Handshake with programmer failed", LogType.FileAndConsole);
}
public void SwitchMode(SaharaMode Mode)
{ if (!Connected)
byte[] SwitchModeCommand = new byte[] { 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; {
ByteOperations.WriteUInt32(SwitchModeCommand, 8, (UInt32)Mode); LogFile.Log("Phone programmer is now ignoring us, leaving...", LogType.FileAndConsole);
byte[] ResponsePattern = null;
switch (Mode) // Workaround for problem
{ // SerialPort is sometimes not disposed correctly when the device is already removed.
case SaharaMode.ImageTransferPending: // So explicitly dispose here
ResponsePattern = new byte[] { 0x04, 0x00, 0x00, 0x00 }; Serial.Close();
break;
case SaharaMode.MemoryDebug: LogFile.Log("Phone has been emergency flashed unsuccessfully!", LogType.FileAndConsole);
ResponsePattern = new byte[] { 0x09, 0x00, 0x00, 0x00 }; PayloadStream.Dispose();
break;
case SaharaMode.Command: return false;
ResponsePattern = new byte[] { 0x0B, 0x00, 0x00, 0x00 }; }
break; }
} else
Serial.SendCommand(SwitchModeCommand, ResponsePattern); {
} do
{
public void StartProgrammer() Serial.SetTimeOut(500);
{ Incoming = Encoding.ASCII.GetString(Serial.GetResponse(null));
LogFile.Log("Starting programmer", LogType.FileAndConsole); Serial.SetTimeOut(200);
byte[] DoneCommand = new byte[] { 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00 }; LogFile.Log("In: " + Incoming, LogType.FileAndConsole);
bool Started = false; }
int count = 0; while (Incoming.IndexOf("response value") < 0);
do
{ if (Incoming.Contains("rawmode=\"false\""))
count++; {
try ProgrammerRawMode = false;
{ LogFile.Log("Raw mode: OFF", LogType.FileAndConsole);
byte[] DoneResponse = Serial.SendCommand(DoneCommand, new byte[] { 0x06, 0x00, 0x00, 0x00 }); }
Started = true;
} if (Incoming.Contains("rawmode=\"true\""))
catch (BadConnectionException) {
{ ProgrammerRawMode = true;
LogFile.Log("Problem while starting programmer. Attempting again.", LogType.FileAndConsole); LogFile.Log("Raw mode: ON", LogType.FileAndConsole);
} }
} while (!Started && count < 3);
if (count >= 3 && !Started) if (!Incoming.Contains("ACK"))
{ {
LogFile.Log("Maximum number of attempts to start the programmer exceeded.", LogType.FileAndConsole); LogFile.Log("Phone programmer is now ignoring us, leaving...", LogType.FileAndConsole);
throw new BadConnectionException();
} // Workaround for problem
LogFile.Log("Programmer being launched on phone", LogType.FileOnly); // SerialPort is sometimes not disposed correctly when the device is already removed.
} // So explicitly dispose here
Serial.Close();
public async Task<bool> SendEdPayload(string ProgrammerPath, string PayloadPath)
{ LogFile.Log("Phone has been emergency flashed unsuccessfully!", LogType.FileAndConsole);
// First, let's read the Emergency Download payload header and verify its validity PayloadStream.Dispose();
FileStream PayloadStream = File.OpenRead(PayloadPath);
return false;
byte[] ValidReferencePayloadHeader = new byte[] { 0x45, 0x6D, 0x65, 0x72, 0x67, 0x65, 0x6E, 0x63, 0x79, 0x20, 0x50, 0x61, 0x79, 0x6C, 0x6F, 0x61, 0x64 }; }
}
byte[] PayloadHeader = new byte[17]; }
PayloadStream.Read(PayloadHeader, 0, 17); }
bool IsValidEdPayloadImage = StructuralComparisons.StructuralEqualityComparer.Equals(PayloadHeader, ValidReferencePayloadHeader); // Workaround for problem
if (!IsValidEdPayloadImage) // SerialPort is sometimes not disposed correctly when the device is already removed.
{ // So explicitly dispose here
return false; Serial.Close();
}
LogFile.Log("Phone has been emergency flashed successfully!", LogType.FileAndConsole);
// Now let's read the information block PayloadStream.Dispose();
PayloadStream.Seek(0x64, SeekOrigin.Begin);
byte[] PayloadInformationBlock = new byte[0x64]; return true;
}
PayloadStream.Read(PayloadInformationBlock, 0, 0x64); }
string buildtime = Encoding.ASCII.GetString(PayloadInformationBlock).Trim('\0'); }
PayloadStream.Read(PayloadInformationBlock, 0, 0x64);
string builddate = Encoding.ASCII.GetString(PayloadInformationBlock).Trim('\0');
PayloadStream.Read(PayloadInformationBlock, 0, 0x64);
string version = Encoding.ASCII.GetString(PayloadInformationBlock).Trim('\0');
PayloadInformationBlock = new byte[0x670];
PayloadStream.Read(PayloadInformationBlock, 0, 0x670);
string Info = Encoding.ASCII.GetString(PayloadInformationBlock).Trim('\0');
// Print some information about the payload
LogFile.Log("Emerency flasher version 0.1", LogType.FileAndConsole);
LogFile.Log("Programmer information:", LogType.FileAndConsole);
LogFile.Log("Build time: " + buildtime, LogType.FileAndConsole);
LogFile.Log("Build date: " + builddate, LogType.FileAndConsole);
LogFile.Log("Version: " + version, LogType.FileAndConsole);
LogFile.Log("Info: " + Info, LogType.FileAndConsole);
// Send the emergency programmer to the phone
bool SendImageResult = await Task.Run(() => SendImage(ProgrammerPath));
if (!SendImageResult)
{
return false;
}
// Start the emergency programmer on the phone
await Task.Run(() => StartProgrammer());
// Wait a few seconds before sending commands
LogFile.Log("Waiting...", LogType.FileAndConsole);
Thread.Sleep(2000);
LogFile.Log("Waiting...OK", LogType.FileAndConsole);
bool Terminated = false;
bool Connected = false;
bool ProgrammerRawMode = false;
string Incoming;
while (!Terminated)
{
PayloadInformationBlock = new byte[0x200];
PayloadStream.Read(PayloadInformationBlock, 0, 0x200);
string ProgrammerCommand = Encoding.ASCII.GetString(PayloadInformationBlock.Skip(0xC).ToArray()).Trim('\0');
LogFile.Log(ProgrammerCommand, LogType.FileAndConsole);
byte[] PacketFromPcToProgrammer = Array.Empty<byte>();
byte[] temp = new byte[0x200];
while (true)
{
if (PayloadStream.Position == PayloadStream.Length)
{
Terminated = true;
break;
}
PayloadStream.Read(temp, 0, 0x200);
if (temp[12] == 77 && temp[13] == 83 && temp[14] == 71 && temp[15] == 95)
{
PayloadStream.Seek(-0x200, SeekOrigin.Current);
break;
}
PacketFromPcToProgrammer = PacketFromPcToProgrammer.Concat(temp).ToArray();
}
bool ExpectingReplyFromProgrammer = false;
if (ProgrammerCommand.Contains("XML"))
{
string Outgoing = Encoding.ASCII.GetString(PacketFromPcToProgrammer).Trim('\0');
PacketFromPcToProgrammer = Encoding.ASCII.GetBytes(Outgoing);
LogFile.Log("Out: " + Outgoing, LogType.FileAndConsole);
}
if (!ProgrammerCommand.Contains("RAW_DATA") && !ProgrammerRawMode)
{
ExpectingReplyFromProgrammer = true;
}
if (ProgrammerCommand.Contains("LAST") && ProgrammerRawMode)
{
ExpectingReplyFromProgrammer = true;
}
if (ProgrammerCommand.Contains("DATA_ALL") && ProgrammerRawMode)
{
ExpectingReplyFromProgrammer = true;
}
if (ProgrammerCommand.Contains("RAW_DATA") && !ProgrammerRawMode)
{
LogFile.Log("Phone is not in raw mode ON, leaving...", LogType.FileAndConsole);
// Workaround for problem
// SerialPort is sometimes not disposed correctly when the device is already removed.
// So explicitly dispose here
Serial.Close();
LogFile.Log("Phone has been emergency flashed unsuccessfully!", LogType.FileAndConsole);
PayloadStream.Dispose();
return false;
}
if (!ProgrammerCommand.Contains("RAW_DATA") && ProgrammerRawMode)
{
LogFile.Log("Phone is not in raw mode ON, leaving...", LogType.FileAndConsole);
// Workaround for problem
// SerialPort is sometimes not disposed correctly when the device is already removed.
// So explicitly dispose here
Serial.Close();
LogFile.Log("Phone has been emergency flashed unsuccessfully!", LogType.FileAndConsole);
PayloadStream.Dispose();
return false;
}
if (Connected)
{
Serial.SendData(PacketFromPcToProgrammer);
}
if (ExpectingReplyFromProgrammer)
{
if (!Connected)
{
Connected = ConnectToProgrammer(PacketFromPcToProgrammer);
if (Connected)
{
LogFile.Log("Handshake completed with programmer in validated image programming (VIP) mode", LogType.FileAndConsole);
}
else
{
LogFile.Log("Handshake with programmer failed", LogType.FileAndConsole);
}
if (!Connected)
{
LogFile.Log("Phone programmer is now ignoring us, leaving...", LogType.FileAndConsole);
// Workaround for problem
// SerialPort is sometimes not disposed correctly when the device is already removed.
// So explicitly dispose here
Serial.Close();
LogFile.Log("Phone has been emergency flashed unsuccessfully!", LogType.FileAndConsole);
PayloadStream.Dispose();
return false;
}
}
else
{
do
{
Serial.SetTimeOut(500);
Incoming = Encoding.ASCII.GetString(Serial.GetResponse(null));
Serial.SetTimeOut(200);
LogFile.Log("In: " + Incoming, LogType.FileAndConsole);
}
while (Incoming.IndexOf("response value") < 0);
if (Incoming.Contains("rawmode=\"false\""))
{
ProgrammerRawMode = false;
LogFile.Log("Raw mode: OFF", LogType.FileAndConsole);
}
if (Incoming.Contains("rawmode=\"true\""))
{
ProgrammerRawMode = true;
LogFile.Log("Raw mode: ON", LogType.FileAndConsole);
}
if (!Incoming.Contains("ACK"))
{
LogFile.Log("Phone programmer is now ignoring us, leaving...", LogType.FileAndConsole);
// Workaround for problem
// SerialPort is sometimes not disposed correctly when the device is already removed.
// So explicitly dispose here
Serial.Close();
LogFile.Log("Phone has been emergency flashed unsuccessfully!", LogType.FileAndConsole);
PayloadStream.Dispose();
return false;
}
}
}
}
// Workaround for problem
// SerialPort is sometimes not disposed correctly when the device is already removed.
// So explicitly dispose here
Serial.Close();
LogFile.Log("Phone has been emergency flashed successfully!", LogType.FileAndConsole);
PayloadStream.Dispose();
return true;
}
}
}
@@ -1,228 +1,224 @@
// 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"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // 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: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // 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 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.IO; using System.IO;
namespace WPinternals namespace WPinternals
{ {
internal enum FlashUnit internal enum FlashUnit
{ {
Bytes, Bytes,
Sectors Sectors
} }
internal class QualcommFlasher internal class QualcommFlasher
{ {
private readonly QualcommSerial Serial; private readonly QualcommSerial Serial;
public QualcommFlasher(QualcommSerial Serial) public QualcommFlasher(QualcommSerial Serial)
{ {
this.Serial = Serial; this.Serial = Serial;
} }
public void CloseSerial() public void CloseSerial()
{ {
Serial.Close(); Serial.Close();
} }
public void Hello() public void Hello()
{ {
byte[] Command = new byte[] byte[] Command =
{ [
0x01, // Hello command 0x01, // Hello command
0x51, 0x43, 0x4F, 0x4D, 0x20, 0x66, 0x61, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x6C, 0x6F, // "QCOM fast download protocol host" 0x51, 0x43, 0x4F, 0x4D, 0x20, 0x66, 0x61, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x6C, 0x6F, // "QCOM fast download protocol host"
0x61, 0x64, 0x20, 0x70, 0x72, 0x6F, 0x74, 0x6F, 0x63, 0x6F, 0x6C, 0x20, 0x68, 0x6F, 0x73, 0x74, 0x61, 0x64, 0x20, 0x70, 0x72, 0x6F, 0x74, 0x6F, 0x63, 0x6F, 0x6C, 0x20, 0x68, 0x6F, 0x73, 0x74,
0x02, 0x02,
0x02, // Protocol version - Must be at least 0x02 0x02, // Protocol version - Must be at least 0x02
0x01 0x01
}; ];
Serial.SendCommand(Command, new byte[] { 0x02 }); Serial.SendCommand(Command, [0x02]);
} }
public void SetSecurityMode(byte Mode) public void SetSecurityMode(byte Mode)
{ {
byte[] Command = new byte[2]; byte[] Command = [0x17, Mode];
Command[0] = 0x17;
Command[1] = Mode; Serial.SendCommand(Command, [0x18]);
}
Serial.SendCommand(Command, new byte[] { 0x18 });
} // Use PartitionID 0x21
public void OpenPartition(byte PartitionID)
// Use PartitionID 0x21 {
public void OpenPartition(byte PartitionID) byte[] Command = [0x1B, PartitionID];
{
byte[] Command = new byte[2]; Serial.SendCommand(Command, [0x1C]);
Command[0] = 0x1B; }
Command[1] = PartitionID;
public void ClosePartition()
Serial.SendCommand(Command, new byte[] { 0x1C }); {
} Serial.SendCommand([0x15], [0x16]);
}
public void ClosePartition()
{ public void Flash(UInt32 StartInBytes, Stream Data, UInt32 LengthInBytes = UInt32.MaxValue)
Serial.SendCommand(new byte[] { 0x15 }, new byte[] { 0x16 }); {
} Flash(StartInBytes, Data, null, null, LengthInBytes);
}
public void Flash(UInt32 StartInBytes, Stream Data, UInt32 LengthInBytes = UInt32.MaxValue)
{ public void Flash(UInt32 StartInBytes, Stream Data, Action<int, TimeSpan?> ProgressUpdateCallback, UInt32 LengthInBytes = UInt32.MaxValue)
Flash(StartInBytes, Data, null, null, LengthInBytes); {
} Flash(StartInBytes, Data, ProgressUpdateCallback, null, LengthInBytes);
}
public void Flash(UInt32 StartInBytes, Stream Data, Action<int, TimeSpan?> ProgressUpdateCallback, UInt32 LengthInBytes = UInt32.MaxValue)
{ public void Flash(UInt32 StartInBytes, Stream Data, ProgressUpdater UpdaterPerSector, UInt32 LengthInBytes = UInt32.MaxValue)
Flash(StartInBytes, Data, ProgressUpdateCallback, null, LengthInBytes); {
} Flash(StartInBytes, Data, null, UpdaterPerSector, LengthInBytes);
}
public void Flash(UInt32 StartInBytes, Stream Data, ProgressUpdater UpdaterPerSector, UInt32 LengthInBytes = UInt32.MaxValue)
{ public void Flash(UInt32 StartInBytes, Stream Data, Action<int, TimeSpan?> ProgressUpdateCallback, ProgressUpdater UpdaterPerSector, UInt32 LengthInBytes = UInt32.MaxValue)
Flash(StartInBytes, Data, null, UpdaterPerSector, LengthInBytes); {
} long Remaining = (LengthInBytes == UInt32.MaxValue) || (LengthInBytes > (Data.Length - Data.Position))
? Data.Length - Data.Position
public void Flash(UInt32 StartInBytes, Stream Data, Action<int, TimeSpan?> ProgressUpdateCallback, ProgressUpdater UpdaterPerSector, UInt32 LengthInBytes = UInt32.MaxValue) : LengthInBytes;
{ UInt32 CurrentLength;
long Remaining = (LengthInBytes == UInt32.MaxValue) || (LengthInBytes > (Data.Length - Data.Position)) byte[] Buffer = new byte[0x405];
? Data.Length - Data.Position byte[] ResponsePattern = new byte[5];
: LengthInBytes; byte[] FinalCommand;
UInt32 CurrentLength; Buffer[0] = 0x07;
byte[] Buffer = new byte[0x405]; ResponsePattern[0] = 0x08;
byte[] ResponsePattern = new byte[5]; UInt32 CurrentPosition = StartInBytes;
byte[] FinalCommand;
Buffer[0] = 0x07; ProgressUpdater Progress = UpdaterPerSector;
ResponsePattern[0] = 0x08; if ((Progress == null) && (ProgressUpdateCallback != null))
UInt32 CurrentPosition = StartInBytes; {
Progress = new ProgressUpdater(GetSectorCount((UInt64)Remaining), ProgressUpdateCallback);
ProgressUpdater Progress = UpdaterPerSector; }
if ((Progress == null) && (ProgressUpdateCallback != null))
{ while (Remaining > 0)
Progress = new ProgressUpdater(GetSectorCount((UInt64)Remaining), ProgressUpdateCallback); {
} System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentPosition), 0, Buffer, 1, 4); // Start is in bytes and in Little Endian (on Samsung devices start is in sectors!)
System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentPosition), 0, ResponsePattern, 1, 4); // Start is in bytes and in Little Endian (on Samsung devices start is in sectors!)
while (Remaining > 0)
{ CurrentLength = Remaining >= 0x400 ? 0x400 : (UInt32)Remaining;
System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentPosition), 0, Buffer, 1, 4); // Start is in bytes and in Little Endian (on Samsung devices start is in sectors!)
System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentPosition), 0, ResponsePattern, 1, 4); // Start is in bytes and in Little Endian (on Samsung devices start is in sectors!) CurrentLength = (uint)Data.Read(Buffer, 5, (int)CurrentLength);
CurrentLength = Remaining >= 0x400 ? 0x400 : (UInt32)Remaining; if (CurrentLength < 0x400)
{
CurrentLength = (uint)Data.Read(Buffer, 5, (int)CurrentLength); FinalCommand = new byte[CurrentLength + 5];
System.Buffer.BlockCopy(Buffer, 0, FinalCommand, 0, (int)CurrentLength + 5);
if (CurrentLength < 0x400) }
{ else
FinalCommand = new byte[CurrentLength + 5]; {
System.Buffer.BlockCopy(Buffer, 0, FinalCommand, 0, (int)CurrentLength + 5); FinalCommand = Buffer;
} }
else
{ Serial.SendCommand(FinalCommand, ResponsePattern);
FinalCommand = Buffer;
} CurrentPosition += CurrentLength;
Remaining -= CurrentLength;
Serial.SendCommand(FinalCommand, ResponsePattern);
Progress?.IncreaseProgress(GetSectorCount(CurrentLength));
CurrentPosition += CurrentLength; }
Remaining -= CurrentLength; }
Progress?.IncreaseProgress(GetSectorCount(CurrentLength)); public void Flash(UInt32 StartInBytes, byte[] Data, UInt32 OffsetInBytes = 0, UInt32 LengthInBytes = UInt32.MaxValue)
} {
} Flash(StartInBytes, Data, null, null, OffsetInBytes, LengthInBytes);
}
public void Flash(UInt32 StartInBytes, byte[] Data, UInt32 OffsetInBytes = 0, UInt32 LengthInBytes = UInt32.MaxValue)
{ public void Flash(UInt32 StartInBytes, byte[] Data, Action<int, TimeSpan?> ProgressUpdateCallback, UInt32 OffsetInBytes = 0, UInt32 LengthInBytes = UInt32.MaxValue)
Flash(StartInBytes, Data, null, null, OffsetInBytes, LengthInBytes); {
} Flash(StartInBytes, Data, ProgressUpdateCallback, null, OffsetInBytes, LengthInBytes);
}
public void Flash(UInt32 StartInBytes, byte[] Data, Action<int, TimeSpan?> ProgressUpdateCallback, UInt32 OffsetInBytes = 0, UInt32 LengthInBytes = UInt32.MaxValue)
{ public void Flash(UInt32 StartInBytes, byte[] Data, ProgressUpdater UpdaterPerSector, UInt32 OffsetInBytes = 0, UInt32 LengthInBytes = UInt32.MaxValue)
Flash(StartInBytes, Data, ProgressUpdateCallback, null, OffsetInBytes, LengthInBytes); {
} Flash(StartInBytes, Data, null, UpdaterPerSector, OffsetInBytes, LengthInBytes);
}
public void Flash(UInt32 StartInBytes, byte[] Data, ProgressUpdater UpdaterPerSector, UInt32 OffsetInBytes = 0, UInt32 LengthInBytes = UInt32.MaxValue)
{ public void Flash(UInt32 StartInBytes, byte[] Data, Action<int, TimeSpan?> ProgressUpdateCallback, ProgressUpdater UpdaterPerSector, UInt32 OffsetInBytes = 0, UInt32 LengthInBytes = UInt32.MaxValue)
Flash(StartInBytes, Data, null, UpdaterPerSector, OffsetInBytes, LengthInBytes); {
} long RemainingBytes;
if (OffsetInBytes > (Data.Length - 1))
public void Flash(UInt32 StartInBytes, byte[] Data, Action<int, TimeSpan?> ProgressUpdateCallback, ProgressUpdater UpdaterPerSector, UInt32 OffsetInBytes = 0, UInt32 LengthInBytes = UInt32.MaxValue) {
{ throw new ArgumentException("Wrong offset");
long RemainingBytes; }
if (OffsetInBytes > (Data.Length - 1))
{ RemainingBytes = (LengthInBytes == UInt32.MaxValue) || (LengthInBytes > (Data.Length - OffsetInBytes))
throw new ArgumentException("Wrong offset"); ? Data.Length - OffsetInBytes
} : LengthInBytes;
RemainingBytes = (LengthInBytes == UInt32.MaxValue) || (LengthInBytes > (Data.Length - OffsetInBytes)) UInt32 CurrentLength;
? Data.Length - OffsetInBytes UInt32 CurrentOffset = OffsetInBytes;
: LengthInBytes; byte[] Buffer = new byte[0x405];
byte[] ResponsePattern = new byte[5];
UInt32 CurrentLength; byte[] FinalCommand;
UInt32 CurrentOffset = OffsetInBytes; Buffer[0] = 0x07;
byte[] Buffer = new byte[0x405]; ResponsePattern[0] = 0x08;
byte[] ResponsePattern = new byte[5]; UInt32 CurrentPosition = StartInBytes;
byte[] FinalCommand;
Buffer[0] = 0x07; ProgressUpdater Progress = UpdaterPerSector;
ResponsePattern[0] = 0x08; if ((Progress == null) && (ProgressUpdateCallback != null))
UInt32 CurrentPosition = StartInBytes; {
Progress = new ProgressUpdater(GetSectorCount((UInt64)RemainingBytes), ProgressUpdateCallback);
ProgressUpdater Progress = UpdaterPerSector; }
if ((Progress == null) && (ProgressUpdateCallback != null))
{ while (RemainingBytes > 0)
Progress = new ProgressUpdater(GetSectorCount((UInt64)RemainingBytes), ProgressUpdateCallback); {
} System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentPosition), 0, Buffer, 1, 4); // Start position is in bytes and in Little Endian (on Samsung phones the start position is in Sectors!!)
System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentPosition), 0, ResponsePattern, 1, 4); // Start position is in bytes and in Little Endian (on Samsung phones the start position is in Sectors!!)
while (RemainingBytes > 0)
{ CurrentLength = RemainingBytes >= 0x400 ? 0x400 : (UInt32)RemainingBytes;
System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentPosition), 0, Buffer, 1, 4); // Start position is in bytes and in Little Endian (on Samsung phones the start position is in Sectors!!)
System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentPosition), 0, ResponsePattern, 1, 4); // Start position is in bytes and in Little Endian (on Samsung phones the start position is in Sectors!!) System.Buffer.BlockCopy(Data, (int)CurrentOffset, Buffer, 5, (int)CurrentLength);
CurrentLength = RemainingBytes >= 0x400 ? 0x400 : (UInt32)RemainingBytes; if (CurrentLength < 0x400)
{
System.Buffer.BlockCopy(Data, (int)CurrentOffset, Buffer, 5, (int)CurrentLength); FinalCommand = new byte[CurrentLength + 5];
System.Buffer.BlockCopy(Buffer, 0, FinalCommand, 0, (int)CurrentLength + 5);
if (CurrentLength < 0x400) }
{ else
FinalCommand = new byte[CurrentLength + 5]; {
System.Buffer.BlockCopy(Buffer, 0, FinalCommand, 0, (int)CurrentLength + 5); FinalCommand = Buffer;
} }
else
{ Serial.SendCommand(FinalCommand, ResponsePattern);
FinalCommand = Buffer;
} CurrentPosition += CurrentLength;
CurrentOffset += CurrentLength;
Serial.SendCommand(FinalCommand, ResponsePattern); RemainingBytes -= CurrentLength;
CurrentPosition += CurrentLength; Progress?.IncreaseProgress(GetSectorCount(CurrentLength));
CurrentOffset += CurrentLength; }
RemainingBytes -= CurrentLength; }
Progress?.IncreaseProgress(GetSectorCount(CurrentLength)); public UInt64 GetSectorCount(UInt64 ByteCount)
} {
} return (ByteCount / 0x200) + ((ByteCount % 0x200) > 0 ? 1 : (UInt64)0);
}
public UInt64 GetSectorCount(UInt64 ByteCount)
{ public void Reboot()
return (ByteCount / 0x200) + ((ByteCount % 0x200) > 0 ? 1 : (UInt64)0); {
} Serial.SendCommand([0x0B], [0x0C]);
}
public void Reboot() }
{ }
Serial.SendCommand(new byte[] { 0x0B }, new byte[] { 0x0C });
}
}
}
@@ -1,125 +1,138 @@
// 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"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // 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: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // 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 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
namespace WPinternals namespace WPinternals
{ {
internal static class QualcommLoaders internal static class QualcommLoaders
{ {
internal static List<QualcommPartition> GetPossibleLoadersForRootKeyHash(string Path, byte[] RootKeyHash) internal static List<QualcommPartition> GetPossibleLoadersForRootKeyHash(string Path, byte[] RootKeyHash)
{ {
List<QualcommPartition> Result = new(); List<QualcommPartition> Result = new();
try try
{ {
IEnumerable<string> FilePaths = Directory.EnumerateFiles(Path); foreach (string FilePath in Directory.EnumerateFiles(Path))
foreach (string FilePath in FilePaths) {
{ try
try {
{ FileInfo Info = new(FilePath);
FileInfo Info = new(FilePath); if (Info.Length <= 0x80000)
if (Info.Length <= 0x80000) {
{ QualcommPartition Loader;
QualcommPartition Loader;
#if DEBUG
#if DEBUG System.Diagnostics.Debug.Print("Evaluating loader: " + FilePath);
System.Diagnostics.Debug.Print("Evaluating loader: " + FilePath); #endif
#endif
byte[] Binary = ParseAsHexFile(FilePath);
byte[] Binary = ParseAsHexFile(FilePath); Loader = Binary == null ? new QualcommPartition(FilePath) : new QualcommPartition(Binary);
Loader = Binary == null ? new QualcommPartition(FilePath) : new QualcommPartition(Binary);
// Make sure the RootKeyHash is not blank
// Make sure the RootKeyHash is not blank // If the RootKeyHash is blank, this is an engineering device, and it will accept any RKH
// If the RootKeyHash is blank, this is an engineering device, and it will accept any RKH // We expect the user to know what he is doing in such case and we will ignore checks
// We expect the user to know what he is doing in such case and we will ignore checks if (!StructuralComparisons.StructuralEqualityComparer.Equals(RootKeyHash, new byte[RootKeyHash.Length]))
if (!StructuralComparisons.StructuralEqualityComparer.Equals(RootKeyHash, new byte[RootKeyHash.Length])) {
{ if (StructuralComparisons.StructuralEqualityComparer.Equals(Loader.RootKeyHash, RootKeyHash)
if (StructuralComparisons.StructuralEqualityComparer.Equals(Loader.RootKeyHash, RootKeyHash) && (ByteOperations.FindUnicode(Loader.Binary, "QHSUSB_ARMPRG") != null)) // To detect that this is a loader, and not SBL1 or something. V1 loaders are QHSUSB_ARMPRG. V2 loaders are QHSUSB__BULK. Only V1 supported for now, because V2 only accepts signed payload.
&& (ByteOperations.FindUnicode(Loader.Binary, "QHSUSB_ARMPRG") != null)) // To detect that this is a loader, and not SBL1 or something. V1 loaders are QHSUSB_ARMPRG. V2 loaders are QHSUSB__BULK. Only V1 supported for now, because V2 only accepts signed payload. {
{ Result.Add(Loader);
Result.Add(Loader); }
} }
} else
else {
{ if (ByteOperations.FindUnicode(Loader.Binary, "QHSUSB_ARMPRG") != null) // To detect that this is a loader, and not SBL1 or something. V1 loaders are QHSUSB_ARMPRG. V2 loaders are QHSUSB__BULK. Only V1 supported for now, because V2 only accepts signed payload.
if (ByteOperations.FindUnicode(Loader.Binary, "QHSUSB_ARMPRG") != null) // To detect that this is a loader, and not SBL1 or something. V1 loaders are QHSUSB_ARMPRG. V2 loaders are QHSUSB__BULK. Only V1 supported for now, because V2 only accepts signed payload. {
{ Result.Add(Loader);
Result.Add(Loader); }
} }
} }
} }
} catch (Exception ex)
catch { } {
} LogFile.LogException(ex, LogType.FileOnly);
} }
catch { } }
}
return Result; catch (Exception ex)
} {
LogFile.LogException(ex, LogType.FileOnly);
internal static byte[] ParseAsHexFile(string FilePath) }
{
byte[] Result = null; return Result;
}
try
{ internal static byte[] ParseAsHexFile(string FilePath)
string[] Lines = File.ReadAllLines(FilePath); {
byte[] Buffer = null; byte[] Result = null;
int BufferSize = 0;
try
foreach (string Line in Lines) {
{ string[] Lines = File.ReadAllLines(FilePath);
if (Line[0] != ':') byte[] Buffer = null;
{ int BufferSize = 0;
throw new BadImageFormatException();
} foreach (string Line in Lines)
{
byte[] LineBytes = Converter.ConvertStringToHex(Line[1..]); if (string.IsNullOrEmpty(Line))
{
if ((LineBytes[0] + 5) != LineBytes.Length) continue;
{ }
throw new BadImageFormatException();
} if (Line[0] != ':')
{
if (Buffer == null) throw new BadImageFormatException();
{ }
Buffer = new byte[0x40000];
} byte[] LineBytes = Converter.ConvertStringToHex(Line[1..]);
if (LineBytes[3] == 0) // This is mem data if ((LineBytes[0] + 5) != LineBytes.Length)
{ {
System.Buffer.BlockCopy(LineBytes, 4, Buffer, BufferSize, LineBytes[0]); throw new BadImageFormatException();
BufferSize += LineBytes[0]; }
}
} if (Buffer == null)
{
Result = new byte[BufferSize]; Buffer = new byte[0x40000];
System.Buffer.BlockCopy(Buffer, 0, Result, 0, BufferSize); }
}
catch { } if (LineBytes[3] == 0) // This is mem data
{
return Result; System.Buffer.BlockCopy(LineBytes, 4, Buffer, BufferSize, LineBytes[0]);
} BufferSize += LineBytes[0];
} }
} }
Result = new byte[BufferSize];
System.Buffer.BlockCopy(Buffer, 0, Result, 0, BufferSize);
}
catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
return Result;
}
}
}
@@ -1,174 +1,188 @@
// 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"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // 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: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // 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 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.IO; using System.Collections.Generic;
using System.Security.Cryptography; using System.IO;
using System.Security.Cryptography;
namespace WPinternals
{ namespace WPinternals
internal enum QualcommPartitionHeaderType {
{ internal enum QualcommPartitionHeaderType
Long, {
Short Long,
}; Short
};
internal class QualcommPartition
{ internal class QualcommPartition
internal byte[] Binary; {
internal uint HeaderOffset; internal byte[] Binary;
internal QualcommPartitionHeaderType HeaderType; internal uint HeaderOffset;
internal uint ImageOffset; internal QualcommPartitionHeaderType HeaderType;
internal uint ImageAddress; internal uint ImageOffset;
internal uint ImageSize; internal uint ImageAddress;
internal uint CodeSize; internal uint ImageSize;
internal uint SignatureAddress; internal uint CodeSize;
internal uint SignatureSize; internal uint SignatureAddress;
internal uint SignatureOffset; internal uint SignatureSize;
internal uint CertificatesAddress; internal uint SignatureOffset;
internal uint CertificatesSize; internal uint CertificatesAddress;
internal uint CertificatesOffset; internal uint CertificatesSize;
internal byte[] RootKeyHash = null; internal uint CertificatesOffset;
internal byte[] RootKeyHash = null;
internal QualcommPartition(string Path) : this(File.ReadAllBytes(Path)) { }
internal QualcommPartition(string Path) : this(File.ReadAllBytes(Path)) { }
internal QualcommPartition(byte[] Binary, uint Offset = 0)
{ internal QualcommPartition(byte[] Binary, uint Offset = 0)
#if DEBUG {
System.Diagnostics.Debug.Print("Loader: " + Converter.ConvertHexToString(new SHA256Managed().ComputeHash(Binary, 0, Binary.Length), "")); #if DEBUG
#endif System.Diagnostics.Debug.Print("Loader: " + Converter.ConvertHexToString(SHA256.HashData(Binary.AsSpan(0, Binary.Length)), ""));
#endif
this.Binary = Binary;
this.Binary = Binary;
byte[] LongHeaderPattern = new byte[] { 0xD1, 0xDC, 0x4B, 0x84, 0x34, 0x10, 0xD7, 0x73, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
byte[] LongHeaderMask = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; byte[] LongHeaderPattern = [0xD1, 0xDC, 0x4B, 0x84, 0x34, 0x10, 0xD7, 0x73, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
byte[] LongHeaderMask = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
if (ByteOperations.FindPattern(Binary, Offset, 4, new byte[] { 0x7F, 0x45, 0x4C, 0x46 }, new byte[] { 0x00, 0x00, 0x00, 0x00 }, null) == 0)
{ if (ByteOperations.FindPattern(Binary, Offset, 4, [0x7F, 0x45, 0x4C, 0x46], [0x00, 0x00, 0x00, 0x00], null) == 0)
// This is an ELF image {
// First program header is a reference to the elf-header // This is an ELF image
// Second program header is a reference to the signed hash-table // First program header is a reference to the elf-header
HeaderType = QualcommPartitionHeaderType.Short; // Second program header is a reference to the signed hash-table
UInt32 ProgramHeaderOffset; HeaderType = QualcommPartitionHeaderType.Short;
UInt16 ProgramHeaderEntrySize; UInt32 ProgramHeaderOffset;
UInt32 HashTableProgramHeaderOffset; UInt16 ProgramHeaderEntrySize;
if (Binary[Offset + 0x04] == 1) UInt32 HashTableProgramHeaderOffset;
{ if (Binary[Offset + 0x04] == 1)
// 32-bit elf image {
ProgramHeaderOffset = Offset + ByteOperations.ReadUInt32(Binary, Offset + 0x1c); // 32-bit elf image
ProgramHeaderEntrySize = ByteOperations.ReadUInt16(Binary, Offset + 0x2a); ProgramHeaderOffset = Offset + ByteOperations.ReadUInt32(Binary, Offset + 0x1c);
HashTableProgramHeaderOffset = ProgramHeaderOffset + ProgramHeaderEntrySize; ProgramHeaderEntrySize = ByteOperations.ReadUInt16(Binary, Offset + 0x2a);
ImageOffset = Offset + ByteOperations.ReadUInt32(Binary, HashTableProgramHeaderOffset + 0x04); HashTableProgramHeaderOffset = ProgramHeaderOffset + ProgramHeaderEntrySize;
HeaderOffset = ImageOffset + 8; ImageOffset = Offset + ByteOperations.ReadUInt32(Binary, HashTableProgramHeaderOffset + 0x04);
} HeaderOffset = ImageOffset + 8;
else if (Binary[Offset + 0x04] == 2) }
{ else if (Binary[Offset + 0x04] == 2)
// 64-bit elf image {
ProgramHeaderOffset = Offset + ByteOperations.ReadUInt32(Binary, Offset + 0x20); // 64-bit elf image
ProgramHeaderEntrySize = ByteOperations.ReadUInt16(Binary, Offset + 0x36); ProgramHeaderOffset = Offset + ByteOperations.ReadUInt32(Binary, Offset + 0x20);
HashTableProgramHeaderOffset = ProgramHeaderOffset + ProgramHeaderEntrySize; ProgramHeaderEntrySize = ByteOperations.ReadUInt16(Binary, Offset + 0x36);
ImageOffset = Offset + (UInt32)ByteOperations.ReadUInt64(Binary, HashTableProgramHeaderOffset + 0x08); HashTableProgramHeaderOffset = ProgramHeaderOffset + ProgramHeaderEntrySize;
HeaderOffset = ImageOffset + 8; ImageOffset = Offset + (UInt32)ByteOperations.ReadUInt64(Binary, HashTableProgramHeaderOffset + 0x08);
} HeaderOffset = ImageOffset + 8;
else }
{ else
throw new WPinternalsException("Invalid programmer", "The type of elf image could not be determined from the provided programmer."); {
} throw new WPinternalsException("Invalid programmer", "The type of elf image could not be determined from the provided programmer.");
} }
else if (ByteOperations.FindPattern(Binary, Offset, (uint)LongHeaderPattern.Length, LongHeaderPattern, LongHeaderMask, null) == null) }
{ else if (ByteOperations.FindPattern(Binary, Offset, (uint)LongHeaderPattern.Length, LongHeaderPattern, LongHeaderMask, null) == null)
HeaderType = QualcommPartitionHeaderType.Short; {
ImageOffset = Offset; HeaderType = QualcommPartitionHeaderType.Short;
HeaderOffset = ImageOffset + 8; ImageOffset = Offset;
} HeaderOffset = ImageOffset + 8;
else }
{ else
HeaderType = QualcommPartitionHeaderType.Long; {
ImageOffset = Offset; HeaderType = QualcommPartitionHeaderType.Long;
HeaderOffset = ImageOffset + (uint)LongHeaderPattern.Length; ImageOffset = Offset;
} HeaderOffset = ImageOffset + (uint)LongHeaderPattern.Length;
}
if (ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X00) != 0)
{ if (ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X00) != 0)
ImageOffset = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X00); {
} ImageOffset = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X00);
else if (HeaderType == QualcommPartitionHeaderType.Short) }
{ else if (HeaderType == QualcommPartitionHeaderType.Short)
ImageOffset += 0x28; {
} ImageOffset += 0x28;
else }
{ else
ImageOffset += 0x50; {
} ImageOffset += 0x50;
}
ImageAddress = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X04);
ImageSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X08); ImageAddress = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X04);
CodeSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X0C); ImageSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X08);
SignatureAddress = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X10); CodeSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X0C);
SignatureSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X14); SignatureAddress = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X10);
SignatureOffset = SignatureAddress - ImageAddress + ImageOffset; SignatureSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X14);
CertificatesAddress = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X18); SignatureOffset = SignatureAddress - ImageAddress + ImageOffset;
CertificatesSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X1C); CertificatesAddress = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X18);
CertificatesOffset = CertificatesAddress - ImageAddress + ImageOffset; CertificatesSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X1C);
CertificatesOffset = CertificatesAddress - ImageAddress + ImageOffset;
uint CurrentCertificateOffset = CertificatesOffset;
uint CertificateSize = 0; using MemoryStream fileStream = new(Binary);
while (CurrentCertificateOffset < (CertificatesOffset + CertificatesSize)) using BinaryReader reader = new(fileStream);
{
if ((Binary[CurrentCertificateOffset] == 0x30) && (Binary[CurrentCertificateOffset + 1] == 0x82)) List<byte[]> Signatures = [];
{ uint LastOffset = 0;
CertificateSize = (uint)(Binary[CurrentCertificateOffset + 2] * 0x100) + Binary[CurrentCertificateOffset + 3] + 4; // Big endian!
for (uint i = 0; i < fileStream.Length - 6; i++)
if ((CurrentCertificateOffset + CertificateSize) == (CertificatesOffset + CertificatesSize)) {
{ fileStream.Seek(i, SeekOrigin.Begin);
// This is the last certificate. So this is the root key.
RootKeyHash = new SHA256Managed().ComputeHash(Binary, (int)CurrentCertificateOffset, (int)CertificateSize); ushort offset0 = reader.ReadUInt16();
short offset1 = (short)((reader.ReadByte() << 8) | reader.ReadByte());
#if DEBUG ushort offset2 = reader.ReadUInt16();
System.Diagnostics.Debug.Print("RKH: " + Converter.ConvertHexToString(RootKeyHash, ""));
#endif if (offset0 == 0x8230 && offset1 >= 0 && offset2 == 0x8230)
} {
#if DEBUG uint CertificateSize = (uint)offset1 + 4; // Header Size is 4
else
{ bool IsCertificatePartOfExistingChain = LastOffset == 0 || LastOffset == i;
System.Diagnostics.Debug.Print("Cert: " + Converter.ConvertHexToString(new SHA256Managed().ComputeHash(Binary, (int)CurrentCertificateOffset, (int)CertificateSize), "")); if (!IsCertificatePartOfExistingChain)
} {
#endif break;
CurrentCertificateOffset += CertificateSize; }
}
else LastOffset = i + CertificateSize;
{
if ((RootKeyHash == null) && (CurrentCertificateOffset > CertificatesOffset)) fileStream.Seek(i, SeekOrigin.Begin);
{ Signatures.Add(reader.ReadBytes((int)CertificateSize));
CurrentCertificateOffset -= CertificateSize; }
}
// This is the last certificate. So this is the root key.
RootKeyHash = new SHA256Managed().ComputeHash(Binary, (int)CurrentCertificateOffset, (int)CertificateSize); if (Signatures.Count > 0)
{
#if DEBUG byte[] RootCertificate = Signatures[^1];
System.Diagnostics.Debug.Print("RKH: " + Converter.ConvertHexToString(RootKeyHash, ""));
#endif for (int i = 0; i < Signatures.Count; i++)
} {
break; if (i + 1 != Signatures.Count)
} {
} #if DEBUG
} System.Diagnostics.Debug.Print("Cert: " + Converter.ConvertHexToString(SHA256.HashData(Signatures[i]), ""));
} #endif
} }
else
{
// This is the last certificate. So this is the root key.
RootKeyHash = SHA256.HashData(Signatures[i]);
#if DEBUG
System.Diagnostics.Debug.Print("RKH: " + Converter.ConvertHexToString(RootKeyHash, ""));
#endif
}
}
}
}
}
}
+361
View File
@@ -0,0 +1,361 @@
// 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.Threading.Tasks;
namespace WPinternals
{
internal delegate void ReadyHandler();
internal class QualcommSahara
{
private readonly QualcommSerial Serial;
public QualcommSahara(QualcommSerial Serial)
{
Serial.EncodeCommands = false;
Serial.DecodeResponses = false;
this.Serial = Serial;
}
private static byte[] BuildCommandPacket(QualcommSaharaCommand SaharaCommand, byte[] CommandBuffer = null)
{
UInt32 CommandID = (uint)SaharaCommand;
UInt32 CommandBufferLength = 0;
if (CommandBuffer != null)
{
CommandBufferLength = (UInt32)CommandBuffer.Length;
}
UInt32 Length = 0x8u + CommandBufferLength;
byte[] Packet = new byte[Length];
ByteOperations.WriteUInt32(Packet, 0x00, CommandID);
ByteOperations.WriteUInt32(Packet, 0x04, Length);
if (CommandBuffer != null && CommandBufferLength != 0)
{
Buffer.BlockCopy(CommandBuffer, 0, Packet, 0x08, CommandBuffer.Length);
}
return Packet;
}
private static byte[] BuildHelloResponsePacket(QualcommSaharaMode SaharaMode, UInt32 ProtocolVersion = 2, UInt32 SupportedVersion = 1, UInt32 MaxPacketLength = 0 /* 0: Status OK */)
{
UInt32 Mode = (uint)SaharaMode;
// Hello packet:
// xxxxxxxx = Protocol version
// xxxxxxxx = Supported version
// xxxxxxxx = Max packet length
// xxxxxxxx = Expected mode
// 6 dwords reserved space
byte[] Hello = new byte[0x28];
ByteOperations.WriteUInt32(Hello, 0x00, ProtocolVersion);
ByteOperations.WriteUInt32(Hello, 0x04, SupportedVersion);
ByteOperations.WriteUInt32(Hello, 0x08, MaxPacketLength);
ByteOperations.WriteUInt32(Hello, 0x0C, Mode);
ByteOperations.WriteUInt32(Hello, 0x10, 0);
ByteOperations.WriteUInt32(Hello, 0x14, 0);
ByteOperations.WriteUInt32(Hello, 0x18, 0);
ByteOperations.WriteUInt32(Hello, 0x1C, 0);
ByteOperations.WriteUInt32(Hello, 0x20, 0);
ByteOperations.WriteUInt32(Hello, 0x24, 0);
return BuildCommandPacket(QualcommSaharaCommand.HelloResponse, Hello);
}
private static byte[] BuildExecuteRequestPacket(UInt32 RequestID)
{
byte[] Execute = new byte[0x04];
ByteOperations.WriteUInt32(Execute, 0x00, RequestID);
return BuildCommandPacket(QualcommSaharaCommand.ExecuteRequest, Execute);
}
private static byte[] BuildExecuteDataPacket(UInt32 RequestID)
{
byte[] Execute = new byte[0x04];
ByteOperations.WriteUInt32(Execute, 0x00, RequestID);
return BuildCommandPacket(QualcommSaharaCommand.ExecuteData, Execute);
}
public byte[][] GetRKHs()
{
Serial.SendData(BuildExecuteRequestPacket(0x3));
byte[] ReadDataRequest = Serial.GetResponse(null);
UInt32 ResponseID = ByteOperations.ReadUInt32(ReadDataRequest, 0);
if (ResponseID != 0xE)
{
throw new BadConnectionException();
}
uint RKHLength = ByteOperations.ReadUInt32(ReadDataRequest, 0x0C);
Serial.SendData(BuildExecuteDataPacket(0x3));
byte[] Response = Serial.GetResponse(null, Length: (int)RKHLength);
List<byte[]> RootKeyHashes = new();
for (int i = 0; i < RKHLength / 0x20; i++)
{
RootKeyHashes.Add(Response[(i * 0x20)..((i + 1) * 0x20)]);
}
return [.. RootKeyHashes];
}
public byte[] GetRKH()
{
int Step = 0;
UInt32 Offset = 0;
UInt32 Length = 0;
try
{
Step = 1;
byte[] Hello = Serial.GetResponse([0x01, 0x00, 0x00, 0x00]);
// Incoming Hello packet:
// 00000001 = Hello command id
// xxxxxxxx = Length
// xxxxxxxx = Protocol version
// xxxxxxxx = Supported version
// xxxxxxxx = Max packet length
// xxxxxxxx = Expected mode
// 6 dwords reserved space
LogFile.Log("Protocol: 0x" + ByteOperations.ReadUInt32(Hello, 0x08).ToString("X8"), LogType.FileOnly);
LogFile.Log("Supported: 0x" + ByteOperations.ReadUInt32(Hello, 0x0C).ToString("X8"), LogType.FileOnly);
LogFile.Log("MaxLength: 0x" + ByteOperations.ReadUInt32(Hello, 0x10).ToString("X8"), LogType.FileOnly);
LogFile.Log("Mode: 0x" + ByteOperations.ReadUInt32(Hello, 0x14).ToString("X8"), LogType.FileOnly);
Step = 2;
byte[] HelloResponse = BuildHelloResponsePacket(QualcommSaharaMode.Command);
Serial.SendData(HelloResponse);
Step = 3;
byte[] ReadDataRequest = Serial.GetResponse(null);
UInt32 ResponseID = ByteOperations.ReadUInt32(ReadDataRequest, 0);
if (ResponseID != 0xB)
{
throw new BadConnectionException();
}
Step = 4;
byte[][] RKHs = GetRKHs();
return RKHs[0];
}
catch (Exception Ex)
{
LogFile.LogException(Ex, LogType.FileAndConsole, Step.ToString() + " 0x" + Offset.ToString("X8") + " 0x" + Length.ToString("X8"));
}
return null;
}
public bool SendImage(string Path)
{
bool Result = true;
LogFile.Log("Sending programmer: " + Path, LogType.FileOnly);
int Step = 0;
UInt32 Offset = 0;
UInt32 Length = 0;
byte[] ImageBuffer = null;
try
{
Step = 1;
byte[] Hello = Serial.GetResponse([0x01, 0x00, 0x00, 0x00]);
// Incoming Hello packet:
// 00000001 = Hello command id
// xxxxxxxx = Length
// xxxxxxxx = Protocol version
// xxxxxxxx = Supported version
// xxxxxxxx = Max packet length
// xxxxxxxx = Expected mode
// 6 dwords reserved space
LogFile.Log("Protocol: 0x" + ByteOperations.ReadUInt32(Hello, 0x08).ToString("X8"), LogType.FileOnly);
LogFile.Log("Supported: 0x" + ByteOperations.ReadUInt32(Hello, 0x0C).ToString("X8"), LogType.FileOnly);
LogFile.Log("MaxLength: 0x" + ByteOperations.ReadUInt32(Hello, 0x10).ToString("X8"), LogType.FileOnly);
LogFile.Log("Mode: 0x" + ByteOperations.ReadUInt32(Hello, 0x14).ToString("X8"), LogType.FileOnly);
Step = 2;
byte[] HelloResponse = BuildHelloResponsePacket(QualcommSaharaMode.ImageTransferPending);
Serial.SendData(HelloResponse);
Step = 3;
using FileStream FileStream = new(Path, FileMode.Open, FileAccess.Read);
while (true)
{
Step = 4;
byte[] ReadDataRequest = Serial.GetResponse(null);
UInt32 ResponseID = ByteOperations.ReadUInt32(ReadDataRequest, 0);
if (ResponseID == 4)
{
break;
}
if (ResponseID != 3)
{
Step = 5;
throw new BadConnectionException();
}
Offset = ByteOperations.ReadUInt32(ReadDataRequest, 0x0C);
Length = ByteOperations.ReadUInt32(ReadDataRequest, 0x10);
if ((ImageBuffer == null) || (ImageBuffer.Length != Length))
{
ImageBuffer = new byte[Length];
}
if (FileStream.Position != Offset)
{
FileStream.Seek(Offset, SeekOrigin.Begin);
}
Step = 6;
FileStream.Read(ImageBuffer, 0, (int)Length);
Step = 7;
Serial.SendData(ImageBuffer);
}
}
catch (Exception Ex)
{
LogFile.LogException(Ex, LogType.FileAndConsole, Step.ToString() + " 0x" + Offset.ToString("X8") + " 0x" + Length.ToString("X8"));
Result = false;
}
if (Result)
{
LogFile.Log("Programmer loaded into phone memory", LogType.FileOnly);
}
return Result;
}
public bool Handshake()
{
bool Result = true;
try
{
byte[] Hello = Serial.GetResponse([0x01, 0x00, 0x00, 0x00]);
// Incoming Hello packet:
// 00000001 = Hello command id
// xxxxxxxx = Length
// xxxxxxxx = Protocol version
// xxxxxxxx = Supported version
// xxxxxxxx = Max packet length
// xxxxxxxx = Expected mode
// 6 dwords reserved space
LogFile.Log("Protocol: 0x" + ByteOperations.ReadUInt32(Hello, 0x08).ToString("X8"), LogType.FileOnly);
LogFile.Log("Supported: 0x" + ByteOperations.ReadUInt32(Hello, 0x0C).ToString("X8"), LogType.FileOnly);
LogFile.Log("MaxLength: 0x" + ByteOperations.ReadUInt32(Hello, 0x10).ToString("X8"), LogType.FileOnly);
LogFile.Log("Mode: 0x" + ByteOperations.ReadUInt32(Hello, 0x14).ToString("X8"), LogType.FileOnly);
byte[] HelloResponse = BuildHelloResponsePacket(QualcommSaharaMode.ImageTransferPending);
byte[] Ready = Serial.SendCommand(HelloResponse, [0x03, 0x00, 0x00, 0x00]);
}
catch
{
Result = false;
}
return Result;
}
public void ResetSahara()
{
Serial.SendCommand(BuildCommandPacket(QualcommSaharaCommand.ResetRequest), [0x08, 0x00, 0x00, 0x00]);
}
public void SwitchMode(QualcommSaharaMode Mode)
{
byte[] SwitchMode = new byte[0x04];
ByteOperations.WriteUInt32(SwitchMode, 0x00, (UInt32)Mode);
byte[] SwitchModeCommand = BuildCommandPacket(QualcommSaharaCommand.SwitchMode, SwitchMode);
byte[] ResponsePattern = null;
switch (Mode)
{
case QualcommSaharaMode.ImageTransferPending:
ResponsePattern = [0x04, 0x00, 0x00, 0x00];
break;
case QualcommSaharaMode.MemoryDebug:
ResponsePattern = [0x09, 0x00, 0x00, 0x00];
break;
case QualcommSaharaMode.Command:
ResponsePattern = [0x0B, 0x00, 0x00, 0x00];
break;
}
Serial.SendCommand(SwitchModeCommand, ResponsePattern);
}
public void StartProgrammer()
{
LogFile.Log("Starting programmer", LogType.FileAndConsole);
byte[] DoneCommand = BuildCommandPacket(QualcommSaharaCommand.DoneRequest);
bool Started = false;
int count = 0;
do
{
count++;
try
{
byte[] DoneResponse = Serial.SendCommand(DoneCommand, [0x06, 0x00, 0x00, 0x00]);
Started = true;
}
catch (BadConnectionException)
{
LogFile.Log("Problem while starting programmer. Attempting again.", LogType.FileAndConsole);
}
} while (!Started && count < 3);
if (count >= 3 && !Started)
{
LogFile.Log("Maximum number of attempts to start the programmer exceeded.", LogType.FileAndConsole);
throw new BadConnectionException();
}
LogFile.Log("Programmer being launched on phone", LogType.FileOnly);
}
public async Task<bool> LoadProgrammer(string ProgrammerPath)
{
bool SendImageResult = await Task.Run(() => SendImage(ProgrammerPath));
if (!SendImageResult)
{
return false;
}
await Task.Run(() => StartProgrammer());
return true;
}
}
}
@@ -0,0 +1,45 @@
// 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.
namespace WPinternals
{
internal enum QualcommSaharaCommand : uint
{
HelloRequest = 0x01,
HelloResponse = 0x02,
ReadData = 0x03,
EndTransfer = 0x04,
DoneRequest = 0x05,
DoneResponse = 0x06,
ResetRequest = 0x07,
ResetResponse = 0x08,
MemoryDebug = 0x09,
MemoryRead = 0x0A,
CommandReady = 0x0B,
SwitchMode = 0x0C,
ExecuteRequest = 0x0D,
ExecuteResponse = 0x0E,
ExecuteData = 0x0F,
MemoryDebug64 = 0x10,
MemoryRead64 = 0x11,
MemoryReadData64 = 0x12,
ResetStateMachineIdentifier = 0x13
}
}
+30
View File
@@ -0,0 +1,30 @@
// 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.
namespace WPinternals
{
internal enum QualcommSaharaMode : uint
{
ImageTransferPending = 0x00,
ImagetransferComplete = 0x01,
MemoryDebug = 0x02,
Command = 0x03
}
}
@@ -1,379 +1,385 @@
// 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"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // 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: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // 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 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using MadWizard.WinUSBNet; using MadWizard.WinUSBNet;
using System; using System;
using System.IO.Ports; using System.IO.Ports;
namespace WPinternals namespace WPinternals
{ {
internal class QualcommSerial : IDisposable internal class QualcommSerial : IDisposable
{ {
private bool Disposed = false; private bool Disposed = false;
private readonly SerialPort Port = null; private readonly SerialPort Port = null;
private readonly USBDevice USBDevice = null; private readonly USBDevice USBDevice = null;
private readonly CRC16 CRC16; private readonly CRC16 CRC16;
public bool EncodeCommands = true; public bool EncodeCommands = true;
public bool DecodeResponses = true; public bool DecodeResponses = true;
public QualcommSerial(string DevicePath) public QualcommSerial(string DevicePath)
{ {
CRC16 = new CRC16(0x1189, 0xFFFF, 0xFFFF); CRC16 = new CRC16(0x1189, 0xFFFF, 0xFFFF);
string[] DevicePathElements = DevicePath.Split(new char[] { '#' }); string[] DevicePathElements = DevicePath.Split(['#']);
if (string.Equals(DevicePathElements[3], "{86E0D1E0-8089-11D0-9CE4-08003E301F73}", StringComparison.CurrentCultureIgnoreCase)) if (string.Equals(DevicePathElements[3], "{86E0D1E0-8089-11D0-9CE4-08003E301F73}", StringComparison.CurrentCultureIgnoreCase))
{ {
string PortName = (string)Microsoft.Win32.Registry.GetValue(@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\" + DevicePathElements[1] + @"\" + DevicePathElements[2] + @"\Device Parameters", "PortName", null); string PortName = (string)Microsoft.Win32.Registry.GetValue(@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\" + DevicePathElements[1] + @"\" + DevicePathElements[2] + @"\Device Parameters", "PortName", null);
if (PortName != null) if (PortName != null)
{ {
Port = new SerialPort(PortName, 115200) Port = new SerialPort(PortName, 115200)
{ {
ReadTimeout = 1000, ReadTimeout = 1000,
WriteTimeout = 1000 WriteTimeout = 1000
}; };
Port.Open(); Port.Open();
} }
} }
else else
{ {
try try
{ {
this.USBDevice = new USBDevice(DevicePath); this.USBDevice = new USBDevice(DevicePath);
} }
catch { } catch (Exception ex)
} {
} LogFile.LogException(ex, LogType.FileOnly);
}
public void SendData(byte[] Data) }
{ }
byte[] FormattedData = EncodeCommands ? FormatCommand(Data) : Data;
Port?.Write(FormattedData, 0, FormattedData.Length); public void SendData(byte[] Data)
if (USBDevice != null) {
{ byte[] FormattedData = EncodeCommands ? FormatCommand(Data) : Data;
USBDevice.OutputPipe.Write(FormattedData); Port?.Write(FormattedData, 0, FormattedData.Length);
} if (USBDevice != null)
} {
USBDevice.OutputPipe.Write(FormattedData);
public byte[] SendCommand(byte[] Command, byte[] ResponsePattern) }
{ }
byte[] FormattedCommand = EncodeCommands ? FormatCommand(Command) : Command;
Port?.Write(FormattedCommand, 0, FormattedCommand.Length); public byte[] SendCommand(byte[] Command, byte[] ResponsePattern)
if (USBDevice != null) {
{ byte[] FormattedCommand = EncodeCommands ? FormatCommand(Command) : Command;
USBDevice.OutputPipe.Write(FormattedCommand); Port?.Write(FormattedCommand, 0, FormattedCommand.Length);
} if (USBDevice != null)
{
return GetResponse(ResponsePattern); USBDevice.OutputPipe.Write(FormattedCommand);
} }
internal byte[] GetResponse(byte[] ResponsePattern) return GetResponse(ResponsePattern);
{ }
byte[] ResponseBuffer = new byte[0x2000];
int Length = 0; internal byte[] GetResponse(byte[] ResponsePattern, int Length = 0x2000)
bool IsIncomplete = false; {
byte[] ResponseBuffer = new byte[Length];
do Length = 0;
{ bool IsIncomplete = false;
IsIncomplete = false;
do
try {
{ IsIncomplete = false;
int BytesRead = 0;
try
if (Port != null) {
{ int BytesRead = 0;
BytesRead = Port.Read(ResponseBuffer, Length, ResponseBuffer.Length - Length);
} if (Port != null)
{
if (USBDevice != null) BytesRead = Port.Read(ResponseBuffer, Length, ResponseBuffer.Length - Length);
{ }
BytesRead = USBDevice.InputPipe.Read(ResponseBuffer);
} if (USBDevice != null)
{
if (BytesRead == 0) BytesRead = USBDevice.InputPipe.Read(ResponseBuffer);
{ }
LogFile.Log("Emergency mode of phone is ignoring us", LogType.FileAndConsole);
throw new BadMessageException(); if (BytesRead == 0)
} {
LogFile.Log("Emergency mode of phone is ignoring us", LogType.FileAndConsole);
Length += BytesRead; throw new BadMessageException();
byte[] DecodedResponse; }
if (DecodeResponses)
{ Length += BytesRead;
DecodedResponse = DecodeResponse(ResponseBuffer, (UInt32)Length); byte[] DecodedResponse;
} if (DecodeResponses)
else {
{ DecodedResponse = DecodeResponse(ResponseBuffer, (UInt32)Length);
DecodedResponse = new byte[Length]; }
Buffer.BlockCopy(ResponseBuffer, 0, DecodedResponse, 0, Length); else
} {
DecodedResponse = new byte[Length];
if (ResponsePattern != null) Buffer.BlockCopy(ResponseBuffer, 0, DecodedResponse, 0, Length);
{ }
for (int i = 0; i < ResponsePattern.Length; i++)
{ if (ResponsePattern != null)
if (DecodedResponse[i] != ResponsePattern[i]) {
{ for (int i = 0; i < ResponsePattern.Length; i++)
byte[] LogResponse = new byte[DecodedResponse.Length < 0x10 ? DecodedResponse.Length : 0x10]; {
LogFile.Log("Qualcomm serial response: " + Converter.ConvertHexToString(LogResponse, ""), LogType.FileOnly); if (DecodedResponse[i] != ResponsePattern[i])
LogFile.Log("Expected: " + Converter.ConvertHexToString(ResponsePattern, ""), LogType.FileOnly); {
throw new BadMessageException(); byte[] LogResponse = new byte[DecodedResponse.Length < 0x10 ? DecodedResponse.Length : 0x10];
} LogFile.Log("Qualcomm serial response: " + Converter.ConvertHexToString(LogResponse, ""), LogType.FileOnly);
} LogFile.Log("Expected: " + Converter.ConvertHexToString(ResponsePattern, ""), LogType.FileOnly);
} throw new BadMessageException();
}
return DecodedResponse; }
} }
catch (IncompleteMessageException)
{ return DecodedResponse;
IsIncomplete = true; }
} catch (IncompleteMessageException)
catch { } // Will be rethrown as BadConnectionException {
} IsIncomplete = true;
while (IsIncomplete); }
catch (Exception ex) // Will be rethrown as BadConnectionException
Port?.DiscardInBuffer(); {
if (USBDevice != null) LogFile.LogException(ex, LogType.FileOnly);
{ }
USBDevice.InputPipe.Flush(); }
} while (IsIncomplete);
throw new BadConnectionException(); Port?.DiscardInBuffer();
} if (USBDevice != null)
{
private byte[] FormatCommand(byte[] Command) USBDevice.InputPipe.Flush();
{ }
if ((Command == null) || (Command.Length == 0))
{ throw new BadConnectionException();
throw new BadMessageException(); }
}
private byte[] FormatCommand(byte[] Command)
byte[] Decoded = new byte[(Command.Length * 2) + 4]; {
int Length = 0; if ((Command == null) || (Command.Length == 0))
{
Decoded[Length++] = 0x7E; throw new BadMessageException();
}
for (int i = 0; i < Command.Length; i++)
{ byte[] Decoded = new byte[(Command.Length * 2) + 4];
if ((Command[i] == 0x7D) || (Command[i] == 0x7E)) int Length = 0;
{
Decoded[Length++] = 0x7D; Decoded[Length++] = 0x7E;
Decoded[Length++] = (byte)(Command[i] ^ 0x20);
} for (int i = 0; i < Command.Length; i++)
else {
{ if ((Command[i] == 0x7D) || (Command[i] == 0x7E))
Decoded[Length++] = Command[i]; {
} Decoded[Length++] = 0x7D;
} Decoded[Length++] = (byte)(Command[i] ^ 0x20);
}
UInt16 Checksum = CRC16.CalculateChecksum(Command); else
if (((byte)(Checksum & 0xFF) == 0x7D) || ((byte)(Checksum & 0xFF) == 0x7E)) {
{ Decoded[Length++] = Command[i];
Decoded[Length++] = 0x7D; }
Decoded[Length++] = (byte)((Checksum & 0xFF) ^ 0x20); }
}
else UInt16 Checksum = CRC16.CalculateChecksum(Command);
{ if (((byte)(Checksum & 0xFF) == 0x7D) || ((byte)(Checksum & 0xFF) == 0x7E))
Decoded[Length++] = (byte)(Checksum & 0xFF); {
} Decoded[Length++] = 0x7D;
Decoded[Length++] = (byte)((Checksum & 0xFF) ^ 0x20);
if (((byte)(Checksum >> 8) == 0x7D) || ((byte)(Checksum >> 8) == 0x7E)) }
{ else
Decoded[Length++] = 0x7D; {
Decoded[Length++] = (byte)((Checksum >> 8) ^ 0x20); Decoded[Length++] = (byte)(Checksum & 0xFF);
} }
else
{ if (((byte)(Checksum >> 8) == 0x7D) || ((byte)(Checksum >> 8) == 0x7E))
Decoded[Length++] = (byte)(Checksum >> 8); {
} Decoded[Length++] = 0x7D;
Decoded[Length++] = (byte)((Checksum >> 8) ^ 0x20);
Decoded[Length++] = 0x7E; }
else
if (Length > 0) {
{ Decoded[Length++] = (byte)(Checksum >> 8);
byte[] Result = new byte[Length]; }
Buffer.BlockCopy(Decoded, 0, Result, 0, Length);
return Result; Decoded[Length++] = 0x7E;
}
else if (Length > 0)
{ {
return null; byte[] Result = new byte[Length];
} Buffer.BlockCopy(Decoded, 0, Result, 0, Length);
} return Result;
}
private byte[] DecodeResponse(byte[] Response, UInt32 Length) else
{ {
if ((Response == null) || (Response.Length == 0) || (Response[0] != 0x7E)) return null;
{ }
throw new BadMessageException(); }
}
private byte[] DecodeResponse(byte[] Response, UInt32 Length)
UInt32 SourceLength = Length; {
Length = 0; if ((Response == null) || (Response.Length == 0) || (Response[0] != 0x7E))
UInt32 SourcePos = 1; {
throw new BadMessageException();
byte[] Message = new byte[SourceLength]; }
while (SourcePos < SourceLength) UInt32 SourceLength = Length;
{ Length = 0;
if (Response[SourcePos] == 0x7E) UInt32 SourcePos = 1;
{
break; byte[] Message = new byte[SourceLength];
}
while (SourcePos < SourceLength)
Message[Length++] = Response[SourcePos] == 0x7D ? (byte)(Response[++SourcePos] ^ 0x20) : Response[SourcePos]; {
if (Response[SourcePos] == 0x7E)
SourcePos++; {
} break;
}
if (SourcePos == SourceLength)
{ Message[Length++] = Response[SourcePos] == 0x7D ? (byte)(Response[++SourcePos] ^ 0x20) : Response[SourcePos];
throw new IncompleteMessageException();
} SourcePos++;
}
if (Length < 3)
{ if (SourcePos == SourceLength)
throw new BadMessageException(); {
} throw new IncompleteMessageException();
}
byte[] TrimmedMessage = new byte[Length - 2];
Buffer.BlockCopy(Message, 0, TrimmedMessage, 0, (int)(Length - 2)); if (Length < 3)
{
UInt16 Checksum = CRC16.CalculateChecksum(TrimmedMessage); throw new BadMessageException();
if (((byte)(Checksum & 0xFF) != Message[Length - 2]) || ((byte)(Checksum >> 8) != Message[Length - 1])) }
{
throw new BadMessageException(); byte[] TrimmedMessage = new byte[Length - 2];
} Buffer.BlockCopy(Message, 0, TrimmedMessage, 0, (int)(Length - 2));
return TrimmedMessage; UInt16 Checksum = CRC16.CalculateChecksum(TrimmedMessage);
} if (((byte)(Checksum & 0xFF) != Message[Length - 2]) || ((byte)(Checksum >> 8) != Message[Length - 1]))
{
public void Dispose() throw new BadMessageException();
{ }
Dispose(true);
GC.SuppressFinalize(this); return TrimmedMessage;
} }
~QualcommSerial() public void Dispose()
{ {
Dispose(false); Dispose(true);
} GC.SuppressFinalize(this);
}
public void Close()
{ ~QualcommSerial()
Port?.Close(); {
USBDevice?.Dispose(); Dispose(false);
} }
protected virtual void Dispose(bool disposing) public void Close()
{ {
if (Disposed) Port?.Close();
{ USBDevice?.Dispose();
return; }
}
protected virtual void Dispose(bool disposing)
if (disposing) {
{ if (Disposed)
// Other disposables {
} return;
}
// Clean unmanaged resources here.
Close(); if (disposing)
{
Disposed = true; // Other disposables
} }
internal void SetTimeOut(int v) // Clean unmanaged resources here.
{ Close();
if (USBDevice != null)
{ Disposed = true;
USBDevice.ControlPipeTimeout = v; }
}
internal void SetTimeOut(int v)
if (Port != null) {
{ if (USBDevice != null)
Port.ReadTimeout = v; {
Port.WriteTimeout = v; USBDevice.ControlPipeTimeout = v;
} }
}
} if (Port != null)
{
public class IncompleteMessageException : Exception { public IncompleteMessageException() { } public IncompleteMessageException(string message) : base(message) { } public IncompleteMessageException(string message, Exception innerException) : base(message, innerException) { } } Port.ReadTimeout = v;
public class BadMessageException : Exception { public BadMessageException() { } public BadMessageException(string message) : base(message) { } public BadMessageException(string message, Exception innerException) : base(message, innerException) { } } Port.WriteTimeout = v;
public class BadConnectionException : Exception { public BadConnectionException() { } public BadConnectionException(string message) : base(message) { } public BadConnectionException(string message, Exception innerException) : base(message, innerException) { } } }
}
public class CRC16 }
{
private readonly UInt16[] ChecksumTable = public class IncompleteMessageException : Exception { public IncompleteMessageException() { } public IncompleteMessageException(string message) : base(message) { } public IncompleteMessageException(string message, Exception innerException) : base(message, innerException) { } }
new UInt16[] { public class BadMessageException : Exception { public BadMessageException() { } public BadMessageException(string message) : base(message) { } public BadMessageException(string message, Exception innerException) : base(message, innerException) { } }
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, public class BadConnectionException : Exception { public BadConnectionException() { } public BadConnectionException(string message) : base(message) { } public BadConnectionException(string message, Exception innerException) : base(message, innerException) { } }
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, public class CRC16
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, {
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, private readonly UInt16[] ChecksumTable =
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, [
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
}; 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
private readonly UInt16 Seed, FinalXor; 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
public CRC16(UInt16 Polynomial, UInt16 Seed, UInt16 FinalXor) 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
{ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
this.Seed = Seed; ];
this.FinalXor = FinalXor;
} private readonly UInt16 Seed, FinalXor;
public UInt16 CalculateChecksum(byte[] Bytes) public CRC16(UInt16 Polynomial, UInt16 Seed, UInt16 FinalXor)
{ {
UInt16 Crc = Seed; this.Seed = Seed;
for (int i = 0; i < Bytes.Length; ++i) this.FinalXor = FinalXor;
{ }
Crc = (UInt16)((Crc >> 8) ^ ChecksumTable[(byte)(Crc ^ Bytes[i])]); // Qualcomm implementation
} public UInt16 CalculateChecksum(byte[] Bytes)
return (UInt16)(Crc ^ FinalXor); {
} UInt16 Crc = Seed;
} for (int i = 0; i < Bytes.Length; ++i)
} {
Crc = (UInt16)((Crc >> 8) ^ ChecksumTable[(byte)(Crc ^ Bytes[i])]); // Qualcomm implementation
}
return (UInt16)(Crc ^ FinalXor);
}
}
}
+119 -119
View File
@@ -1,119 +1,119 @@
// 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"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // 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: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // 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 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
namespace WPinternals namespace WPinternals
{ {
internal class SBL1 : QualcommPartition internal class SBL1 : QualcommPartition
{ {
internal SBL1(byte[] Binary) : base(Binary, 0x2800) { } internal SBL1(byte[] Binary) : base(Binary, 0x2800) { }
internal byte[] GenerateExtraSector(byte[] PartitionHeader) internal byte[] GenerateExtraSector(byte[] PartitionHeader)
{ {
UInt32? Offset = ByteOperations.FindPattern(Binary, UInt32? Offset = ByteOperations.FindPattern(Binary,
new byte[] { [
0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
}, null, null); ], null, null);
if (Offset == null) if (Offset == null)
{ {
throw new BadImageFormatException(); throw new BadImageFormatException();
} }
UInt32 PartitionLoaderTableOffset = (UInt32)Offset; UInt32 PartitionLoaderTableOffset = (UInt32)Offset;
byte[] FoundPattern = new byte[0x10]; byte[] FoundPattern = new byte[0x10];
Offset = ByteOperations.FindPattern(Binary, Offset = ByteOperations.FindPattern(Binary,
new byte[] { [
0x04, 0x00, 0x9F, 0xE5, 0x28, 0x00, 0xD0, 0xE5, 0x1E, 0xFF, 0x2F, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF 0x04, 0x00, 0x9F, 0xE5, 0x28, 0x00, 0xD0, 0xE5, 0x1E, 0xFF, 0x2F, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF
}, ],
new byte[] { [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF
}, ],
FoundPattern); FoundPattern);
if (Offset == null) if (Offset == null)
{ {
throw new BadImageFormatException(); throw new BadImageFormatException();
} }
UInt32 SharedMemoryAddress = ByteOperations.ReadUInt32(FoundPattern, 0x0C); UInt32 SharedMemoryAddress = ByteOperations.ReadUInt32(FoundPattern, 0x0C);
UInt32 GlobalIsSecurityEnabledAddress = SharedMemoryAddress + 0x28; UInt32 GlobalIsSecurityEnabledAddress = SharedMemoryAddress + 0x28;
Offset = ByteOperations.FindPattern(Binary, Offset = ByteOperations.FindPattern(Binary,
new byte[] { [
0x01, 0xFF, 0xA0, 0xE3, 0xFF, 0xFF, 0xA0, 0xE1, 0x1C, 0xD0, 0x8D, 0xE2, 0xF0, 0x4F, 0xBD, 0xE8, 0x01, 0xFF, 0xA0, 0xE3, 0xFF, 0xFF, 0xA0, 0xE1, 0x1C, 0xD0, 0x8D, 0xE2, 0xF0, 0x4F, 0xBD, 0xE8,
0x1E, 0xFF, 0x2F, 0xE1 0x1E, 0xFF, 0x2F, 0xE1
}, ],
new byte[] { [
0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 0x00, 0x00, 0x00, 0x00
}, ],
null); null);
if (Offset == null) if (Offset == null)
{ {
throw new BadImageFormatException(); throw new BadImageFormatException();
} }
UInt32 ReturnAddress = (UInt32)Offset - ImageOffset + ImageAddress; UInt32 ReturnAddress = (UInt32)Offset - ImageOffset + ImageAddress;
byte[] Sector = new byte[0x200]; byte[] Sector = new byte[0x200];
Array.Clear(Sector, 0, 0x200); Array.Clear(Sector, 0, 0x200);
byte[] Content = new byte[] { byte[] Content = [
0x16, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28, 0xBD, 0x02, 0x00, 0x16, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28, 0xBD, 0x02, 0x00,
0xD8, 0x01, 0x00, 0x00, 0xD8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x01, 0x00, 0x00, 0xD8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xE3, 0x3C, 0x10, 0x9F, 0xE5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xE3, 0x3C, 0x10, 0x9F, 0xE5,
0x00, 0x00, 0xC1, 0xE5, 0x38, 0x00, 0x9F, 0xE5, 0x38, 0x10, 0x9F, 0xE5, 0x00, 0x00, 0x81, 0xE5, 0x00, 0x00, 0xC1, 0xE5, 0x38, 0x00, 0x9F, 0xE5, 0x38, 0x10, 0x9F, 0xE5, 0x00, 0x00, 0x81, 0xE5,
0x34, 0x10, 0x9F, 0xE5, 0x00, 0x00, 0x81, 0xE5, 0x30, 0x00, 0x9F, 0xE5, 0x20, 0x10, 0x9F, 0xE5, 0x34, 0x10, 0x9F, 0xE5, 0x00, 0x00, 0x81, 0xE5, 0x30, 0x00, 0x9F, 0xE5, 0x20, 0x10, 0x9F, 0xE5,
0x2C, 0x30, 0x9F, 0xE5, 0x00, 0x20, 0x90, 0xE5, 0x00, 0x20, 0x81, 0xE5, 0x04, 0x00, 0x80, 0xE2, 0x2C, 0x30, 0x9F, 0xE5, 0x00, 0x20, 0x90, 0xE5, 0x00, 0x20, 0x81, 0xE5, 0x04, 0x00, 0x80, 0xE2,
0x04, 0x10, 0x81, 0xE2, 0x03, 0x00, 0x50, 0xE1, 0xF9, 0xFF, 0xFF, 0xBA, 0x14, 0xF0, 0x9F, 0xE5, 0x04, 0x10, 0x81, 0xE2, 0x03, 0x00, 0x50, 0xE1, 0xF9, 0xFF, 0xFF, 0xBA, 0x14, 0xF0, 0x9F, 0xE5,
0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x90, 0xBF, 0x02, 0x00, 0xD0, 0xBF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x90, 0xBF, 0x02, 0x00, 0xD0, 0xBF, 0x02, 0x00,
0xA0, 0xBD, 0x02, 0x00, 0xA0, 0xBE, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 0xA0, 0xBD, 0x02, 0x00, 0xA0, 0xBE, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00
}; ];
byte[] PartitionTypeGuid = new byte[] { byte[] PartitionTypeGuid = [
0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74
}; ];
Buffer.BlockCopy(Content, 0, Sector, 0, Content.Length); Buffer.BlockCopy(Content, 0, Sector, 0, Content.Length);
// Overwrite first part of partition-header with model-specific header // Overwrite first part of partition-header with model-specific header
Buffer.BlockCopy(PartitionHeader, 0, Sector, 0, PartitionHeader.Length); Buffer.BlockCopy(PartitionHeader, 0, Sector, 0, PartitionHeader.Length);
ByteOperations.WriteUInt32(Sector, 0x70, GlobalIsSecurityEnabledAddress); ByteOperations.WriteUInt32(Sector, 0x70, GlobalIsSecurityEnabledAddress);
ByteOperations.WriteUInt32(Sector, 0x88, ReturnAddress); ByteOperations.WriteUInt32(Sector, 0x88, ReturnAddress);
Buffer.BlockCopy(Binary, (int)PartitionLoaderTableOffset, Sector, 0xA0, 0x50); Buffer.BlockCopy(Binary, (int)PartitionLoaderTableOffset, Sector, 0xA0, 0x50);
ByteOperations.WriteUInt32(Sector, 0xA0 + 0x30, 0); ByteOperations.WriteUInt32(Sector, 0xA0 + 0x30, 0);
Buffer.BlockCopy(Binary, (int)PartitionLoaderTableOffset, Sector, 0xF0, 0x50); Buffer.BlockCopy(Binary, (int)PartitionLoaderTableOffset, Sector, 0xF0, 0x50);
ByteOperations.WriteUInt32(Sector, 0xF0 + 0x2C, 0); ByteOperations.WriteUInt32(Sector, 0xF0 + 0x2C, 0);
ByteOperations.WriteUInt32(Sector, 0xF0 + 0x38, 0x210F0); ByteOperations.WriteUInt32(Sector, 0xF0 + 0x38, 0x210F0);
Buffer.BlockCopy(PartitionTypeGuid, 0, Sector, 0x190, 0x10); Buffer.BlockCopy(PartitionTypeGuid, 0, Sector, 0x190, 0x10);
ByteOperations.WriteUInt32(Sector, 0x1FC, 0x0002BD28); ByteOperations.WriteUInt32(Sector, 0x1FC, 0x0002BD28);
return Sector; return Sector;
} }
} }
} }
+56 -56
View File
@@ -1,56 +1,56 @@
// 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"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // 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: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // 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 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
namespace WPinternals namespace WPinternals
{ {
internal class SBL2 internal class SBL2
{ {
internal byte[] Binary; internal byte[] Binary;
internal SBL2(byte[] Binary) internal SBL2(byte[] Binary)
{ {
this.Binary = Binary; this.Binary = Binary;
} }
// Magic! // Magic!
internal byte[] Patch() internal byte[] Patch()
{ {
UInt32? PatchOffset = ByteOperations.FindPattern(Binary, UInt32? PatchOffset = ByteOperations.FindPattern(Binary,
new byte[] { [
0xFF, 0xFF, 0xFF, 0xE3, 0x01, 0x0E, 0x42, 0xE3, 0x28, 0x00, 0xD0, 0xE5, 0x1E, 0xFF, 0x2F, 0xE1 0xFF, 0xFF, 0xFF, 0xE3, 0x01, 0x0E, 0x42, 0xE3, 0x28, 0x00, 0xD0, 0xE5, 0x1E, 0xFF, 0x2F, 0xE1
}, ],
new byte[] { [
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
}, ],
null); null);
if (PatchOffset == null) if (PatchOffset == null)
{ {
throw new BadImageFormatException(); throw new BadImageFormatException();
} }
Buffer.BlockCopy(new byte[] { 0x00, 0x00, 0xA0, 0xE3 }, 0, Binary, (int)PatchOffset + 8, 4); Buffer.BlockCopy(new byte[] { 0x00, 0x00, 0xA0, 0xE3 }, 0, Binary, (int)PatchOffset + 8, 4);
return Binary; return Binary;
} }
} }
} }
+91 -88
View File
@@ -1,88 +1,91 @@
// 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"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // 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: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // 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 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.IO; using System.IO;
namespace WPinternals namespace WPinternals
{ {
internal class SBL3 internal class SBL3
{ {
internal byte[] Binary; internal byte[] Binary;
internal SBL3(byte[] Binary) internal SBL3(byte[] Binary)
{ {
this.Binary = Binary; this.Binary = Binary;
} }
internal SBL3(string FileName) internal SBL3(string FileName)
{ {
Binary = null; Binary = null;
// First try to parse as FFU // First try to parse as FFU
try try
{ {
if (FFU.IsFFU(FileName)) if (FFU.IsFFU(FileName))
{ {
FFU FFUFile = new(FileName); FFU FFUFile = new(FileName);
Binary = FFUFile.GetPartition("SBL3"); Binary = FFUFile.GetPartition("SBL3");
} }
} }
catch { } catch (Exception ex)
{
// If not succeeded, then try to parse it as raw image LogFile.LogException(ex, LogType.FileOnly);
if (Binary == null) }
{
byte[] SBL3Pattern = new byte[] { 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x8F, 0xFF, 0xFF, 0xFF, 0xFF }; // If not succeeded, then try to parse it as raw image
byte[] SBL3Mask = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF }; if (Binary == null)
{
UInt32? Offset = ByteOperations.FindPatternInFile(FileName, SBL3Pattern, SBL3Mask, out byte[] SBL3Header); byte[] SBL3Pattern = [0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x8F, 0xFF, 0xFF, 0xFF, 0xFF];
byte[] SBL3Mask = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF];
if (Offset != null)
{ UInt32? Offset = ByteOperations.FindPatternInFile(FileName, SBL3Pattern, SBL3Mask, out byte[] SBL3Header);
UInt32 Length = ByteOperations.ReadUInt32(SBL3Header, 0x10) + 0x28; // SBL3 Image Size + Header Size
Binary = new byte[Length]; if (Offset != null)
{
FileStream Stream = new(FileName, FileMode.Open, FileAccess.Read); UInt32 Length = ByteOperations.ReadUInt32(SBL3Header, 0x10) + 0x28; // SBL3 Image Size + Header Size
Stream.Seek((long)Offset, SeekOrigin.Begin); Binary = new byte[Length];
Stream.Read(Binary, 0, (int)Length);
Stream.Close(); FileStream Stream = new(FileName, FileMode.Open, FileAccess.Read);
} Stream.Seek((long)Offset, SeekOrigin.Begin);
} Stream.Read(Binary, 0, (int)Length);
} Stream.Close();
}
// Magic! }
internal byte[] Patch() }
{
UInt32? PatchOffset = ByteOperations.FindPattern(Binary, // Magic!
new byte[] { 0x04, 0x00, 0x9F, 0xE5, 0x28, 0x00, 0xD0, 0xE5, 0x1E, 0xFF, 0x2F, 0xE1 }, internal byte[] Patch()
null, null); {
UInt32? PatchOffset = ByteOperations.FindPattern(Binary,
if (PatchOffset == null) [0x04, 0x00, 0x9F, 0xE5, 0x28, 0x00, 0xD0, 0xE5, 0x1E, 0xFF, 0x2F, 0xE1],
{ null, null);
throw new BadImageFormatException();
} if (PatchOffset == null)
{
Buffer.BlockCopy(new byte[] { 0x00, 0x00, 0xA0, 0xE3 }, 0, Binary, (int)PatchOffset + 4, 4); throw new BadImageFormatException();
}
return Binary;
} Buffer.BlockCopy(new byte[] { 0x00, 0x00, 0xA0, 0xE3 }, 0, Binary, (int)PatchOffset + 4, 4);
}
} return Binary;
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,399 @@
// 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;
namespace WPinternals
{
internal class LumiaBootManagerAppModel : NokiaFlashModel
{
internal readonly LumiaBootManagerPhoneInfo BootManagerInfo = new();
internal enum SecureBootKeyType : byte
{
Retail = 0,
Engineering = 1
}
//
// Not valid commands
//
/* NOK */
private const string Signature = "NOK";
/* NOKX */
private const string ExtendedMessageSignature = $"{Signature}X";
/* NOKXB */
private const string LumiaBootManagerExtendedMessageSignature = $"{ExtendedMessageSignature}B";
//
// Normal commands
//
/* NOKA */
private const string ContinueBootSignature = $"{Signature}A";
/* NOKB */
private const string RPMBSignature = $"{Signature}B";
/* NOKC */
private const string BatteryStatusSignature = $"{Signature}C";
/* NOKD */
private const string DisableTimeoutsSignature = $"{Signature}D";
/* NOKI */
private const string HelloSignature = $"{Signature}I";
/* NOKM */
private const string RebootToMassStorageSignature = $"{Signature}M";
/* NOKP */
private const string RebootToPhoneInfoAppSignature = $"{Signature}P";
/* NOKR */
private const string RebootSignature = $"{Signature}R";
/* NOKS */
private const string RebootToFlashAppSignature = $"{Signature}S";
/* NOKT */
private const string GetGPTSignature = $"{Signature}T";
/* NOKV */
private const string InfoQuerySignature = $"{Signature}V";
/* NOKW */
private const string WriteBootFlagFileSignature = $"{Signature}W";
/* NOKY */
private const string MMOSStartCommandSignature = $"{Signature}Y";
/* NOKZ */
private const string ShutdownSignature = $"{Signature}Z";
//
// Lumia Boot Manager extended commands
//
/* NOKXBD */
private const string PlatformSecureBootEnableSignature = $"{LumiaBootManagerExtendedMessageSignature}D";
/* NOKXBH */
private const string WriteRootCertificateHashSignature = $"{LumiaBootManagerExtendedMessageSignature}H";
/* NOKXBK */
private const string UEFIKeysProvisionSignature = $"{LumiaBootManagerExtendedMessageSignature}K";
/* NOKXBR */
private const string ReadManufacturingStateSignature = $"{LumiaBootManagerExtendedMessageSignature}R";
/* NOKXBU */
private const string FlushVariablesSignature = $"{LumiaBootManagerExtendedMessageSignature}U";
/* NOKXBW */
private const string WriteManufacturingStateSignature = $"{LumiaBootManagerExtendedMessageSignature}W";
public LumiaBootManagerAppModel(string DevicePath) : base(DevicePath)
{
}
internal void ContinueBoot()
{
LogFile.Log("Continue boot...");
byte[] Request = new byte[4];
ByteOperations.WriteAsciiString(Request, 0, ContinueBootSignature);
ExecuteRawVoidMethod(Request);
}
internal LumiaBootManagerPhoneInfo ReadPhoneInfo(bool ExtendedInfo = true)
{
// NOKH = Get Phone Info (IMEI and info from Product.dat) - Not available on some phones, like Lumia 640.
// NOKV = Info Query
bool PhoneInfoLogged = BootManagerInfo.State != PhoneInfoState.Empty;
ReadPhoneInfoBootManager();
LumiaBootManagerPhoneInfo Result = BootManagerInfo;
if (!PhoneInfoLogged)
{
Result.Log(LogType.FileOnly);
}
return Result;
}
internal LumiaBootManagerPhoneInfo ReadPhoneInfoBootManager()
{
// NOKH = Get Phone Info (IMEI and info from Product.dat) - Not available on some phones, like Lumia 640.
// NOKV = Info Query
LumiaBootManagerPhoneInfo Result = BootManagerInfo;
if (Result.State == PhoneInfoState.Empty)
{
byte[] Request = new byte[4];
ByteOperations.WriteAsciiString(Request, 0, InfoQuerySignature);
byte[] Response = ExecuteRawMethod(Request);
if ((Response != null) && (ByteOperations.ReadAsciiString(Response, 0, 4) != "NOKU"))
{
Result.App = (FlashAppType)Response[5];
switch (Result.App)
{
case FlashAppType.BootManager:
Result.BootManagerProtocolVersionMajor = Response[6];
Result.BootManagerProtocolVersionMinor = Response[7];
Result.BootManagerVersionMajor = Response[8];
Result.BootManagerVersionMinor = Response[9];
break;
}
byte SubblockCount = Response[10];
int SubblockOffset = 11;
for (int i = 0; i < SubblockCount; i++)
{
byte SubblockID = Response[SubblockOffset + 0x00];
LogFile.Log($"{Result.App} SubblockID: 0x{SubblockID:X}");
UInt16 SubblockLength = BigEndian.ToUInt16(Response, SubblockOffset + 0x01);
int SubblockPayloadOffset = SubblockOffset + 3;
byte SubblockVersion;
switch (SubblockID)
{
case 0x01:
Result.TransferSize = BigEndian.ToUInt32(Response, SubblockPayloadOffset);
break;
case 0x04:
Result.FlashAppProtocolVersionMajor = Response[SubblockPayloadOffset + 0x00];
Result.FlashAppProtocolVersionMinor = Response[SubblockPayloadOffset + 0x01];
Result.FlashAppVersionMajor = Response[SubblockPayloadOffset + 0x02];
Result.FlashAppVersionMinor = Response[SubblockPayloadOffset + 0x03];
break;
case 0x1F:
Result.MmosOverUsbSupported = Response[SubblockPayloadOffset] == 1;
break;
case 0x20:
// CRC header info
break;
}
SubblockOffset += SubblockLength + 3;
}
}
Result.State = PhoneInfoState.Basic;
}
return Result;
}
internal GPT ReadGPT()
{
// If this function is used with a locked BootMgr v1,
// then the mode-switching should be done outside this function,
// because the context-switches that are used here are not supported on BootMgr v1.
// Only works in BootLoader-mode or on unlocked bootloaders in Flash-mode!!
byte[] Request = new byte[0x04];
const string Header = GetGPTSignature;
System.Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
byte[] Buffer = ExecuteRawMethod(Request);
if ((Buffer == null) || (Buffer.Length < 0x4408))
{
throw new InvalidOperationException("Unable to read GPT!");
}
UInt16 Error = (UInt16)((Buffer[6] << 8) + Buffer[7]);
if (Error > 0)
{
throw new NotSupportedException("ReadGPT: Error 0x" + Error.ToString("X4"));
}
byte[] GPTBuffer = new byte[Buffer.Length - 0x208];
System.Buffer.BlockCopy(Buffer, 0x208, GPTBuffer, 0, 0x4200);
return new GPT(GPTBuffer); // NOKT message header and MBR are ignored
}
internal byte[] GetGptChunk(UInt32 Size) // TODO!
{
// This function is also used to generate a dummy chunk to flash for testing.
// The dummy chunk will contain the GPT, so it can be flashed to the first sectors for testing.
byte[] GPTChunk = new byte[Size];
byte[] Request = new byte[0x04];
const string Header = "NOKT";
System.Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
byte[] Buffer = ExecuteRawMethod(Request);
if ((Buffer == null) || (Buffer.Length < 0x4408))
{
throw new InvalidOperationException("Unable to read GPT!");
}
UInt16 Error = (UInt16)((Buffer[6] << 8) + Buffer[7]);
if (Error > 0)
{
throw new NotSupportedException("ReadGPT: Error 0x" + Error.ToString("X4"));
}
System.Buffer.BlockCopy(Buffer, 8, GPTChunk, 0, 0x4400);
return GPTChunk;
}
internal void ProvisionSecureBootKeys(SecureBootKeyType KeyType) // Only for Flashmode, not BootManager mode.
{
byte[] Request = new byte[8];
ByteOperations.WriteAsciiString(Request, 0, UEFIKeysProvisionSignature);
Request[6] = 0; // Options
Request[7] = (byte)KeyType;
byte[] Response = ExecuteRawMethod(Request);
UInt32 Status = ByteOperations.ReadUInt32(Response, 6);
if (Status != 0)
{
ThrowFlashError((int)Status);
}
}
private void ThrowFlashError(int ErrorCode)
{
string SubMessage = ErrorCode switch
{
0x0008 => "Unsupported protocol / Invalid options",
0x000F => "Invalid sub block count",
0x0010 => "Invalid sub block length",
0x0012 => "Authentication required",
0x000E => "Invalid sub block type",
0x0013 => "Failed async message",
0x1000 => "Invalid header type",
0x1001 => "FFU header contain unknown extra data",
0x0001 => "Couldn't allocate memory",
0x1106 => "Security header validation failed",
0x1105 => "Invalid hash table size",
0x1104 => "Invalid catalog size",
0x1103 => "Invalid chunk size",
0x1102 => "Unsupported algorithm",
0x1101 => "Invalid struct size",
0x1100 => "Invalid signature",
0x1202 => "Invalid struct size",
0x1203 => "Unsupported algorithm",
0x1204 => "Invalid chunk size",
0x1005 => "Data not aligned correctly",
0x0009 => "Locate protocol failed",
0x1003 => "Hash mismatch",
0x1006 => "Couldn't find hash from security header for index",
0x1004 => "Security header import missing / All FFU headers have not been imported",
0x1304 => "Invalid platform ID",
0x1307 => "Invalid write descriptor info",
0x1306 => "Invalid write descriptor info",
0x1305 => "Invalid block size",
0x1303 => "Unsupported FFU version",
0x1302 => "Unsupported struct version",
0x1301 => "Invalid update type",
0x100B => "Too much payload data, all data has already been written",
0x1008 => "Internal error",
0x1007 => "Payload data does not contain all data",
0x0004 => "Flash write failed",
0x000D => "Flash verify failed",
0x0002 => "Flash read failed",
_ => "Unknown error",
};
WPinternalsException Ex = new("Flash failed!");
Ex.SubMessage = "Error 0x" + ErrorCode.ToString("X4") + ": " + SubMessage;
throw Ex;
}
public void Shutdown()
{
byte[] Request = new byte[4];
const string Header = ShutdownSignature;
Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
ExecuteRawMethod(Request);
}
internal void ResetPhone()
{
LogFile.Log("Rebooting phone", LogType.FileAndConsole);
try
{
byte[] Request = new byte[4];
ByteOperations.WriteAsciiString(Request, 0, RebootSignature);
ExecuteRawVoidMethod(Request);
}
catch
{
LogFile.Log("Sending reset-request failed", LogType.FileOnly);
LogFile.Log("Assuming automatic reset already in progress", LogType.FileOnly);
}
}
internal void ResetPhoneToFlashMode()
{
LumiaBootManagerPhoneInfo info = ReadPhoneInfoBootManager();
bool ModernFlashApp = info.BootManagerVersionMajor >= 2;
// This only works when the phone is in BootMgr mode. If it is already in FlashApp, it will not reboot. It only makes the phone unresponsive.
LogFile.Log("Rebooting phone to Flash mode...");
byte[] Request = new byte[4];
ByteOperations.WriteAsciiString(Request, 0, RebootToFlashAppSignature);
ExecuteRawVoidMethod(Request);
if (ModernFlashApp)
{
DisableRebootTimeOut();
info.App = FlashAppType.FlashApp;
RaiseInterfaceChanged(PhoneInterfaces.Lumia_Flash);
}
}
internal void SwitchToPhoneInfoAppContextLegacy()
{
LumiaBootManagerPhoneInfo info = ReadPhoneInfoBootManager();
bool ModernFlashApp = info.BootManagerVersionMajor >= 2;
byte[] Request = new byte[4];
ByteOperations.WriteAsciiString(Request, 0, RebootToPhoneInfoAppSignature);
ExecuteRawVoidMethod(Request);
if (ModernFlashApp)
{
DisableRebootTimeOut();
info.App = FlashAppType.PhoneInfoApp;
RaiseInterfaceChanged(PhoneInterfaces.Lumia_PhoneInfo);
}
}
internal void RebootToFlashApp()
{
LumiaBootManagerPhoneInfo info = ReadPhoneInfoBootManager();
bool ModernFlashApp = info.BootManagerVersionMajor >= 2;
byte[] Request = new byte[4];
ByteOperations.WriteAsciiString(Request, 0, RebootToFlashAppSignature); // This will let the phone charge
ExecuteRawVoidMethod(Request); // On phone with bootloader Spec A this triggers a reboot, so DisableRebootTimeOut() cannot be called immediately.
if (ModernFlashApp)
{
DisableRebootTimeOut();
info.App = FlashAppType.FlashApp;
RaiseInterfaceChanged(PhoneInterfaces.Lumia_Flash);
}
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,239 @@
// 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;
namespace WPinternals
{
internal class LumiaPhoneInfoAppModel : NokiaFlashModel
{
internal readonly LumiaPhoneInfoAppPhoneInfo PhoneInfoAppInfo = new();
//
// Not valid commands
//
/* NOK */
private const string Signature = "NOK";
/* NOKX */
private const string ExtendedMessageSignature = $"{Signature}X";
/* NOKXP */
private const string PhoneInfoAppExtendedMessageSignature = $"{ExtendedMessageSignature}P";
//
// Normal commands
//
/* NOKA */
private const string ContinueBootSignature = $"{Signature}A";
/* NOKD */
private const string DisableTimeoutsSignature = $"{Signature}D";
/* NOKH */
private const string GetPhoneInfoSignature = $"{Signature}H";
/* NOKI */
private const string HelloSignature = $"{Signature}I";
/* NOKV */
private const string InfoQuerySignature = $"{Signature}V";
//
// Phone Info App extended commands
//
/* NOKXPH */
private const string GetVariableSignature = $"{PhoneInfoAppExtendedMessageSignature}H";
public LumiaPhoneInfoAppModel(string DevicePath) : base(DevicePath)
{
}
internal void ContinueBoot()
{
LogFile.Log("Continue boot...");
byte[] Request = new byte[4];
ByteOperations.WriteAsciiString(Request, 0, ContinueBootSignature);
ExecuteRawVoidMethod(Request);
}
internal string GetPhoneInfo()
{
// NOKH = Get Phone Info (IMEI and info from Product.dat) - Not available on some phones, like Lumia 640.
// NOKV = Info Query
if (PhoneInfoAppInfo.PhoneInfoAppVersionMajor >= 2)
{
return null;
}
byte[] Request = new byte[4];
ByteOperations.WriteAsciiString(Request, 0, GetPhoneInfoSignature);
byte[] Response = ExecuteRawMethod(Request);
if ((Response == null) || (ByteOperations.ReadAsciiString(Response, 0, 4) == "NOKU"))
{
throw new NotSupportedException();
}
UInt16 Length = BigEndian.ToUInt16(Response, 0x04);
string PhoneInfoData = ByteOperations.ReadAsciiString(Response, 0x8, Length);
return PhoneInfoData;
}
internal LumiaPhoneInfoAppPhoneInfo ReadPhoneInfo(bool ExtendedInfo = true)
{
// NOKH = Get Phone Info (IMEI and info from Product.dat) - Not available on some phones, like Lumia 640.
// NOKV = Info Query
bool PhoneInfoLogged = PhoneInfoAppInfo.State != PhoneInfoState.Empty;
ReadPhoneInfoPhoneInfoApp();
LumiaPhoneInfoAppPhoneInfo Result = PhoneInfoAppInfo;
if (ExtendedInfo && (Result.State == PhoneInfoState.Basic))
{
try
{
if (Result.PhoneInfoAppProtocolVersionMajor >= 2)
{
Result.Type = ReadPhoneInfoVariable("TYPE");
Result.ProductCode = ReadPhoneInfoVariable("CTR");
Result.Imei = ReadPhoneInfoVariable("IMEI");
}
else
{
/*
* Version: 1.1.1.3
* TYPE: RM-885
* BTR: 059R0M0
* LPSN: ...
* HWID: 1000
* CTR: 059S4B1
* MC: 0205354
* IMEI: ...
*/
string PhoneInfoData = GetPhoneInfo();
if (!string.IsNullOrEmpty(PhoneInfoData))
{
string[] Variables = PhoneInfoData.Split("\n");
Dictionary<string, string> FormattedVariables = [];
foreach (string Variable in Variables)
{
if (!Variable.Contains(":"))
{
continue;
}
FormattedVariables.Add(Variable.Split(":")[0].Trim(), Variable.Split(":")[1].Trim());
}
Result.Type = FormattedVariables["TYPE"];
Result.ProductCode = FormattedVariables["CTR"];
Result.Imei = FormattedVariables["IMEI"];
}
}
}
catch (Exception ex)
{
LogFile.LogException(ex, LogType.FileOnly);
}
Result.State = PhoneInfoState.Extended;
}
if (!PhoneInfoLogged)
{
Result.Log(LogType.FileOnly);
}
return Result;
}
internal LumiaPhoneInfoAppPhoneInfo ReadPhoneInfoPhoneInfoApp()
{
// NOKH = Get Phone Info (IMEI and info from Product.dat) - Not available on some phones, like Lumia 640.
// NOKV = Info Query
LumiaPhoneInfoAppPhoneInfo Result = PhoneInfoAppInfo;
if (Result.State == PhoneInfoState.Empty)
{
byte[] Request = new byte[4];
ByteOperations.WriteAsciiString(Request, 0, InfoQuerySignature);
byte[] Response = ExecuteRawMethod(Request);
if ((Response != null) && (ByteOperations.ReadAsciiString(Response, 0, 4) != "NOKU"))
{
Result.App = (FlashAppType)Response[5];
switch (Result.App)
{
case FlashAppType.PhoneInfoApp:
Result.PhoneInfoAppProtocolVersionMajor = Response[6];
Result.PhoneInfoAppProtocolVersionMinor = Response[7];
Result.PhoneInfoAppVersionMajor = Response[8];
Result.PhoneInfoAppVersionMinor = Response[9];
break;
}
byte SubblockCount = Response[10];
int SubblockOffset = 11;
for (int i = 0; i < SubblockCount; i++)
{
byte SubblockID = Response[SubblockOffset + 0x00];
LogFile.Log($"{Result.App} SubblockID: 0x{SubblockID:X}");
UInt16 SubblockLength = BigEndian.ToUInt16(Response, SubblockOffset + 0x01);
int SubblockPayloadOffset = SubblockOffset + 3;
byte SubblockVersion;
switch (SubblockID)
{
case 0x20:
// CRC header info
break;
}
SubblockOffset += SubblockLength + 3;
}
}
Result.State = PhoneInfoState.Basic;
}
return Result;
}
internal string ReadPhoneInfoVariable(string VariableName)
{
// This function assumes the phone is in Phone Info App context
byte[] Request = new byte[16];
ByteOperations.WriteAsciiString(Request, 0, GetVariableSignature + VariableName + "\0"); // BTR or CTR, CTR is public ProductCode
byte[] Response = ExecuteRawMethod(Request);
UInt16 Length = BigEndian.ToUInt16(Response, 6);
return ByteOperations.ReadAsciiString(Response, 8, Length).Trim([' ', '\0']);
}
internal string ReadProductCode()
{
string Result = ReadPhoneInfoVariable("CTR");
return Result;
}
}
}
@@ -0,0 +1,241 @@
// 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;
namespace WPinternals
{
internal delegate void InterfaceChangedHandler(PhoneInterfaces NewInterface, string DevicePath);
internal class NokiaFlashModel : NokiaPhoneModel
{
private string _devicePath;
private readonly CommonPhoneInfo CommonInfo = new();
internal event InterfaceChangedHandler InterfaceChanged = delegate { };
//
// Not valid commands
//
/* NOK */
private const string Signature = "NOK";
/* NOKX */
private const string ExtendedMessageSignature = $"{Signature}X";
/* NOKXC */
private const string CommonExtendedMessageSignature = $"{ExtendedMessageSignature}C";
//
// Common extended commands
//
/* NOKXCB */
private const string SwitchModeSignature = $"{CommonExtendedMessageSignature}B";
/* NOKXCE */
private const string EchoSignature = $"{CommonExtendedMessageSignature}E";
public NokiaFlashModel(string DevicePath) : base(DevicePath)
{
_devicePath = DevicePath;
}
internal void SwitchToBootManagerContext(bool DisableTimeOut = true)
{
CommonPhoneInfo info = ReadPhoneInfoCommon();
bool ModernFlashApp = info.VersionMajor >= 2;
byte[] Request = new byte[7];
ByteOperations.WriteAsciiString(Request, 0, $"{SwitchModeSignature}B");
byte[] Response = ExecuteRawMethod(Request);
if (ByteOperations.ReadAsciiString(Response, 0, 4) == "NOKU")
{
throw new NotSupportedException();
}
UInt16 Error = (UInt16)((Response[6] << 8) + Response[7]);
if (Error > 0)
{
throw new NotSupportedException("SwitchToBootManagerContext: Error 0x" + Error.ToString("X4"));
}
if (ModernFlashApp)
{
DisableRebootTimeOut();
InterfaceChanged(PhoneInterfaces.Lumia_Bootloader, _devicePath);
}
}
internal void SwitchToPhoneInfoAppContext()
{
CommonPhoneInfo info = ReadPhoneInfoCommon();
bool ModernFlashApp = info.VersionMajor >= 2;
byte[] Request = new byte[7];
ByteOperations.WriteAsciiString(Request, 0, SwitchModeSignature + "P");
byte[] Response = ExecuteRawMethod(Request);
if (ByteOperations.ReadAsciiString(Response, 0, 4) == "NOKU")
{
throw new NotSupportedException();
}
UInt16 Error = (UInt16)((Response[6] << 8) + Response[7]);
if (Error > 0)
{
throw new NotSupportedException("SwitchToPhoneInfoAppContext: Error 0x" + Error.ToString("X4"));
}
if (ModernFlashApp)
{
DisableRebootTimeOut();
CommonInfo.App = FlashAppType.PhoneInfoApp;
InterfaceChanged(PhoneInterfaces.Lumia_PhoneInfo, _devicePath);
}
}
internal void SwitchToMmosContext()
{
byte[] Request = new byte[7];
ByteOperations.WriteAsciiString(Request, 0, $"{SwitchModeSignature}A");
byte[] Response = ExecuteRawMethod(Request);
if (ByteOperations.ReadAsciiString(Response, 0, 4) == "NOKU")
{
throw new NotSupportedException();
}
UInt16 Error = (UInt16)((Response[6] << 8) + Response[7]);
if (Error > 0)
{
throw new NotSupportedException("SwitchToPhoneInfoAppContext: Error 0x" + Error.ToString("X4"));
}
}
internal void SwitchToFlashAppContext()
{
CommonPhoneInfo info = ReadPhoneInfoCommon();
bool ModernFlashApp = info.VersionMajor >= 2;
byte[] Request = new byte[7];
ByteOperations.WriteAsciiString(Request, 0, $"{SwitchModeSignature}F"); // This will stop charging the phone
byte[] Response = ExecuteRawMethod(Request);
if (ByteOperations.ReadAsciiString(Response, 0, 4) == "NOKU")
{
throw new NotSupportedException();
}
UInt16 Error = (UInt16)((Response[6] << 8) + Response[7]);
if (Error > 0)
{
throw new NotSupportedException("SwitchToFlashAppContext: Error 0x" + Error.ToString("X4"));
}
if (ModernFlashApp)
{
DisableRebootTimeOut();
InterfaceChanged(PhoneInterfaces.Lumia_Flash, _devicePath);
}
}
//
// Normal commands
//
/* NOKD */
private const string DisableTimeoutsSignature = $"{Signature}D";
/* NOKI */
private const string HelloSignature = $"{Signature}I";
/* NOKV */
private const string InfoQuerySignature = $"{Signature}V";
internal FlashAppType GetFlashAppType()
{
byte[] Request = new byte[4];
ByteOperations.WriteAsciiString(Request, 0, InfoQuerySignature);
byte[] Response = ExecuteRawMethod(Request);
if ((Response == null) || (ByteOperations.ReadAsciiString(Response, 0, 4) == "NOKU"))
{
throw new NotSupportedException();
}
return (FlashAppType)Response[5];
}
internal CommonPhoneInfo ReadPhoneInfoCommon()
{
// NOKH = Get Phone Info (IMEI and info from Product.dat) - Not available on some phones, like Lumia 640.
// NOKV = Info Query
CommonPhoneInfo Result = CommonInfo;
if (Result.State == PhoneInfoState.Empty)
{
byte[] Request = new byte[4];
ByteOperations.WriteAsciiString(Request, 0, InfoQuerySignature);
byte[] Response = ExecuteRawMethod(Request);
if ((Response != null) && (ByteOperations.ReadAsciiString(Response, 0, 4) != "NOKU"))
{
Result.App = (FlashAppType)Response[5];
Result.ProtocolVersionMajor = Response[6];
Result.ProtocolVersionMinor = Response[7];
Result.VersionMajor = Response[8];
Result.VersionMinor = Response[9];
}
Result.State = PhoneInfoState.Basic;
}
return Result;
}
public void DisableRebootTimeOut()
{
byte[] Request = new byte[4];
const string Header = DisableTimeoutsSignature;
Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length);
ExecuteRawMethod(Request);
}
internal void Hello()
{
byte[] Request = new byte[4];
ByteOperations.WriteAsciiString(Request, 0, HelloSignature);
byte[] Response = ExecuteRawMethod(Request);
if (Response == null)
{
throw new BadConnectionException();
}
if (ByteOperations.ReadAsciiString(Response, 0, 4) != HelloSignature)
{
throw new WPinternalsException("Bad response from phone!", "The phone did not answer properly to the Hello message sent.");
}
}
internal void RaiseInterfaceChanged(PhoneInterfaces NewInterface)
{
InterfaceChanged(NewInterface, _devicePath);
}
}
}
@@ -0,0 +1,34 @@
// 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.
namespace WPinternals
{
internal class UefiSecurityStatusResponse
{
public byte IsTestDevice;
public bool PlatformSecureBootStatus;
public bool SecureFfuEfuseStatus;
public bool DebugStatus;
public bool RdcStatus;
public bool AuthenticationStatus;
public bool UefiSecureBootStatus;
public bool CryptoHardwareKey;
}
}
File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

@@ -1,51 +1,51 @@
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Windows; using System.Windows;
// General Information about an assembly is controlled through the following // General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information // set of attributes. Change these attribute values to modify the information
// associated with an assembly. // associated with an assembly.
[assembly: AssemblyTitle("WPinternals")] [assembly: AssemblyTitle("WPinternals")]
[assembly: AssemblyDescription("")] [assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")] [assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("WPinternals")] [assembly: AssemblyProduct("WPinternals")]
[assembly: AssemblyCopyright("Copyright © 2018-2019")] [assembly: AssemblyCopyright("Copyright © 2018-2023")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible // 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 // to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type. // COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)] [assembly: ComVisible(false)]
//In order to begin building localizable applications, set //In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file //<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english //inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment //in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in //the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file. //the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo( [assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page, //(used if a resource is not found in the page,
// or application resource dictionaries) // or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page, //(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries) // app, or any theme specific resource dictionaries)
)] )]
// Version information for an assembly consists of the following four values: // Version information for an assembly consists of the following four values:
// //
// Major Version // Major Version
// Minor Version // Minor Version
// Build Number // Build Number
// Revision // Revision
// //
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("2.9.*")] [assembly: AssemblyVersion("3.0.*")]
// [assembly: AssemblyFileVersion("1.0.0.0")] // [assembly: AssemblyFileVersion("1.0.0.0")]

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