mirror of
https://github.com/Iemand005/MetroUnlocker.git
synced 2026-04-11 17:37:21 +10:00
Initial commit
This commit is contained in:
63
.gitattributes
vendored
Normal file
63
.gitattributes
vendored
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
###############################################################################
|
||||||
|
# Set default behavior to automatically normalize line endings.
|
||||||
|
###############################################################################
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Set default behavior for command prompt diff.
|
||||||
|
#
|
||||||
|
# This is need for earlier builds of msysgit that does not have it on by
|
||||||
|
# default for csharp files.
|
||||||
|
# Note: This is only used by command line
|
||||||
|
###############################################################################
|
||||||
|
#*.cs diff=csharp
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Set the merge driver for project and solution files
|
||||||
|
#
|
||||||
|
# Merging from the command prompt will add diff markers to the files if there
|
||||||
|
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||||
|
# the diff markers are never inserted). Diff markers may cause the following
|
||||||
|
# file extensions to fail to load in VS. An alternative would be to treat
|
||||||
|
# these files as binary and thus will always conflict and require user
|
||||||
|
# intervention with every merge. To do so, just uncomment the entries below
|
||||||
|
###############################################################################
|
||||||
|
#*.sln merge=binary
|
||||||
|
#*.csproj merge=binary
|
||||||
|
#*.vbproj merge=binary
|
||||||
|
#*.vcxproj merge=binary
|
||||||
|
#*.vcproj merge=binary
|
||||||
|
#*.dbproj merge=binary
|
||||||
|
#*.fsproj merge=binary
|
||||||
|
#*.lsproj merge=binary
|
||||||
|
#*.wixproj merge=binary
|
||||||
|
#*.modelproj merge=binary
|
||||||
|
#*.sqlproj merge=binary
|
||||||
|
#*.wwaproj merge=binary
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# behavior for image files
|
||||||
|
#
|
||||||
|
# image files are treated as binary by default.
|
||||||
|
###############################################################################
|
||||||
|
#*.jpg binary
|
||||||
|
#*.png binary
|
||||||
|
#*.gif binary
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# diff behavior for common document formats
|
||||||
|
#
|
||||||
|
# Convert binary document formats to text before diffing them. This feature
|
||||||
|
# is only available from the command line. Turn it on by uncommenting the
|
||||||
|
# entries below.
|
||||||
|
###############################################################################
|
||||||
|
#*.doc diff=astextplain
|
||||||
|
#*.DOC diff=astextplain
|
||||||
|
#*.docx diff=astextplain
|
||||||
|
#*.DOCX diff=astextplain
|
||||||
|
#*.dot diff=astextplain
|
||||||
|
#*.DOT diff=astextplain
|
||||||
|
#*.pdf diff=astextplain
|
||||||
|
#*.PDF diff=astextplain
|
||||||
|
#*.rtf diff=astextplain
|
||||||
|
#*.RTF diff=astextplain
|
||||||
189
.gitignore
vendored
Normal file
189
.gitignore
vendored
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
x64/
|
||||||
|
build/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
|
||||||
|
# Roslyn cache directories
|
||||||
|
*.ide/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
#NUNIT
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_i.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# JustCode is a .NET coding addin-in
|
||||||
|
.JustCode
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
## TODO: Comment the next line if you want to checkin your
|
||||||
|
## web deploy settings but do note that will include unencrypted
|
||||||
|
## passwords
|
||||||
|
#*.pubxml
|
||||||
|
|
||||||
|
# NuGet Packages Directory
|
||||||
|
packages/*
|
||||||
|
## TODO: If the tool you use requires repositories.config
|
||||||
|
## uncomment the next line
|
||||||
|
#!packages/repositories.config
|
||||||
|
|
||||||
|
# Enable "build/" folder in the NuGet Packages folder since
|
||||||
|
# NuGet packages use it for MSBuild targets.
|
||||||
|
# This line needs to be after the ignore of the build folder
|
||||||
|
# (and the packages folder if the line above has been uncommented)
|
||||||
|
!packages/build/
|
||||||
|
|
||||||
|
# Windows Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Windows Store app package directory
|
||||||
|
AppPackages/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
sql/
|
||||||
|
*.Cache
|
||||||
|
ClientBin/
|
||||||
|
[Ss]tyle[Cc]op.*
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# LightSwitch generated files
|
||||||
|
GeneratedArtifacts/
|
||||||
|
_Pvt_Extensions/
|
||||||
|
ModelManifest.xml
|
||||||
22
MetroUnlocker.sln
Normal file
22
MetroUnlocker.sln
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 2013
|
||||||
|
VisualStudioVersion = 12.0.40629.0
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MetroUnlocker", "MetroUnlocker\MetroUnlocker.csproj", "{D27EB145-0B58-43AD-BB94-BE000D236D38}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{D27EB145-0B58-43AD-BB94-BE000D236D38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{D27EB145-0B58-43AD-BB94-BE000D236D38}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{D27EB145-0B58-43AD-BB94-BE000D236D38}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{D27EB145-0B58-43AD-BB94-BE000D236D38}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
205
MetroUnlocker/App.Designer.cs
generated
Normal file
205
MetroUnlocker/App.Designer.cs
generated
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
namespace MetroUnlocker
|
||||||
|
{
|
||||||
|
partial class App
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Required designer variable.
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clean up any resources being used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param Name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && (components != null))
|
||||||
|
{
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Windows Form Designer generated code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required method for Designer support - do not modify
|
||||||
|
/// the contents of this method with the code editor.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(App));
|
||||||
|
this.temporaryButton = new System.Windows.Forms.Button();
|
||||||
|
this.developmentCheckbox = new System.Windows.Forms.CheckBox();
|
||||||
|
this.signedCheckbox = new System.Windows.Forms.CheckBox();
|
||||||
|
this.allUsersCheckbox = new System.Windows.Forms.CheckBox();
|
||||||
|
this.statusTextLabel = new System.Windows.Forms.Label();
|
||||||
|
this.statusLabel = new System.Windows.Forms.Label();
|
||||||
|
this.LOBCheckBox = new System.Windows.Forms.CheckBox();
|
||||||
|
this.SPPCheckBox = new System.Windows.Forms.CheckBox();
|
||||||
|
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
||||||
|
this.groupBox2 = new System.Windows.Forms.GroupBox();
|
||||||
|
this.Manual = new System.Windows.Forms.TabControl();
|
||||||
|
this.tabPage1 = new System.Windows.Forms.TabPage();
|
||||||
|
this.button1 = new System.Windows.Forms.Button();
|
||||||
|
this.tabPage2 = new System.Windows.Forms.TabPage();
|
||||||
|
this.button2 = new System.Windows.Forms.Button();
|
||||||
|
this.groupBox1.SuspendLayout();
|
||||||
|
this.groupBox2.SuspendLayout();
|
||||||
|
this.Manual.SuspendLayout();
|
||||||
|
this.tabPage1.SuspendLayout();
|
||||||
|
this.tabPage2.SuspendLayout();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// temporaryButton
|
||||||
|
//
|
||||||
|
resources.ApplyResources(this.temporaryButton, "temporaryButton");
|
||||||
|
this.temporaryButton.Name = "temporaryButton";
|
||||||
|
this.temporaryButton.UseVisualStyleBackColor = true;
|
||||||
|
this.temporaryButton.Click += new System.EventHandler(this.button1_Click);
|
||||||
|
//
|
||||||
|
// developmentCheckbox
|
||||||
|
//
|
||||||
|
resources.ApplyResources(this.developmentCheckbox, "developmentCheckbox");
|
||||||
|
this.developmentCheckbox.DataBindings.Add(new System.Windows.Forms.Binding("Checked", this, "DevelopmentEnabled", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||||
|
this.developmentCheckbox.Name = "developmentCheckbox";
|
||||||
|
this.developmentCheckbox.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// signedCheckbox
|
||||||
|
//
|
||||||
|
resources.ApplyResources(this.signedCheckbox, "signedCheckbox");
|
||||||
|
this.signedCheckbox.DataBindings.Add(new System.Windows.Forms.Binding("Checked", this, "LOBEnabled", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||||
|
this.signedCheckbox.Name = "signedCheckbox";
|
||||||
|
this.signedCheckbox.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// allUsersCheckbox
|
||||||
|
//
|
||||||
|
resources.ApplyResources(this.allUsersCheckbox, "allUsersCheckbox");
|
||||||
|
this.allUsersCheckbox.DataBindings.Add(new System.Windows.Forms.Binding("Checked", this, "SpecialProfilesEnabled", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
||||||
|
this.allUsersCheckbox.Name = "allUsersCheckbox";
|
||||||
|
this.allUsersCheckbox.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// statusTextLabel
|
||||||
|
//
|
||||||
|
resources.ApplyResources(this.statusTextLabel, "statusTextLabel");
|
||||||
|
this.statusTextLabel.Name = "statusTextLabel";
|
||||||
|
//
|
||||||
|
// statusLabel
|
||||||
|
//
|
||||||
|
resources.ApplyResources(this.statusLabel, "statusLabel");
|
||||||
|
this.statusLabel.Name = "statusLabel";
|
||||||
|
//
|
||||||
|
// LOBCheckBox
|
||||||
|
//
|
||||||
|
resources.ApplyResources(this.LOBCheckBox, "LOBCheckBox");
|
||||||
|
this.LOBCheckBox.Name = "LOBCheckBox";
|
||||||
|
this.LOBCheckBox.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// SPPCheckBox
|
||||||
|
//
|
||||||
|
resources.ApplyResources(this.SPPCheckBox, "SPPCheckBox");
|
||||||
|
this.SPPCheckBox.Name = "SPPCheckBox";
|
||||||
|
this.SPPCheckBox.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// groupBox1
|
||||||
|
//
|
||||||
|
resources.ApplyResources(this.groupBox1, "groupBox1");
|
||||||
|
this.groupBox1.Controls.Add(this.signedCheckbox);
|
||||||
|
this.groupBox1.Controls.Add(this.allUsersCheckbox);
|
||||||
|
this.groupBox1.Controls.Add(this.developmentCheckbox);
|
||||||
|
this.groupBox1.Name = "groupBox1";
|
||||||
|
this.groupBox1.TabStop = false;
|
||||||
|
//
|
||||||
|
// groupBox2
|
||||||
|
//
|
||||||
|
resources.ApplyResources(this.groupBox2, "groupBox2");
|
||||||
|
this.groupBox2.Controls.Add(this.LOBCheckBox);
|
||||||
|
this.groupBox2.Controls.Add(this.SPPCheckBox);
|
||||||
|
this.groupBox2.Controls.Add(this.temporaryButton);
|
||||||
|
this.groupBox2.Name = "groupBox2";
|
||||||
|
this.groupBox2.TabStop = false;
|
||||||
|
//
|
||||||
|
// Manual
|
||||||
|
//
|
||||||
|
resources.ApplyResources(this.Manual, "Manual");
|
||||||
|
this.Manual.Controls.Add(this.tabPage1);
|
||||||
|
this.Manual.Controls.Add(this.tabPage2);
|
||||||
|
this.Manual.Name = "Manual";
|
||||||
|
this.Manual.SelectedIndex = 0;
|
||||||
|
//
|
||||||
|
// tabPage1
|
||||||
|
//
|
||||||
|
this.tabPage1.Controls.Add(this.button2);
|
||||||
|
this.tabPage1.Controls.Add(this.button1);
|
||||||
|
resources.ApplyResources(this.tabPage1, "tabPage1");
|
||||||
|
this.tabPage1.Name = "tabPage1";
|
||||||
|
this.tabPage1.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// button1
|
||||||
|
//
|
||||||
|
resources.ApplyResources(this.button1, "button1");
|
||||||
|
this.button1.Name = "button1";
|
||||||
|
this.button1.UseVisualStyleBackColor = true;
|
||||||
|
this.button1.Click += new System.EventHandler(this.JailbreakButton_Click);
|
||||||
|
//
|
||||||
|
// tabPage2
|
||||||
|
//
|
||||||
|
this.tabPage2.Controls.Add(this.groupBox2);
|
||||||
|
this.tabPage2.Controls.Add(this.groupBox1);
|
||||||
|
resources.ApplyResources(this.tabPage2, "tabPage2");
|
||||||
|
this.tabPage2.Name = "tabPage2";
|
||||||
|
this.tabPage2.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// button2
|
||||||
|
//
|
||||||
|
resources.ApplyResources(this.button2, "button2");
|
||||||
|
this.button2.Name = "button2";
|
||||||
|
this.button2.UseVisualStyleBackColor = true;
|
||||||
|
this.button2.Click += new System.EventHandler(this.Uninstall);
|
||||||
|
//
|
||||||
|
// App
|
||||||
|
//
|
||||||
|
resources.ApplyResources(this, "$this");
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.Controls.Add(this.Manual);
|
||||||
|
this.Controls.Add(this.statusLabel);
|
||||||
|
this.Controls.Add(this.statusTextLabel);
|
||||||
|
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||||
|
this.MaximizeBox = false;
|
||||||
|
this.MinimizeBox = false;
|
||||||
|
this.Name = "App";
|
||||||
|
this.ShowIcon = false;
|
||||||
|
this.ShowInTaskbar = false;
|
||||||
|
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
|
||||||
|
this.groupBox1.ResumeLayout(false);
|
||||||
|
this.groupBox1.PerformLayout();
|
||||||
|
this.groupBox2.ResumeLayout(false);
|
||||||
|
this.groupBox2.PerformLayout();
|
||||||
|
this.Manual.ResumeLayout(false);
|
||||||
|
this.tabPage1.ResumeLayout(false);
|
||||||
|
this.tabPage2.ResumeLayout(false);
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private System.Windows.Forms.Button temporaryButton;
|
||||||
|
private System.Windows.Forms.CheckBox developmentCheckbox;
|
||||||
|
private System.Windows.Forms.CheckBox signedCheckbox;
|
||||||
|
private System.Windows.Forms.CheckBox allUsersCheckbox;
|
||||||
|
private System.Windows.Forms.Label statusTextLabel;
|
||||||
|
private System.Windows.Forms.Label statusLabel;
|
||||||
|
private System.Windows.Forms.GroupBox groupBox2;
|
||||||
|
private System.Windows.Forms.CheckBox LOBCheckBox;
|
||||||
|
private System.Windows.Forms.CheckBox SPPCheckBox;
|
||||||
|
private System.Windows.Forms.GroupBox groupBox1;
|
||||||
|
private System.Windows.Forms.TabControl Manual;
|
||||||
|
private System.Windows.Forms.TabPage tabPage1;
|
||||||
|
private System.Windows.Forms.Button button1;
|
||||||
|
private System.Windows.Forms.TabPage tabPage2;
|
||||||
|
private System.Windows.Forms.Button button2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
173
MetroUnlocker/App.cs
Normal file
173
MetroUnlocker/App.cs
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Data;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
|
||||||
|
using MetroUnlocker.ProductPolicy;
|
||||||
|
|
||||||
|
namespace MetroUnlocker
|
||||||
|
{
|
||||||
|
public partial class App : Form
|
||||||
|
{
|
||||||
|
public const string AppxKey = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Policies\\Microsoft\\Windows\\Appx";
|
||||||
|
|
||||||
|
string trustedAppsPolicyName = "AllowAllTrustedApps";
|
||||||
|
string developmentPolicyName = "AllowDevelopmentWithoutDevLicense";
|
||||||
|
string specialProfilesPolicyName = "AllowDeploymentInSpecialProfiles";
|
||||||
|
|
||||||
|
public bool LOBEnabled
|
||||||
|
{
|
||||||
|
get { return GetGroupPolicy(trustedAppsPolicyName); }
|
||||||
|
set { SetGroupPolicy(trustedAppsPolicyName, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DevelopmentEnabled
|
||||||
|
{
|
||||||
|
get { return GetGroupPolicy(developmentPolicyName); }
|
||||||
|
set { SetGroupPolicy(developmentPolicyName, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SpecialProfilesEnabled
|
||||||
|
{
|
||||||
|
get { return GetGroupPolicy(specialProfilesPolicyName); }
|
||||||
|
set { SetGroupPolicy(specialProfilesPolicyName, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetGroupPolicy(string policyName, bool enabled)
|
||||||
|
{
|
||||||
|
Registry.SetValue(AppxKey, policyName, enabled ? 1 : 0, RegistryValueKind.DWord);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool GetGroupPolicy(string policyName)
|
||||||
|
{
|
||||||
|
object value = Registry.GetValue(AppxKey, policyName, 0);
|
||||||
|
return value is int ? (int)value == 1 : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public App()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
UpdatePolicyState();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdatePolicyState()
|
||||||
|
{
|
||||||
|
var productPolicyEditor = new ProductPolicyEditor();
|
||||||
|
|
||||||
|
var policyState = productPolicyEditor.GetPolicyStateByName("WSLicensingService-LOBSideloadingActivated");
|
||||||
|
var isSideloadingKeyInstalled = LOBManager.IsSideloadingKeyInstalled();
|
||||||
|
|
||||||
|
switch (policyState)
|
||||||
|
{
|
||||||
|
case PolicyState.Disabled:
|
||||||
|
statusLabel.Text = "Disabled";
|
||||||
|
statusLabel.ForeColor = Color.DarkRed;
|
||||||
|
break;
|
||||||
|
case PolicyState.Enabled:
|
||||||
|
if (isSideloadingKeyInstalled)
|
||||||
|
{
|
||||||
|
statusLabel.Text = "Sideloading enabled";
|
||||||
|
statusLabel.ForeColor = Color.DarkGreen;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
statusLabel.Text = "Sideloading will be disabled soon";
|
||||||
|
statusLabel.ForeColor = Color.DarkOrange;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PolicyState.Unknown:
|
||||||
|
statusLabel.Text = "Unknown";
|
||||||
|
statusLabel.ForeColor = Color.Black;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string CombineArguments(params string[] arguments)
|
||||||
|
{
|
||||||
|
return string.Join(" ", arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetSetupParameter(string key, object value, RegistryValueKind valueKind)
|
||||||
|
{
|
||||||
|
Registry.SetValue("HKEY_LOCAL_MACHINE\\SYSTEM\\Setup", key, value, valueKind);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetSetupType(int type)
|
||||||
|
{
|
||||||
|
SetSetupParameter("SetupType", type, RegistryValueKind.DWord);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void button1_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
StartupArgument startupArgument;
|
||||||
|
|
||||||
|
if (LOBCheckBox.Checked && SPPCheckBox.Checked)
|
||||||
|
startupArgument = StartupArgument.EnableLOBAndEnableSPP;
|
||||||
|
else if (LOBCheckBox.Checked)
|
||||||
|
startupArgument = StartupArgument.EnableLOBAndDisableSPP;
|
||||||
|
else if (SPPCheckBox.Checked)
|
||||||
|
startupArgument = StartupArgument.DisableLOBAndEnableSPP;
|
||||||
|
else
|
||||||
|
startupArgument = StartupArgument.DisableLOBAndDisableSPP;
|
||||||
|
|
||||||
|
string commandLine = CombineArguments(new string[] { Application.ExecutablePath, StartupArguments.GetStartupArgumentString(startupArgument) });
|
||||||
|
|
||||||
|
SetSetupParameter("CmdLine", commandLine, RegistryValueKind.String);
|
||||||
|
SetSetupType(1);
|
||||||
|
DialogResult result = MessageBox.Show("Sideloading will be enabled after a reboot. Would you like to reboot now?", "Reboot?", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
|
||||||
|
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case DialogResult.Yes:
|
||||||
|
Rebooter.Reboot();
|
||||||
|
break;
|
||||||
|
case DialogResult.Cancel:
|
||||||
|
SetSetupType(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void JailbreakButton_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Guid productKey;
|
||||||
|
if (LOBManager.IsSideloadingKeyInstalled(out productKey))
|
||||||
|
if (MessageBox.Show(this, "There is already a sideloading key installed. If you continue, the current key will be deleted and a new one will be generated.", "Already activated", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.Cancel)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LOBManager.ActivateZeroCID();
|
||||||
|
MessageBox.Show(this, "Sideloading activated!", "Success!", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||||
|
UpdatePolicyState();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show(this, ex.Message, "Error while activating sideloading!", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Uninstall(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
Guid productKey;
|
||||||
|
if (LOBManager.IsSideloadingKeyInstalled(out productKey))
|
||||||
|
{
|
||||||
|
if (MessageBox.Show(this, "Are you sure you want to disable sideloading?", "Really?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
|
||||||
|
{
|
||||||
|
if (LOBManager.UninstallSideloadingKey(productKey))
|
||||||
|
MessageBox.Show(this, "The sideloading key was uninstalled successfully.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||||
|
else MessageBox.Show(this, "Could not uninstall the sideloading key.", "Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
UpdatePolicyState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else MessageBox.Show(this, "There is no sideloading key installed.", "I got nothing to do...", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
564
MetroUnlocker/App.resx
Normal file
564
MetroUnlocker/App.resx
Normal file
@@ -0,0 +1,564 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||||
|
<data name="temporaryButton.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||||
|
<value>Bottom, Left, Right</value>
|
||||||
|
</data>
|
||||||
|
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||||
|
<data name="temporaryButton.Location" type="System.Drawing.Point, System.Drawing">
|
||||||
|
<value>6, 42</value>
|
||||||
|
</data>
|
||||||
|
<data name="temporaryButton.Size" type="System.Drawing.Size, System.Drawing">
|
||||||
|
<value>210, 23</value>
|
||||||
|
</data>
|
||||||
|
<assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||||
|
<data name="temporaryButton.TabIndex" type="System.Int32, mscorlib">
|
||||||
|
<value>0</value>
|
||||||
|
</data>
|
||||||
|
<data name="temporaryButton.Text" xml:space="preserve">
|
||||||
|
<value>Reboot to Apply</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>temporaryButton.Name" xml:space="preserve">
|
||||||
|
<value>temporaryButton</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>temporaryButton.Type" xml:space="preserve">
|
||||||
|
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>temporaryButton.Parent" xml:space="preserve">
|
||||||
|
<value>groupBox2</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>temporaryButton.ZOrder" xml:space="preserve">
|
||||||
|
<value>2</value>
|
||||||
|
</data>
|
||||||
|
<data name="developmentCheckbox.AccessibleDescription" xml:space="preserve">
|
||||||
|
<value>Allows sideloading of unpackaged apps.</value>
|
||||||
|
</data>
|
||||||
|
<data name="developmentCheckbox.AutoSize" type="System.Boolean, mscorlib">
|
||||||
|
<value>True</value>
|
||||||
|
</data>
|
||||||
|
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>True</value>
|
||||||
|
</metadata>
|
||||||
|
<data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
|
||||||
|
<value>6, 13</value>
|
||||||
|
</data>
|
||||||
|
<data name="$this.AutoSize" type="System.Boolean, mscorlib">
|
||||||
|
<value>True</value>
|
||||||
|
</data>
|
||||||
|
<data name="$this.AutoSizeMode" type="System.Windows.Forms.AutoSizeMode, System.Windows.Forms">
|
||||||
|
<value>GrowAndShrink</value>
|
||||||
|
</data>
|
||||||
|
<data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
|
||||||
|
<value>266, 215</value>
|
||||||
|
</data>
|
||||||
|
<data name="Manual.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||||
|
<value>Top, Bottom, Left, Right</value>
|
||||||
|
</data>
|
||||||
|
<data name="button2.Location" type="System.Drawing.Point, System.Drawing">
|
||||||
|
<value>7, 123</value>
|
||||||
|
</data>
|
||||||
|
<data name="button2.Size" type="System.Drawing.Size, System.Drawing">
|
||||||
|
<value>221, 23</value>
|
||||||
|
</data>
|
||||||
|
<data name="button2.TabIndex" type="System.Int32, mscorlib">
|
||||||
|
<value>1</value>
|
||||||
|
</data>
|
||||||
|
<data name="button2.Text" xml:space="preserve">
|
||||||
|
<value>Disable Sideloading</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>button2.Name" xml:space="preserve">
|
||||||
|
<value>button2</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>button2.Type" xml:space="preserve">
|
||||||
|
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>button2.Parent" xml:space="preserve">
|
||||||
|
<value>tabPage1</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>button2.ZOrder" xml:space="preserve">
|
||||||
|
<value>0</value>
|
||||||
|
</data>
|
||||||
|
<data name="button1.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||||
|
<value>Top, Bottom, Left, Right</value>
|
||||||
|
</data>
|
||||||
|
<data name="button1.Location" type="System.Drawing.Point, System.Drawing">
|
||||||
|
<value>6, 6</value>
|
||||||
|
</data>
|
||||||
|
<data name="button1.Size" type="System.Drawing.Size, System.Drawing">
|
||||||
|
<value>222, 111</value>
|
||||||
|
</data>
|
||||||
|
<data name="button1.TabIndex" type="System.Int32, mscorlib">
|
||||||
|
<value>0</value>
|
||||||
|
</data>
|
||||||
|
<data name="button1.Text" xml:space="preserve">
|
||||||
|
<value>Unlock!</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>button1.Name" xml:space="preserve">
|
||||||
|
<value>button1</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>button1.Type" xml:space="preserve">
|
||||||
|
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>button1.Parent" xml:space="preserve">
|
||||||
|
<value>tabPage1</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>button1.ZOrder" xml:space="preserve">
|
||||||
|
<value>1</value>
|
||||||
|
</data>
|
||||||
|
<data name="tabPage1.Location" type="System.Drawing.Point, System.Drawing">
|
||||||
|
<value>4, 22</value>
|
||||||
|
</data>
|
||||||
|
<data name="tabPage1.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||||
|
<value>3, 3, 3, 3</value>
|
||||||
|
</data>
|
||||||
|
<data name="tabPage1.Size" type="System.Drawing.Size, System.Drawing">
|
||||||
|
<value>234, 152</value>
|
||||||
|
</data>
|
||||||
|
<data name="tabPage1.TabIndex" type="System.Int32, mscorlib">
|
||||||
|
<value>0</value>
|
||||||
|
</data>
|
||||||
|
<data name="tabPage1.Text" xml:space="preserve">
|
||||||
|
<value>Jailbreak</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>tabPage1.Name" xml:space="preserve">
|
||||||
|
<value>tabPage1</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>tabPage1.Type" xml:space="preserve">
|
||||||
|
<value>System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>tabPage1.Parent" xml:space="preserve">
|
||||||
|
<value>Manual</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>tabPage1.ZOrder" xml:space="preserve">
|
||||||
|
<value>0</value>
|
||||||
|
</data>
|
||||||
|
<data name="groupBox2.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||||
|
<value>Top, Bottom, Left, Right</value>
|
||||||
|
</data>
|
||||||
|
<data name="LOBCheckBox.AutoSize" type="System.Boolean, mscorlib">
|
||||||
|
<value>True</value>
|
||||||
|
</data>
|
||||||
|
<data name="LOBCheckBox.Location" type="System.Drawing.Point, System.Drawing">
|
||||||
|
<value>6, 19</value>
|
||||||
|
</data>
|
||||||
|
<data name="LOBCheckBox.Size" type="System.Drawing.Size, System.Drawing">
|
||||||
|
<value>81, 17</value>
|
||||||
|
</data>
|
||||||
|
<data name="LOBCheckBox.TabIndex" type="System.Int32, mscorlib">
|
||||||
|
<value>1</value>
|
||||||
|
</data>
|
||||||
|
<data name="LOBCheckBox.Text" xml:space="preserve">
|
||||||
|
<value>Sideloading</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>LOBCheckBox.Name" xml:space="preserve">
|
||||||
|
<value>LOBCheckBox</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>LOBCheckBox.Type" xml:space="preserve">
|
||||||
|
<value>System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>LOBCheckBox.Parent" xml:space="preserve">
|
||||||
|
<value>groupBox2</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>LOBCheckBox.ZOrder" xml:space="preserve">
|
||||||
|
<value>0</value>
|
||||||
|
</data>
|
||||||
|
<data name="SPPCheckBox.AutoSize" type="System.Boolean, mscorlib">
|
||||||
|
<value>True</value>
|
||||||
|
</data>
|
||||||
|
<data name="SPPCheckBox.Location" type="System.Drawing.Point, System.Drawing">
|
||||||
|
<value>95, 19</value>
|
||||||
|
</data>
|
||||||
|
<data name="SPPCheckBox.Size" type="System.Drawing.Size, System.Drawing">
|
||||||
|
<value>119, 17</value>
|
||||||
|
</data>
|
||||||
|
<data name="SPPCheckBox.TabIndex" type="System.Int32, mscorlib">
|
||||||
|
<value>2</value>
|
||||||
|
</data>
|
||||||
|
<data name="SPPCheckBox.Text" xml:space="preserve">
|
||||||
|
<value>Software Protection</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>SPPCheckBox.Name" xml:space="preserve">
|
||||||
|
<value>SPPCheckBox</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>SPPCheckBox.Type" xml:space="preserve">
|
||||||
|
<value>System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>SPPCheckBox.Parent" xml:space="preserve">
|
||||||
|
<value>groupBox2</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>SPPCheckBox.ZOrder" xml:space="preserve">
|
||||||
|
<value>1</value>
|
||||||
|
</data>
|
||||||
|
<data name="groupBox2.Location" type="System.Drawing.Point, System.Drawing">
|
||||||
|
<value>6, 75</value>
|
||||||
|
</data>
|
||||||
|
<data name="groupBox2.Size" type="System.Drawing.Size, System.Drawing">
|
||||||
|
<value>222, 71</value>
|
||||||
|
</data>
|
||||||
|
<data name="groupBox2.TabIndex" type="System.Int32, mscorlib">
|
||||||
|
<value>8</value>
|
||||||
|
</data>
|
||||||
|
<data name="groupBox2.Text" xml:space="preserve">
|
||||||
|
<value>Product Policy</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>groupBox2.Name" xml:space="preserve">
|
||||||
|
<value>groupBox2</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>groupBox2.Type" xml:space="preserve">
|
||||||
|
<value>System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>groupBox2.Parent" xml:space="preserve">
|
||||||
|
<value>tabPage2</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>groupBox2.ZOrder" xml:space="preserve">
|
||||||
|
<value>0</value>
|
||||||
|
</data>
|
||||||
|
<data name="groupBox1.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||||
|
<value>Top, Left, Right</value>
|
||||||
|
</data>
|
||||||
|
<data name="signedCheckbox.AccessibleDescription" xml:space="preserve">
|
||||||
|
<value>Enables sideloading of signed apps.</value>
|
||||||
|
</data>
|
||||||
|
<data name="signedCheckbox.AutoSize" type="System.Boolean, mscorlib">
|
||||||
|
<value>True</value>
|
||||||
|
</data>
|
||||||
|
<data name="signedCheckbox.Location" type="System.Drawing.Point, System.Drawing">
|
||||||
|
<value>6, 19</value>
|
||||||
|
</data>
|
||||||
|
<data name="signedCheckbox.Size" type="System.Drawing.Size, System.Drawing">
|
||||||
|
<value>117, 17</value>
|
||||||
|
</data>
|
||||||
|
<data name="signedCheckbox.TabIndex" type="System.Int32, mscorlib">
|
||||||
|
<value>3</value>
|
||||||
|
</data>
|
||||||
|
<data name="signedCheckbox.Text" xml:space="preserve">
|
||||||
|
<value>Signed Sideloading</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>signedCheckbox.Name" xml:space="preserve">
|
||||||
|
<value>signedCheckbox</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>signedCheckbox.Type" xml:space="preserve">
|
||||||
|
<value>System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>signedCheckbox.Parent" xml:space="preserve">
|
||||||
|
<value>groupBox1</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>signedCheckbox.ZOrder" xml:space="preserve">
|
||||||
|
<value>0</value>
|
||||||
|
</data>
|
||||||
|
<data name="allUsersCheckbox.AccessibleDescription" xml:space="preserve">
|
||||||
|
<value>Enables managing Store apps on guest and temporary users.</value>
|
||||||
|
</data>
|
||||||
|
<data name="allUsersCheckbox.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||||
|
<value>Top, Right</value>
|
||||||
|
</data>
|
||||||
|
<data name="allUsersCheckbox.AutoSize" type="System.Boolean, mscorlib">
|
||||||
|
<value>True</value>
|
||||||
|
</data>
|
||||||
|
<data name="allUsersCheckbox.Location" type="System.Drawing.Point, System.Drawing">
|
||||||
|
<value>149, 19</value>
|
||||||
|
</data>
|
||||||
|
<data name="allUsersCheckbox.Size" type="System.Drawing.Size, System.Drawing">
|
||||||
|
<value>67, 17</value>
|
||||||
|
</data>
|
||||||
|
<data name="allUsersCheckbox.TabIndex" type="System.Int32, mscorlib">
|
||||||
|
<value>4</value>
|
||||||
|
</data>
|
||||||
|
<data name="allUsersCheckbox.Text" xml:space="preserve">
|
||||||
|
<value>All Users</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>allUsersCheckbox.Name" xml:space="preserve">
|
||||||
|
<value>allUsersCheckbox</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>allUsersCheckbox.Type" xml:space="preserve">
|
||||||
|
<value>System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>allUsersCheckbox.Parent" xml:space="preserve">
|
||||||
|
<value>groupBox1</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>allUsersCheckbox.ZOrder" xml:space="preserve">
|
||||||
|
<value>1</value>
|
||||||
|
</data>
|
||||||
|
<data name="groupBox1.Location" type="System.Drawing.Point, System.Drawing">
|
||||||
|
<value>6, 6</value>
|
||||||
|
</data>
|
||||||
|
<data name="groupBox1.Size" type="System.Drawing.Size, System.Drawing">
|
||||||
|
<value>222, 63</value>
|
||||||
|
</data>
|
||||||
|
<data name="groupBox1.TabIndex" type="System.Int32, mscorlib">
|
||||||
|
<value>7</value>
|
||||||
|
</data>
|
||||||
|
<data name="groupBox1.Text" xml:space="preserve">
|
||||||
|
<value>Group Policy</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>groupBox1.Name" xml:space="preserve">
|
||||||
|
<value>groupBox1</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>groupBox1.Type" xml:space="preserve">
|
||||||
|
<value>System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>groupBox1.Parent" xml:space="preserve">
|
||||||
|
<value>tabPage2</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>groupBox1.ZOrder" xml:space="preserve">
|
||||||
|
<value>1</value>
|
||||||
|
</data>
|
||||||
|
<data name="tabPage2.Location" type="System.Drawing.Point, System.Drawing">
|
||||||
|
<value>4, 22</value>
|
||||||
|
</data>
|
||||||
|
<data name="tabPage2.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||||
|
<value>3, 3, 3, 3</value>
|
||||||
|
</data>
|
||||||
|
<data name="tabPage2.Size" type="System.Drawing.Size, System.Drawing">
|
||||||
|
<value>234, 152</value>
|
||||||
|
</data>
|
||||||
|
<data name="tabPage2.TabIndex" type="System.Int32, mscorlib">
|
||||||
|
<value>1</value>
|
||||||
|
</data>
|
||||||
|
<data name="tabPage2.Text" xml:space="preserve">
|
||||||
|
<value>Manual</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>tabPage2.Name" xml:space="preserve">
|
||||||
|
<value>tabPage2</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>tabPage2.Type" xml:space="preserve">
|
||||||
|
<value>System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>tabPage2.Parent" xml:space="preserve">
|
||||||
|
<value>Manual</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>tabPage2.ZOrder" xml:space="preserve">
|
||||||
|
<value>1</value>
|
||||||
|
</data>
|
||||||
|
<data name="Manual.Location" type="System.Drawing.Point, System.Drawing">
|
||||||
|
<value>12, 25</value>
|
||||||
|
</data>
|
||||||
|
<data name="Manual.Size" type="System.Drawing.Size, System.Drawing">
|
||||||
|
<value>242, 178</value>
|
||||||
|
</data>
|
||||||
|
<data name="Manual.TabIndex" type="System.Int32, mscorlib">
|
||||||
|
<value>9</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>Manual.Name" xml:space="preserve">
|
||||||
|
<value>Manual</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>Manual.Type" xml:space="preserve">
|
||||||
|
<value>System.Windows.Forms.TabControl, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>Manual.Parent" xml:space="preserve">
|
||||||
|
<value>$this</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>Manual.ZOrder" xml:space="preserve">
|
||||||
|
<value>0</value>
|
||||||
|
</data>
|
||||||
|
<data name="statusLabel.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||||
|
<value>Top, Right</value>
|
||||||
|
</data>
|
||||||
|
<data name="statusLabel.Location" type="System.Drawing.Point, System.Drawing">
|
||||||
|
<value>58, 9</value>
|
||||||
|
</data>
|
||||||
|
<data name="statusLabel.Size" type="System.Drawing.Size, System.Drawing">
|
||||||
|
<value>196, 13</value>
|
||||||
|
</data>
|
||||||
|
<data name="statusLabel.TabIndex" type="System.Int32, mscorlib">
|
||||||
|
<value>6</value>
|
||||||
|
</data>
|
||||||
|
<data name="statusLabel.Text" xml:space="preserve">
|
||||||
|
<value>Unknown</value>
|
||||||
|
</data>
|
||||||
|
<data name="statusLabel.TextAlign" type="System.Drawing.ContentAlignment, System.Drawing">
|
||||||
|
<value>TopRight</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>statusLabel.Name" xml:space="preserve">
|
||||||
|
<value>statusLabel</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>statusLabel.Type" xml:space="preserve">
|
||||||
|
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>statusLabel.Parent" xml:space="preserve">
|
||||||
|
<value>$this</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>statusLabel.ZOrder" xml:space="preserve">
|
||||||
|
<value>1</value>
|
||||||
|
</data>
|
||||||
|
<data name="statusTextLabel.AutoSize" type="System.Boolean, mscorlib">
|
||||||
|
<value>True</value>
|
||||||
|
</data>
|
||||||
|
<data name="statusTextLabel.Location" type="System.Drawing.Point, System.Drawing">
|
||||||
|
<value>12, 9</value>
|
||||||
|
</data>
|
||||||
|
<data name="statusTextLabel.Size" type="System.Drawing.Size, System.Drawing">
|
||||||
|
<value>40, 13</value>
|
||||||
|
</data>
|
||||||
|
<data name="statusTextLabel.TabIndex" type="System.Int32, mscorlib">
|
||||||
|
<value>5</value>
|
||||||
|
</data>
|
||||||
|
<data name="statusTextLabel.Text" xml:space="preserve">
|
||||||
|
<value>Status:</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>statusTextLabel.Name" xml:space="preserve">
|
||||||
|
<value>statusTextLabel</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>statusTextLabel.Type" xml:space="preserve">
|
||||||
|
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>statusTextLabel.Parent" xml:space="preserve">
|
||||||
|
<value>$this</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>statusTextLabel.ZOrder" xml:space="preserve">
|
||||||
|
<value>2</value>
|
||||||
|
</data>
|
||||||
|
<data name="$this.StartPosition" type="System.Windows.Forms.FormStartPosition, System.Windows.Forms">
|
||||||
|
<value>CenterScreen</value>
|
||||||
|
</data>
|
||||||
|
<data name="$this.Text" xml:space="preserve">
|
||||||
|
<value>Sideloading Unlocker</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>$this.Name" xml:space="preserve">
|
||||||
|
<value>App</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>$this.Type" xml:space="preserve">
|
||||||
|
<value>System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</data>
|
||||||
|
<data name="developmentCheckbox.Location" type="System.Drawing.Point, System.Drawing">
|
||||||
|
<value>6, 42</value>
|
||||||
|
</data>
|
||||||
|
<data name="developmentCheckbox.Size" type="System.Drawing.Size, System.Drawing">
|
||||||
|
<value>147, 17</value>
|
||||||
|
</data>
|
||||||
|
<data name="developmentCheckbox.TabIndex" type="System.Int32, mscorlib">
|
||||||
|
<value>2</value>
|
||||||
|
</data>
|
||||||
|
<data name="developmentCheckbox.Text" xml:space="preserve">
|
||||||
|
<value>Development Sideloading</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>developmentCheckbox.Name" xml:space="preserve">
|
||||||
|
<value>developmentCheckbox</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>developmentCheckbox.Type" xml:space="preserve">
|
||||||
|
<value>System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>developmentCheckbox.Parent" xml:space="preserve">
|
||||||
|
<value>groupBox1</value>
|
||||||
|
</data>
|
||||||
|
<data name=">>developmentCheckbox.ZOrder" xml:space="preserve">
|
||||||
|
<value>2</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
107
MetroUnlocker/LOBManager.cs
Normal file
107
MetroUnlocker/LOBManager.cs
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
using MetroUnlocker.ProductPolicy;
|
||||||
|
using MetroUnlocker;
|
||||||
|
using MetroUnlocker.LibTSForge.PhysicalStore;
|
||||||
|
using MetroUnlocker.LibTSForge.Modifiers;
|
||||||
|
using MetroUnlocker.LibTSForge.TokenStore;
|
||||||
|
using MetroUnlocker.LibTSForge.SPP;
|
||||||
|
|
||||||
|
namespace MetroUnlocker
|
||||||
|
{
|
||||||
|
public class LOBManager
|
||||||
|
{
|
||||||
|
private static Guid ActivationId = new Guid("ec67814b-30e6-4a50-bf7b-d55daf729d1e");
|
||||||
|
|
||||||
|
public static bool Backup = true;
|
||||||
|
|
||||||
|
public static void ActivateZeroCID()
|
||||||
|
{
|
||||||
|
PSVersion version = Utils.DetectVersion();
|
||||||
|
bool production = Utils.DetectCurrentKey();
|
||||||
|
|
||||||
|
if (Backup) BackupPhysicalStore();
|
||||||
|
|
||||||
|
GenPKeyInstall.InstallGenPKey(version, production, ActivationId);
|
||||||
|
|
||||||
|
ZeroCID.Activate(version, production, ActivationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Guid GetInstalledSideloadingKeyId()
|
||||||
|
{
|
||||||
|
return SLApi.GetInstalledPkeyId(ActivationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsSideloadingKeyInstalled(out Guid sideloadingKeyId)
|
||||||
|
{
|
||||||
|
return (sideloadingKeyId = GetInstalledSideloadingKeyId()) != Guid.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool UninstallSideloadingKey(Guid sideloadingKeyId)
|
||||||
|
{
|
||||||
|
if (Backup) BackupPhysicalStore();
|
||||||
|
bool result = SLApi.UninstallProductKey(sideloadingKeyId) == 0;
|
||||||
|
SLApi.RefreshLicenseStatus();
|
||||||
|
SLApi.FireStateChangedEvent(SLApi.GetAppId(ActivationId));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetUniqueFileName(string fileName)
|
||||||
|
{
|
||||||
|
string uniqueFileName = fileName;
|
||||||
|
|
||||||
|
for (int i = 1; File.Exists(uniqueFileName); i++)
|
||||||
|
{
|
||||||
|
string extension = Path.GetExtension(fileName);
|
||||||
|
string path = Path.GetFileNameWithoutExtension(fileName);
|
||||||
|
uniqueFileName = string.Format("{0}{1}.{2}", path, extension, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return uniqueFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void BackupPhysicalStore()
|
||||||
|
{
|
||||||
|
string backupFileName = "data.dat.bak";
|
||||||
|
|
||||||
|
string physicalStore = PhysicalStore.GetPath();
|
||||||
|
|
||||||
|
File.Copy(physicalStore, GetUniqueFileName(backupFileName), false);
|
||||||
|
|
||||||
|
|
||||||
|
backupFileName = "tokens.dat.bak";
|
||||||
|
|
||||||
|
physicalStore = TokenStore.GetPath();
|
||||||
|
|
||||||
|
File.Copy(physicalStore, GetUniqueFileName(backupFileName), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool SetPolicyState(PolicyState state)
|
||||||
|
{
|
||||||
|
ProductPolicyEditor policyEditor = new ProductPolicyEditor();
|
||||||
|
policyEditor.SetPolicyStateByName("WSLicensingService-LOBSideloadingActivated", state);
|
||||||
|
return policyEditor.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool Enable()
|
||||||
|
{
|
||||||
|
return SetPolicyState(PolicyState.Enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool Disable()
|
||||||
|
{
|
||||||
|
return SetPolicyState(PolicyState.Disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsSideloadingKeyInstalled()
|
||||||
|
{
|
||||||
|
Guid sideloadingKeyId;
|
||||||
|
return IsSideloadingKeyInstalled(out sideloadingKeyId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
281
MetroUnlocker/LibTSForge/Common.cs
Normal file
281
MetroUnlocker/LibTSForge/Common.cs
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
using Microsoft.Win32;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.ServiceProcess;
|
||||||
|
using System.Text;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
//using MetroUnlocker.Crypto;
|
||||||
|
//using MetroUnlocker.PhysicalStore;
|
||||||
|
using MetroUnlocker.LibTSForge.SPP;
|
||||||
|
//using MetroUnlocker.TokenStore;
|
||||||
|
|
||||||
|
// Common.cs
|
||||||
|
namespace MetroUnlocker
|
||||||
|
{
|
||||||
|
public enum PSVersion
|
||||||
|
{
|
||||||
|
Win8Early,
|
||||||
|
Win8,
|
||||||
|
WinBlue,
|
||||||
|
WinModern
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum BlockType : uint
|
||||||
|
{
|
||||||
|
NONE,
|
||||||
|
NAMED,
|
||||||
|
ATTRIBUTE,
|
||||||
|
TIMER
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Constants
|
||||||
|
{
|
||||||
|
public static readonly string ZeroCID = new string('0', 48);
|
||||||
|
public static readonly byte[] UniversalHWIDBlock =
|
||||||
|
{
|
||||||
|
0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 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, 0x01, 0x0c, 0x01, 0x00
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Utils
|
||||||
|
{
|
||||||
|
[DllImport("kernel32.dll")]
|
||||||
|
public static extern uint GetSystemDefaultLCID();
|
||||||
|
|
||||||
|
public static string GetArchitecture()
|
||||||
|
{
|
||||||
|
string arch = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE", EnvironmentVariableTarget.Machine).ToUpperInvariant();
|
||||||
|
return arch == "AMD64" ? "X64" : arch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void WritePadding(this BinaryWriter writer, int len)
|
||||||
|
{
|
||||||
|
writer.Write(Enumerable.Repeat((byte)0, len).ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void WriteFixedString(this BinaryWriter writer, string str, int bLen)
|
||||||
|
{
|
||||||
|
writer.Write(Encoding.ASCII.GetBytes(str));
|
||||||
|
writer.WritePadding(bLen - str.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void WriteFixedString16(this BinaryWriter writer, string str, int bLen)
|
||||||
|
{
|
||||||
|
byte[] bstr = Utils.EncodeString(str);
|
||||||
|
writer.Write(bstr);
|
||||||
|
writer.WritePadding(bLen - bstr.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Align(this BinaryWriter writer, int to)
|
||||||
|
{
|
||||||
|
int pos = (int)writer.BaseStream.Position;
|
||||||
|
writer.Write(Enumerable.Repeat((byte)0, -pos & (to - 1)).ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Align(this BinaryReader reader, int to)
|
||||||
|
{
|
||||||
|
int pos = (int)reader.BaseStream.Position;
|
||||||
|
reader.BaseStream.Seek(-pos & (to - 1), SeekOrigin.Current);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ReadNullTerminatedString(this BinaryReader reader, int maxLen)
|
||||||
|
{
|
||||||
|
return Encoding.Unicode.GetString(reader.ReadBytes(maxLen)).Split(new char[] { '\0' }, 2)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] GetBytes(this BinaryWriter writer)
|
||||||
|
{
|
||||||
|
return ((MemoryStream)writer.BaseStream).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void WriteAllBytes(FileStream fs, byte[] data)
|
||||||
|
{
|
||||||
|
fs.Seek(0, SeekOrigin.Begin);
|
||||||
|
fs.SetLength(data.Length);
|
||||||
|
fs.Write(data, 0, data.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] ReadAllBytes(FileStream fs)
|
||||||
|
{
|
||||||
|
BinaryReader br = new BinaryReader(fs);
|
||||||
|
return br.ReadBytes((int)fs.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static uint CRC32(byte[] data)
|
||||||
|
{
|
||||||
|
const uint polynomial = 0x04C11DB7;
|
||||||
|
uint crc = 0xffffffff;
|
||||||
|
|
||||||
|
foreach (byte b in data)
|
||||||
|
{
|
||||||
|
crc ^= (uint)b << 24;
|
||||||
|
for (int bit = 0; bit < 8; bit++)
|
||||||
|
{
|
||||||
|
if ((crc & 0x80000000) != 0)
|
||||||
|
{
|
||||||
|
crc = (crc << 1) ^ polynomial;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
crc <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ~crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void KillSPP()
|
||||||
|
{
|
||||||
|
ServiceController sc;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sc = new ServiceController("sppsvc");
|
||||||
|
|
||||||
|
if (sc.Status == ServiceControllerStatus.Stopped)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException ex)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Unable to access sppsvc: " + ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Logger.WriteLine("Stopping sppsvc...");
|
||||||
|
|
||||||
|
bool stopped = false;
|
||||||
|
|
||||||
|
for (int i = 0; stopped == false && i < 60; i++)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (sc.Status != ServiceControllerStatus.StopPending)
|
||||||
|
sc.Stop();
|
||||||
|
|
||||||
|
sc.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromMilliseconds(500));
|
||||||
|
}
|
||||||
|
catch (System.ServiceProcess.TimeoutException)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException)
|
||||||
|
{
|
||||||
|
System.Threading.Thread.Sleep(500);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
stopped = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stopped)
|
||||||
|
throw new System.TimeoutException("Failed to stop sppsvc");
|
||||||
|
|
||||||
|
//Logger.WriteLine("sppsvc stopped successfully.");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PSVersion DetectVersion()
|
||||||
|
{
|
||||||
|
int build = Environment.OSVersion.Version.Build;
|
||||||
|
|
||||||
|
if (build >= 9600) return PSVersion.WinModern;
|
||||||
|
//if (build >= 6000 && build <= 6003) return PSVersion.Vista;
|
||||||
|
//if (build >= 7600 && build <= 7602) return PSVersion.Win7;
|
||||||
|
if (build == 9200) return PSVersion.Win8;
|
||||||
|
|
||||||
|
throw new NotSupportedException("This version of Windows is not supported. (build " + build + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool DetectCurrentKey()
|
||||||
|
{
|
||||||
|
SLApi.RefreshLicenseStatus();
|
||||||
|
|
||||||
|
using (RegistryKey wpaKey = Registry.LocalMachine.OpenSubKey(@"SYSTEM\WPA"))
|
||||||
|
{
|
||||||
|
foreach (string subKey in wpaKey.GetSubKeyNames())
|
||||||
|
{
|
||||||
|
if (subKey.StartsWith("8DEC0AF1") && subKey.EndsWith("-1"))
|
||||||
|
{
|
||||||
|
return subKey.Contains("P");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new FileNotFoundException("Failed to autodetect key type, specify physical store key with /prod or /test arguments.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string DecodeString(byte[] data)
|
||||||
|
{
|
||||||
|
return Encoding.Unicode.GetString(data).Trim('\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] EncodeString(string str)
|
||||||
|
{
|
||||||
|
return Encoding.Unicode.GetBytes(str + '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string GetTokenStorePath()
|
||||||
|
{
|
||||||
|
return (string)Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform", "TokenStore", string.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TokenMeta
|
||||||
|
{
|
||||||
|
public string Name;
|
||||||
|
public Dictionary<string, string> Data = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
public byte[] Serialize()
|
||||||
|
{
|
||||||
|
BinaryWriter writer = new BinaryWriter(new MemoryStream());
|
||||||
|
writer.Write(1);
|
||||||
|
byte[] nameBytes = Utils.EncodeString(Name);
|
||||||
|
writer.Write(nameBytes.Length);
|
||||||
|
writer.Write(nameBytes);
|
||||||
|
|
||||||
|
foreach (KeyValuePair<string, string> kv in Data)
|
||||||
|
{
|
||||||
|
byte[] keyBytes = Utils.EncodeString(kv.Key);
|
||||||
|
byte[] valueBytes = Utils.EncodeString(kv.Value);
|
||||||
|
writer.Write(keyBytes.Length);
|
||||||
|
writer.Write(valueBytes.Length);
|
||||||
|
writer.Write(keyBytes);
|
||||||
|
writer.Write(valueBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return writer.GetBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Deserialize(byte[] data)
|
||||||
|
{
|
||||||
|
BinaryReader reader = new BinaryReader(new MemoryStream(data));
|
||||||
|
reader.ReadInt32();
|
||||||
|
int nameLen = reader.ReadInt32();
|
||||||
|
Name = reader.ReadNullTerminatedString(nameLen);
|
||||||
|
|
||||||
|
while (reader.BaseStream.Position < data.Length - 0x8)
|
||||||
|
{
|
||||||
|
int keyLen = reader.ReadInt32();
|
||||||
|
int valueLen = reader.ReadInt32();
|
||||||
|
string key = reader.ReadNullTerminatedString(keyLen);
|
||||||
|
string value = reader.ReadNullTerminatedString(valueLen);
|
||||||
|
Data[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenMeta(byte[] data)
|
||||||
|
{
|
||||||
|
Deserialize(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenMeta()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
121
MetroUnlocker/LibTSForge/Crypto/CryptoUtils.cs
Normal file
121
MetroUnlocker/LibTSForge/Crypto/CryptoUtils.cs
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
namespace MetroUnlocker.LibTSForge.Crypto
|
||||||
|
{
|
||||||
|
public static class CryptoUtils
|
||||||
|
{
|
||||||
|
public static byte[] GenerateRandomKey(int len)
|
||||||
|
{
|
||||||
|
byte[] rand = new byte[len];
|
||||||
|
Random r = new Random();
|
||||||
|
r.NextBytes(rand);
|
||||||
|
|
||||||
|
return rand;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] AESEncrypt(byte[] data, byte[] key)
|
||||||
|
{
|
||||||
|
using (Aes aes = Aes.Create())
|
||||||
|
{
|
||||||
|
aes.Key = key;
|
||||||
|
aes.Mode = CipherMode.CBC;
|
||||||
|
aes.Padding = PaddingMode.PKCS7;
|
||||||
|
|
||||||
|
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, Enumerable.Repeat((byte)0, 16).ToArray());
|
||||||
|
byte[] encryptedData = encryptor.TransformFinalBlock(data, 0, data.Length);
|
||||||
|
return encryptedData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] AESDecrypt(byte[] data, byte[] key)
|
||||||
|
{
|
||||||
|
using (Aes aes = Aes.Create())
|
||||||
|
{
|
||||||
|
aes.Key = key;
|
||||||
|
aes.Mode = CipherMode.CBC;
|
||||||
|
aes.Padding = PaddingMode.PKCS7;
|
||||||
|
|
||||||
|
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, Enumerable.Repeat((byte)0, 16).ToArray());
|
||||||
|
byte[] decryptedData = decryptor.TransformFinalBlock(data, 0, data.Length);
|
||||||
|
return decryptedData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] RSADecrypt(byte[] rsaKey, byte[] data)
|
||||||
|
{
|
||||||
|
|
||||||
|
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
|
||||||
|
{
|
||||||
|
rsa.ImportCspBlob(rsaKey);
|
||||||
|
return rsa.Decrypt(data, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] RSAEncrypt(byte[] rsaKey, byte[] data)
|
||||||
|
{
|
||||||
|
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
|
||||||
|
{
|
||||||
|
rsa.ImportCspBlob(rsaKey);
|
||||||
|
return rsa.Encrypt(data, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] RSASign(byte[] rsaKey, byte[] data)
|
||||||
|
{
|
||||||
|
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
|
||||||
|
{
|
||||||
|
rsa.ImportCspBlob(rsaKey);
|
||||||
|
RSAPKCS1SignatureFormatter formatter = new RSAPKCS1SignatureFormatter(rsa);
|
||||||
|
formatter.SetHashAlgorithm("SHA1");
|
||||||
|
|
||||||
|
byte[] hash;
|
||||||
|
using (SHA1 sha1 = SHA1.Create())
|
||||||
|
{
|
||||||
|
hash = sha1.ComputeHash(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return formatter.CreateSignature(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool RSAVerifySignature(byte[] rsaKey, byte[] data, byte[] signature)
|
||||||
|
{
|
||||||
|
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
|
||||||
|
{
|
||||||
|
rsa.ImportCspBlob(rsaKey);
|
||||||
|
RSAPKCS1SignatureDeformatter deformatter = new RSAPKCS1SignatureDeformatter(rsa);
|
||||||
|
deformatter.SetHashAlgorithm("SHA1");
|
||||||
|
|
||||||
|
byte[] hash;
|
||||||
|
using (SHA1 sha1 = SHA1.Create())
|
||||||
|
{
|
||||||
|
hash = sha1.ComputeHash(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return deformatter.VerifySignature(hash, signature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] HMACSign(byte[] key, byte[] data)
|
||||||
|
{
|
||||||
|
HMACSHA1 hmac = new HMACSHA1(key);
|
||||||
|
return hmac.ComputeHash(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool HMACVerify(byte[] key, byte[] data, byte[] signature)
|
||||||
|
{
|
||||||
|
HMACSHA1 hmac = new HMACSHA1(key);
|
||||||
|
return Enumerable.SequenceEqual(signature, HMACSign(key, data));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] SHA256Hash(byte[] data)
|
||||||
|
{
|
||||||
|
using (SHA256 sha256 = SHA256.Create())
|
||||||
|
{
|
||||||
|
return sha256.ComputeHash(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
87
MetroUnlocker/LibTSForge/Crypto/Keys.cs
Normal file
87
MetroUnlocker/LibTSForge/Crypto/Keys.cs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
namespace MetroUnlocker.LibTSForge.Crypto
|
||||||
|
{
|
||||||
|
public static class Keys
|
||||||
|
{
|
||||||
|
public static readonly byte[] PRODUCTION = {
|
||||||
|
0x07, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32, 0x00, 0x04, 0x00, 0x00,
|
||||||
|
0x01, 0x00, 0x01, 0x00, 0x29, 0x87, 0xBA, 0x3F, 0x52, 0x90, 0x57, 0xD8, 0x12, 0x26, 0x6B, 0x38,
|
||||||
|
0xB2, 0x3B, 0xF9, 0x67, 0x08, 0x4F, 0xDD, 0x8B, 0xF5, 0xE3, 0x11, 0xB8, 0x61, 0x3A, 0x33, 0x42,
|
||||||
|
0x51, 0x65, 0x05, 0x86, 0x1E, 0x00, 0x41, 0xDE, 0xC5, 0xDD, 0x44, 0x60, 0x56, 0x3D, 0x14, 0x39,
|
||||||
|
0xB7, 0x43, 0x65, 0xE9, 0xF7, 0x2B, 0xA5, 0xF0, 0xA3, 0x65, 0x68, 0xE9, 0xE4, 0x8B, 0x5C, 0x03,
|
||||||
|
0x2D, 0x36, 0xFE, 0x28, 0x4C, 0xD1, 0x3C, 0x3D, 0xC1, 0x90, 0x75, 0xF9, 0x6E, 0x02, 0xE0, 0x58,
|
||||||
|
0x97, 0x6A, 0xCA, 0x80, 0x02, 0x42, 0x3F, 0x6C, 0x15, 0x85, 0x4D, 0x83, 0x23, 0x6A, 0x95, 0x9E,
|
||||||
|
0x38, 0x52, 0x59, 0x38, 0x6A, 0x99, 0xF0, 0xB5, 0xCD, 0x53, 0x7E, 0x08, 0x7C, 0xB5, 0x51, 0xD3,
|
||||||
|
0x8F, 0xA3, 0x0D, 0xA0, 0xFA, 0x8D, 0x87, 0x3C, 0xFC, 0x59, 0x21, 0xD8, 0x2E, 0xD9, 0x97, 0x8B,
|
||||||
|
0x40, 0x60, 0xB1, 0xD7, 0x2B, 0x0A, 0x6E, 0x60, 0xB5, 0x50, 0xCC, 0x3C, 0xB1, 0x57, 0xE4, 0xB7,
|
||||||
|
0xDC, 0x5A, 0x4D, 0xE1, 0x5C, 0xE0, 0x94, 0x4C, 0x5E, 0x28, 0xFF, 0xFA, 0x80, 0x6A, 0x13, 0x53,
|
||||||
|
0x52, 0xDB, 0xF3, 0x04, 0x92, 0x43, 0x38, 0xB9, 0x1B, 0xD9, 0x85, 0x54, 0x7B, 0x14, 0xC7, 0x89,
|
||||||
|
0x16, 0x8A, 0x4B, 0x82, 0xA1, 0x08, 0x02, 0x99, 0x23, 0x48, 0xDD, 0x75, 0x9C, 0xC8, 0xC1, 0xCE,
|
||||||
|
0xB0, 0xD7, 0x1B, 0xD8, 0xFB, 0x2D, 0xA7, 0x2E, 0x47, 0xA7, 0x18, 0x4B, 0xF6, 0x29, 0x69, 0x44,
|
||||||
|
0x30, 0x33, 0xBA, 0xA7, 0x1F, 0xCE, 0x96, 0x9E, 0x40, 0xE1, 0x43, 0xF0, 0xE0, 0x0D, 0x0A, 0x32,
|
||||||
|
0xB4, 0xEE, 0xA1, 0xC3, 0x5E, 0x9B, 0xC7, 0x7F, 0xF5, 0x9D, 0xD8, 0xF2, 0x0F, 0xD9, 0x8F, 0xAD,
|
||||||
|
0x75, 0x0A, 0x00, 0xD5, 0x25, 0x43, 0xF7, 0xAE, 0x51, 0x7F, 0xB7, 0xDE, 0xB7, 0xAD, 0xFB, 0xCE,
|
||||||
|
0x83, 0xE1, 0x81, 0xFF, 0xDD, 0xA2, 0x77, 0xFE, 0xEB, 0x27, 0x1F, 0x10, 0xFA, 0x82, 0x37, 0xF4,
|
||||||
|
0x7E, 0xCC, 0xE2, 0xA1, 0x58, 0xC8, 0xAF, 0x1D, 0x1A, 0x81, 0x31, 0x6E, 0xF4, 0x8B, 0x63, 0x34,
|
||||||
|
0xF3, 0x05, 0x0F, 0xE1, 0xCC, 0x15, 0xDC, 0xA4, 0x28, 0x7A, 0x9E, 0xEB, 0x62, 0xD8, 0xD8, 0x8C,
|
||||||
|
0x85, 0xD7, 0x07, 0x87, 0x90, 0x2F, 0xF7, 0x1C, 0x56, 0x85, 0x2F, 0xEF, 0x32, 0x37, 0x07, 0xAB,
|
||||||
|
0xB0, 0xE6, 0xB5, 0x02, 0x19, 0x35, 0xAF, 0xDB, 0xD4, 0xA2, 0x9C, 0x36, 0x80, 0xC6, 0xDC, 0x82,
|
||||||
|
0x08, 0xE0, 0xC0, 0x5F, 0x3C, 0x59, 0xAA, 0x4E, 0x26, 0x03, 0x29, 0xB3, 0x62, 0x58, 0x41, 0x59,
|
||||||
|
0x3A, 0x37, 0x43, 0x35, 0xE3, 0x9F, 0x34, 0xE2, 0xA1, 0x04, 0x97, 0x12, 0x9D, 0x8C, 0xAD, 0xF7,
|
||||||
|
0xFB, 0x8C, 0xA1, 0xA2, 0xE9, 0xE4, 0xEF, 0xD9, 0xC5, 0xE5, 0xDF, 0x0E, 0xBF, 0x4A, 0xE0, 0x7A,
|
||||||
|
0x1E, 0x10, 0x50, 0x58, 0x63, 0x51, 0xE1, 0xD4, 0xFE, 0x57, 0xB0, 0x9E, 0xD7, 0xDA, 0x8C, 0xED,
|
||||||
|
0x7D, 0x82, 0xAC, 0x2F, 0x25, 0x58, 0x0A, 0x58, 0xE6, 0xA4, 0xF4, 0x57, 0x4B, 0xA4, 0x1B, 0x65,
|
||||||
|
0xB9, 0x4A, 0x87, 0x46, 0xEB, 0x8C, 0x0F, 0x9A, 0x48, 0x90, 0xF9, 0x9F, 0x76, 0x69, 0x03, 0x72,
|
||||||
|
0x77, 0xEC, 0xC1, 0x42, 0x4C, 0x87, 0xDB, 0x0B, 0x3C, 0xD4, 0x74, 0xEF, 0xE5, 0x34, 0xE0, 0x32,
|
||||||
|
0x45, 0xB0, 0xF8, 0xAB, 0xD5, 0x26, 0x21, 0xD7, 0xD2, 0x98, 0x54, 0x8F, 0x64, 0x88, 0x20, 0x2B,
|
||||||
|
0x14, 0xE3, 0x82, 0xD5, 0x2A, 0x4B, 0x8F, 0x4E, 0x35, 0x20, 0x82, 0x7E, 0x1B, 0xFE, 0xFA, 0x2C,
|
||||||
|
0x79, 0x6C, 0x6E, 0x66, 0x94, 0xBB, 0x0A, 0xEB, 0xBA, 0xD9, 0x70, 0x61, 0xE9, 0x47, 0xB5, 0x82,
|
||||||
|
0xFC, 0x18, 0x3C, 0x66, 0x3A, 0x09, 0x2E, 0x1F, 0x61, 0x74, 0xCA, 0xCB, 0xF6, 0x7A, 0x52, 0x37,
|
||||||
|
0x1D, 0xAC, 0x8D, 0x63, 0x69, 0x84, 0x8E, 0xC7, 0x70, 0x59, 0xDD, 0x2D, 0x91, 0x1E, 0xF7, 0xB1,
|
||||||
|
0x56, 0xED, 0x7A, 0x06, 0x9D, 0x5B, 0x33, 0x15, 0xDD, 0x31, 0xD0, 0xE6, 0x16, 0x07, 0x9B, 0xA5,
|
||||||
|
0x94, 0x06, 0x7D, 0xC1, 0xE9, 0xD6, 0xC8, 0xAF, 0xB4, 0x1E, 0x2D, 0x88, 0x06, 0xA7, 0x63, 0xB8,
|
||||||
|
0xCF, 0xC8, 0xA2, 0x6E, 0x84, 0xB3, 0x8D, 0xE5, 0x47, 0xE6, 0x13, 0x63, 0x8E, 0xD1, 0x7F, 0xD4,
|
||||||
|
0x81, 0x44, 0x38, 0xBF
|
||||||
|
};
|
||||||
|
|
||||||
|
public static readonly byte[] TEST = {
|
||||||
|
0x07, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32, 0x00, 0x04, 0x00, 0x00,
|
||||||
|
0x01, 0x00, 0x01, 0x00, 0x0F, 0xBE, 0x77, 0xB8, 0xDD, 0x54, 0x36, 0xDD, 0x67, 0xD4, 0x17, 0x66,
|
||||||
|
0xC4, 0x13, 0xD1, 0x3F, 0x1E, 0x16, 0x0C, 0x16, 0x35, 0xAB, 0x6D, 0x3D, 0x34, 0x51, 0xED, 0x3F,
|
||||||
|
0x57, 0x14, 0xB6, 0xB7, 0x08, 0xE9, 0xD9, 0x7A, 0x80, 0xB3, 0x5F, 0x9B, 0x3A, 0xFD, 0x9E, 0x37,
|
||||||
|
0x3A, 0x53, 0x72, 0x67, 0x92, 0x60, 0xC3, 0xEF, 0xB5, 0x8E, 0x1E, 0xCF, 0x9D, 0x9C, 0xD3, 0x90,
|
||||||
|
0xE5, 0xDD, 0xF4, 0xDB, 0xF3, 0xD6, 0x65, 0xB3, 0xC1, 0xBD, 0x69, 0xE1, 0x76, 0x95, 0xD9, 0x37,
|
||||||
|
0xB8, 0x5E, 0xCA, 0x3D, 0x98, 0xFC, 0x50, 0x5C, 0x98, 0xAE, 0xE3, 0x7C, 0x4C, 0x27, 0xC3, 0xD0,
|
||||||
|
0xCE, 0x78, 0x06, 0x51, 0x68, 0x23, 0xE6, 0x70, 0xF8, 0x7C, 0xAE, 0x36, 0xBE, 0x41, 0x57, 0xE2,
|
||||||
|
0xC3, 0x2D, 0xAF, 0x21, 0xB1, 0xB3, 0x15, 0x81, 0x19, 0x26, 0x6B, 0x10, 0xB3, 0xE9, 0xD1, 0x45,
|
||||||
|
0x21, 0x77, 0x9C, 0xF6, 0xE1, 0xDD, 0xB6, 0x78, 0x9D, 0x1D, 0x32, 0x61, 0xBC, 0x2B, 0xDB, 0x86,
|
||||||
|
0xFB, 0x07, 0x24, 0x10, 0x19, 0x4F, 0x09, 0x6D, 0x03, 0x90, 0xD4, 0x5E, 0x30, 0x85, 0xC5, 0x58,
|
||||||
|
0x7E, 0x5D, 0xAE, 0x9F, 0x64, 0x93, 0x04, 0x82, 0x09, 0x0E, 0x1C, 0x66, 0xA8, 0x95, 0x91, 0x51,
|
||||||
|
0xB2, 0xED, 0x9A, 0x75, 0x04, 0x87, 0x50, 0xAC, 0xCC, 0x20, 0x06, 0x45, 0xB9, 0x7B, 0x42, 0x53,
|
||||||
|
0x9A, 0xD1, 0x29, 0xFC, 0xEF, 0xB9, 0x47, 0x16, 0x75, 0x69, 0x05, 0x87, 0x2B, 0xCB, 0x54, 0x9C,
|
||||||
|
0x21, 0x2D, 0x50, 0x8E, 0x12, 0xDE, 0xD3, 0x6B, 0xEC, 0x92, 0xA1, 0xB1, 0xE9, 0x4B, 0xBF, 0x6B,
|
||||||
|
0x9A, 0x38, 0xC7, 0x13, 0xFA, 0x78, 0xA1, 0x3C, 0x1E, 0xBB, 0x38, 0x31, 0xBB, 0x0C, 0x9F, 0x70,
|
||||||
|
0x1A, 0x31, 0x00, 0xD7, 0x5A, 0xA5, 0x84, 0x24, 0x89, 0x80, 0xF5, 0x88, 0xC2, 0x31, 0x18, 0xDC,
|
||||||
|
0x53, 0x05, 0x5D, 0xFA, 0x81, 0xDC, 0xE1, 0xCE, 0xA4, 0xAA, 0xBA, 0x07, 0xDA, 0x28, 0x4F, 0x64,
|
||||||
|
0x0E, 0x84, 0x9B, 0x06, 0xDE, 0xC8, 0x78, 0x66, 0x2F, 0x17, 0x25, 0xA8, 0x9C, 0x99, 0xFC, 0xBC,
|
||||||
|
0x7D, 0x01, 0x42, 0xD7, 0x35, 0xBF, 0x19, 0xF6, 0x3F, 0x20, 0xD9, 0x98, 0x9B, 0x5D, 0xDD, 0x39,
|
||||||
|
0xBE, 0x81, 0x00, 0x0B, 0xDE, 0x6F, 0x14, 0xCA, 0x7E, 0xF8, 0xC0, 0x26, 0xA8, 0x1D, 0xD1, 0x16,
|
||||||
|
0x88, 0x64, 0x87, 0x36, 0x45, 0x37, 0x50, 0xDA, 0x6C, 0xEB, 0x85, 0xB5, 0x43, 0x29, 0x88, 0x6F,
|
||||||
|
0x2F, 0xFE, 0x8D, 0x12, 0x8B, 0x72, 0xB7, 0x5A, 0xCB, 0x66, 0xC2, 0x2E, 0x1D, 0x7D, 0x42, 0xA6,
|
||||||
|
0xF4, 0xFE, 0x26, 0x5D, 0x54, 0x9E, 0x77, 0x1D, 0x97, 0xC2, 0xF3, 0xFD, 0x60, 0xB3, 0x22, 0x88,
|
||||||
|
0xCA, 0x27, 0x99, 0xDF, 0xC8, 0xB1, 0xD7, 0xC6, 0x54, 0xA6, 0x50, 0xB9, 0x54, 0xF5, 0xDE, 0xFE,
|
||||||
|
0xE1, 0x81, 0xA2, 0xBE, 0x81, 0x9F, 0x48, 0xFF, 0x2F, 0xB8, 0xA4, 0xB3, 0x17, 0xD8, 0xC1, 0xB9,
|
||||||
|
0x5D, 0x21, 0x3D, 0xA2, 0xED, 0x1C, 0x96, 0x66, 0xEE, 0x1F, 0x47, 0xCF, 0x62, 0xFA, 0xD6, 0xC1,
|
||||||
|
0x87, 0x5B, 0xC4, 0xE5, 0xD9, 0x08, 0x38, 0x22, 0xFA, 0x21, 0xBD, 0xF2, 0x88, 0xDA, 0xE2, 0x24,
|
||||||
|
0x25, 0x1F, 0xF1, 0x0B, 0x2D, 0xAE, 0x04, 0xBE, 0xA6, 0x7F, 0x75, 0x8C, 0xD9, 0x97, 0xE1, 0xCA,
|
||||||
|
0x35, 0xB9, 0xFC, 0x6F, 0x01, 0x68, 0x11, 0xD3, 0x68, 0x32, 0xD0, 0xC1, 0x69, 0xA3, 0xCF, 0x9B,
|
||||||
|
0x10, 0xE4, 0x69, 0xA7, 0xCF, 0xE1, 0xFE, 0x2A, 0x07, 0x9E, 0xC1, 0x37, 0x84, 0x68, 0xE5, 0xC5,
|
||||||
|
0xAB, 0x25, 0xEC, 0x7D, 0x7D, 0x74, 0x6A, 0xD1, 0xD5, 0x4D, 0xD7, 0xE1, 0x7D, 0xDE, 0x30, 0x4B,
|
||||||
|
0xE6, 0x5D, 0xCD, 0x91, 0x59, 0xF6, 0x80, 0xFD, 0xC6, 0x3C, 0xDD, 0x94, 0x7F, 0x15, 0x9D, 0xEF,
|
||||||
|
0x2F, 0x00, 0x62, 0xD7, 0xDA, 0xB9, 0xB3, 0xD9, 0x8D, 0xE8, 0xD7, 0x3C, 0x96, 0x45, 0x5D, 0x1E,
|
||||||
|
0x50, 0xFB, 0xAA, 0x43, 0xD3, 0x47, 0x77, 0x81, 0xE9, 0x67, 0xE4, 0xFE, 0xDF, 0x42, 0x79, 0xCB,
|
||||||
|
0xA7, 0xAD, 0x5D, 0x48, 0xF5, 0xB7, 0x74, 0x96, 0x12, 0x23, 0x06, 0x70, 0x42, 0x68, 0x7A, 0x44,
|
||||||
|
0xFC, 0xA0, 0x31, 0x7F, 0x68, 0xCA, 0xA2, 0x14, 0x5D, 0xA3, 0xCF, 0x42, 0x23, 0xAB, 0x47, 0xF6,
|
||||||
|
0xB2, 0xFC, 0x6D, 0xF1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
68
MetroUnlocker/LibTSForge/Crypto/PhysicalStoreCrypto.cs
Normal file
68
MetroUnlocker/LibTSForge/Crypto/PhysicalStoreCrypto.cs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using MetroUnlocker.LibTSForge;
|
||||||
|
|
||||||
|
namespace MetroUnlocker.LibTSForge.Crypto
|
||||||
|
{
|
||||||
|
public static class PhysicalStoreCrypto
|
||||||
|
{
|
||||||
|
public static byte[] DecryptPhysicalStore(byte[] data, bool production)
|
||||||
|
{
|
||||||
|
byte[] rsaKey = production ? Keys.PRODUCTION : Keys.TEST;
|
||||||
|
BinaryReader br = new BinaryReader(new MemoryStream(data));
|
||||||
|
br.BaseStream.Seek(0x10, SeekOrigin.Begin);
|
||||||
|
byte[] aesKeySig = br.ReadBytes(0x80);
|
||||||
|
byte[] encAesKey = br.ReadBytes(0x80);
|
||||||
|
|
||||||
|
if (!CryptoUtils.RSAVerifySignature(rsaKey, encAesKey, aesKeySig))
|
||||||
|
throw new Exception("Failed to decrypt physical store.");
|
||||||
|
|
||||||
|
byte[] aesKey = CryptoUtils.RSADecrypt(rsaKey, encAesKey);
|
||||||
|
byte[] decData = CryptoUtils.AESDecrypt(br.ReadBytes((int)br.BaseStream.Length - 0x110), aesKey);
|
||||||
|
byte[] hmacKey = decData.Take(0x10).ToArray();
|
||||||
|
byte[] hmacSig = decData.Skip(0x10).Take(0x14).ToArray();
|
||||||
|
byte[] psData = decData.Skip(0x28).ToArray();
|
||||||
|
|
||||||
|
if (!CryptoUtils.HMACVerify(hmacKey, psData, hmacSig))
|
||||||
|
throw new Exception("Failed to verify HMAC. Physical store is either corrupt or in Vista format.");
|
||||||
|
|
||||||
|
return psData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] EncryptPhysicalStore(byte[] data, bool production, PSVersion version)
|
||||||
|
{
|
||||||
|
Dictionary<PSVersion, int> versionTable = new Dictionary<PSVersion, int>
|
||||||
|
{
|
||||||
|
{PSVersion.Win8, 1},
|
||||||
|
{PSVersion.WinBlue, 2},
|
||||||
|
{PSVersion.WinModern, 3}
|
||||||
|
};
|
||||||
|
|
||||||
|
byte[] rsaKey = production ? Keys.PRODUCTION : Keys.TEST;
|
||||||
|
|
||||||
|
byte[] aesKey = Encoding.UTF8.GetBytes("Boop Foxyz nose!");
|
||||||
|
byte[] hmacKey = CryptoUtils.GenerateRandomKey(0x10);
|
||||||
|
|
||||||
|
byte[] encAesKey = CryptoUtils.RSAEncrypt(rsaKey, aesKey);
|
||||||
|
byte[] aesKeySig = CryptoUtils.RSASign(rsaKey, encAesKey);
|
||||||
|
byte[] hmacSig = CryptoUtils.HMACSign(hmacKey, data);
|
||||||
|
|
||||||
|
byte[] decData = new byte[] { };
|
||||||
|
decData = decData.Concat(hmacKey).Concat(hmacSig).Concat(BitConverter.GetBytes(0)).Concat(data).ToArray();
|
||||||
|
byte[] encData = CryptoUtils.AESEncrypt(decData, aesKey);
|
||||||
|
|
||||||
|
BinaryWriter bw = new BinaryWriter(new MemoryStream());
|
||||||
|
bw.Write(versionTable[version]);
|
||||||
|
bw.Write(Encoding.UTF8.GetBytes("UNTRUSTSTORE"));
|
||||||
|
bw.Write(aesKeySig);
|
||||||
|
bw.Write(encAesKey);
|
||||||
|
bw.Write(encData);
|
||||||
|
|
||||||
|
return bw.GetBytes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
44
MetroUnlocker/LibTSForge/Modifiers/GenPKeyInstall.cs
Normal file
44
MetroUnlocker/LibTSForge/Modifiers/GenPKeyInstall.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace MetroUnlocker.LibTSForge.Modifiers
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
using MetroUnlocker.LibTSForge.PhysicalStore;
|
||||||
|
using MetroUnlocker.LibTSForge.SPP;
|
||||||
|
using MetroUnlocker.LibTSForge.TokenStore;
|
||||||
|
|
||||||
|
public static class GenPKeyInstall
|
||||||
|
{
|
||||||
|
public static void InstallGenPKey(PSVersion version, bool production, Guid actId)
|
||||||
|
{
|
||||||
|
PKeyConfig pkc = new PKeyConfig();
|
||||||
|
|
||||||
|
pkc.LoadConfig(actId);
|
||||||
|
|
||||||
|
ProductConfig config;
|
||||||
|
pkc.Products.TryGetValue(actId, out config);
|
||||||
|
|
||||||
|
if (config == null) throw new ArgumentException("Activation ID " + actId + " not found in PKeyConfig.");
|
||||||
|
|
||||||
|
ProductKey pkey = config.GetRandomKey();
|
||||||
|
|
||||||
|
Guid instPkeyId = SLApi.GetInstalledPkeyId(actId);
|
||||||
|
if (instPkeyId != Guid.Empty) SLApi.UninstallProductKey(instPkeyId);
|
||||||
|
|
||||||
|
if (pkey.Algorithm != PKeyAlgorithm.PKEY2009)
|
||||||
|
throw new Exception("The key algorithm isn't 2009");
|
||||||
|
|
||||||
|
uint status = SLApi.InstallProductKey(pkey);
|
||||||
|
|
||||||
|
if (status != 0)
|
||||||
|
throw new ApplicationException("Failed to install generated product key.");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
111
MetroUnlocker/LibTSForge/PhysicalStore/CRCBlock.cs
Normal file
111
MetroUnlocker/LibTSForge/PhysicalStore/CRCBlock.cs
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace MetroUnlocker.LibTSForge.PhysicalStore
|
||||||
|
{
|
||||||
|
public enum CRCBlockType : uint
|
||||||
|
{
|
||||||
|
UINT = 1 << 0,
|
||||||
|
STRING = 1 << 1,
|
||||||
|
BINARY = 1 << 2
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CRCBlock
|
||||||
|
{
|
||||||
|
public CRCBlockType DataType;
|
||||||
|
public byte[] Key;
|
||||||
|
public string KeyAsStr
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Utils.DecodeString(Key);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Key = Utils.EncodeString(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public byte[] Value;
|
||||||
|
public string ValueAsStr
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Utils.DecodeString(Value);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Value = Utils.EncodeString(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public uint ValueAsInt
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BitConverter.ToUInt32(Value, 0);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Value = BitConverter.GetBytes(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Encode(BinaryWriter writer)
|
||||||
|
{
|
||||||
|
uint crc = CRC();
|
||||||
|
writer.Write(crc);
|
||||||
|
writer.Write((uint)DataType);
|
||||||
|
writer.Write(Key.Length);
|
||||||
|
writer.Write(Value.Length);
|
||||||
|
|
||||||
|
writer.Write(Key);
|
||||||
|
writer.Align(8);
|
||||||
|
|
||||||
|
writer.Write(Value);
|
||||||
|
writer.Align(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CRCBlock Decode(BinaryReader reader)
|
||||||
|
{
|
||||||
|
uint crc = reader.ReadUInt32();
|
||||||
|
uint type = reader.ReadUInt32();
|
||||||
|
uint lenName = reader.ReadUInt32();
|
||||||
|
uint lenVal = reader.ReadUInt32();
|
||||||
|
|
||||||
|
byte[] key = reader.ReadBytes((int)lenName);
|
||||||
|
|
||||||
|
reader.Align(8);
|
||||||
|
|
||||||
|
byte[] value = reader.ReadBytes((int)lenVal);
|
||||||
|
reader.Align(8);
|
||||||
|
|
||||||
|
CRCBlock block = new CRCBlock
|
||||||
|
{
|
||||||
|
DataType = (CRCBlockType)type,
|
||||||
|
Key = key,
|
||||||
|
Value = value,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (block.CRC() != crc)
|
||||||
|
{
|
||||||
|
throw new InvalidDataException("Invalid CRC in variable bag.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint CRC()
|
||||||
|
{
|
||||||
|
BinaryWriter wtemp = new BinaryWriter(new MemoryStream());
|
||||||
|
wtemp.Write(0);
|
||||||
|
wtemp.Write((uint)DataType);
|
||||||
|
wtemp.Write(Key.Length);
|
||||||
|
wtemp.Write(Value.Length);
|
||||||
|
wtemp.Write(Key);
|
||||||
|
wtemp.Write(Value);
|
||||||
|
return Utils.CRC32(((MemoryStream)wtemp.BaseStream).ToArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
106
MetroUnlocker/LibTSForge/PhysicalStore/ModernBlock.cs
Normal file
106
MetroUnlocker/LibTSForge/PhysicalStore/ModernBlock.cs
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace MetroUnlocker.LibTSForge.PhysicalStore
|
||||||
|
{
|
||||||
|
public class ModernBlock
|
||||||
|
{
|
||||||
|
public BlockType Type;
|
||||||
|
public uint Flags;
|
||||||
|
public uint Unknown;
|
||||||
|
public byte[] Key;
|
||||||
|
public string KeyAsStr
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Utils.DecodeString(Key);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Key = Utils.EncodeString(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public byte[] Value;
|
||||||
|
public string ValueAsStr
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Utils.DecodeString(Value);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Value = Utils.EncodeString(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public uint ValueAsInt
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BitConverter.ToUInt32(Value, 0);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Value = BitConverter.GetBytes(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public byte[] Data;
|
||||||
|
public string DataAsStr
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Utils.DecodeString(Data);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Data = Utils.EncodeString(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public uint DataAsInt
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BitConverter.ToUInt32(Data, 0);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Data = BitConverter.GetBytes(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Encode(BinaryWriter writer)
|
||||||
|
{
|
||||||
|
writer.Write((uint)Type);
|
||||||
|
writer.Write(Flags);
|
||||||
|
writer.Write((uint)Value.Length);
|
||||||
|
writer.Write((uint)Data.Length);
|
||||||
|
writer.Write(Unknown);
|
||||||
|
writer.Write(Value);
|
||||||
|
writer.Write(Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ModernBlock Decode(BinaryReader reader)
|
||||||
|
{
|
||||||
|
uint type = reader.ReadUInt32();
|
||||||
|
uint flags = reader.ReadUInt32();
|
||||||
|
|
||||||
|
uint valueLen = reader.ReadUInt32();
|
||||||
|
uint dataLen = reader.ReadUInt32();
|
||||||
|
uint unk3 = reader.ReadUInt32();
|
||||||
|
|
||||||
|
byte[] value = reader.ReadBytes((int)valueLen);
|
||||||
|
byte[] data = reader.ReadBytes((int)dataLen);
|
||||||
|
|
||||||
|
return new ModernBlock
|
||||||
|
{
|
||||||
|
Type = (BlockType)type,
|
||||||
|
Flags = flags,
|
||||||
|
Unknown = unk3,
|
||||||
|
Value = value,
|
||||||
|
Data = data,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
282
MetroUnlocker/LibTSForge/PhysicalStore/PhysicalStore.cs
Normal file
282
MetroUnlocker/LibTSForge/PhysicalStore/PhysicalStore.cs
Normal file
@@ -0,0 +1,282 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
using Microsoft.Win32;
|
||||||
|
|
||||||
|
using MetroUnlocker.LibTSForge.Crypto;
|
||||||
|
|
||||||
|
namespace MetroUnlocker.LibTSForge.PhysicalStore
|
||||||
|
{
|
||||||
|
public sealed class PhysicalStore : IDisposable
|
||||||
|
{
|
||||||
|
private byte[] PreHeaderBytes = new byte[] { };
|
||||||
|
private readonly Dictionary<string, List<ModernBlock>> Data = new Dictionary<string, List<ModernBlock>>();
|
||||||
|
private readonly FileStream TSFile;
|
||||||
|
private readonly PSVersion Version;
|
||||||
|
private readonly bool Production;
|
||||||
|
|
||||||
|
public byte[] Serialize()
|
||||||
|
{
|
||||||
|
BinaryWriter writer = new BinaryWriter(new MemoryStream());
|
||||||
|
writer.Write(PreHeaderBytes);
|
||||||
|
writer.Write(Data.Keys.Count);
|
||||||
|
|
||||||
|
foreach (string key in Data.Keys)
|
||||||
|
{
|
||||||
|
List<ModernBlock> blocks = Data[key];
|
||||||
|
byte[] keyNameEnc = Utils.EncodeString(key);
|
||||||
|
|
||||||
|
writer.Write(keyNameEnc.Length);
|
||||||
|
writer.Write(keyNameEnc);
|
||||||
|
writer.Write(blocks.Count);
|
||||||
|
writer.Align(4);
|
||||||
|
|
||||||
|
|
||||||
|
foreach (ModernBlock block in blocks)
|
||||||
|
{
|
||||||
|
block.Encode(writer);
|
||||||
|
writer.Align(4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Utils.GetBytes(writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Deserialize(byte[] data)
|
||||||
|
{
|
||||||
|
BinaryReader reader = new BinaryReader(new MemoryStream(data));
|
||||||
|
PreHeaderBytes = reader.ReadBytes(8);
|
||||||
|
|
||||||
|
while (reader.BaseStream.Position < data.Length - 0x4)
|
||||||
|
{
|
||||||
|
uint numKeys = reader.ReadUInt32();
|
||||||
|
|
||||||
|
for (int i = 0; i < numKeys; i++)
|
||||||
|
{
|
||||||
|
uint lenKeyName = reader.ReadUInt32();
|
||||||
|
string keyName = Utils.DecodeString(reader.ReadBytes((int)lenKeyName)); uint numValues = reader.ReadUInt32();
|
||||||
|
|
||||||
|
reader.Align(4);
|
||||||
|
|
||||||
|
Data[keyName] = new List<ModernBlock>();
|
||||||
|
|
||||||
|
for (int j = 0; j < numValues; j++)
|
||||||
|
{
|
||||||
|
Data[keyName].Add(ModernBlock.Decode(reader));
|
||||||
|
reader.Align(4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddBlock(ModernBlock block)
|
||||||
|
{
|
||||||
|
if (!Data.ContainsKey(block.KeyAsStr))
|
||||||
|
{
|
||||||
|
Data[block.KeyAsStr] = new List<ModernBlock>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Data[block.KeyAsStr].Add(new ModernBlock
|
||||||
|
{
|
||||||
|
Type = block.Type,
|
||||||
|
Flags = block.Flags,
|
||||||
|
Unknown = block.Unknown,
|
||||||
|
Value = block.Value,
|
||||||
|
Data = block.Data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddBlocks(IEnumerable<ModernBlock> blocks)
|
||||||
|
{
|
||||||
|
foreach (ModernBlock block in blocks)
|
||||||
|
{
|
||||||
|
AddBlock(block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModernBlock GetBlock(string key, string value)
|
||||||
|
{
|
||||||
|
List<ModernBlock> blocks = Data[key];
|
||||||
|
|
||||||
|
foreach (ModernBlock block in blocks)
|
||||||
|
{
|
||||||
|
if (block.ValueAsStr == value)
|
||||||
|
{
|
||||||
|
return new ModernBlock
|
||||||
|
{
|
||||||
|
Type = block.Type,
|
||||||
|
Flags = block.Flags,
|
||||||
|
Key = Utils.EncodeString(key),
|
||||||
|
Value = block.Value,
|
||||||
|
Data = block.Data
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModernBlock GetBlock(string key, uint value)
|
||||||
|
{
|
||||||
|
List<ModernBlock> blocks = Data[key];
|
||||||
|
|
||||||
|
foreach (ModernBlock block in blocks)
|
||||||
|
{
|
||||||
|
if (block.ValueAsInt == value)
|
||||||
|
{
|
||||||
|
return new ModernBlock
|
||||||
|
{
|
||||||
|
Type = block.Type,
|
||||||
|
Flags = block.Flags,
|
||||||
|
Key = Utils.EncodeString(key),
|
||||||
|
Value = block.Value,
|
||||||
|
Data = block.Data
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetBlock(string key, string value, byte[] data)
|
||||||
|
{
|
||||||
|
List<ModernBlock> blocks = Data[key];
|
||||||
|
|
||||||
|
for (int i = 0; i < blocks.Count; i++)
|
||||||
|
{
|
||||||
|
ModernBlock block = blocks[i];
|
||||||
|
|
||||||
|
if (block.ValueAsStr == value)
|
||||||
|
{
|
||||||
|
block.Data = data;
|
||||||
|
blocks[i] = block;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Data[key] = blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetBlock(string key, uint value, byte[] data)
|
||||||
|
{
|
||||||
|
List<ModernBlock> blocks = Data[key];
|
||||||
|
|
||||||
|
for (int i = 0; i < blocks.Count; i++)
|
||||||
|
{
|
||||||
|
ModernBlock block = blocks[i];
|
||||||
|
|
||||||
|
if (block.ValueAsInt == value)
|
||||||
|
{
|
||||||
|
block.Data = data;
|
||||||
|
blocks[i] = block;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Data[key] = blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetBlock(string key, string value, string data)
|
||||||
|
{
|
||||||
|
SetBlock(key, value, Utils.EncodeString(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetBlock(string key, string value, uint data)
|
||||||
|
{
|
||||||
|
SetBlock(key, value, BitConverter.GetBytes(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetBlock(string key, uint value, string data)
|
||||||
|
{
|
||||||
|
SetBlock(key, value, Utils.EncodeString(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetBlock(string key, uint value, uint data)
|
||||||
|
{
|
||||||
|
SetBlock(key, value, BitConverter.GetBytes(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteBlock(string key, string value)
|
||||||
|
{
|
||||||
|
if (Data.ContainsKey(key))
|
||||||
|
{
|
||||||
|
List<ModernBlock> blocks = Data[key];
|
||||||
|
|
||||||
|
foreach (ModernBlock block in blocks)
|
||||||
|
{
|
||||||
|
if (block.ValueAsStr == value)
|
||||||
|
{
|
||||||
|
blocks.Remove(block);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Data[key] = blocks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteBlock(string key, uint value)
|
||||||
|
{
|
||||||
|
if (Data.ContainsKey(key))
|
||||||
|
{
|
||||||
|
List<ModernBlock> blocks = Data[key];
|
||||||
|
|
||||||
|
foreach (ModernBlock block in blocks)
|
||||||
|
{
|
||||||
|
if (block.ValueAsInt == value)
|
||||||
|
{
|
||||||
|
blocks.Remove(block);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Data[key] = blocks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPath()
|
||||||
|
{
|
||||||
|
string sppRoot = Utils.GetTokenStorePath();
|
||||||
|
|
||||||
|
return Path.Combine(Environment.ExpandEnvironmentVariables(sppRoot), "data.dat");
|
||||||
|
}
|
||||||
|
|
||||||
|
public PhysicalStore(PSVersion version, bool production)
|
||||||
|
{
|
||||||
|
Version = version;
|
||||||
|
Production = production;
|
||||||
|
|
||||||
|
TSFile = File.Open(GetPath(), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
|
||||||
|
|
||||||
|
Deserialize(ReadRaw());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
WriteRaw(Serialize());
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] ReadRaw()
|
||||||
|
{
|
||||||
|
byte[] data = PhysicalStoreCrypto.DecryptPhysicalStore(Utils.ReadAllBytes(TSFile), Production);
|
||||||
|
TSFile.Seek(0, SeekOrigin.Begin);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteRaw(byte[] data)
|
||||||
|
{
|
||||||
|
if (TSFile.CanWrite)
|
||||||
|
{
|
||||||
|
byte[] encrData = PhysicalStoreCrypto.EncryptPhysicalStore(data, Production, Version);
|
||||||
|
TSFile.SetLength(encrData.LongLength);
|
||||||
|
TSFile.Seek(0, SeekOrigin.Begin);
|
||||||
|
Utils.WriteAllBytes(TSFile, encrData);
|
||||||
|
TSFile.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
78
MetroUnlocker/LibTSForge/PhysicalStore/VariableBag.cs
Normal file
78
MetroUnlocker/LibTSForge/PhysicalStore/VariableBag.cs
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace MetroUnlocker.LibTSForge.PhysicalStore
|
||||||
|
{
|
||||||
|
public class VariableBag
|
||||||
|
{
|
||||||
|
public List<CRCBlock> Blocks = new List<CRCBlock>();
|
||||||
|
|
||||||
|
public VariableBag() { }
|
||||||
|
public VariableBag(byte[] data)
|
||||||
|
{
|
||||||
|
Deserialize(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Deserialize(byte[] data)
|
||||||
|
{
|
||||||
|
int len = data.Length;
|
||||||
|
|
||||||
|
BinaryReader reader = new BinaryReader(new MemoryStream(data));
|
||||||
|
|
||||||
|
while (reader.BaseStream.Position < len - 0x10)
|
||||||
|
{
|
||||||
|
Blocks.Add(CRCBlock.Decode(reader));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] Serialize()
|
||||||
|
{
|
||||||
|
BinaryWriter writer = new BinaryWriter(new MemoryStream());
|
||||||
|
|
||||||
|
foreach (CRCBlock block in Blocks)
|
||||||
|
block.Encode(writer);
|
||||||
|
|
||||||
|
return ((MemoryStream)writer.BaseStream).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CRCBlock GetBlock(string key)
|
||||||
|
{
|
||||||
|
foreach (CRCBlock block in Blocks)
|
||||||
|
{
|
||||||
|
if (block.KeyAsStr == key)
|
||||||
|
{
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetBlock(string key, byte[] value)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Blocks.Count; i++)
|
||||||
|
{
|
||||||
|
CRCBlock block = Blocks[i];
|
||||||
|
|
||||||
|
if (block.KeyAsStr == key)
|
||||||
|
{
|
||||||
|
block.Value = value;
|
||||||
|
Blocks[i] = block;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteBlock(string key)
|
||||||
|
{
|
||||||
|
foreach (CRCBlock block in Blocks)
|
||||||
|
if (block.KeyAsStr == key)
|
||||||
|
{
|
||||||
|
Blocks.Remove(block);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
202
MetroUnlocker/LibTSForge/SPP/PKeyConfig.cs
Normal file
202
MetroUnlocker/LibTSForge/SPP/PKeyConfig.cs
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.IO;
|
||||||
|
using System.Xml;
|
||||||
|
|
||||||
|
namespace MetroUnlocker.LibTSForge.SPP
|
||||||
|
{
|
||||||
|
|
||||||
|
public enum PKeyAlgorithm
|
||||||
|
{
|
||||||
|
PKEY2005,
|
||||||
|
PKEY2009
|
||||||
|
}
|
||||||
|
|
||||||
|
public class KeyRange
|
||||||
|
{
|
||||||
|
public int Start;
|
||||||
|
public int End;
|
||||||
|
public string EulaType;
|
||||||
|
public string PartNumber;
|
||||||
|
public bool Valid;
|
||||||
|
|
||||||
|
public bool Contains(int n)
|
||||||
|
{
|
||||||
|
return Start <= n && End <= n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ProductConfig
|
||||||
|
{
|
||||||
|
public int GroupId;
|
||||||
|
public string Edition;
|
||||||
|
public string Description;
|
||||||
|
public string Channel;
|
||||||
|
public bool Randomized;
|
||||||
|
public PKeyAlgorithm Algorithm;
|
||||||
|
public List<KeyRange> Ranges;
|
||||||
|
public Guid ActivationId;
|
||||||
|
|
||||||
|
private List<KeyRange> GetPkeyRanges()
|
||||||
|
{
|
||||||
|
if (Ranges.Count == 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("No key ranges.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Algorithm == PKeyAlgorithm.PKEY2005)
|
||||||
|
{
|
||||||
|
return Ranges;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<KeyRange> FilteredRanges = Ranges.Where(r => !r.EulaType.Contains("WAU")).ToList();
|
||||||
|
|
||||||
|
if (FilteredRanges.Count == 0)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("Specified Activation ID is usable only for Windows Anytime Upgrade. Please use a non-WAU Activation ID instead.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return FilteredRanges;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProductKey GetRandomKey()
|
||||||
|
{
|
||||||
|
List<KeyRange> KeyRanges = GetPkeyRanges();
|
||||||
|
Random rnd = new Random();
|
||||||
|
|
||||||
|
KeyRange range = KeyRanges[rnd.Next(KeyRanges.Count)];
|
||||||
|
int serial = rnd.Next(range.Start, range.End);
|
||||||
|
|
||||||
|
return new ProductKey(serial, 0, false, Algorithm, this, range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PKeyConfig
|
||||||
|
{
|
||||||
|
public Dictionary<Guid, ProductConfig> Products = new Dictionary<Guid, ProductConfig>();
|
||||||
|
private List<Guid> loadedPkeyConfigs = new List<Guid>();
|
||||||
|
|
||||||
|
public void LoadConfig(Guid actId)
|
||||||
|
{
|
||||||
|
string pkcData;
|
||||||
|
Guid pkcFileId = SLApi.GetPkeyConfigFileId(actId);
|
||||||
|
|
||||||
|
if (loadedPkeyConfigs.Contains(pkcFileId)) return;
|
||||||
|
|
||||||
|
string licConts = SLApi.GetLicenseContents(pkcFileId);
|
||||||
|
|
||||||
|
using (TextReader tr = new StringReader(licConts))
|
||||||
|
{
|
||||||
|
XmlDocument lic = new XmlDocument();
|
||||||
|
lic.Load(tr);
|
||||||
|
|
||||||
|
XmlNamespaceManager nsmgr = new XmlNamespaceManager(lic.NameTable);
|
||||||
|
nsmgr.AddNamespace("rg", "urn:mpeg:mpeg21:2003:01-REL-R-NS");
|
||||||
|
nsmgr.AddNamespace("r", "urn:mpeg:mpeg21:2003:01-REL-R-NS");
|
||||||
|
nsmgr.AddNamespace("tm", "http://www.microsoft.com/DRM/XrML2/TM/v2");
|
||||||
|
|
||||||
|
XmlNode root = lic.DocumentElement;
|
||||||
|
XmlNode pkcDataNode = root.SelectSingleNode("/rg:licenseGroup/r:license/r:otherInfo/tm:infoTables/tm:infoList/tm:infoBin[@name=\"pkeyConfigData\"]", nsmgr);
|
||||||
|
pkcData = Encoding.UTF8.GetString(Convert.FromBase64String(pkcDataNode.InnerText));
|
||||||
|
}
|
||||||
|
|
||||||
|
using (TextReader tr = new StringReader(pkcData))
|
||||||
|
{
|
||||||
|
XmlDocument lic = new XmlDocument();
|
||||||
|
lic.Load(tr);
|
||||||
|
|
||||||
|
XmlNamespaceManager nsmgr = new XmlNamespaceManager(lic.NameTable);
|
||||||
|
nsmgr.AddNamespace("p", "http://www.microsoft.com/DRM/PKEY/Configuration/2.0");
|
||||||
|
XmlNodeList configNodes = lic.SelectNodes("//p:ProductKeyConfiguration/p:Configurations/p:Configuration", nsmgr);
|
||||||
|
XmlNodeList rangeNodes = lic.SelectNodes("//p:ProductKeyConfiguration/p:KeyRanges/p:KeyRange", nsmgr);
|
||||||
|
XmlNodeList pubKeyNodes = lic.SelectNodes("//p:ProductKeyConfiguration/p:PublicKeys/p:PublicKey", nsmgr);
|
||||||
|
|
||||||
|
Dictionary<int, PKeyAlgorithm> algorithms = new Dictionary<int, PKeyAlgorithm>();
|
||||||
|
Dictionary<string, List<KeyRange>> ranges = new Dictionary<string, List<KeyRange>>();
|
||||||
|
|
||||||
|
Dictionary<string, PKeyAlgorithm> algoConv = new Dictionary<string, PKeyAlgorithm>
|
||||||
|
{
|
||||||
|
{ "msft:rm/algorithm/pkey/2005", PKeyAlgorithm.PKEY2005 },
|
||||||
|
{ "msft:rm/algorithm/pkey/2009", PKeyAlgorithm.PKEY2009 }
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (XmlNode pubKeyNode in pubKeyNodes)
|
||||||
|
{
|
||||||
|
int group = int.Parse(pubKeyNode.SelectSingleNode("./p:GroupId", nsmgr).InnerText);
|
||||||
|
algorithms[group] = algoConv[pubKeyNode.SelectSingleNode("./p:AlgorithmId", nsmgr).InnerText];
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (XmlNode rangeNode in rangeNodes)
|
||||||
|
{
|
||||||
|
string refActIdStr = rangeNode.SelectSingleNode("./p:RefActConfigId", nsmgr).InnerText;
|
||||||
|
|
||||||
|
if (!ranges.ContainsKey(refActIdStr))
|
||||||
|
{
|
||||||
|
ranges[refActIdStr] = new List<KeyRange>();
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyRange keyRange = new KeyRange();
|
||||||
|
keyRange.Start = int.Parse(rangeNode.SelectSingleNode("./p:Start", nsmgr).InnerText);
|
||||||
|
keyRange.End = int.Parse(rangeNode.SelectSingleNode("./p:End", nsmgr).InnerText);
|
||||||
|
keyRange.EulaType = rangeNode.SelectSingleNode("./p:EulaType", nsmgr).InnerText;
|
||||||
|
keyRange.PartNumber = rangeNode.SelectSingleNode("./p:PartNumber", nsmgr).InnerText;
|
||||||
|
keyRange.Valid = rangeNode.SelectSingleNode("./p:IsValid", nsmgr).InnerText.ToLower() == "true";
|
||||||
|
|
||||||
|
ranges[refActIdStr].Add(keyRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (XmlNode configNode in configNodes)
|
||||||
|
{
|
||||||
|
string refActIdStr = configNode.SelectSingleNode("./p:ActConfigId", nsmgr).InnerText;
|
||||||
|
Guid refActId = new Guid(refActIdStr);
|
||||||
|
int group = int.Parse(configNode.SelectSingleNode("./p:RefGroupId", nsmgr).InnerText);
|
||||||
|
List<KeyRange> keyRanges = ranges[refActIdStr];
|
||||||
|
|
||||||
|
if (keyRanges.Count > 0 && !Products.ContainsKey(refActId))
|
||||||
|
{
|
||||||
|
ProductConfig productConfig = new ProductConfig();
|
||||||
|
productConfig.GroupId = group;
|
||||||
|
productConfig.Edition = configNode.SelectSingleNode("./p:EditionId", nsmgr).InnerText;
|
||||||
|
productConfig.Description = configNode.SelectSingleNode("./p:ProductDescription", nsmgr).InnerText;
|
||||||
|
productConfig.Channel = configNode.SelectSingleNode("./p:ProductKeyType", nsmgr).InnerText;
|
||||||
|
productConfig.Randomized = configNode.SelectSingleNode("./p:ProductKeyType", nsmgr).InnerText.ToLower() == "true";
|
||||||
|
productConfig.Algorithm = algorithms[group];
|
||||||
|
productConfig.Ranges = keyRanges;
|
||||||
|
productConfig.ActivationId = refActId;
|
||||||
|
|
||||||
|
Products[refActId] = productConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadedPkeyConfigs.Add(pkcFileId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProductConfig MatchParams(int group, int serial)
|
||||||
|
{
|
||||||
|
foreach (ProductConfig config in Products.Values)
|
||||||
|
{
|
||||||
|
if (config.GroupId == group)
|
||||||
|
{
|
||||||
|
foreach (KeyRange range in config.Ranges)
|
||||||
|
{
|
||||||
|
if (range.Contains(serial))
|
||||||
|
{
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new FileNotFoundException("Failed to find product matching supplied product key parameters.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public PKeyConfig()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
310
MetroUnlocker/LibTSForge/SPP/ProductKey.cs
Normal file
310
MetroUnlocker/LibTSForge/SPP/ProductKey.cs
Normal file
@@ -0,0 +1,310 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
using MetroUnlocker.LibTSForge.Crypto;
|
||||||
|
using MetroUnlocker.LibTSForge.PhysicalStore;
|
||||||
|
|
||||||
|
namespace MetroUnlocker.LibTSForge.SPP
|
||||||
|
{
|
||||||
|
|
||||||
|
public class ProductKey
|
||||||
|
{
|
||||||
|
private static readonly string ALPHABET = "BCDFGHJKMPQRTVWXY2346789";
|
||||||
|
|
||||||
|
private readonly ulong klow;
|
||||||
|
private readonly ulong khigh;
|
||||||
|
|
||||||
|
public int Group;
|
||||||
|
public int Serial;
|
||||||
|
public ulong Security;
|
||||||
|
public bool Upgrade;
|
||||||
|
public PKeyAlgorithm Algorithm;
|
||||||
|
public string EulaType;
|
||||||
|
public string PartNumber;
|
||||||
|
public string Edition;
|
||||||
|
public string Channel;
|
||||||
|
public Guid ActivationId;
|
||||||
|
|
||||||
|
private string mpc;
|
||||||
|
private string pid2;
|
||||||
|
|
||||||
|
public byte[] KeyBytes
|
||||||
|
{
|
||||||
|
get { return BitConverter.GetBytes(klow).Concat(BitConverter.GetBytes(khigh)).ToArray(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProductKey(int serial, ulong security, bool upgrade, PKeyAlgorithm algorithm, ProductConfig config, KeyRange range)
|
||||||
|
{
|
||||||
|
Group = config.GroupId;
|
||||||
|
Serial = serial;
|
||||||
|
Security = security;
|
||||||
|
Upgrade = upgrade;
|
||||||
|
Algorithm = algorithm;
|
||||||
|
EulaType = range.EulaType;
|
||||||
|
PartNumber = range.PartNumber.Split(':', ';')[0];
|
||||||
|
Edition = config.Edition;
|
||||||
|
Channel = config.Channel;
|
||||||
|
ActivationId = config.ActivationId;
|
||||||
|
|
||||||
|
klow = ((security & 0x3fff) << 50 | ((ulong)serial & 0x3fffffff) << 20 | ((ulong)Group & 0xfffff));
|
||||||
|
khigh = ((upgrade ? (ulong)1 : 0) << 49 | ((security >> 14) & 0x7fffffffff));
|
||||||
|
|
||||||
|
uint checksum = Utils.CRC32(KeyBytes) & 0x3ff;
|
||||||
|
|
||||||
|
khigh |= ((ulong)checksum << 39);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetAlgoUri()
|
||||||
|
{
|
||||||
|
return "msft:rm/algorithm/pkey/" + (Algorithm == PKeyAlgorithm.PKEY2005 ? "2005" : (Algorithm == PKeyAlgorithm.PKEY2009 ? "2009" : "Unknown"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid GetPkeyId()
|
||||||
|
{
|
||||||
|
VariableBag pkb = new VariableBag();
|
||||||
|
pkb.Blocks.AddRange(new CRCBlock[]
|
||||||
|
{
|
||||||
|
new CRCBlock
|
||||||
|
{
|
||||||
|
DataType = CRCBlockType.STRING,
|
||||||
|
KeyAsStr = "SppPkeyBindingProductKey",
|
||||||
|
ValueAsStr = ToString()
|
||||||
|
},
|
||||||
|
new CRCBlock
|
||||||
|
{
|
||||||
|
DataType = CRCBlockType.BINARY,
|
||||||
|
KeyAsStr = "SppPkeyBindingMiscData",
|
||||||
|
Value = new byte[] { }
|
||||||
|
},
|
||||||
|
new CRCBlock
|
||||||
|
{
|
||||||
|
DataType = CRCBlockType.STRING,
|
||||||
|
KeyAsStr = "SppPkeyBindingAlgorithm",
|
||||||
|
ValueAsStr = GetAlgoUri()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Guid(CryptoUtils.SHA256Hash(pkb.Serialize()).Take(16).ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetDefaultMPC()
|
||||||
|
{
|
||||||
|
int build = Environment.OSVersion.Version.Build;
|
||||||
|
string defaultMPC = build >= 10240 ? "03612" :
|
||||||
|
build >= 9600 ? "06401" :
|
||||||
|
build >= 9200 ? "05426" :
|
||||||
|
"55041";
|
||||||
|
return defaultMPC;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetMPC()
|
||||||
|
{
|
||||||
|
if (mpc != null)
|
||||||
|
{
|
||||||
|
return mpc;
|
||||||
|
}
|
||||||
|
|
||||||
|
mpc = GetDefaultMPC();
|
||||||
|
|
||||||
|
// setup.cfg doesn't exist in Windows 8+
|
||||||
|
string setupcfg = string.Format("{0}\\oobe\\{1}", Environment.SystemDirectory, "setup.cfg");
|
||||||
|
|
||||||
|
if (!File.Exists(setupcfg) || Edition.Contains(";"))
|
||||||
|
{
|
||||||
|
return mpc;
|
||||||
|
}
|
||||||
|
|
||||||
|
string mpcKey = string.Format("{0}.{1}=", Utils.GetArchitecture(), Edition);
|
||||||
|
string localMPC = File.ReadAllLines(setupcfg).FirstOrDefault(line => line.Contains(mpcKey));
|
||||||
|
if (localMPC != null)
|
||||||
|
{
|
||||||
|
mpc = localMPC.Split('=')[1].Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
return mpc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetPid2()
|
||||||
|
{
|
||||||
|
if (pid2 != null)
|
||||||
|
{
|
||||||
|
return pid2;
|
||||||
|
}
|
||||||
|
|
||||||
|
pid2 = "";
|
||||||
|
|
||||||
|
if (Algorithm == PKeyAlgorithm.PKEY2005)
|
||||||
|
{
|
||||||
|
string mpc = GetMPC();
|
||||||
|
string serialHigh;
|
||||||
|
int serialLow;
|
||||||
|
int lastPart;
|
||||||
|
|
||||||
|
if (EulaType == "OEM")
|
||||||
|
{
|
||||||
|
serialHigh = "OEM";
|
||||||
|
serialLow = ((Group / 2) % 100) * 10000 + (Serial / 100000);
|
||||||
|
lastPart = Serial % 100000;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serialHigh = (Serial / 1000000).ToString("D3");
|
||||||
|
serialLow = Serial % 1000000;
|
||||||
|
lastPart = ((Group / 2) % 100) * 1000 + new Random().Next(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
int checksum = 0;
|
||||||
|
|
||||||
|
foreach (char c in serialLow.ToString())
|
||||||
|
{
|
||||||
|
checksum += int.Parse(c.ToString());
|
||||||
|
}
|
||||||
|
checksum = 7 - (checksum % 7);
|
||||||
|
|
||||||
|
pid2 = string.Format("{0}-{1}-{2:D6}{3}-{4:D5}", mpc, serialHigh, serialLow, checksum, lastPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pid2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] GetPid3()
|
||||||
|
{
|
||||||
|
BinaryWriter writer = new BinaryWriter(new MemoryStream());
|
||||||
|
writer.Write(0xA4);
|
||||||
|
writer.Write(0x3);
|
||||||
|
writer.WriteFixedString(GetPid2(), 24);
|
||||||
|
writer.Write(Group);
|
||||||
|
writer.WriteFixedString(PartNumber, 16);
|
||||||
|
writer.WritePadding(0x6C);
|
||||||
|
byte[] data = writer.GetBytes();
|
||||||
|
byte[] crc = BitConverter.GetBytes(~Utils.CRC32(data.Reverse().ToArray())).Reverse().ToArray();
|
||||||
|
writer.Write(crc);
|
||||||
|
|
||||||
|
return writer.GetBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] GetPid4()
|
||||||
|
{
|
||||||
|
BinaryWriter writer = new BinaryWriter(new MemoryStream());
|
||||||
|
writer.Write(0x4F8);
|
||||||
|
writer.Write(0x4);
|
||||||
|
writer.WriteFixedString16(GetExtendedPid(), 0x80);
|
||||||
|
writer.WriteFixedString16(ActivationId.ToString(), 0x80);
|
||||||
|
writer.WritePadding(0x10);
|
||||||
|
writer.WriteFixedString16(Edition, 0x208);
|
||||||
|
writer.Write(Upgrade ? (ulong)1 : 0);
|
||||||
|
writer.WritePadding(0x50);
|
||||||
|
writer.WriteFixedString16(PartNumber, 0x80);
|
||||||
|
writer.WriteFixedString16(Channel, 0x80);
|
||||||
|
writer.WriteFixedString16(EulaType, 0x80);
|
||||||
|
|
||||||
|
return writer.GetBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetExtendedPid()
|
||||||
|
{
|
||||||
|
string mpc = GetMPC();
|
||||||
|
int serialHigh = Serial / 1000000;
|
||||||
|
int serialLow = Serial % 1000000;
|
||||||
|
int licenseType;
|
||||||
|
uint lcid = Utils.GetSystemDefaultLCID();
|
||||||
|
int build = Environment.OSVersion.Version.Build;
|
||||||
|
int dayOfYear = DateTime.Now.DayOfYear;
|
||||||
|
int year = DateTime.Now.Year;
|
||||||
|
|
||||||
|
switch (EulaType)
|
||||||
|
{
|
||||||
|
case "OEM":
|
||||||
|
licenseType = 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Volume":
|
||||||
|
licenseType = 3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
licenseType = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Format(
|
||||||
|
"{0}-{1:D5}-{2:D3}-{3:D6}-{4:D2}-{5:D4}-{6:D4}.0000-{7:D3}{8:D4}",
|
||||||
|
mpc,
|
||||||
|
Group,
|
||||||
|
serialHigh,
|
||||||
|
serialLow,
|
||||||
|
licenseType,
|
||||||
|
lcid,
|
||||||
|
build,
|
||||||
|
dayOfYear,
|
||||||
|
year
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] GetPhoneData(PSVersion version)
|
||||||
|
{
|
||||||
|
int serialHigh = Serial / 1000000;
|
||||||
|
int serialLow = Serial % 1000000;
|
||||||
|
|
||||||
|
BinaryWriter writer = new BinaryWriter(new MemoryStream());
|
||||||
|
writer.Write(new Guid("B8731595-A2F6-430B-A799-FBFFB81A8D73").ToByteArray());
|
||||||
|
writer.Write(Group);
|
||||||
|
writer.Write(serialHigh);
|
||||||
|
writer.Write(serialLow);
|
||||||
|
writer.Write(Upgrade ? 1 : 0);
|
||||||
|
writer.Write(Security);
|
||||||
|
|
||||||
|
return writer.GetBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
string keyStr = "";
|
||||||
|
Random rnd = new Random(Group * 1000000000 + Serial);
|
||||||
|
|
||||||
|
if (Algorithm == PKeyAlgorithm.PKEY2005)
|
||||||
|
{
|
||||||
|
keyStr = "H4X3DH4X3DH4X3DH4X3D";
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
keyStr += ALPHABET[rnd.Next(24)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Algorithm == PKeyAlgorithm.PKEY2009)
|
||||||
|
{
|
||||||
|
int last = 0;
|
||||||
|
byte[] bKey = KeyBytes;
|
||||||
|
|
||||||
|
for (int i = 24; i >= 0; i--)
|
||||||
|
{
|
||||||
|
int current = 0;
|
||||||
|
|
||||||
|
for (int j = 14; j >= 0; j--)
|
||||||
|
{
|
||||||
|
current *= 0x100;
|
||||||
|
current += bKey[j];
|
||||||
|
bKey[j] = (byte)(current / 24);
|
||||||
|
current %= 24;
|
||||||
|
last = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
keyStr = ALPHABET[current] + keyStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
keyStr = keyStr.Substring(1, last) + "N" + keyStr.Substring(last + 1, keyStr.Length - last - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 5; i < keyStr.Length; i += 6)
|
||||||
|
{
|
||||||
|
keyStr = keyStr.Insert(i, "-");
|
||||||
|
}
|
||||||
|
|
||||||
|
return keyStr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
307
MetroUnlocker/LibTSForge/SPP/SLAPI.cs
Normal file
307
MetroUnlocker/LibTSForge/SPP/SLAPI.cs
Normal file
@@ -0,0 +1,307 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace MetroUnlocker.LibTSForge.SPP
|
||||||
|
{
|
||||||
|
public static class SLApi
|
||||||
|
{
|
||||||
|
private enum SLIDTYPE
|
||||||
|
{
|
||||||
|
SL_ID_APPLICATION,
|
||||||
|
SL_ID_PRODUCT_SKU,
|
||||||
|
SL_ID_LICENSE_FILE,
|
||||||
|
SL_ID_LICENSE,
|
||||||
|
SL_ID_PKEY,
|
||||||
|
SL_ID_ALL_LICENSES,
|
||||||
|
SL_ID_ALL_LICENSE_FILES,
|
||||||
|
SL_ID_STORE_TOKEN,
|
||||||
|
SL_ID_LAST
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum SLDATATYPE
|
||||||
|
{
|
||||||
|
SL_DATA_NONE,
|
||||||
|
SL_DATA_SZ,
|
||||||
|
SL_DATA_DWORD,
|
||||||
|
SL_DATA_BINARY,
|
||||||
|
SL_DATA_MULTI_SZ,
|
||||||
|
SL_DATA_SUM
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
private struct SL_LICENSING_STATUS
|
||||||
|
{
|
||||||
|
public Guid SkuId;
|
||||||
|
public uint eStatus;
|
||||||
|
public uint dwGraceTime;
|
||||||
|
public uint dwTotalGraceDays;
|
||||||
|
public uint hrReason;
|
||||||
|
public ulong qwValidityExpiration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly Guid WINDOWS_APP_ID = new Guid("55c92734-d682-4d71-983e-d6ec3f16059f");
|
||||||
|
|
||||||
|
[DllImport("sppc.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
|
||||||
|
private static extern void SLOpen(out IntPtr hSLC);
|
||||||
|
|
||||||
|
[DllImport("sppc.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
|
||||||
|
private static extern void SLClose(IntPtr hSLC);
|
||||||
|
|
||||||
|
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
|
||||||
|
private static extern uint SLGetWindowsInformationDWORD(string ValueName, ref int Value);
|
||||||
|
|
||||||
|
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
|
||||||
|
private static extern uint SLInstallProofOfPurchase(IntPtr hSLC, string pwszPKeyAlgorithm, string pwszPKeyString, uint cbPKeySpecificData, byte[] pbPKeySpecificData, ref Guid PKeyId);
|
||||||
|
|
||||||
|
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
|
||||||
|
private static extern uint SLUninstallProofOfPurchase(IntPtr hSLC, ref Guid PKeyId);
|
||||||
|
|
||||||
|
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
|
||||||
|
private static extern uint SLGetPKeyInformation(IntPtr hSLC, ref Guid pPKeyId, string pwszValueName, out SLDATATYPE peDataType, out uint pcbValue, out IntPtr ppbValue);
|
||||||
|
|
||||||
|
[DllImport("sppcext.dll", CharSet = CharSet.Unicode)]
|
||||||
|
private static extern uint SLActivateProduct(IntPtr hSLC, ref Guid pProductSkuId, byte[] cbAppSpecificData, byte[] pvAppSpecificData, byte[] pActivationInfo, string pwszProxyServer, ushort wProxyPort);
|
||||||
|
|
||||||
|
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
|
||||||
|
private static extern uint SLGenerateOfflineInstallationId(IntPtr hSLC, ref Guid pProductSkuId, ref string ppwszInstallationId);
|
||||||
|
|
||||||
|
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
|
||||||
|
private static extern uint SLDepositOfflineConfirmationId(IntPtr hSLC, ref Guid pProductSkuId, string pwszInstallationId, string pwszConfirmationId);
|
||||||
|
|
||||||
|
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
|
||||||
|
private static extern uint SLGetSLIDList(IntPtr hSLC, SLIDTYPE eQueryIdType, ref Guid pQueryId, SLIDTYPE eReturnIdType, out uint pnReturnIds, out IntPtr ppReturnIds);
|
||||||
|
|
||||||
|
[DllImport("sppc.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
|
||||||
|
private static extern void SLGetLicensingStatusInformation(IntPtr hSLC, ref Guid pAppID, IntPtr pProductSkuId, string pwszRightName, out uint pnStatusCount, out IntPtr ppLicensingStatus);
|
||||||
|
|
||||||
|
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
|
||||||
|
private static extern uint SLGetInstalledProductKeyIds(IntPtr hSLC, ref Guid pProductSkuId, out uint pnProductKeyIds, out IntPtr ppProductKeyIds);
|
||||||
|
|
||||||
|
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
|
||||||
|
private static extern uint SLConsumeWindowsRight(uint unknown);
|
||||||
|
|
||||||
|
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
|
||||||
|
private static extern uint SLGetProductSkuInformation(IntPtr hSLC, ref Guid pProductSkuId, string pwszValueName, out SLDATATYPE peDataType, out uint pcbValue, out IntPtr ppbValue);
|
||||||
|
|
||||||
|
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
|
||||||
|
private static extern uint SLGetProductSkuInformation(IntPtr hSLC, ref Guid pProductSkuId, string pwszValueName, IntPtr peDataType, out uint pcbValue, out IntPtr ppbValue);
|
||||||
|
|
||||||
|
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
|
||||||
|
private static extern uint SLGetLicense(IntPtr hSLC, ref Guid pLicenseFileId, out uint pcbLicenseFile, out IntPtr ppbLicenseFile);
|
||||||
|
|
||||||
|
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
|
||||||
|
private static extern uint SLSetCurrentProductKey(IntPtr hSLC, ref Guid pProductSkuId, ref Guid pProductKeyId);
|
||||||
|
|
||||||
|
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
|
||||||
|
private static extern uint SLFireEvent(IntPtr hSLC, string pwszEventId, ref Guid pApplicationId);
|
||||||
|
|
||||||
|
public class SLContext : IDisposable
|
||||||
|
{
|
||||||
|
public readonly IntPtr Handle;
|
||||||
|
|
||||||
|
public SLContext()
|
||||||
|
{
|
||||||
|
SLOpen(out Handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
SLClose(Handle);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
~SLContext()
|
||||||
|
{
|
||||||
|
Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Guid GetPkeyConfigFileId(Guid actId)
|
||||||
|
{
|
||||||
|
using (SLContext sl = new SLContext())
|
||||||
|
{
|
||||||
|
SLDATATYPE type;
|
||||||
|
uint len;
|
||||||
|
IntPtr ppReturnLics;
|
||||||
|
|
||||||
|
uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "pkeyConfigLicenseId", out type, out len, out ppReturnLics);
|
||||||
|
|
||||||
|
if (status != 0 || len == 0)
|
||||||
|
{
|
||||||
|
return Guid.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
Guid pkcId = new Guid(Marshal.PtrToStringAuto(ppReturnLics));
|
||||||
|
return GetLicenseFileId(pkcId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Guid GetLicenseFileId(Guid licId)
|
||||||
|
{
|
||||||
|
using (SLContext sl = new SLContext())
|
||||||
|
{
|
||||||
|
uint status;
|
||||||
|
uint count;
|
||||||
|
IntPtr ppReturnLics;
|
||||||
|
|
||||||
|
status = SLGetSLIDList(sl.Handle, SLIDTYPE.SL_ID_LICENSE, ref licId, SLIDTYPE.SL_ID_LICENSE_FILE, out count, out ppReturnLics);
|
||||||
|
|
||||||
|
return (status == 0 && count != 0) ? (Guid)Marshal.PtrToStructure(ppReturnLics, typeof(Guid)) : Guid.Empty;//new Guid(Marshal.PtrToStringAuto(ppReturnLics));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetLicenseContents(Guid fileId)
|
||||||
|
{
|
||||||
|
if (fileId == Guid.Empty) throw new ArgumentException("License contents could not be retrieved.");
|
||||||
|
|
||||||
|
using (SLContext sl = new SLContext())
|
||||||
|
{
|
||||||
|
uint dataLen;
|
||||||
|
IntPtr dataPtr;
|
||||||
|
|
||||||
|
if (SLGetLicense(sl.Handle, ref fileId, out dataLen, out dataPtr) != 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] data = new byte[dataLen];
|
||||||
|
Marshal.Copy(dataPtr, data, 0, (int)dataLen);
|
||||||
|
|
||||||
|
data = data.Skip(Array.IndexOf(data, (byte)'<')).ToArray();
|
||||||
|
return Encoding.UTF8.GetString(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetMetaStr(Guid actId, string value)
|
||||||
|
{
|
||||||
|
using (SLContext sl = new SLContext())
|
||||||
|
{
|
||||||
|
uint len;
|
||||||
|
SLDATATYPE type;
|
||||||
|
IntPtr ppbValue;
|
||||||
|
|
||||||
|
uint status = SLGetProductSkuInformation(sl.Handle, ref actId, value, out type, out len, out ppbValue);
|
||||||
|
|
||||||
|
if (status != 0 || len == 0 || type != SLDATATYPE.SL_DATA_SZ)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Marshal.PtrToStringAuto(ppbValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetInstallationId(Guid actId)
|
||||||
|
{
|
||||||
|
using (SLContext sl = new SLContext())
|
||||||
|
{
|
||||||
|
string installationId = null;
|
||||||
|
var status = SLGenerateOfflineInstallationId(sl.Handle, ref actId, ref installationId);
|
||||||
|
|
||||||
|
if (status != 0)
|
||||||
|
throw new Exception(string.Format("Failed to get installation ID: 0x{0}. Your data.dat is probably corrupt at the moment. Try again later.", status.ToString("X")));
|
||||||
|
|
||||||
|
return installationId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Guid GetInstalledPkeyId(Guid actId)
|
||||||
|
{
|
||||||
|
using (SLContext sl = new SLContext())
|
||||||
|
{
|
||||||
|
uint status;
|
||||||
|
uint count;
|
||||||
|
IntPtr pProductKeyIds;
|
||||||
|
|
||||||
|
status = SLGetInstalledProductKeyIds(sl.Handle, ref actId, out count, out pProductKeyIds);
|
||||||
|
|
||||||
|
//unsafe { return *(Guid*)pProductKeyIds; }
|
||||||
|
return (status == 0 && count != 0) ? (Guid)Marshal.PtrToStructure(pProductKeyIds, typeof(Guid)) : Guid.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static uint DepositConfirmationId(Guid actId, string installationId, string confirmationId)
|
||||||
|
{
|
||||||
|
using (SLContext sl = new SLContext())
|
||||||
|
return SLDepositOfflineConfirmationId(sl.Handle, ref actId, installationId, confirmationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RefreshLicenseStatus()
|
||||||
|
{
|
||||||
|
SLConsumeWindowsRight(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool RefreshTrustedTime(Guid actId)
|
||||||
|
{
|
||||||
|
using (SLContext sl = new SLContext())
|
||||||
|
{
|
||||||
|
SLDATATYPE type;
|
||||||
|
uint count;
|
||||||
|
IntPtr ppbValue;
|
||||||
|
|
||||||
|
uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "TrustedTime", out type, out count, out ppbValue);
|
||||||
|
return (int)status >= 0 && status != 0xC004F012;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void FireStateChangedEvent(Guid appId)
|
||||||
|
{
|
||||||
|
using (SLContext sl = new SLContext())
|
||||||
|
{
|
||||||
|
SLFireEvent(sl.Handle, "msft:rm/event/licensingstatechanged", ref appId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Guid GetAppId(Guid actId)
|
||||||
|
{
|
||||||
|
using (SLContext sl = new SLContext())
|
||||||
|
{
|
||||||
|
uint count;
|
||||||
|
IntPtr pAppIds;
|
||||||
|
|
||||||
|
uint status = SLGetSLIDList(sl.Handle, SLIDTYPE.SL_ID_PRODUCT_SKU, ref actId, SLIDTYPE.SL_ID_APPLICATION, out count, out pAppIds);
|
||||||
|
|
||||||
|
if (status != 0 || count == 0)
|
||||||
|
return Guid.Empty;
|
||||||
|
|
||||||
|
return (Guid)Marshal.PtrToStructure(pAppIds, typeof(Guid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsAddon(Guid actId)
|
||||||
|
{
|
||||||
|
using (SLContext sl = new SLContext())
|
||||||
|
{
|
||||||
|
uint count;
|
||||||
|
SLDATATYPE type;
|
||||||
|
IntPtr ppbValue;
|
||||||
|
|
||||||
|
uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "DependsOn", out type, out count, out ppbValue);
|
||||||
|
return (int)status >= 0 && status != 0xC004F012;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static uint InstallProductKey(ProductKey pkey)
|
||||||
|
{
|
||||||
|
using (SLContext sl = new SLContext())
|
||||||
|
{
|
||||||
|
Guid pkeyId = Guid.Empty;
|
||||||
|
return SLInstallProofOfPurchase(sl.Handle, pkey.GetAlgoUri(), pkey.ToString(), 0, null, ref pkeyId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static uint UninstallProductKey(Guid pkeyId)
|
||||||
|
{
|
||||||
|
using (SLContext sl = new SLContext())
|
||||||
|
return SLUninstallProofOfPurchase(sl.Handle, ref pkeyId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
MetroUnlocker/LibTSForge/TokenStore/TokenEntry.cs
Normal file
15
MetroUnlocker/LibTSForge/TokenStore/TokenEntry.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace MetroUnlocker.LibTSForge.TokenStore
|
||||||
|
{
|
||||||
|
public class TokenEntry
|
||||||
|
{
|
||||||
|
public string Name;
|
||||||
|
public string Extension;
|
||||||
|
public byte[] Data;
|
||||||
|
public bool Populated;
|
||||||
|
}
|
||||||
|
}
|
||||||
292
MetroUnlocker/LibTSForge/TokenStore/TokenStore.cs
Normal file
292
MetroUnlocker/LibTSForge/TokenStore/TokenStore.cs
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.IO;
|
||||||
|
using MetroUnlocker.LibTSForge.Crypto;
|
||||||
|
|
||||||
|
namespace MetroUnlocker.LibTSForge.TokenStore
|
||||||
|
{
|
||||||
|
|
||||||
|
public class TokenStore : IDisposable
|
||||||
|
{
|
||||||
|
private static readonly uint VERSION = 3;
|
||||||
|
private static readonly int ENTRY_SIZE = 0x9E;
|
||||||
|
private static readonly int BLOCK_SIZE = 0x4020;
|
||||||
|
private static readonly int ENTRIES_PER_BLOCK = BLOCK_SIZE / ENTRY_SIZE;
|
||||||
|
private static readonly int BLOCK_PAD_SIZE = 0x66;
|
||||||
|
|
||||||
|
private static readonly byte[] CONTS_HEADER = Enumerable.Repeat((byte)0x55, 0x20).ToArray();
|
||||||
|
private static readonly byte[] CONTS_FOOTER = Enumerable.Repeat((byte)0xAA, 0x20).ToArray();
|
||||||
|
|
||||||
|
private List<TokenEntry> Entries = new List<TokenEntry>();
|
||||||
|
public FileStream TokensFile;
|
||||||
|
|
||||||
|
public void Deserialize()
|
||||||
|
{
|
||||||
|
if (TokensFile.Length < BLOCK_SIZE) return;
|
||||||
|
|
||||||
|
TokensFile.Seek(0x24, SeekOrigin.Begin);
|
||||||
|
uint nextBlock = 0;
|
||||||
|
|
||||||
|
BinaryReader reader = new BinaryReader(TokensFile);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
uint curOffset = reader.ReadUInt32();
|
||||||
|
nextBlock = reader.ReadUInt32();
|
||||||
|
|
||||||
|
for (int i = 0; i < ENTRIES_PER_BLOCK; i++)
|
||||||
|
{
|
||||||
|
curOffset = reader.ReadUInt32();
|
||||||
|
bool populated = reader.ReadUInt32() == 1;
|
||||||
|
uint contentOffset = reader.ReadUInt32();
|
||||||
|
uint contentLength = reader.ReadUInt32();
|
||||||
|
uint allocLength = reader.ReadUInt32();
|
||||||
|
byte[] contentData = new byte[] { };
|
||||||
|
|
||||||
|
if (populated)
|
||||||
|
{
|
||||||
|
reader.BaseStream.Seek(contentOffset + 0x20, SeekOrigin.Begin);
|
||||||
|
uint dataLength = reader.ReadUInt32();
|
||||||
|
|
||||||
|
if (dataLength != contentLength)
|
||||||
|
{
|
||||||
|
throw new FormatException("Data length in tokens content is inconsistent with entry.");
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.ReadBytes(0x20);
|
||||||
|
contentData = reader.ReadBytes((int)contentLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.BaseStream.Seek(curOffset + 0x14, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
Entries.Add(new TokenEntry
|
||||||
|
{
|
||||||
|
Name = reader.ReadNullTerminatedString(0x82),
|
||||||
|
Extension = reader.ReadNullTerminatedString(0x8),
|
||||||
|
Data = contentData,
|
||||||
|
Populated = populated
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.BaseStream.Seek(nextBlock, SeekOrigin.Begin);
|
||||||
|
} while (nextBlock != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Serialize()
|
||||||
|
{
|
||||||
|
MemoryStream tokens = new MemoryStream();
|
||||||
|
|
||||||
|
using (BinaryWriter writer = new BinaryWriter(tokens))
|
||||||
|
{
|
||||||
|
writer.Write(VERSION);
|
||||||
|
writer.Write(CONTS_HEADER);
|
||||||
|
|
||||||
|
int curBlockOffset = (int)writer.BaseStream.Position;
|
||||||
|
int curEntryOffset = curBlockOffset + 0x8;
|
||||||
|
int curContsOffset = curBlockOffset + BLOCK_SIZE;
|
||||||
|
|
||||||
|
for (int eIndex = 0; eIndex < ((Entries.Count / ENTRIES_PER_BLOCK) + 1) * ENTRIES_PER_BLOCK; eIndex++)
|
||||||
|
{
|
||||||
|
TokenEntry entry;
|
||||||
|
|
||||||
|
if (eIndex < Entries.Count)
|
||||||
|
{
|
||||||
|
entry = Entries[eIndex];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entry = new TokenEntry
|
||||||
|
{
|
||||||
|
Name = "",
|
||||||
|
Extension = "",
|
||||||
|
Populated = false,
|
||||||
|
Data = new byte[] { }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.BaseStream.Seek(curBlockOffset, SeekOrigin.Begin);
|
||||||
|
writer.Write(curBlockOffset);
|
||||||
|
writer.Write(0);
|
||||||
|
|
||||||
|
writer.BaseStream.Seek(curEntryOffset, SeekOrigin.Begin);
|
||||||
|
writer.Write(curEntryOffset);
|
||||||
|
writer.Write(entry.Populated ? 1 : 0);
|
||||||
|
writer.Write(entry.Populated ? curContsOffset : 0);
|
||||||
|
writer.Write(entry.Populated ? entry.Data.Length : -1);
|
||||||
|
writer.Write(entry.Populated ? entry.Data.Length : -1);
|
||||||
|
writer.WriteFixedString16(entry.Name, 0x82);
|
||||||
|
writer.WriteFixedString16(entry.Extension, 0x8);
|
||||||
|
curEntryOffset = (int)writer.BaseStream.Position;
|
||||||
|
|
||||||
|
if (entry.Populated)
|
||||||
|
{
|
||||||
|
writer.BaseStream.Seek(curContsOffset, SeekOrigin.Begin);
|
||||||
|
writer.Write(CONTS_HEADER);
|
||||||
|
writer.Write(entry.Data.Length);
|
||||||
|
writer.Write(CryptoUtils.SHA256Hash(entry.Data));
|
||||||
|
writer.Write(entry.Data);
|
||||||
|
writer.Write(CONTS_FOOTER);
|
||||||
|
curContsOffset = (int)writer.BaseStream.Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((eIndex + 1) % ENTRIES_PER_BLOCK == 0 && eIndex != 0)
|
||||||
|
{
|
||||||
|
if (eIndex < Entries.Count)
|
||||||
|
{
|
||||||
|
writer.BaseStream.Seek(curBlockOffset + 0x4, SeekOrigin.Begin);
|
||||||
|
writer.Write(curContsOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.BaseStream.Seek(curEntryOffset, SeekOrigin.Begin);
|
||||||
|
writer.WritePadding(BLOCK_PAD_SIZE);
|
||||||
|
|
||||||
|
writer.BaseStream.Seek(curBlockOffset, SeekOrigin.Begin);
|
||||||
|
byte[] blockHash;
|
||||||
|
byte[] blockData = new byte[BLOCK_SIZE - 0x20];
|
||||||
|
|
||||||
|
tokens.Read(blockData, 0, BLOCK_SIZE - 0x20);
|
||||||
|
blockHash = CryptoUtils.SHA256Hash(blockData);
|
||||||
|
|
||||||
|
writer.BaseStream.Seek(curBlockOffset + BLOCK_SIZE - 0x20, SeekOrigin.Begin);
|
||||||
|
writer.Write(blockHash);
|
||||||
|
|
||||||
|
curBlockOffset = curContsOffset;
|
||||||
|
curEntryOffset = curBlockOffset + 0x8;
|
||||||
|
curContsOffset = curBlockOffset + BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens.SetLength(curBlockOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] tokensData = tokens.ToArray();
|
||||||
|
byte[] tokensHash = CryptoUtils.SHA256Hash(tokensData.Take(0x4).Concat(tokensData.Skip(0x24)).ToArray());
|
||||||
|
|
||||||
|
tokens = new MemoryStream(tokensData);
|
||||||
|
|
||||||
|
BinaryWriter tokWriter = new BinaryWriter(TokensFile);
|
||||||
|
using (BinaryReader reader = new BinaryReader(tokens))
|
||||||
|
{
|
||||||
|
TokensFile.Seek(0, SeekOrigin.Begin);
|
||||||
|
TokensFile.SetLength(tokens.Length);
|
||||||
|
tokWriter.Write(reader.ReadBytes(0x4));
|
||||||
|
reader.ReadBytes(0x20);
|
||||||
|
tokWriter.Write(tokensHash);
|
||||||
|
tokWriter.Write(reader.ReadBytes((int)reader.BaseStream.Length - 0x4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddEntry(TokenEntry entry)
|
||||||
|
{
|
||||||
|
Entries.Add(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddEntries(TokenEntry[] entries)
|
||||||
|
{
|
||||||
|
Entries.AddRange(entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteEntry(string name, string ext)
|
||||||
|
{
|
||||||
|
foreach (TokenEntry entry in Entries)
|
||||||
|
{
|
||||||
|
if (entry.Name == name && entry.Extension == ext)
|
||||||
|
{
|
||||||
|
Entries.Remove(entry);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteUnpopEntry(string name, string ext)
|
||||||
|
{
|
||||||
|
List<TokenEntry> delEntries = new List<TokenEntry>();
|
||||||
|
foreach (TokenEntry entry in Entries)
|
||||||
|
{
|
||||||
|
if (entry.Name == name && entry.Extension == ext && !entry.Populated)
|
||||||
|
{
|
||||||
|
delEntries.Add(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Entries = Entries.Except(delEntries).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenEntry GetEntry(string name, string ext)
|
||||||
|
{
|
||||||
|
foreach (TokenEntry entry in Entries)
|
||||||
|
{
|
||||||
|
if (entry.Name == name && entry.Extension == ext)
|
||||||
|
{
|
||||||
|
if (!entry.Populated) continue;
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenMeta GetMetaEntry(string name)
|
||||||
|
{
|
||||||
|
DeleteUnpopEntry(name, "xml");
|
||||||
|
TokenEntry entry = GetEntry(name, "xml");
|
||||||
|
TokenMeta meta;
|
||||||
|
|
||||||
|
if (entry == null)
|
||||||
|
{
|
||||||
|
meta = new TokenMeta
|
||||||
|
{
|
||||||
|
Name = name
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
meta = new TokenMeta(entry.Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetEntry(string name, string ext, byte[] data)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Entries.Count; i++)
|
||||||
|
{
|
||||||
|
TokenEntry entry = Entries[i];
|
||||||
|
|
||||||
|
if (entry.Name == name && entry.Extension == ext && entry.Populated)
|
||||||
|
{
|
||||||
|
entry.Data = data;
|
||||||
|
Entries[i] = entry;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Entries.Add(new TokenEntry
|
||||||
|
{
|
||||||
|
Populated = true,
|
||||||
|
Name = name,
|
||||||
|
Extension = ext,
|
||||||
|
Data = data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPath()
|
||||||
|
{
|
||||||
|
return Path.Combine(Environment.ExpandEnvironmentVariables(Utils.GetTokenStorePath()), "tokens.dat");
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenStore()
|
||||||
|
{
|
||||||
|
string tokensPath = GetPath();
|
||||||
|
TokensFile = File.Open(tokensPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
|
||||||
|
Deserialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Serialize();
|
||||||
|
TokensFile.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
98
MetroUnlocker/LibTSForge/ZeroCID.cs
Normal file
98
MetroUnlocker/LibTSForge/ZeroCID.cs
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.IO;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
|
||||||
|
|
||||||
|
using MetroUnlocker.LibTSForge.SPP;
|
||||||
|
using MetroUnlocker.LibTSForge.PhysicalStore;
|
||||||
|
using MetroUnlocker.LibTSForge.Crypto;
|
||||||
|
|
||||||
|
namespace MetroUnlocker
|
||||||
|
{
|
||||||
|
|
||||||
|
class ZeroCID
|
||||||
|
{
|
||||||
|
public static void Deposit(Guid actId, string instId)
|
||||||
|
{
|
||||||
|
uint status = SLApi.DepositConfirmationId(actId, instId, Constants.ZeroCID);
|
||||||
|
|
||||||
|
if (status != 0)
|
||||||
|
throw new InvalidOperationException(string.Format("Failed to deposit fake CID. Status code: 0x{0}", status.ToString("X")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Activate(PSVersion version, bool production, Guid actId)
|
||||||
|
{
|
||||||
|
Guid appId = SLApi.GetAppId(actId);
|
||||||
|
|
||||||
|
string instId = SLApi.GetInstallationId(actId);
|
||||||
|
Guid pkeyId = SLApi.GetInstalledPkeyId(actId);
|
||||||
|
|
||||||
|
Utils.KillSPP();
|
||||||
|
|
||||||
|
using (PhysicalStore store = new PhysicalStore(version, production))
|
||||||
|
{
|
||||||
|
byte[] hwidBlock = Constants.UniversalHWIDBlock;
|
||||||
|
|
||||||
|
byte[] iidHash = CryptoUtils.SHA256Hash(Utils.EncodeString(instId + '\0' + Constants.ZeroCID));
|
||||||
|
|
||||||
|
|
||||||
|
string key = string.Format("SPPSVC\\{0}\\{1}", appId, actId);
|
||||||
|
ModernBlock keyBlock = store.GetBlock(key, pkeyId.ToString());
|
||||||
|
|
||||||
|
if (keyBlock == null)
|
||||||
|
{
|
||||||
|
throw new InvalidDataException("Failed to get product key data for activation ID: 0x" + actId + ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
VariableBag pkb = new VariableBag(keyBlock.Data);
|
||||||
|
|
||||||
|
byte[] pkeyData = pkb.GetBlock("SppPkeyPhoneActivationData").Value;
|
||||||
|
|
||||||
|
pkb.DeleteBlock("SppPkeyVirtual");
|
||||||
|
store.SetBlock(key, pkeyId.ToString(), pkb.Serialize());
|
||||||
|
|
||||||
|
BinaryWriter writer = new BinaryWriter(new MemoryStream());
|
||||||
|
writer.Write(0x20);
|
||||||
|
writer.Write(iidHash);
|
||||||
|
writer.Write(hwidBlock.Length);
|
||||||
|
writer.Write(hwidBlock);
|
||||||
|
byte[] tsHwidData = Utils.GetBytes(writer);
|
||||||
|
|
||||||
|
writer = new BinaryWriter(new MemoryStream());
|
||||||
|
writer.Write(0x20);
|
||||||
|
writer.Write(iidHash);
|
||||||
|
writer.Write(pkeyData.Length);
|
||||||
|
writer.Write(pkeyData);
|
||||||
|
byte[] tsPkeyInfoData = Utils.GetBytes(writer);
|
||||||
|
|
||||||
|
store.AddBlocks(new ModernBlock[] {
|
||||||
|
new ModernBlock
|
||||||
|
{
|
||||||
|
Type = BlockType.NAMED,
|
||||||
|
Flags = 0,
|
||||||
|
KeyAsStr = key,
|
||||||
|
ValueAsStr = "msft:Windows/7.0/Phone/Cached/HwidBlock/" + pkeyId,
|
||||||
|
Data = tsHwidData
|
||||||
|
},
|
||||||
|
new ModernBlock
|
||||||
|
{
|
||||||
|
Type = BlockType.NAMED,
|
||||||
|
Flags = 0,
|
||||||
|
KeyAsStr = key,
|
||||||
|
ValueAsStr = "msft:Windows/7.0/Phone/Cached/PKeyInfo/" + pkeyId,
|
||||||
|
Data = tsPkeyInfoData
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Deposit(actId, instId);
|
||||||
|
|
||||||
|
SLApi.RefreshLicenseStatus();
|
||||||
|
SLApi.FireStateChangedEvent(appId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
116
MetroUnlocker/MetroUnlocker.csproj
Normal file
116
MetroUnlocker/MetroUnlocker.csproj
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="12.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)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{D27EB145-0B58-43AD-BB94-BE000D236D38}</ProjectGuid>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>MetroUnlocker</RootNamespace>
|
||||||
|
<AssemblyName>MetroUnlocker</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup />
|
||||||
|
<PropertyGroup>
|
||||||
|
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Management" />
|
||||||
|
<Reference Include="System.ServiceProcess" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Deployment" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.Windows.Forms" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="App.cs">
|
||||||
|
<SubType>Form</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="App.Designer.cs">
|
||||||
|
<DependentUpon>App.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="LibTSForge\Common.cs" />
|
||||||
|
<Compile Include="LibTSForge\Crypto\CryptoUtils.cs" />
|
||||||
|
<Compile Include="LibTSForge\Crypto\Keys.cs" />
|
||||||
|
<Compile Include="LibTSForge\Crypto\PhysicalStoreCrypto.cs" />
|
||||||
|
<Compile Include="LibTSForge\Modifiers\GenPKeyInstall.cs" />
|
||||||
|
<Compile Include="LibTSForge\PhysicalStore\CRCBlock.cs" />
|
||||||
|
<Compile Include="LibTSForge\PhysicalStore\ModernBlock.cs" />
|
||||||
|
<Compile Include="LibTSForge\PhysicalStore\PhysicalStore.cs" />
|
||||||
|
<Compile Include="LibTSForge\PhysicalStore\VariableBag.cs" />
|
||||||
|
<Compile Include="LibTSForge\SPP\PKeyConfig.cs" />
|
||||||
|
<Compile Include="LibTSForge\SPP\ProductKey.cs" />
|
||||||
|
<Compile Include="LibTSForge\SPP\SLApi.cs" />
|
||||||
|
<Compile Include="LibTSForge\TokenStore\TokenEntry.cs" />
|
||||||
|
<Compile Include="LibTSForge\TokenStore\TokenStore.cs" />
|
||||||
|
<Compile Include="LibTSForge\ZeroCID.cs" />
|
||||||
|
<Compile Include="LOBManager.cs" />
|
||||||
|
<Compile Include="ProductPolicy\ProductPolicy.cs" />
|
||||||
|
<Compile Include="ProductPolicy\ProductPolicyEditor.cs" />
|
||||||
|
<Compile Include="ProductPolicy\Tools.cs" />
|
||||||
|
<Compile Include="Program.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="Rebooter.cs" />
|
||||||
|
<Compile Include="SPPManager.cs" />
|
||||||
|
<Compile Include="StartupArguments.cs" />
|
||||||
|
<EmbeddedResource Include="App.resx">
|
||||||
|
<DependentUpon>App.cs</DependentUpon>
|
||||||
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Include="Properties\Resources.resx">
|
||||||
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
|
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</EmbeddedResource>
|
||||||
|
<Compile Include="Properties\Resources.Designer.cs">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Resources.resx</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<None Include="app.manifest" />
|
||||||
|
<None Include="Properties\Settings.settings">
|
||||||
|
<Generator>SettingsSingleFileGenerator</Generator>
|
||||||
|
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||||
|
</None>
|
||||||
|
<Compile Include="Properties\Settings.Designer.cs">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Settings.settings</DependentUpon>
|
||||||
|
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup />
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.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>
|
||||||
153
MetroUnlocker/ProductPolicy/ProductPolicy.cs
Normal file
153
MetroUnlocker/ProductPolicy/ProductPolicy.cs
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
using Microsoft.Win32;
|
||||||
|
|
||||||
|
|
||||||
|
namespace MetroUnlocker.ProductPolicy
|
||||||
|
{
|
||||||
|
//public struct ProductPolicyData
|
||||||
|
//{
|
||||||
|
// public string String;
|
||||||
|
// public byte[] Bytes;
|
||||||
|
// public uint DWord;
|
||||||
|
//};
|
||||||
|
class ProductPolicy
|
||||||
|
{
|
||||||
|
public bool Modified { get; set; }
|
||||||
|
public ProductPolicyValue Header { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
//private ProductPolicyData _data;
|
||||||
|
|
||||||
|
//public ProductPolicyData Data
|
||||||
|
//{
|
||||||
|
// get { return _data; }
|
||||||
|
// set { _data = value; }
|
||||||
|
//}
|
||||||
|
|
||||||
|
public byte[] Bytes { get; set; }
|
||||||
|
public string StringValue
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Encoding.Unicode.GetString(Bytes);
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
Bytes = Encoding.Unicode.GetBytes(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public uint DWordValue
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BitConverter.ToUInt32(Bytes, 0);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Bytes = BitConverter.GetBytes(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegistryValueKind Type
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (RegistryValueKind)Header.DataType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NameFromBin(ref byte[] PolicyBlob, int offset)
|
||||||
|
{
|
||||||
|
Name = Encoding.Unicode.GetString(PolicyBlob, offset + Marshal.SizeOf(Header), Header.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ValFromBin(ref byte[] PolicyBlob, int offset)
|
||||||
|
{
|
||||||
|
int posdata = offset + Marshal.SizeOf(Header) + Header.Name;
|
||||||
|
Bytes = new byte[Header.Data];
|
||||||
|
Array.Copy(PolicyBlob, posdata, Bytes, 0, Header.Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FromBin(ref byte[] PolicyBlob, int offset)
|
||||||
|
{
|
||||||
|
Header = Tools.BytesToStruct<ProductPolicyValue>(PolicyBlob, typeof(ProductPolicyValue), offset);
|
||||||
|
if ((Header.Data + Header.Name + Marshal.SizeOf(Header)) > Header.Size ||
|
||||||
|
(offset + Header.Size) > PolicyBlob.Length)
|
||||||
|
{
|
||||||
|
throw new Exception("Invalid _data Header format");
|
||||||
|
}
|
||||||
|
NameFromBin(ref PolicyBlob, offset);
|
||||||
|
ValFromBin(ref PolicyBlob, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
switch (Type)
|
||||||
|
{
|
||||||
|
case RegistryValueKind.String:
|
||||||
|
return StringValue;
|
||||||
|
case RegistryValueKind.DWord:
|
||||||
|
return DWordValue.ToString();
|
||||||
|
default:
|
||||||
|
return Bytes != null ? BitConverter.ToString(Bytes) : "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Size()
|
||||||
|
{
|
||||||
|
//switch (Type)
|
||||||
|
//{
|
||||||
|
// case RegistryValueKind.String:
|
||||||
|
// return StringValue.Length * 2;
|
||||||
|
// case RegistryValueKind.DWord:
|
||||||
|
// return 4;
|
||||||
|
// default:
|
||||||
|
// return Bytes.Length;
|
||||||
|
//}
|
||||||
|
return Bytes.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
//public byte[] ToBinary()
|
||||||
|
//{
|
||||||
|
// switch (Type)
|
||||||
|
// {
|
||||||
|
// case RegistryValueKind.String:
|
||||||
|
// return Encoding.Unicode.GetBytes(_data.String);
|
||||||
|
// case RegistryValueKind.DWord:
|
||||||
|
// return Tools.StructToBytes(DWordVq);
|
||||||
|
// default:
|
||||||
|
// return Bytes;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
public byte[] ToBin()
|
||||||
|
{
|
||||||
|
ProductPolicyValue value = new ProductPolicyValue();
|
||||||
|
value.Name = (UInt16)(2 * Name.Length);
|
||||||
|
value.Data = (UInt16)Size();
|
||||||
|
int datablocksize = Marshal.SizeOf(Header) + value.Name + value.Data;
|
||||||
|
int suffixLength = 4 - (datablocksize % 4);
|
||||||
|
value.Size = (UInt16)(Marshal.SizeOf(Header) + value.Name + value.Data + suffixLength);
|
||||||
|
value.DataType = Header.DataType;
|
||||||
|
value.Unknown1 = Header.Unknown1;
|
||||||
|
value.Unknown2 = Header.Unknown2;
|
||||||
|
byte[] bytes = Tools.StructToBytes(value);
|
||||||
|
|
||||||
|
Tools.AppendBytes(ref bytes, Encoding.Unicode.GetBytes(Name));
|
||||||
|
Tools.AppendBytes(ref bytes, Bytes);
|
||||||
|
Tools.PaddingAppend(ref bytes, suffixLength);
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// I would like to not split the data into dword and string on parsing but on getting.
|
||||||
|
//public void SetDWordValue(uint value)
|
||||||
|
//{
|
||||||
|
// Data = new ProductPolicyData { DWord = value };
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
157
MetroUnlocker/ProductPolicy/ProductPolicyEditor.cs
Normal file
157
MetroUnlocker/ProductPolicy/ProductPolicyEditor.cs
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Microsoft.Win32;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace MetroUnlocker.ProductPolicy
|
||||||
|
{
|
||||||
|
public struct ProductPolicyHeader
|
||||||
|
{
|
||||||
|
public UInt32 Size, DataSize, EndMarker, Unknown1, Unknown2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct ProductPolicyValue
|
||||||
|
{
|
||||||
|
public UInt16 Size, Name, DataType, Data;
|
||||||
|
public UInt32 Unknown1, Unknown2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PolicyState : uint
|
||||||
|
{
|
||||||
|
Disabled = 0,
|
||||||
|
Enabled = 1,
|
||||||
|
Unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProductPolicyEditor
|
||||||
|
{
|
||||||
|
public List<ProductPolicy> PolicyValues { get; set; }
|
||||||
|
public ProductPolicyHeader Header;
|
||||||
|
private byte[] _policyBytes;
|
||||||
|
private byte[] _productPolicyBlobSuffix;
|
||||||
|
|
||||||
|
const string ProductOptionsKey = "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\ProductOptions";
|
||||||
|
|
||||||
|
public ProductPolicyEditor()
|
||||||
|
{
|
||||||
|
_policyBytes = GetPolicyBlob();
|
||||||
|
PolicyValues = FromBinary();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Save()
|
||||||
|
{
|
||||||
|
return SetPolicyBlob(ToBin());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] GetPolicyBlob()
|
||||||
|
{
|
||||||
|
return (byte[])Registry.GetValue(ProductOptionsKey, "ProductPolicy", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool SetPolicyBlob(byte[] bytes)
|
||||||
|
{
|
||||||
|
Registry.SetValue(ProductOptionsKey, "ProductPolicy", bytes);
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
return Tools.ArraysEqual(GetPolicyBlob(), bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ProductPolicy> FromBinary()
|
||||||
|
{
|
||||||
|
return FromBinary(_policyBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ProductPolicy> FromBinary(byte[] policyBlob)
|
||||||
|
{
|
||||||
|
var header = Tools.BytesToStruct<ProductPolicyHeader>(policyBlob, typeof(ProductPolicyHeader));
|
||||||
|
|
||||||
|
if (header.Size < policyBlob.Length || (header.DataSize + Marshal.SizeOf(header) + header.EndMarker) != header.Size)
|
||||||
|
throw new Exception("Invalid Header format");
|
||||||
|
|
||||||
|
int pos = Marshal.SizeOf(header);
|
||||||
|
int pos_end = pos + (int)header.DataSize;
|
||||||
|
|
||||||
|
PolicyValues = new List<ProductPolicy>();
|
||||||
|
|
||||||
|
while (pos < pos_end)
|
||||||
|
{
|
||||||
|
ProductPolicy pv = new ProductPolicy();
|
||||||
|
pv.FromBin(ref policyBlob, pos);
|
||||||
|
PolicyValues.Add(pv);
|
||||||
|
|
||||||
|
pos += pv.Header.Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos < header.Size)
|
||||||
|
{
|
||||||
|
_productPolicyBlobSuffix = new byte[policyBlob.Length - pos];
|
||||||
|
Array.Copy(policyBlob, pos, _productPolicyBlobSuffix, 0, _productPolicyBlobSuffix.Length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_productPolicyBlobSuffix = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PolicyValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] ToBin()
|
||||||
|
{
|
||||||
|
int headerSize = Marshal.SizeOf(Header);
|
||||||
|
byte[] policyBlob = new byte[headerSize];
|
||||||
|
|
||||||
|
foreach (ProductPolicy v in PolicyValues)
|
||||||
|
Tools.AppendBytes(ref policyBlob, v.ToBin());
|
||||||
|
|
||||||
|
Tools.AppendBytes(ref policyBlob, _productPolicyBlobSuffix);
|
||||||
|
|
||||||
|
Header.Size = (UInt32)policyBlob.Length;
|
||||||
|
Header.EndMarker = (UInt32)_productPolicyBlobSuffix.Length;
|
||||||
|
Header.DataSize = (UInt32)(Header.Size - Header.EndMarker - headerSize);
|
||||||
|
Array.Copy(Tools.StructToBytes(Header), 0, policyBlob, 0, headerSize);
|
||||||
|
|
||||||
|
return policyBlob;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProductPolicy GetPolicyWithName(string name)
|
||||||
|
{
|
||||||
|
return PolicyValues.Find(value => value.Name == name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PolicyState GetPolicyStateByName(string name)
|
||||||
|
{
|
||||||
|
ProductPolicy policy = GetPolicyWithName(name);
|
||||||
|
if (policy.Type == RegistryValueKind.DWord)
|
||||||
|
{
|
||||||
|
if (policy.DWordValue == 0)
|
||||||
|
return PolicyState.Disabled;
|
||||||
|
else if (policy.DWordValue == 1)
|
||||||
|
return PolicyState.Enabled;
|
||||||
|
}
|
||||||
|
return PolicyState.Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SetPolicyStateByName(string name, PolicyState state)
|
||||||
|
{
|
||||||
|
ProductPolicy policy = GetPolicyWithName(name);
|
||||||
|
|
||||||
|
if (policy.Type == RegistryValueKind.DWord)
|
||||||
|
{
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case PolicyState.Disabled:
|
||||||
|
policy.DWordValue = 0;
|
||||||
|
break;
|
||||||
|
case PolicyState.Enabled:
|
||||||
|
policy.DWordValue = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
82
MetroUnlocker/ProductPolicy/Tools.cs
Normal file
82
MetroUnlocker/ProductPolicy/Tools.cs
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace MetroUnlocker.ProductPolicy
|
||||||
|
{
|
||||||
|
class Tools
|
||||||
|
{
|
||||||
|
public static void AppendBytes(ref byte[] b1, byte[] b2)
|
||||||
|
{
|
||||||
|
int length = b1.Length;
|
||||||
|
Array.Resize(ref b1, length + b2.Length);
|
||||||
|
Array.Copy(b2, 0, b1, length, b2.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
static public T BytesToStruct<T>(byte[] bytes, Type type, int offset = 0)
|
||||||
|
{
|
||||||
|
int size = Marshal.SizeOf(type);
|
||||||
|
IntPtr buffer = Marshal.AllocHGlobal(size);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Marshal.Copy(bytes, offset, buffer, size);
|
||||||
|
return (T)Marshal.PtrToStructure(buffer, type);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static public byte[] StructToBytes(object structObject)
|
||||||
|
{
|
||||||
|
int size = Marshal.SizeOf(structObject);
|
||||||
|
IntPtr buffer = Marshal.AllocHGlobal(size);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Marshal.StructureToPtr(structObject, buffer, false);
|
||||||
|
byte[] bytes = new byte[size];
|
||||||
|
Marshal.Copy(buffer, bytes, 0, size);
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PaddingAppend(ref byte[] b1, int paddinglen)
|
||||||
|
{
|
||||||
|
if (paddinglen > 0)
|
||||||
|
{
|
||||||
|
int l = b1.Length;
|
||||||
|
Array.Resize(ref b1, b1.Length + paddinglen);
|
||||||
|
for (; l < b1.Length; l++)
|
||||||
|
b1[l] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static public bool ArraysEqual(Array a1, Array a2)
|
||||||
|
{
|
||||||
|
if (a1 == a2)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (a1 == null || a2 == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (a1.Length != a2.Length)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
System.Collections.IList list1 = a1, list2 = a2; //error CS0305: Using the generic type 'System.Collections.Generic.IList<T>' requires '1' type arguments
|
||||||
|
for (int i = 0; i < a1.Length; i++)
|
||||||
|
{
|
||||||
|
if (!Object.Equals(list1[i], list2[i])) //error CS0021: Cannot apply indexing with [] to an expression of type 'IList'(x2)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
24
MetroUnlocker/Program.cs
Normal file
24
MetroUnlocker/Program.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
using System.Security.Principal;
|
||||||
|
|
||||||
|
namespace MetroUnlocker
|
||||||
|
{
|
||||||
|
static class Program
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The main entry point for the application.
|
||||||
|
/// </summary>
|
||||||
|
[STAThread]
|
||||||
|
static void Main()
|
||||||
|
{
|
||||||
|
Application.EnableVisualStyles();
|
||||||
|
Application.SetCompatibleTextRenderingDefault(false);
|
||||||
|
Application.Run(new App());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
36
MetroUnlocker/Properties/AssemblyInfo.cs
Normal file
36
MetroUnlocker/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
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("MetroUnlocker")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("MetroUnlocker")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2025")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("b976c029-d312-41a8-9d67-63cb061f7847")]
|
||||||
|
|
||||||
|
// 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")]
|
||||||
71
MetroUnlocker/Properties/Resources.Designer.cs
generated
Normal file
71
MetroUnlocker/Properties/Resources.Designer.cs
generated
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace MetroUnlocker.Properties
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||||
|
/// </summary>
|
||||||
|
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||||
|
// class via a tool like ResGen or Visual Studio.
|
||||||
|
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
|
// with the /str option, or rebuild your VS project.
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
internal class Resources
|
||||||
|
{
|
||||||
|
|
||||||
|
private static global::System.Resources.ResourceManager resourceMan;
|
||||||
|
|
||||||
|
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||||
|
|
||||||
|
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
internal Resources()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the cached ResourceManager instance used by this class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Resources.ResourceManager ResourceManager
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if ((resourceMan == null))
|
||||||
|
{
|
||||||
|
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MetroUnlocker.Properties.Resources", typeof(Resources).Assembly);
|
||||||
|
resourceMan = temp;
|
||||||
|
}
|
||||||
|
return resourceMan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overrides the current thread's CurrentUICulture property for all
|
||||||
|
/// resource lookups using this strongly typed resource class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Globalization.CultureInfo Culture
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return resourceCulture;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
resourceCulture = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
117
MetroUnlocker/Properties/Resources.resx
Normal file
117
MetroUnlocker/Properties/Resources.resx
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
</root>
|
||||||
30
MetroUnlocker/Properties/Settings.Designer.cs
generated
Normal file
30
MetroUnlocker/Properties/Settings.Designer.cs
generated
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace MetroUnlocker.Properties
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
|
||||||
|
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
|
||||||
|
{
|
||||||
|
|
||||||
|
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||||
|
|
||||||
|
public static Settings Default
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return defaultInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
MetroUnlocker/Properties/Settings.settings
Normal file
7
MetroUnlocker/Properties/Settings.settings
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
|
||||||
|
<Profiles>
|
||||||
|
<Profile Name="(Default)" />
|
||||||
|
</Profiles>
|
||||||
|
<Settings />
|
||||||
|
</SettingsFile>
|
||||||
33
MetroUnlocker/Rebooter.cs
Normal file
33
MetroUnlocker/Rebooter.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
//using System.Runtime.InteropServices;
|
||||||
|
using System.Management;
|
||||||
|
|
||||||
|
namespace MetroUnlocker
|
||||||
|
{
|
||||||
|
public class Rebooter
|
||||||
|
{
|
||||||
|
public enum RebootMethod
|
||||||
|
{
|
||||||
|
LogOff = 0,
|
||||||
|
PowerOff = 8,
|
||||||
|
Reboot = 2,
|
||||||
|
ShutDown = 1,
|
||||||
|
Suspend = -1,
|
||||||
|
Hibernate = -2
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Reboot(RebootMethod method = RebootMethod.Reboot)
|
||||||
|
{
|
||||||
|
ManagementClass management = new ManagementClass("Win32_OperatingSystem");
|
||||||
|
management.Scope.Options.EnablePrivileges = true;
|
||||||
|
ManagementBaseObject mboShutdownParams = management.GetMethodParameters("Win32Shutdown");
|
||||||
|
mboShutdownParams["Flags"] = method;
|
||||||
|
mboShutdownParams["Reserved"] = 0;
|
||||||
|
management.GetInstances().OfType<ManagementObject>().First().InvokeMethod("Win32Shutdown", mboShutdownParams, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
100
MetroUnlocker/SPPManager.cs
Normal file
100
MetroUnlocker/SPPManager.cs
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Management;
|
||||||
|
|
||||||
|
namespace MetroUnlocker
|
||||||
|
{
|
||||||
|
enum SPPStartupMode
|
||||||
|
{
|
||||||
|
Disabled,
|
||||||
|
Enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
class SPPManager
|
||||||
|
{
|
||||||
|
private static string LogFullName = "C:\\Temp\\W8Sideloader.log";
|
||||||
|
|
||||||
|
private static string RunCommand(string command, string arguments)
|
||||||
|
{
|
||||||
|
string output;
|
||||||
|
RunCommand(command, arguments, out output);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RunCommand(string command, string arguments, out string output)
|
||||||
|
{
|
||||||
|
Process process = Process.Start(new ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = command,
|
||||||
|
Arguments = arguments,
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardError = true,
|
||||||
|
UseShellExecute = false,
|
||||||
|
CreateNoWindow = true
|
||||||
|
});
|
||||||
|
|
||||||
|
output = process.StandardOutput.ReadToEnd();
|
||||||
|
string error = process.StandardError.ReadToEnd();
|
||||||
|
if (!string.IsNullOrWhiteSpace(error)) throw new Exception(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string SetStartupMode(SPPStartupMode startupMode)
|
||||||
|
{
|
||||||
|
string output;
|
||||||
|
bool enabled = startupMode == SPPStartupMode.Enabled;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
RunCommand("sc", "sdset sppsvc D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWRPLOCRRC;;;IU)(A;;CCLCSWRPLOCRRC;;;SU)(A;;LCRP;;;AU)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)", out output);
|
||||||
|
//RunCommand("sc", "config sppsvc start=" + (enabled ? "enabled" : "disabled"), out output);
|
||||||
|
using (var m = new ManagementObject("Win32_Service.Name=\"sppsvc\""))
|
||||||
|
m.InvokeMethod("ChangeStartMode", new object[] { enabled ? "Automatic" : "Disabledx" });
|
||||||
|
|
||||||
|
RunCommand("net", "stop sppsvc", out output);
|
||||||
|
|
||||||
|
if (!enabled)
|
||||||
|
{
|
||||||
|
DisableScheduledTask("SvcRestartTask");
|
||||||
|
DisableScheduledTask("SvcRestartTaskLogon");
|
||||||
|
DisableScheduledTask("SvcRestartTaskNetwork");
|
||||||
|
}
|
||||||
|
|
||||||
|
//MessageBox.Show(output + "\n----------------------\n", "sppsvc config change");
|
||||||
|
}
|
||||||
|
catch { throw; }
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DisableScheduledTask(string key)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
RunCommand("schtasks", "/change /disable /tn \"\\Microsoft\\Windows\\SoftwareProtectionPlatform\\" + key + "\"");
|
||||||
|
}
|
||||||
|
catch { throw; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Disable()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return SetStartupMode(SPPStartupMode.Disabled);
|
||||||
|
}
|
||||||
|
catch { throw; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Enable()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return SetStartupMode(SPPStartupMode.Enabled);
|
||||||
|
}
|
||||||
|
catch { throw; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
49
MetroUnlocker/StartupArguments.cs
Normal file
49
MetroUnlocker/StartupArguments.cs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MetroUnlocker
|
||||||
|
{
|
||||||
|
public enum StartupArgument
|
||||||
|
{
|
||||||
|
EnableLOBAndEnableSPP,
|
||||||
|
EnableLOBAndDisableSPP,
|
||||||
|
DisableLOBAndEnableSPP,
|
||||||
|
DisableLOBAndDisableSPP,
|
||||||
|
Other
|
||||||
|
}
|
||||||
|
|
||||||
|
public class StartupArguments
|
||||||
|
{
|
||||||
|
|
||||||
|
public static Dictionary<StartupArgument, string> KnownArguments = new Dictionary<StartupArgument, string>()
|
||||||
|
{
|
||||||
|
{StartupArgument.EnableLOBAndEnableSPP, "hi"},
|
||||||
|
{StartupArgument.EnableLOBAndDisableSPP, "mister"},
|
||||||
|
{StartupArgument.DisableLOBAndEnableSPP, "fox"},
|
||||||
|
{StartupArgument.DisableLOBAndDisableSPP, ":3"},
|
||||||
|
};
|
||||||
|
|
||||||
|
public static StartupArgument GetStartupArgument(string[] args)
|
||||||
|
{
|
||||||
|
return KnownArguments.ContainsValue(args[1]) ? KnownArguments.First(arg => arg.Value == args[1]).Key : StartupArgument.Other;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetStartupArgumentString(StartupArgument startupArgument)
|
||||||
|
{
|
||||||
|
return KnownArguments[startupArgument];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool HasStartupArgument(string[] args)
|
||||||
|
{
|
||||||
|
return args.Length > 1 && !HasOtherArgument(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool HasOtherArgument(string[] args)
|
||||||
|
{
|
||||||
|
return GetStartupArgument(args) == StartupArgument.Other;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
58
MetroUnlocker/app.manifest
Normal file
58
MetroUnlocker/app.manifest
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
|
||||||
|
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||||
|
<security>
|
||||||
|
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<!-- UAC Manifest Options
|
||||||
|
If you want to change the Windows User Account Control level replace the
|
||||||
|
requestedExecutionLevel node with one of the following.
|
||||||
|
|
||||||
|
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||||
|
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||||
|
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
|
||||||
|
|
||||||
|
Specifying requestedExecutionLevel node will disable file and registry virtualization.
|
||||||
|
If you want to utilize File and Registry Virtualization for backward
|
||||||
|
compatibility then delete the requestedExecutionLevel node.
|
||||||
|
-->
|
||||||
|
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
|
||||||
|
</requestedPrivileges>
|
||||||
|
</security>
|
||||||
|
</trustInfo>
|
||||||
|
|
||||||
|
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||||
|
<application>
|
||||||
|
<!-- A list of all Windows versions that this application is designed to work with.
|
||||||
|
Windows will automatically select the most compatible environment.-->
|
||||||
|
|
||||||
|
<!-- If your application is designed to work with Windows Vista, uncomment the following supportedOS node-->
|
||||||
|
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"></supportedOS>-->
|
||||||
|
|
||||||
|
<!-- If your application is designed to work with Windows 7, uncomment the following supportedOS node-->
|
||||||
|
<!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>-->
|
||||||
|
|
||||||
|
<!-- If your application is designed to work with Windows 8, uncomment the following supportedOS node-->
|
||||||
|
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"></supportedOS>
|
||||||
|
|
||||||
|
<!-- If your application is designed to work with Windows 8.1, uncomment the following supportedOS node-->
|
||||||
|
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
|
||||||
|
|
||||||
|
</application>
|
||||||
|
</compatibility>
|
||||||
|
|
||||||
|
<!-- Enable themes for Windows common controls and dialogs (Windows XP and later) -->
|
||||||
|
<!-- <dependency>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity
|
||||||
|
type="win32"
|
||||||
|
name="Microsoft.Windows.Common-Controls"
|
||||||
|
version="6.0.0.0"
|
||||||
|
processorArchitecture="*"
|
||||||
|
publicKeyToken="6595b64144ccf1df"
|
||||||
|
language="*"
|
||||||
|
/>
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>-->
|
||||||
|
|
||||||
|
</asmv1:assembly>
|
||||||
Reference in New Issue
Block a user