10 Commits

Author SHA1 Message Date
Lasse Lauwerys
590588c3bc Update README.md 2025-05-23 23:57:31 +02:00
Lasse Lauwerys
fbb27f8ed0 Update README.md 2025-05-23 23:56:58 +02:00
Lasse Lauwerys
b286f8aa41 Update README.md 2025-05-23 23:55:01 +02:00
Lasse Lauwerys
845e783cfd Update README.md 2025-05-23 23:54:46 +02:00
Lasse Lauwerys
d0d1683b0d Update README.md 2025-05-23 23:38:46 +02:00
Lasse Lauwerys
f527acdf97 Update README.md 2025-05-23 23:36:54 +02:00
Mona Lassa
5ae6b4da9a Refactor and cleanup 2025-05-22 02:52:38 +02:00
Mona Lassa
f90695dfda First release build. 2025-05-22 01:31:03 +02:00
Lasse Lauwerys
ec55169d57 Credit where credit's due 2025-02-20 16:43:32 +01:00
Lasse Lauwerys
aa0c40def3 Update readme 2025-02-20 16:41:59 +01:00
33 changed files with 725 additions and 1726 deletions

BIN
MetroUnlocker.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -5,6 +5,11 @@ 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
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C9C14067-F9A1-4D85-A1D2-162E91B71CC3}"
ProjectSection(SolutionItems) = preProject
DependencyGraph.dgml = DependencyGraph.dgml
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU

View File

@@ -29,35 +29,17 @@
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.groupBox = new System.Windows.Forms.GroupBox();
this.disableButton = new System.Windows.Forms.Button();
this.unlockButton = new System.Windows.Forms.Button();
this.groupBox.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");
@@ -89,79 +71,36 @@
resources.ApplyResources(this.statusLabel, "statusLabel");
this.statusLabel.Name = "statusLabel";
//
// LOBCheckBox
// groupBox
//
resources.ApplyResources(this.LOBCheckBox, "LOBCheckBox");
this.LOBCheckBox.Name = "LOBCheckBox";
this.LOBCheckBox.UseVisualStyleBackColor = true;
resources.ApplyResources(this.groupBox, "groupBox");
this.groupBox.Controls.Add(this.signedCheckbox);
this.groupBox.Controls.Add(this.allUsersCheckbox);
this.groupBox.Controls.Add(this.developmentCheckbox);
this.groupBox.Name = "groupBox";
this.groupBox.TabStop = false;
//
// SPPCheckBox
// disableButton
//
resources.ApplyResources(this.SPPCheckBox, "SPPCheckBox");
this.SPPCheckBox.Name = "SPPCheckBox";
this.SPPCheckBox.UseVisualStyleBackColor = true;
resources.ApplyResources(this.disableButton, "disableButton");
this.disableButton.Name = "disableButton";
this.disableButton.UseVisualStyleBackColor = true;
this.disableButton.Click += new System.EventHandler(this.Uninstall);
//
// groupBox1
// unlockButton
//
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);
resources.ApplyResources(this.unlockButton, "unlockButton");
this.unlockButton.Name = "unlockButton";
this.unlockButton.UseVisualStyleBackColor = true;
this.unlockButton.Click += new System.EventHandler(this.Jailbreak);
//
// App
//
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.Manual);
this.Controls.Add(this.disableButton);
this.Controls.Add(this.groupBox);
this.Controls.Add(this.unlockButton);
this.Controls.Add(this.statusLabel);
this.Controls.Add(this.statusTextLabel);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
@@ -171,13 +110,8 @@
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.groupBox.ResumeLayout(false);
this.groupBox.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
@@ -185,21 +119,14 @@
#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;
private System.Windows.Forms.GroupBox groupBox;
private System.Windows.Forms.Button unlockButton;
private System.Windows.Forms.Button disableButton;
}
}

View File

@@ -6,6 +6,7 @@ using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
using Microsoft.Win32;
@@ -16,38 +17,38 @@ namespace MetroUnlocker
{
public partial class App : Form
{
public const string AppxKey = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Policies\\Microsoft\\Windows\\Appx";
public const string AppxRegistryKey = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Policies\\Microsoft\\Windows\\Appx";
string trustedAppsPolicyName = "AllowAllTrustedApps";
string developmentPolicyName = "AllowDevelopmentWithoutDevLicense";
string specialProfilesPolicyName = "AllowDeploymentInSpecialProfiles";
string TrustedAppsPolicyName = "AllowAllTrustedApps";
string DevelopmentPolicyName = "AllowDevelopmentWithoutDevLicense";
string SpecialProfilesPolicyName = "AllowDeploymentInSpecialProfiles";
public bool LOBEnabled
{
get { return GetGroupPolicy(trustedAppsPolicyName); }
set { SetGroupPolicy(trustedAppsPolicyName, value); }
get { return GetGroupPolicy(TrustedAppsPolicyName); }
set { SetGroupPolicy(TrustedAppsPolicyName, value); }
}
public bool DevelopmentEnabled
{
get { return GetGroupPolicy(developmentPolicyName); }
set { SetGroupPolicy(developmentPolicyName, value); }
get { return GetGroupPolicy(DevelopmentPolicyName); }
set { SetGroupPolicy(DevelopmentPolicyName, value); }
}
public bool SpecialProfilesEnabled
{
get { return GetGroupPolicy(specialProfilesPolicyName); }
set { SetGroupPolicy(specialProfilesPolicyName, value); }
get { return GetGroupPolicy(SpecialProfilesPolicyName); }
set { SetGroupPolicy(SpecialProfilesPolicyName, value); }
}
public void SetGroupPolicy(string policyName, bool enabled)
{
Registry.SetValue(AppxKey, policyName, enabled ? 1 : 0, RegistryValueKind.DWord);
Registry.SetValue(AppxRegistryKey, policyName, enabled ? 1 : 0, RegistryValueKind.DWord);
}
public bool GetGroupPolicy(string policyName)
{
object value = Registry.GetValue(AppxKey, policyName, 0);
object value = Registry.GetValue(AppxRegistryKey, policyName, 0);
return value is int ? (int)value == 1 : false;
}
@@ -60,82 +61,36 @@ namespace MetroUnlocker
public void UpdatePolicyState()
{
var productPolicyEditor = new ProductPolicyEditor();
var productPolicyEditor = new ProductPolicyReader();
var policyState = productPolicyEditor.GetPolicyStateByName("WSLicensingService-LOBSideloadingActivated");
var isSideloadingKeyInstalled = LOBManager.IsSideloadingKeyInstalled();
statusLabel.ForeColor = isSideloadingKeyInstalled ? Color.DarkGreen: Color.DarkOrange;
disableButton.Enabled = 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;
}
statusLabel.Text = "Enabling...";
else
{
statusLabel.Text = "Sideloading will be disabled soon";
statusLabel.ForeColor = Color.DarkOrange;
statusLabel.Text = "Disabled";
statusLabel.ForeColor = Color.DarkRed;
}
break;
case PolicyState.Unknown:
case PolicyState.Enabled:
statusLabel.Text = isSideloadingKeyInstalled ? "Sideloading enabled" : "Disabling...";
break;
default:
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)
private void Jailbreak(object sender, EventArgs e)
{
try
{
@@ -145,12 +100,19 @@ namespace MetroUnlocker
return;
LOBManager.ActivateZeroCID();
LOBEnabled = true;
DevelopmentEnabled = true;
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);
if (ex is COMException && ((uint)((COMException)ex).ErrorCode) == 0xC004F014)
MessageBox.Show(this, "You likely ran out of storage or something else caused your tokens.dat to get corrupted. SPPSVC will recreate it. Try rebooting to let Windows reactivate itself before trying again. Make sure you have at least 30MB free before using Sideloading Unlocker.", "The key was recognised but I can't activate it.", MessageBoxButtons.OK, MessageBoxIcon.Error);
else MessageBox.Show(this, ex.Message, "Error while activating sideloading!", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}

View File

@@ -117,221 +117,59 @@
<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>
<assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<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>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<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>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<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>
<value>252, 200</value>
</data>
<data name="Manual.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Bottom, Left, Right</value>
<data name="disableButton.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Bottom, Left, Right</value>
</data>
<data name="button2.Location" type="System.Drawing.Point, System.Drawing">
<value>7, 123</value>
<data name="disableButton.Location" type="System.Drawing.Point, System.Drawing">
<value>12, 165</value>
</data>
<data name="button2.Size" type="System.Drawing.Size, System.Drawing">
<value>221, 23</value>
<data name="disableButton.Size" type="System.Drawing.Size, System.Drawing">
<value>228, 23</value>
</data>
<data name="button2.TabIndex" type="System.Int32, mscorlib">
<data name="disableButton.TabIndex" type="System.Int32, mscorlib">
<value>1</value>
</data>
<data name="button2.Text" xml:space="preserve">
<data name="disableButton.Text" xml:space="preserve">
<value>Disable Sideloading</value>
</data>
<data name="&gt;&gt;button2.Name" xml:space="preserve">
<value>button2</value>
<data name="&gt;&gt;disableButton.Name" xml:space="preserve">
<value>disableButton</value>
</data>
<data name="&gt;&gt;button2.Type" xml:space="preserve">
<data name="&gt;&gt;disableButton.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 name="&gt;&gt;disableButton.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;button2.ZOrder" xml:space="preserve">
<data name="&gt;&gt;disableButton.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 name="groupBox.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Bottom, Left, Right</value>
</data>
<data name="signedCheckbox.AccessibleDescription" xml:space="preserve">
<value>Enables sideloading of signed apps.</value>
@@ -358,7 +196,7 @@
<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>
<value>groupBox</value>
</data>
<data name="&gt;&gt;signedCheckbox.ZOrder" xml:space="preserve">
<value>0</value>
@@ -373,7 +211,7 @@
<value>True</value>
</data>
<data name="allUsersCheckbox.Location" type="System.Drawing.Point, System.Drawing">
<value>149, 19</value>
<value>155, 19</value>
</data>
<data name="allUsersCheckbox.Size" type="System.Drawing.Size, System.Drawing">
<value>67, 17</value>
@@ -391,88 +229,67 @@
<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>
<value>groupBox</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 name="groupBox.Location" type="System.Drawing.Point, System.Drawing">
<value>12, 96</value>
</data>
<data name="groupBox1.Size" type="System.Drawing.Size, System.Drawing">
<value>222, 63</value>
<data name="groupBox.Size" type="System.Drawing.Size, System.Drawing">
<value>228, 63</value>
</data>
<data name="groupBox1.TabIndex" type="System.Int32, mscorlib">
<data name="groupBox.TabIndex" type="System.Int32, mscorlib">
<value>7</value>
</data>
<data name="groupBox1.Text" xml:space="preserve">
<data name="groupBox.Text" xml:space="preserve">
<value>Group Policy</value>
</data>
<data name="&gt;&gt;groupBox1.Name" xml:space="preserve">
<value>groupBox1</value>
<data name="&gt;&gt;groupBox.Name" xml:space="preserve">
<value>groupBox</value>
</data>
<data name="&gt;&gt;groupBox1.Type" xml:space="preserve">
<data name="&gt;&gt;groupBox.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">
<data name="&gt;&gt;groupBox.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;Manual.ZOrder" xml:space="preserve">
<data name="&gt;&gt;groupBox.ZOrder" xml:space="preserve">
<value>1</value>
</data>
<data name="unlockButton.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Bottom, Left, Right</value>
</data>
<data name="unlockButton.Location" type="System.Drawing.Point, System.Drawing">
<value>12, 25</value>
</data>
<data name="unlockButton.Size" type="System.Drawing.Size, System.Drawing">
<value>228, 65</value>
</data>
<data name="unlockButton.TabIndex" type="System.Int32, mscorlib">
<value>0</value>
</data>
<data name="unlockButton.Text" xml:space="preserve">
<value>Unlock!</value>
</data>
<data name="&gt;&gt;unlockButton.Name" xml:space="preserve">
<value>unlockButton</value>
</data>
<data name="&gt;&gt;unlockButton.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;unlockButton.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;unlockButton.ZOrder" xml:space="preserve">
<value>2</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>
<value>44, 9</value>
</data>
<data name="statusLabel.Size" type="System.Drawing.Size, System.Drawing">
<value>196, 13</value>
@@ -496,7 +313,7 @@
<value>$this</value>
</data>
<data name="&gt;&gt;statusLabel.ZOrder" xml:space="preserve">
<value>1</value>
<value>3</value>
</data>
<data name="statusTextLabel.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
@@ -523,7 +340,7 @@
<value>$this</value>
</data>
<data name="&gt;&gt;statusTextLabel.ZOrder" xml:space="preserve">
<value>2</value>
<value>4</value>
</data>
<data name="$this.StartPosition" type="System.Windows.Forms.FormStartPosition, System.Windows.Forms">
<value>CenterScreen</value>
@@ -556,7 +373,7 @@
<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>
<value>groupBox</value>
</data>
<data name="&gt;&gt;developmentCheckbox.ZOrder" xml:space="preserve">
<value>2</value>

View File

@@ -14,7 +14,7 @@ using MetroUnlocker.LibTSForge.SPP;
// Common.cs
namespace MetroUnlocker
{
public enum PSVersion
public enum PhysicalStoreVersion
{
Win8Early,
Win8,
@@ -33,7 +33,7 @@ namespace MetroUnlocker
public static class Constants
{
public static readonly string ZeroCID = new string('0', 48);
public static readonly byte[] UniversalHWIDBlock =
public static readonly byte[] UniversalHardwareIdBlock =
{
0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -45,9 +45,6 @@ namespace MetroUnlocker
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();
@@ -146,8 +143,6 @@ namespace MetroUnlocker
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++)
@@ -174,19 +169,14 @@ namespace MetroUnlocker
if (!stopped)
throw new System.TimeoutException("Failed to stop sppsvc");
//Logger.WriteLine("sppsvc stopped successfully.");
}
public static PSVersion DetectVersion()
public static PhysicalStoreVersion 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;
if (build >= 9600) return PhysicalStoreVersion.WinModern;
if (build == 9200) return PhysicalStoreVersion.Win8;
throw new NotSupportedException("This version of Windows is not supported. (build " + build + ")");
}
@@ -196,15 +186,9 @@ namespace MetroUnlocker
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.");
}
@@ -230,6 +214,10 @@ namespace MetroUnlocker
public string Name;
public Dictionary<string, string> Data = new Dictionary<string, string>();
public TokenMeta() { }
public TokenMeta(string name) { Name = name; }
public TokenMeta(byte[] data) { Deserialize(data); }
public byte[] Serialize()
{
BinaryWriter writer = new BinaryWriter(new MemoryStream());
@@ -267,15 +255,5 @@ namespace MetroUnlocker
Data[key] = value;
}
}
public TokenMeta(byte[] data)
{
Deserialize(data);
}
public TokenMeta()
{
}
}
}

View File

@@ -5,12 +5,11 @@ using System.Text;
using System.Threading.Tasks;
using System.IO;
using MetroUnlocker.ProductPolicy;
using MetroUnlocker;
using MetroUnlocker.LibTSForge.PhysicalStore;
using MetroUnlocker.LibTSForge.SPP;
using MetroUnlocker.LibTSForge.Modifiers;
using MetroUnlocker.LibTSForge.TokenStore;
using MetroUnlocker.LibTSForge.SPP;
using MetroUnlocker.LibTSForge.PhysicalStore;
namespace MetroUnlocker
{
@@ -22,19 +21,25 @@ namespace MetroUnlocker
public static void ActivateZeroCID()
{
PSVersion version = Utils.DetectVersion();
PhysicalStoreVersion version = Utils.DetectVersion();
bool production = Utils.DetectCurrentKey();
if (Backup) BackupPhysicalStore();
GenPKeyInstall.InstallGenPKey(version, production, ActivationId);
ProductKeyInstaller.InstallGeneratedProductKey(version, production, ActivationId);
ZeroCID.Activate(version, production, ActivationId);
}
public static Guid GetInstalledSideloadingKeyId()
{
return SLApi.GetInstalledPkeyId(ActivationId);
return SLApi.GetInstalledProductKeyId(ActivationId);
}
public static bool IsSideloadingKeyInstalled()
{
Guid sideloadingKeyId;
return IsSideloadingKeyInstalled(out sideloadingKeyId);
}
public static bool IsSideloadingKeyInstalled(out Guid sideloadingKeyId)
@@ -80,28 +85,5 @@ namespace MetroUnlocker
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

@@ -6,13 +6,13 @@ namespace MetroUnlocker.LibTSForge.Crypto
{
public static class CryptoUtils
{
public static byte[] GenerateRandomKey(int len)
public static byte[] GenerateRandomKey(int length)
{
byte[] rand = new byte[len];
Random r = new Random();
r.NextBytes(rand);
byte[] randomKey = new byte[length];
Random random = new Random();
random.NextBytes(randomKey);
return rand;
return randomKey;
}
public static byte[] AESEncrypt(byte[] data, byte[] key)
@@ -72,9 +72,7 @@ namespace MetroUnlocker.LibTSForge.Crypto
byte[] hash;
using (SHA1 sha1 = SHA1.Create())
{
hash = sha1.ComputeHash(data);
}
return formatter.CreateSignature(hash);
}
@@ -90,9 +88,7 @@ namespace MetroUnlocker.LibTSForge.Crypto
byte[] hash;
using (SHA1 sha1 = SHA1.Create())
{
hash = sha1.ComputeHash(data);
}
return deformatter.VerifySignature(hash, signature);
}
@@ -113,9 +109,7 @@ namespace MetroUnlocker.LibTSForge.Crypto
public static byte[] SHA256Hash(byte[] data)
{
using (SHA256 sha256 = SHA256.Create())
{
return sha256.ComputeHash(data);
}
}
}
}

View File

@@ -2,7 +2,7 @@ namespace MetroUnlocker.LibTSForge.Crypto
{
public static class Keys
{
public static readonly byte[] PRODUCTION = {
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,
@@ -43,7 +43,7 @@ namespace MetroUnlocker.LibTSForge.Crypto
0x81, 0x44, 0x38, 0xBF
};
public static readonly byte[] TEST = {
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,

View File

@@ -12,7 +12,7 @@ namespace MetroUnlocker.LibTSForge.Crypto
{
public static byte[] DecryptPhysicalStore(byte[] data, bool production)
{
byte[] rsaKey = production ? Keys.PRODUCTION : Keys.TEST;
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);
@@ -33,33 +33,33 @@ namespace MetroUnlocker.LibTSForge.Crypto
return psData;
}
public static byte[] EncryptPhysicalStore(byte[] data, bool production, PSVersion version)
public static byte[] EncryptPhysicalStore(byte[] data, bool production, PhysicalStoreVersion version)
{
Dictionary<PSVersion, int> versionTable = new Dictionary<PSVersion, int>
Dictionary<PhysicalStoreVersion, int> versionTable = new Dictionary<PhysicalStoreVersion, int>
{
{PSVersion.Win8, 1},
{PSVersion.WinBlue, 2},
{PSVersion.WinModern, 3}
{PhysicalStoreVersion.Win8, 1},
{PhysicalStoreVersion.WinBlue, 2},
{PhysicalStoreVersion.WinModern, 3}
};
byte[] rsaKey = production ? Keys.PRODUCTION : Keys.TEST;
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[] encryptedAesKey = CryptoUtils.RSAEncrypt(rsaKey, aesKey);
byte[] aesKeySignature = CryptoUtils.RSASign(rsaKey, encryptedAesKey);
byte[] hmacSignature = CryptoUtils.HMACSign(hmacKey, data);
byte[] decData = new byte[] { };
decData = decData.Concat(hmacKey).Concat(hmacSig).Concat(BitConverter.GetBytes(0)).Concat(data).ToArray();
decData = decData.Concat(hmacKey).Concat(hmacSignature).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(aesKeySignature);
bw.Write(encryptedAesKey);
bw.Write(encData);
return bw.GetBytes();

View File

@@ -1,44 +0,0 @@
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,36 @@
using System;
using MetroUnlocker.LibTSForge.SPP;
namespace MetroUnlocker.LibTSForge.Modifiers
{
public static class ProductKeyInstaller
{
public static void InstallGeneratedProductKey(PhysicalStoreVersion version, bool production, Guid actId)
{
ProductKeyConfig keyConfig = new ProductKeyConfig();
keyConfig.LoadConfig(actId);
ProductConfig config;
keyConfig.Products.TryGetValue(actId, out config);
if (config == null) throw new ArgumentException("Activation ID " + actId + " not found in ProductKeyConfig.");
ProductKey pkey = config.GetRandomKey();
Guid instPkeyId = SLApi.GetInstalledProductKeyId(actId);
if (instPkeyId != Guid.Empty) SLApi.UninstallProductKey(instPkeyId);
if (pkey.Algorithm != ProductKeyAlgorithm.ProductKey2009)
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,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MetroUnlocker.LibTSForge.PhysicalStore
{
public class BasicBlock
{
public byte[] Key;
public string KeyAsString
{
get { return Utils.DecodeString(Key); }
set { Key = Utils.EncodeString(value); }
}
public byte[] Value;
public string ValueAsString
{
get { return Utils.DecodeString(Value); }
set { Value = Utils.EncodeString(value); }
}
public uint ValueAsInteger
{
get { return BitConverter.ToUInt32(Value, 0); }
set { Value = BitConverter.GetBytes(value); }
}
}
}

View File

@@ -1,55 +1,42 @@
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
UInt = 1 << 0,
String = 1 << 1,
Binary = 1 << 2
}
public class CRCBlock
public class CRCBlock : BasicBlock
{
public CRCBlockType DataType;
public byte[] Key;
public string KeyAsStr
public CRCBlock() { }
public CRCBlock(BinaryReader reader)
{
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);
}
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);
DataType = (CRCBlockType)type;
Key = key;
Value = value;
if (CRC() != crc)
throw new InvalidDataException("Invalid CRC in variable bag.");
}
public void Encode(BinaryWriter writer)
@@ -67,45 +54,16 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore
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());
BinaryWriter writer = new BinaryWriter(new MemoryStream());
writer.Write(0);
writer.Write((uint)DataType);
writer.Write(Key.Length);
writer.Write(Value.Length);
writer.Write(Key);
writer.Write(Value);
return Utils.CRC32(((MemoryStream)writer.BaseStream).ToArray());
}
}
}

View File

@@ -6,68 +6,41 @@ using System.IO;
namespace MetroUnlocker.LibTSForge.PhysicalStore
{
public class ModernBlock
public class ModernBlock : BasicBlock
{
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
public string DataAsString
{
get
{
return Utils.DecodeString(Data);
}
set
{
Data = Utils.EncodeString(value);
}
get { return Utils.DecodeString(Data); }
set { Data = Utils.EncodeString(value); }
}
public uint DataAsInt
{
get
{
return BitConverter.ToUInt32(Data, 0);
}
set
{
Data = BitConverter.GetBytes(value);
}
get { return BitConverter.ToUInt32(Data, 0); }
set { Data = BitConverter.GetBytes(value); }
}
public ModernBlock() { }
public ModernBlock(string key, string value, byte[] data, BlockType type = BlockType.NAMED, uint flags = 0)
{
Type = type;
Flags = flags;
KeyAsString = key;
ValueAsString = value;
Data = data;
}
public ModernBlock(ModernBlock block)
{
Type = block.Type;
Flags = block.Flags;
Unknown = block.Unknown;
Value = block.Value;
Data = block.Data;
}
public void Encode(BinaryWriter writer)
@@ -81,7 +54,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore
writer.Write(Data);
}
public static ModernBlock Decode(BinaryReader reader)
public ModernBlock(BinaryReader reader)
{
uint type = reader.ReadUInt32();
uint flags = reader.ReadUInt32();
@@ -93,14 +66,11 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore
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,
};
Type = (BlockType)type;
Flags = flags;
Unknown = unk3;
Value = value;
Data = data;
}
}
}

View File

@@ -16,7 +16,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore
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 PhysicalStoreVersion Version;
private readonly bool Production;
public byte[] Serialize()
@@ -66,7 +66,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore
for (int j = 0; j < numValues; j++)
{
Data[keyName].Add(ModernBlock.Decode(reader));
Data[keyName].Add(new ModernBlock(reader));
reader.Align(4);
}
}
@@ -75,12 +75,10 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore
public void AddBlock(ModernBlock block)
{
if (!Data.ContainsKey(block.KeyAsStr))
{
Data[block.KeyAsStr] = new List<ModernBlock>();
}
if (!Data.ContainsKey(block.KeyAsString))
Data[block.KeyAsString] = new List<ModernBlock>();
Data[block.KeyAsStr].Add(new ModernBlock
Data[block.KeyAsString].Add(new ModernBlock
{
Type = block.Type,
Flags = block.Flags,
@@ -92,92 +90,33 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore
public void AddBlocks(IEnumerable<ModernBlock> blocks)
{
foreach (ModernBlock block in blocks)
{
AddBlock(block);
}
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;
if (!Data.ContainsKey(key)) return null;
return Data[key].Find(block => block.ValueAsString == value);
}
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;
if (!Data.ContainsKey(key)) return null;
return Data[key].Find(block => block.ValueAsInteger == value);
}
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;
if (!Data.ContainsKey(key)) return;
int index = Data[key].FindIndex(block => block.ValueAsString == value);
Data[key][index].Data = data;
}
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;
if (!Data.ContainsKey(key)) return;
int index = Data[key].FindIndex(block => block.ValueAsInteger == value);
Data[key][index].Data = data;
}
public void SetBlock(string key, string value, string data)
@@ -202,40 +141,12 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore
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;
}
Data[key].Remove(GetBlock(key, value));
}
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;
}
Data[key].Remove(GetBlock(key, value));
}
public static string GetPath()
@@ -245,7 +156,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore
return Path.Combine(Environment.ExpandEnvironmentVariables(sppRoot), "data.dat");
}
public PhysicalStore(PSVersion version, bool production)
public PhysicalStore(PhysicalStoreVersion version, bool production)
{
Version = version;
Production = production;

View File

@@ -10,10 +10,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore
public List<CRCBlock> Blocks = new List<CRCBlock>();
public VariableBag() { }
public VariableBag(byte[] data)
{
Deserialize(data);
}
public VariableBag(byte[] data) { Deserialize(data); }
public void Deserialize(byte[] data)
{
@@ -22,9 +19,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore
BinaryReader reader = new BinaryReader(new MemoryStream(data));
while (reader.BaseStream.Position < len - 0x10)
{
Blocks.Add(CRCBlock.Decode(reader));
}
Blocks.Add(new CRCBlock(reader));
}
public byte[] Serialize()
@@ -39,40 +34,19 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore
public CRCBlock GetBlock(string key)
{
foreach (CRCBlock block in Blocks)
{
if (block.KeyAsStr == key)
{
return block;
}
}
return null;
return Blocks.Find(block => block.KeyAsString == key);
}
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;
}
}
int index = Blocks.FindIndex(block => block.KeyAsString == key);
if (index != -1) Blocks[index].Value = value;
}
public void DeleteBlock(string key)
{
foreach (CRCBlock block in Blocks)
if (block.KeyAsStr == key)
{
Blocks.Remove(block);
return;
}
CRCBlock block = GetBlock(key);
if (block != null) Blocks.Remove(block);
}
}
}

View File

@@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace MetroUnlocker.LibTSForge.SPP
{
public enum SLIDType
{
Application,
ProductSku,
LicenseFile,
License,
ProductKey,
AllLicenses,
AllLicenseFiles,
StoreToken,
Last
}
public enum SLDataType
{
None,
String,
DWord,
Binary,
MultiString,
Sum
}
[StructLayout(LayoutKind.Sequential)]
public struct SLLicensingStatus
{
public Guid SkuId;
public uint Status;
public uint GraceTimeDWord;
public uint TotalGraceDaysDWord;
public uint ReasonHResult;
public ulong ValidityExpiration;
}
public class NativeMethods
{
[DllImport("kernel32.dll")]
internal static extern uint GetSystemDefaultLCID();
[DllImport("sppc.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
internal static extern void SLOpen(out IntPtr hSLC);
[DllImport("sppc.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
internal static extern void SLClose(IntPtr hSLC);
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
internal static extern uint SLInstallProofOfPurchase(IntPtr hSLC, string pwszPKeyAlgorithm, string pwszPKeyString, uint cbPKeySpecificData, byte[] pbPKeySpecificData, ref Guid PKeyId);
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
internal static extern uint SLUninstallProofOfPurchase(IntPtr hSLC, ref Guid PKeyId);
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
internal static extern uint SLGenerateOfflineInstallationId(IntPtr hSLC, ref Guid pProductSkuId, ref string ppwszInstallationId);
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
internal static extern uint SLDepositOfflineConfirmationId(IntPtr hSLC, ref Guid pProductSkuId, string pwszInstallationId, string pwszConfirmationId);
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
internal 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)]
internal static extern uint SLGetInstalledProductKeyIds(IntPtr hSLC, ref Guid pProductSkuId, out uint pnProductKeyIds, out IntPtr ppProductKeyIds);
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
internal static extern uint SLConsumeWindowsRight(uint unknown);
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
internal 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)]
internal 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)]
internal static extern uint SLGetLicense(IntPtr hSLC, ref Guid pLicenseFileId, out uint pcbLicenseFile, out IntPtr ppbLicenseFile);
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
internal static extern uint SLSetCurrentProductKey(IntPtr hSLC, ref Guid pProductSkuId, ref Guid pProductKeyId);
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
internal static extern uint SLFireEvent(IntPtr hSLC, string pwszEventId, ref Guid pApplicationId);
}
}

View File

@@ -22,7 +22,7 @@ namespace MetroUnlocker.LibTSForge.SPP
public int Serial;
public ulong Security;
public bool Upgrade;
public PKeyAlgorithm Algorithm;
public ProductKeyAlgorithm Algorithm;
public string EulaType;
public string PartNumber;
public string Edition;
@@ -37,7 +37,7 @@ namespace MetroUnlocker.LibTSForge.SPP
get { return BitConverter.GetBytes(klow).Concat(BitConverter.GetBytes(khigh)).ToArray(); }
}
public ProductKey(int serial, ulong security, bool upgrade, PKeyAlgorithm algorithm, ProductConfig config, KeyRange range)
public ProductKey(int serial, ulong security, bool upgrade, ProductKeyAlgorithm algorithm, ProductConfig config, KeyRange range)
{
Group = config.GroupId;
Serial = serial;
@@ -60,7 +60,7 @@ namespace MetroUnlocker.LibTSForge.SPP
public string GetAlgoUri()
{
return "msft:rm/algorithm/pkey/" + (Algorithm == PKeyAlgorithm.PKEY2005 ? "2005" : (Algorithm == PKeyAlgorithm.PKEY2009 ? "2009" : "Unknown"));
return "msft:rm/algorithm/pkey/" + (Algorithm == ProductKeyAlgorithm.ProductKey2005 ? "2005" : (Algorithm == ProductKeyAlgorithm.ProductKey2009 ? "2009" : "Unknown"));
}
public Guid GetPkeyId()
@@ -70,21 +70,21 @@ namespace MetroUnlocker.LibTSForge.SPP
{
new CRCBlock
{
DataType = CRCBlockType.STRING,
KeyAsStr = "SppPkeyBindingProductKey",
ValueAsStr = ToString()
DataType = CRCBlockType.String,
KeyAsString = "SppPkeyBindingProductKey",
ValueAsString = ToString()
},
new CRCBlock
{
DataType = CRCBlockType.BINARY,
KeyAsStr = "SppPkeyBindingMiscData",
DataType = CRCBlockType.Binary,
KeyAsString = "SppPkeyBindingMiscData",
Value = new byte[] { }
},
new CRCBlock
{
DataType = CRCBlockType.STRING,
KeyAsStr = "SppPkeyBindingAlgorithm",
ValueAsStr = GetAlgoUri()
DataType = CRCBlockType.String,
KeyAsString = "SppPkeyBindingAlgorithm",
ValueAsString = GetAlgoUri()
}
});
@@ -137,7 +137,7 @@ namespace MetroUnlocker.LibTSForge.SPP
pid2 = "";
if (Algorithm == PKeyAlgorithm.PKEY2005)
if (Algorithm == ProductKeyAlgorithm.ProductKey2005)
{
string mpc = GetMPC();
string serialHigh;
@@ -211,7 +211,7 @@ namespace MetroUnlocker.LibTSForge.SPP
int serialHigh = Serial / 1000000;
int serialLow = Serial % 1000000;
int licenseType;
uint lcid = Utils.GetSystemDefaultLCID();
uint lcid = NativeMethods.GetSystemDefaultLCID();
int build = Environment.OSVersion.Version.Build;
int dayOfYear = DateTime.Now.DayOfYear;
int year = DateTime.Now.Year;
@@ -245,7 +245,7 @@ namespace MetroUnlocker.LibTSForge.SPP
);
}
public byte[] GetPhoneData(PSVersion version)
public byte[] GetPhoneData(PhysicalStoreVersion version)
{
int serialHigh = Serial / 1000000;
int serialLow = Serial % 1000000;
@@ -266,7 +266,7 @@ namespace MetroUnlocker.LibTSForge.SPP
string keyStr = "";
Random rnd = new Random(Group * 1000000000 + Serial);
if (Algorithm == PKeyAlgorithm.PKEY2005)
if (Algorithm == ProductKeyAlgorithm.ProductKey2005)
{
keyStr = "H4X3DH4X3DH4X3DH4X3D";
@@ -275,7 +275,7 @@ namespace MetroUnlocker.LibTSForge.SPP
keyStr += ALPHABET[rnd.Next(24)];
}
}
else if (Algorithm == PKeyAlgorithm.PKEY2009)
else if (Algorithm == ProductKeyAlgorithm.ProductKey2009)
{
int last = 0;
byte[] bKey = KeyBytes;

View File

@@ -9,10 +9,10 @@ using System.Xml;
namespace MetroUnlocker.LibTSForge.SPP
{
public enum PKeyAlgorithm
public enum ProductKeyAlgorithm
{
PKEY2005,
PKEY2009
ProductKey2005,
ProductKey2009
}
public class KeyRange
@@ -23,10 +23,7 @@ namespace MetroUnlocker.LibTSForge.SPP
public string PartNumber;
public bool Valid;
public bool Contains(int n)
{
return Start <= n && End <= n;
}
public bool Contains(int n) { return Start <= n && End <= n; }
}
public class ProductConfig
@@ -36,70 +33,67 @@ namespace MetroUnlocker.LibTSForge.SPP
public string Description;
public string Channel;
public bool Randomized;
public PKeyAlgorithm Algorithm;
public ProductKeyAlgorithm Algorithm;
public List<KeyRange> Ranges;
public Guid ActivationId;
private List<KeyRange> GetPkeyRanges()
private List<KeyRange> GetProductKeyRanges()
{
if (Ranges.Count == 0)
{
throw new ArgumentException("No key ranges.");
}
if (Algorithm == PKeyAlgorithm.PKEY2005)
{
if (Algorithm == ProductKeyAlgorithm.ProductKey2005)
return Ranges;
}
List<KeyRange> FilteredRanges = Ranges.Where(r => !r.EulaType.Contains("WAU")).ToList();
List<KeyRange> FilteredRanges = Ranges.FindAll(r => !r.EulaType.Contains("WAU"));
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();
List<KeyRange> KeyRanges = GetProductKeyRanges();
Random random = new Random();
KeyRange range = KeyRanges[rnd.Next(KeyRanges.Count)];
int serial = rnd.Next(range.Start, range.End);
KeyRange range = KeyRanges[random.Next(KeyRanges.Count)];
int serial = random.Next(range.Start, range.End);
return new ProductKey(serial, 0, false, Algorithm, this, range);
}
}
public class PKeyConfig
public class ProductKeyConfig
{
public Dictionary<Guid, ProductConfig> Products = new Dictionary<Guid, ProductConfig>();
private List<Guid> loadedPkeyConfigs = new List<Guid>();
private List<Guid> _loadedProductKeyConfigs = new List<Guid>();
public void LoadConfig(Guid actId)
{
string pkcData;
Guid pkcFileId = SLApi.GetPkeyConfigFileId(actId);
Guid configFileId = SLApi.GetProductKeyConfigFileId(actId);
if (loadedPkeyConfigs.Contains(pkcFileId)) return;
if (configFileId == Guid.Empty) throw new Exception("This edition of Windows does not support sideloading keys.");
string licConts = SLApi.GetLicenseContents(pkcFileId);
if (_loadedProductKeyConfigs.Contains(configFileId)) return;
using (TextReader tr = new StringReader(licConts))
string licenseContents = SLApi.GetLicenseContents(configFileId);
using (TextReader tr = new StringReader(licenseContents))
{
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("random", "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);
XmlNode pkcDataNode = root.SelectSingleNode("/rg:licenseGroup/random:license/random:otherInfo/tm:infoTables/tm:infoList/tm:infoBin[@name=\"pkeyConfigData\"]", nsmgr);
pkcData = Encoding.UTF8.GetString(Convert.FromBase64String(pkcDataNode.InnerText));
}
@@ -114,13 +108,13 @@ namespace MetroUnlocker.LibTSForge.SPP
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<int, ProductKeyAlgorithm> algorithms = new Dictionary<int, ProductKeyAlgorithm>();
Dictionary<string, List<KeyRange>> ranges = new Dictionary<string, List<KeyRange>>();
Dictionary<string, PKeyAlgorithm> algoConv = new Dictionary<string, PKeyAlgorithm>
Dictionary<string, ProductKeyAlgorithm> algoConv = new Dictionary<string, ProductKeyAlgorithm>
{
{ "msft:rm/algorithm/pkey/2005", PKeyAlgorithm.PKEY2005 },
{ "msft:rm/algorithm/pkey/2009", PKeyAlgorithm.PKEY2009 }
{ "msft:rm/algorithm/pkey/2005", ProductKeyAlgorithm.ProductKey2005 },
{ "msft:rm/algorithm/pkey/2009", ProductKeyAlgorithm.ProductKey2009 }
};
foreach (XmlNode pubKeyNode in pubKeyNodes)
@@ -131,12 +125,10 @@ namespace MetroUnlocker.LibTSForge.SPP
foreach (XmlNode rangeNode in rangeNodes)
{
string refActIdStr = rangeNode.SelectSingleNode("./p:RefActConfigId", nsmgr).InnerText;
string refActIdString = rangeNode.SelectSingleNode("./p:RefActConfigId", nsmgr).InnerText;
if (!ranges.ContainsKey(refActIdStr))
{
ranges[refActIdStr] = new List<KeyRange>();
}
if (!ranges.ContainsKey(refActIdString))
ranges[refActIdString] = new List<KeyRange>();
KeyRange keyRange = new KeyRange();
keyRange.Start = int.Parse(rangeNode.SelectSingleNode("./p:Start", nsmgr).InnerText);
@@ -145,15 +137,15 @@ namespace MetroUnlocker.LibTSForge.SPP
keyRange.PartNumber = rangeNode.SelectSingleNode("./p:PartNumber", nsmgr).InnerText;
keyRange.Valid = rangeNode.SelectSingleNode("./p:IsValid", nsmgr).InnerText.ToLower() == "true";
ranges[refActIdStr].Add(keyRange);
ranges[refActIdString].Add(keyRange);
}
foreach (XmlNode configNode in configNodes)
{
string refActIdStr = configNode.SelectSingleNode("./p:ActConfigId", nsmgr).InnerText;
Guid refActId = new Guid(refActIdStr);
string refActIdString = configNode.SelectSingleNode("./p:ActConfigId", nsmgr).InnerText;
Guid refActId = new Guid(refActIdString);
int group = int.Parse(configNode.SelectSingleNode("./p:RefGroupId", nsmgr).InnerText);
List<KeyRange> keyRanges = ranges[refActIdStr];
List<KeyRange> keyRanges = ranges[refActIdString];
if (keyRanges.Count > 0 && !Products.ContainsKey(refActId))
{
@@ -172,31 +164,14 @@ namespace MetroUnlocker.LibTSForge.SPP
}
}
loadedPkeyConfigs.Add(pkcFileId);
_loadedProductKeyConfigs.Add(configFileId);
}
public ProductConfig MatchParams(int group, int serial)
public ProductConfig MatchParams(int groupId, 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()
{
ProductConfig matchingConfig = Products.Values.FirstOrDefault(config => config.GroupId == groupId && config.Ranges.Any(range => range.Contains(serial)));
if (matchingConfig == null) throw new FileNotFoundException("Failed to find product matching supplied product key parameters.");
return matchingConfig;
}
}
}

View File

@@ -3,158 +3,56 @@ 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 SLContext() { NativeMethods.SLOpen(out Handle); }
public void Dispose()
{
SLClose(Handle);
NativeMethods.SLClose(Handle);
GC.SuppressFinalize(this);
}
~SLContext()
{
Dispose();
}
~SLContext() { Dispose(); }
}
public static Guid GetPkeyConfigFileId(Guid actId)
public static Guid GetProductKeyConfigFileId(Guid activationId)
{
using (SLContext sl = new SLContext())
{
SLDATATYPE type;
uint len;
IntPtr ppReturnLics;
SLDataType type;
uint length;
IntPtr fileIdPointer;
uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "pkeyConfigLicenseId", out type, out len, out ppReturnLics);
uint status = NativeMethods.SLGetProductSkuInformation(sl.Handle, ref activationId, "pkeyConfigLicenseId", out type, out length, out fileIdPointer);
if (status != 0 || len == 0)
{
if (status != 0 || length == 0)
return Guid.Empty;
}
Guid pkcId = new Guid(Marshal.PtrToStringAuto(ppReturnLics));
return GetLicenseFileId(pkcId);
Guid configLicenseId = new Guid(Marshal.PtrToStringAuto(fileIdPointer));
return GetLicenseFileId(configLicenseId);
}
}
public static Guid GetLicenseFileId(Guid licId)
public static Guid GetLicenseFileId(Guid licenseId)
{
using (SLContext sl = new SLContext())
{
uint status;
uint count;
IntPtr ppReturnLics;
IntPtr returnLicenses;
status = SLGetSLIDList(sl.Handle, SLIDTYPE.SL_ID_LICENSE, ref licId, SLIDTYPE.SL_ID_LICENSE_FILE, out count, out ppReturnLics);
status = NativeMethods.SLGetSLIDList(sl.Handle, SLIDType.License, ref licenseId, SLIDType.LicenseFile, out count, out returnLicenses);
return (status == 0 && count != 0) ? (Guid)Marshal.PtrToStructure(ppReturnLics, typeof(Guid)) : Guid.Empty;//new Guid(Marshal.PtrToStringAuto(ppReturnLics));
return (status == 0 && count != 0) ? (Guid)Marshal.PtrToStructure(returnLicenses, typeof(Guid)) : Guid.Empty;
}
}
@@ -164,38 +62,34 @@ namespace MetroUnlocker.LibTSForge.SPP
using (SLContext sl = new SLContext())
{
uint dataLen;
IntPtr dataPtr;
uint length;
IntPtr dataPointer;
if (SLGetLicense(sl.Handle, ref fileId, out dataLen, out dataPtr) != 0)
{
if (NativeMethods.SLGetLicense(sl.Handle, ref fileId, out length, out dataPointer) != 0)
return null;
}
byte[] data = new byte[dataLen];
Marshal.Copy(dataPtr, data, 0, (int)dataLen);
byte[] data = new byte[length];
Marshal.Copy(dataPointer, data, 0, (int)length);
data = data.Skip(Array.IndexOf(data, (byte)'<')).ToArray();
return Encoding.UTF8.GetString(data);
}
}
public static string GetMetaStr(Guid actId, string value)
public static string GetMetaStr(Guid productSkuId, string value)
{
using (SLContext sl = new SLContext())
{
uint len;
SLDATATYPE type;
IntPtr ppbValue;
uint length;
SLDataType type;
IntPtr binaryValue;
uint status = SLGetProductSkuInformation(sl.Handle, ref actId, value, out type, out len, out ppbValue);
uint status = NativeMethods.SLGetProductSkuInformation(sl.Handle, ref productSkuId, value, out type, out length, out binaryValue);
if (status != 0 || len == 0 || type != SLDATATYPE.SL_DATA_SZ)
{
if (status != 0 || length == 0 || type != SLDataType.String)
return null;
}
return Marshal.PtrToStringAuto(ppbValue);
return Marshal.PtrToStringAuto(binaryValue);
}
}
@@ -204,7 +98,7 @@ namespace MetroUnlocker.LibTSForge.SPP
using (SLContext sl = new SLContext())
{
string installationId = null;
var status = SLGenerateOfflineInstallationId(sl.Handle, ref actId, ref installationId);
var status = NativeMethods.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")));
@@ -213,41 +107,40 @@ namespace MetroUnlocker.LibTSForge.SPP
}
}
public static Guid GetInstalledPkeyId(Guid actId)
public static Guid GetInstalledProductKeyId(Guid actId)
{
using (SLContext sl = new SLContext())
{
uint status;
uint count;
IntPtr pProductKeyIds;
IntPtr productKeyIds;
status = SLGetInstalledProductKeyIds(sl.Handle, ref actId, out count, out pProductKeyIds);
status = NativeMethods.SLGetInstalledProductKeyIds(sl.Handle, ref actId, out count, out productKeyIds);
//unsafe { return *(Guid*)pProductKeyIds; }
return (status == 0 && count != 0) ? (Guid)Marshal.PtrToStructure(pProductKeyIds, typeof(Guid)) : Guid.Empty;
return (status == 0 && count != 0) ? (Guid)Marshal.PtrToStructure(productKeyIds, 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);
return NativeMethods.SLDepositOfflineConfirmationId(sl.Handle, ref actId, installationId, confirmationId);
}
public static void RefreshLicenseStatus()
{
SLConsumeWindowsRight(0);
NativeMethods.SLConsumeWindowsRight(0);
}
public static bool RefreshTrustedTime(Guid actId)
{
using (SLContext sl = new SLContext())
{
SLDATATYPE type;
SLDataType type;
uint count;
IntPtr ppbValue;
uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "TrustedTime", out type, out count, out ppbValue);
uint status = NativeMethods.SLGetProductSkuInformation(sl.Handle, ref actId, "TrustedTime", out type, out count, out ppbValue);
return (int)status >= 0 && status != 0xC004F012;
}
}
@@ -255,24 +148,22 @@ namespace MetroUnlocker.LibTSForge.SPP
public static void FireStateChangedEvent(Guid appId)
{
using (SLContext sl = new SLContext())
{
SLFireEvent(sl.Handle, "msft:rm/event/licensingstatechanged", ref appId);
}
NativeMethods.SLFireEvent(sl.Handle, "msft:rm/event/licensingstatechanged", ref appId);
}
public static Guid GetAppId(Guid actId)
public static Guid GetAppId(Guid activationId)
{
using (SLContext sl = new SLContext())
{
uint count;
IntPtr pAppIds;
IntPtr appIdPointer;
uint status = SLGetSLIDList(sl.Handle, SLIDTYPE.SL_ID_PRODUCT_SKU, ref actId, SLIDTYPE.SL_ID_APPLICATION, out count, out pAppIds);
uint status = NativeMethods.SLGetSLIDList(sl.Handle, SLIDType.ProductSku, ref activationId, SLIDType.Application, out count, out appIdPointer);
if (status != 0 || count == 0)
return Guid.Empty;
return (Guid)Marshal.PtrToStructure(pAppIds, typeof(Guid));
return (Guid)Marshal.PtrToStructure(appIdPointer, typeof(Guid));
}
}
@@ -281,10 +172,10 @@ namespace MetroUnlocker.LibTSForge.SPP
using (SLContext sl = new SLContext())
{
uint count;
SLDATATYPE type;
SLDataType type;
IntPtr ppbValue;
uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "DependsOn", out type, out count, out ppbValue);
uint status = NativeMethods.SLGetProductSkuInformation(sl.Handle, ref actId, "DependsOn", out type, out count, out ppbValue);
return (int)status >= 0 && status != 0xC004F012;
}
}
@@ -293,15 +184,15 @@ namespace MetroUnlocker.LibTSForge.SPP
{
using (SLContext sl = new SLContext())
{
Guid pkeyId = Guid.Empty;
return SLInstallProofOfPurchase(sl.Handle, pkey.GetAlgoUri(), pkey.ToString(), 0, null, ref pkeyId);
Guid productKeyId = Guid.Empty;
return NativeMethods.SLInstallProofOfPurchase(sl.Handle, pkey.GetAlgoUri(), pkey.ToString(), 0, null, ref productKeyId);
}
}
public static uint UninstallProductKey(Guid pkeyId)
public static uint UninstallProductKey(Guid productKeyId)
{
using (SLContext sl = new SLContext())
return SLUninstallProofOfPurchase(sl.Handle, ref pkeyId);
return NativeMethods.SLUninstallProofOfPurchase(sl.Handle, ref productKeyId);
}
}
}

View File

@@ -7,9 +7,18 @@ namespace MetroUnlocker.LibTSForge.TokenStore
{
public class TokenEntry
{
public string Name;
public string Extension;
public byte[] Data;
public bool Populated;
public string Name { get; set; }
public string Extension { get; set; }
public byte[] Data { get; set; }
public bool Populated { get; set; }
public TokenEntry() : this("", "", new byte[] { }, false) {}
public TokenEntry(string name, string extension, byte[] data, bool populated = true)
{
Name = name;
Extension = extension;
Data = data;
Populated = populated;
}
}
}

View File

@@ -10,21 +10,21 @@ 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 uint Version = 3;
private static readonly int EntrySize = 0x9E;
private static readonly int BlockSize = 0x4020;
private static readonly int EntriesPerBlock = BlockSize / EntrySize;
private static readonly int BlockPadSize = 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 static readonly byte[] Header = Enumerable.Repeat((byte)0x55, 0x20).ToArray();
private static readonly byte[] Footer = Enumerable.Repeat((byte)0xAA, 0x20).ToArray();
private List<TokenEntry> Entries = new List<TokenEntry>();
public FileStream TokensFile;
public FileStream TokensFile { get; set; }
public void Deserialize()
{
if (TokensFile.Length < BLOCK_SIZE) return;
if (TokensFile.Length < BlockSize) return;
TokensFile.Seek(0x24, SeekOrigin.Begin);
uint nextBlock = 0;
@@ -35,7 +35,7 @@ namespace MetroUnlocker.LibTSForge.TokenStore
uint curOffset = reader.ReadUInt32();
nextBlock = reader.ReadUInt32();
for (int i = 0; i < ENTRIES_PER_BLOCK; i++)
for (int i = 0; i < EntriesPerBlock; i++)
{
curOffset = reader.ReadUInt32();
bool populated = reader.ReadUInt32() == 1;
@@ -50,9 +50,7 @@ namespace MetroUnlocker.LibTSForge.TokenStore
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);
@@ -60,13 +58,7 @@ namespace MetroUnlocker.LibTSForge.TokenStore
reader.BaseStream.Seek(curOffset + 0x14, SeekOrigin.Begin);
Entries.Add(new TokenEntry
{
Name = reader.ReadNullTerminatedString(0x82),
Extension = reader.ReadNullTerminatedString(0x8),
Data = contentData,
Populated = populated
});
Entries.Add(new TokenEntry(reader.ReadNullTerminatedString(0x82), reader.ReadNullTerminatedString(0x8), contentData, populated));
}
reader.BaseStream.Seek(nextBlock, SeekOrigin.Begin);
@@ -79,31 +71,16 @@ namespace MetroUnlocker.LibTSForge.TokenStore
using (BinaryWriter writer = new BinaryWriter(tokens))
{
writer.Write(VERSION);
writer.Write(CONTS_HEADER);
writer.Write(Version);
writer.Write(Header);
int curBlockOffset = (int)writer.BaseStream.Position;
int curEntryOffset = curBlockOffset + 0x8;
int curContsOffset = curBlockOffset + BLOCK_SIZE;
int curContsOffset = curBlockOffset + BlockSize;
for (int eIndex = 0; eIndex < ((Entries.Count / ENTRIES_PER_BLOCK) + 1) * ENTRIES_PER_BLOCK; eIndex++)
for (int eIndex = 0; eIndex < ((Entries.Count / EntriesPerBlock) + 1) * EntriesPerBlock; eIndex++)
{
TokenEntry entry;
if (eIndex < Entries.Count)
{
entry = Entries[eIndex];
}
else
{
entry = new TokenEntry
{
Name = "",
Extension = "",
Populated = false,
Data = new byte[] { }
};
}
TokenEntry entry = eIndex < Entries.Count ? entry = Entries[eIndex] : new TokenEntry();
writer.BaseStream.Seek(curBlockOffset, SeekOrigin.Begin);
writer.Write(curBlockOffset);
@@ -122,15 +99,15 @@ namespace MetroUnlocker.LibTSForge.TokenStore
if (entry.Populated)
{
writer.BaseStream.Seek(curContsOffset, SeekOrigin.Begin);
writer.Write(CONTS_HEADER);
writer.Write(Header);
writer.Write(entry.Data.Length);
writer.Write(CryptoUtils.SHA256Hash(entry.Data));
writer.Write(entry.Data);
writer.Write(CONTS_FOOTER);
writer.Write(Footer);
curContsOffset = (int)writer.BaseStream.Position;
}
if ((eIndex + 1) % ENTRIES_PER_BLOCK == 0 && eIndex != 0)
if ((eIndex + 1) % EntriesPerBlock == 0 && eIndex != 0)
{
if (eIndex < Entries.Count)
{
@@ -139,21 +116,21 @@ namespace MetroUnlocker.LibTSForge.TokenStore
}
writer.BaseStream.Seek(curEntryOffset, SeekOrigin.Begin);
writer.WritePadding(BLOCK_PAD_SIZE);
writer.WritePadding(BlockPadSize);
writer.BaseStream.Seek(curBlockOffset, SeekOrigin.Begin);
byte[] blockHash;
byte[] blockData = new byte[BLOCK_SIZE - 0x20];
byte[] blockData = new byte[BlockSize - 0x20];
tokens.Read(blockData, 0, BLOCK_SIZE - 0x20);
tokens.Read(blockData, 0, BlockSize - 0x20);
blockHash = CryptoUtils.SHA256Hash(blockData);
writer.BaseStream.Seek(curBlockOffset + BLOCK_SIZE - 0x20, SeekOrigin.Begin);
writer.BaseStream.Seek(curBlockOffset + BlockSize - 0x20, SeekOrigin.Begin);
writer.Write(blockHash);
curBlockOffset = curContsOffset;
curEntryOffset = curBlockOffset + 0x8;
curContsOffset = curBlockOffset + BLOCK_SIZE;
curContsOffset = curBlockOffset + BlockSize;
}
}
@@ -190,71 +167,41 @@ namespace MetroUnlocker.LibTSForge.TokenStore
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)
public void DeleteUnpopulatedEntry(string name, string extension)
{
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();
Entries = Entries.FindAll(entry => entry.Name != name && entry.Extension != extension && entry.Populated);
}
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;
}
}
if (entry.Populated) return entry;
return null;
}
public TokenMeta GetMetaEntry(string name)
{
DeleteUnpopEntry(name, "xml");
DeleteUnpopulatedEntry(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;
return entry == null ? new TokenMeta(name) : new TokenMeta(entry.Data);
}
public void SetEntry(string name, string ext, byte[] data)
public void SetEntry(string name, string extension, byte[] data)
{
for (int i = 0; i < Entries.Count; i++)
{
TokenEntry entry = Entries[i];
if (entry.Name == name && entry.Extension == ext && entry.Populated)
if (entry.Name == name && entry.Extension == extension && entry.Populated)
{
entry.Data = data;
Entries[i] = entry;
@@ -262,13 +209,7 @@ namespace MetroUnlocker.LibTSForge.TokenStore
}
}
Entries.Add(new TokenEntry
{
Populated = true,
Name = name,
Extension = ext,
Data = data
});
Entries.Add(new TokenEntry(name, extension, data));
}
public static string GetPath()

View File

@@ -4,8 +4,9 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Microsoft.Win32;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using MetroUnlocker.LibTSForge.SPP;
using MetroUnlocker.LibTSForge.PhysicalStore;
@@ -21,39 +22,37 @@ namespace MetroUnlocker
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")));
throw new COMException(string.Format("Failed to deposit fake CID. Status code: 0x{0}", status.ToString("X")), (int)status);
}
public static void Activate(PSVersion version, bool production, Guid actId)
public static void Activate(PhysicalStoreVersion version, bool production, Guid activationId)
{
Guid appId = SLApi.GetAppId(actId);
Guid appId = SLApi.GetAppId(activationId);
string instId = SLApi.GetInstallationId(actId);
Guid pkeyId = SLApi.GetInstalledPkeyId(actId);
string instId = SLApi.GetInstallationId(activationId);
Guid pkeyId = SLApi.GetInstalledProductKeyId(activationId);
Utils.KillSPP();
using (PhysicalStore store = new PhysicalStore(version, production))
{
byte[] hwidBlock = Constants.UniversalHWIDBlock;
byte[] hwidBlock = Constants.UniversalHardwareIdBlock;
byte[] iidHash = CryptoUtils.SHA256Hash(Utils.EncodeString(instId + '\0' + Constants.ZeroCID));
string key = string.Format("SPPSVC\\{0}\\{1}", appId, actId);
string key = string.Format("SPPSVC\\{0}\\{1}", appId, activationId);
ModernBlock keyBlock = store.GetBlock(key, pkeyId.ToString());
if (keyBlock == null)
{
throw new InvalidDataException("Failed to get product key data for activation ID: 0x" + actId + ".");
}
throw new InvalidDataException("Failed to get product key data for activation ID: 0x" + activationId + ".");
VariableBag pkb = new VariableBag(keyBlock.Data);
VariableBag keyBag = new VariableBag(keyBlock.Data);
byte[] pkeyData = pkb.GetBlock("SppPkeyPhoneActivationData").Value;
byte[] pkeyData = keyBag.GetBlock("SppPkeyPhoneActivationData").Value;
pkb.DeleteBlock("SppPkeyVirtual");
store.SetBlock(key, pkeyId.ToString(), pkb.Serialize());
keyBag.DeleteBlock("SppPkeyVirtual");
store.SetBlock(key, pkeyId.ToString(), keyBag.Serialize());
BinaryWriter writer = new BinaryWriter(new MemoryStream());
writer.Write(0x20);
@@ -69,27 +68,15 @@ namespace MetroUnlocker
writer.Write(pkeyData);
byte[] tsPkeyInfoData = Utils.GetBytes(writer);
string path = "msft:Windows/7.0/Phone/Cached/";
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
}
new ModernBlock(key, path + "HwidBlock/" + pkeyId, tsHwidData),
new ModernBlock(key, path + "PKeyInfo/" + pkeyId, tsPkeyInfoData)
});
}
Deposit(actId, instId);
Deposit(activationId, instId);
SLApi.RefreshLicenseStatus();
SLApi.FireStateChangedEvent(appId);

View File

@@ -57,16 +57,18 @@
<Compile Include="App.Designer.cs">
<DependentUpon>App.cs</DependentUpon>
</Compile>
<Compile Include="LibTSForge\Common.cs" />
<Compile Include="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\Modifiers\ProductKeyInstaller.cs" />
<Compile Include="LibTSForge\PhysicalStore\BasicBlock.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\NativeMethods.cs" />
<Compile Include="LibTSForge\SPP\ProductKeyConfig.cs" />
<Compile Include="LibTSForge\SPP\ProductKey.cs" />
<Compile Include="LibTSForge\SPP\SLApi.cs" />
<Compile Include="LibTSForge\TokenStore\TokenEntry.cs" />
@@ -74,13 +76,9 @@
<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="ProductPolicy\ProductPolicyReader.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>
@@ -93,7 +91,9 @@
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="app.manifest" />
<None Include="app.manifest">
<SubType>Designer</SubType>
</None>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>

View File

@@ -7,57 +7,20 @@ 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 string StringValue { get { return Encoding.Unicode.GetString(Bytes); } }
public uint DWordValue { get { return BitConverter.ToUInt32(Bytes, 0); } }
public RegistryValueKind Type
{
get
{
return (RegistryValueKind)Header.DataType;
}
get { return (RegistryValueKind)Header.DataType; }
}
private void NameFromBin(ref byte[] PolicyBlob, int offset)
@@ -74,12 +37,10 @@ namespace MetroUnlocker.ProductPolicy
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");
}
Header = ProductPolicyReader.BytesToStruct<ProductPolicyValue>(PolicyBlob, 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);
}
@@ -97,57 +58,6 @@ namespace MetroUnlocker.ProductPolicy
}
}
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 };
//}
public int Size() { return Bytes.Length; }
}
}

View File

@@ -1,157 +0,0 @@
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,101 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using Microsoft.Win32;
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 ProductPolicyReader
{
public List<ProductPolicy> PolicyValues { get; set; }
const string ProductOptionsKey = "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\ProductOptions";
public ProductPolicyReader()
{
PolicyValues = FromBinary(GetPolicyBlob());
}
private static byte[] GetPolicyBlob()
{
return (byte[])Registry.GetValue(ProductOptionsKey, "ProductPolicy", null);
}
static public T BytesToStruct<T>(byte[] bytes, int offset = 0)
{
int size = Marshal.SizeOf(typeof(T));
IntPtr buffer = Marshal.AllocHGlobal(size);
try
{
Marshal.Copy(bytes, offset, buffer, size);
return (T)Marshal.PtrToStructure(buffer, typeof(T));
}
finally { Marshal.FreeHGlobal(buffer); }
}
public List<ProductPolicy> FromBinary(byte[] policyBlob)
{
var header = BytesToStruct<ProductPolicyHeader>(policyBlob);
if (header.Size < policyBlob.Length || (header.DataSize + Marshal.SizeOf(header) + header.EndMarker) != header.Size)
throw new Exception("Invalid Header format");
int position = Marshal.SizeOf(header);
int end = position + (int)header.DataSize;
PolicyValues = new List<ProductPolicy>();
while (position < end)
{
ProductPolicy policy = new ProductPolicy();
policy.FromBin(ref policyBlob, position);
PolicyValues.Add(policy);
position += policy.Header.Size;
}
return PolicyValues;
}
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;
}
}
}

View File

@@ -1,82 +0,0 @@
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;
}
}
}

View File

@@ -1,33 +0,0 @@
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);
}
}
}

View File

@@ -1,100 +0,0 @@
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

@@ -1,49 +0,0 @@
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

@@ -1,11 +1,27 @@
# MetroUnlocker
# Sideloading Unlocker
Unlock signed sideloading on:
![Preview](MetroUnlocker.png "Sideloading Unlocker")
## Unlock signed sideloading on:
- Windows 8.0 and up
Unlock development sideloading on:
## Unlock full sideloading on:
- Windows 8.1 Pro and up
- Windows 8.1 Pro and up
**Development sideloading** might take a while to activate. If it doesn't activate quick enough, you can use **Product Policy Editor** to disable **SPPSVC**, set the system clock to 2026, attempt sideloading until it activates, then revert the system clock and re-enable **SPPSVC**.
**Known bug:**
If your disk has **0 bytes** of free space, the system might fail to write the new tokens file, leaving the `tokens.dat` file empty and when SPPSVC starts, it will recreate the file but everything will be deactivated—including Windows itself.
MetroUnlocker always attempts to create a backup of your tokens before modifying them. Make sure you have at least **30MB** free of space before trying to activate sideloading. If something goes wrong, just restore the tokens.dat file from the backup to `C:\Windows\System32\spp\store\2.0`. In worst-case scenario, you can reactivate whatever you need activated again with **TSForge**.
Feel free to reach out to me or create an issue if you need help.
**Huge thanks to [TSForge](https://github.com/massgravel/TSforge)** for making this possible by reverse-engineering **SPPSVC**!
Thank you Zar!