Initial commit

This commit is contained in:
Lasse Lauwerys
2025-02-20 16:33:04 +01:00
commit f20cf222a8
36 changed files with 4758 additions and 0 deletions

63
.gitattributes vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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="&gt;&gt;temporaryButton.Name" xml:space="preserve">
<value>temporaryButton</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;temporaryButton.Parent" xml:space="preserve">
<value>groupBox2</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;button2.Name" xml:space="preserve">
<value>button2</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;button2.Parent" xml:space="preserve">
<value>tabPage1</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;button1.Name" xml:space="preserve">
<value>button1</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;button1.Parent" xml:space="preserve">
<value>tabPage1</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;tabPage1.Name" xml:space="preserve">
<value>tabPage1</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;tabPage1.Parent" xml:space="preserve">
<value>Manual</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;LOBCheckBox.Name" xml:space="preserve">
<value>LOBCheckBox</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;LOBCheckBox.Parent" xml:space="preserve">
<value>groupBox2</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;SPPCheckBox.Name" xml:space="preserve">
<value>SPPCheckBox</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;SPPCheckBox.Parent" xml:space="preserve">
<value>groupBox2</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;groupBox2.Name" xml:space="preserve">
<value>groupBox2</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;groupBox2.Parent" xml:space="preserve">
<value>tabPage2</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;signedCheckbox.Name" xml:space="preserve">
<value>signedCheckbox</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;signedCheckbox.Parent" xml:space="preserve">
<value>groupBox1</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;allUsersCheckbox.Name" xml:space="preserve">
<value>allUsersCheckbox</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;allUsersCheckbox.Parent" xml:space="preserve">
<value>groupBox1</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;groupBox1.Name" xml:space="preserve">
<value>groupBox1</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;groupBox1.Parent" xml:space="preserve">
<value>tabPage2</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;tabPage2.Name" xml:space="preserve">
<value>tabPage2</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;tabPage2.Parent" xml:space="preserve">
<value>Manual</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;Manual.Name" xml:space="preserve">
<value>Manual</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;Manual.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;statusLabel.Name" xml:space="preserve">
<value>statusLabel</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;statusLabel.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;statusTextLabel.Name" xml:space="preserve">
<value>statusTextLabel</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;statusTextLabel.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;$this.Name" xml:space="preserve">
<value>App</value>
</data>
<data name="&gt;&gt;$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="&gt;&gt;developmentCheckbox.Name" xml:space="preserve">
<value>developmentCheckbox</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;developmentCheckbox.Parent" xml:space="preserve">
<value>groupBox1</value>
</data>
<data name="&gt;&gt;developmentCheckbox.ZOrder" xml:space="preserve">
<value>2</value>
</data>
</root>

107
MetroUnlocker/LOBManager.cs Normal file
View 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);
}
}
}

View 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()
{
}
}
}

View 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);
}
}
}
}

View 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
};
}
}

View 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();
}
}
}

View 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;
}
}
}

View 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());
}
}
}

View 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,
};
}
}
}

View 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();
}
}
}
}

View 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;
}
}
}
}

View 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()
{
}
}
}

View 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;
}
}
}

View 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);
}
}
}

View 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;
}
}

View 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();
}
}
}

View 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);
}
}
}

View 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>

View 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 };
//}
}
}

View 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;
}
}
}

View 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
View 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());
}
}
}

View 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")]

View 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;
}
}
}
}

View 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>

View 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;
}
}
}
}

View 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
View 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
View 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; }
}
}
}

View 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;
}
}
}

View 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>