Archived
1
1

First release build.

This commit is contained in:
Mona Lassa
2025-05-22 01:31:03 +02:00
parent ec55169d57
commit f90695dfda
30 changed files with 499 additions and 1389 deletions

BIN
MetroUnlocker.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -29,35 +29,17 @@
private void InitializeComponent() private void InitializeComponent()
{ {
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(App)); 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.developmentCheckbox = new System.Windows.Forms.CheckBox();
this.signedCheckbox = new System.Windows.Forms.CheckBox(); this.signedCheckbox = new System.Windows.Forms.CheckBox();
this.allUsersCheckbox = new System.Windows.Forms.CheckBox(); this.allUsersCheckbox = new System.Windows.Forms.CheckBox();
this.statusTextLabel = new System.Windows.Forms.Label(); this.statusTextLabel = new System.Windows.Forms.Label();
this.statusLabel = new System.Windows.Forms.Label(); this.statusLabel = new System.Windows.Forms.Label();
this.LOBCheckBox = new System.Windows.Forms.CheckBox(); this.groupBox = new System.Windows.Forms.GroupBox();
this.SPPCheckBox = new System.Windows.Forms.CheckBox(); this.disableButton = new System.Windows.Forms.Button();
this.groupBox1 = new System.Windows.Forms.GroupBox(); this.unlockButton = new System.Windows.Forms.Button();
this.groupBox2 = new System.Windows.Forms.GroupBox(); this.groupBox.SuspendLayout();
this.Manual = new System.Windows.Forms.TabControl();
this.tabPage1 = new System.Windows.Forms.TabPage();
this.button1 = new System.Windows.Forms.Button();
this.tabPage2 = new System.Windows.Forms.TabPage();
this.button2 = new System.Windows.Forms.Button();
this.groupBox1.SuspendLayout();
this.groupBox2.SuspendLayout();
this.Manual.SuspendLayout();
this.tabPage1.SuspendLayout();
this.tabPage2.SuspendLayout();
this.SuspendLayout(); 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 // developmentCheckbox
// //
resources.ApplyResources(this.developmentCheckbox, "developmentCheckbox"); resources.ApplyResources(this.developmentCheckbox, "developmentCheckbox");
@@ -89,79 +71,36 @@
resources.ApplyResources(this.statusLabel, "statusLabel"); resources.ApplyResources(this.statusLabel, "statusLabel");
this.statusLabel.Name = "statusLabel"; this.statusLabel.Name = "statusLabel";
// //
// LOBCheckBox // groupBox
// //
resources.ApplyResources(this.LOBCheckBox, "LOBCheckBox"); resources.ApplyResources(this.groupBox, "groupBox");
this.LOBCheckBox.Name = "LOBCheckBox"; this.groupBox.Controls.Add(this.signedCheckbox);
this.LOBCheckBox.UseVisualStyleBackColor = true; 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"); resources.ApplyResources(this.disableButton, "disableButton");
this.SPPCheckBox.Name = "SPPCheckBox"; this.disableButton.Name = "disableButton";
this.SPPCheckBox.UseVisualStyleBackColor = true; this.disableButton.UseVisualStyleBackColor = true;
this.disableButton.Click += new System.EventHandler(this.Uninstall);
// //
// groupBox1 // unlockButton
// //
resources.ApplyResources(this.groupBox1, "groupBox1"); resources.ApplyResources(this.unlockButton, "unlockButton");
this.groupBox1.Controls.Add(this.signedCheckbox); this.unlockButton.Name = "unlockButton";
this.groupBox1.Controls.Add(this.allUsersCheckbox); this.unlockButton.UseVisualStyleBackColor = true;
this.groupBox1.Controls.Add(this.developmentCheckbox); this.unlockButton.Click += new System.EventHandler(this.Jailbreak);
this.groupBox1.Name = "groupBox1";
this.groupBox1.TabStop = false;
//
// groupBox2
//
resources.ApplyResources(this.groupBox2, "groupBox2");
this.groupBox2.Controls.Add(this.LOBCheckBox);
this.groupBox2.Controls.Add(this.SPPCheckBox);
this.groupBox2.Controls.Add(this.temporaryButton);
this.groupBox2.Name = "groupBox2";
this.groupBox2.TabStop = false;
//
// Manual
//
resources.ApplyResources(this.Manual, "Manual");
this.Manual.Controls.Add(this.tabPage1);
this.Manual.Controls.Add(this.tabPage2);
this.Manual.Name = "Manual";
this.Manual.SelectedIndex = 0;
//
// tabPage1
//
this.tabPage1.Controls.Add(this.button2);
this.tabPage1.Controls.Add(this.button1);
resources.ApplyResources(this.tabPage1, "tabPage1");
this.tabPage1.Name = "tabPage1";
this.tabPage1.UseVisualStyleBackColor = true;
//
// button1
//
resources.ApplyResources(this.button1, "button1");
this.button1.Name = "button1";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.JailbreakButton_Click);
//
// tabPage2
//
this.tabPage2.Controls.Add(this.groupBox2);
this.tabPage2.Controls.Add(this.groupBox1);
resources.ApplyResources(this.tabPage2, "tabPage2");
this.tabPage2.Name = "tabPage2";
this.tabPage2.UseVisualStyleBackColor = true;
//
// button2
//
resources.ApplyResources(this.button2, "button2");
this.button2.Name = "button2";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.Uninstall);
// //
// App // App
// //
resources.ApplyResources(this, "$this"); resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 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.statusLabel);
this.Controls.Add(this.statusTextLabel); this.Controls.Add(this.statusTextLabel);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
@@ -171,13 +110,8 @@
this.ShowIcon = false; this.ShowIcon = false;
this.ShowInTaskbar = false; this.ShowInTaskbar = false;
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
this.groupBox1.ResumeLayout(false); this.groupBox.ResumeLayout(false);
this.groupBox1.PerformLayout(); this.groupBox.PerformLayout();
this.groupBox2.ResumeLayout(false);
this.groupBox2.PerformLayout();
this.Manual.ResumeLayout(false);
this.tabPage1.ResumeLayout(false);
this.tabPage2.ResumeLayout(false);
this.ResumeLayout(false); this.ResumeLayout(false);
this.PerformLayout(); this.PerformLayout();
@@ -185,21 +119,14 @@
#endregion #endregion
private System.Windows.Forms.Button temporaryButton;
private System.Windows.Forms.CheckBox developmentCheckbox; private System.Windows.Forms.CheckBox developmentCheckbox;
private System.Windows.Forms.CheckBox signedCheckbox; private System.Windows.Forms.CheckBox signedCheckbox;
private System.Windows.Forms.CheckBox allUsersCheckbox; private System.Windows.Forms.CheckBox allUsersCheckbox;
private System.Windows.Forms.Label statusTextLabel; private System.Windows.Forms.Label statusTextLabel;
private System.Windows.Forms.Label statusLabel; private System.Windows.Forms.Label statusLabel;
private System.Windows.Forms.GroupBox groupBox2; private System.Windows.Forms.GroupBox groupBox;
private System.Windows.Forms.CheckBox LOBCheckBox; private System.Windows.Forms.Button unlockButton;
private System.Windows.Forms.CheckBox SPPCheckBox; private System.Windows.Forms.Button disableButton;
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;
} }
} }

View File

@@ -6,6 +6,7 @@ using System.Drawing;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Windows.Forms; using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics; using System.Diagnostics;
using Microsoft.Win32; using Microsoft.Win32;
@@ -60,82 +61,36 @@ namespace MetroUnlocker
public void UpdatePolicyState() public void UpdatePolicyState()
{ {
var productPolicyEditor = new ProductPolicyEditor(); var productPolicyEditor = new ProductPolicyReader();
var policyState = productPolicyEditor.GetPolicyStateByName("WSLicensingService-LOBSideloadingActivated"); var policyState = productPolicyEditor.GetPolicyStateByName("WSLicensingService-LOBSideloadingActivated");
var isSideloadingKeyInstalled = LOBManager.IsSideloadingKeyInstalled(); var isSideloadingKeyInstalled = LOBManager.IsSideloadingKeyInstalled();
statusLabel.ForeColor = isSideloadingKeyInstalled ? Color.DarkGreen: Color.DarkOrange;
disableButton.Enabled = isSideloadingKeyInstalled;
switch (policyState) switch (policyState)
{ {
case PolicyState.Disabled: case PolicyState.Disabled:
statusLabel.Text = "Disabled";
statusLabel.ForeColor = Color.DarkRed;
break;
case PolicyState.Enabled:
if (isSideloadingKeyInstalled) if (isSideloadingKeyInstalled)
{ statusLabel.Text = "Enabling...";
statusLabel.Text = "Sideloading enabled";
statusLabel.ForeColor = Color.DarkGreen;
}
else else
{ {
statusLabel.Text = "Sideloading will be disabled soon"; statusLabel.Text = "Disabled";
statusLabel.ForeColor = Color.DarkOrange; statusLabel.ForeColor = Color.DarkRed;
} }
break; break;
case PolicyState.Unknown: case PolicyState.Enabled:
statusLabel.Text = isSideloadingKeyInstalled ? "Sideloading enabled" : "Disabling...";
break;
default:
statusLabel.Text = "Unknown"; statusLabel.Text = "Unknown";
statusLabel.ForeColor = Color.Black; statusLabel.ForeColor = Color.Black;
break; break;
} }
} }
private string CombineArguments(params string[] arguments) private void Jailbreak(object sender, EventArgs e)
{
return string.Join(" ", arguments);
}
private void SetSetupParameter(string key, object value, RegistryValueKind valueKind)
{
Registry.SetValue("HKEY_LOCAL_MACHINE\\SYSTEM\\Setup", key, value, valueKind);
}
private void SetSetupType(int type)
{
SetSetupParameter("SetupType", type, RegistryValueKind.DWord);
}
private void button1_Click(object sender, EventArgs e)
{
StartupArgument startupArgument;
if (LOBCheckBox.Checked && SPPCheckBox.Checked)
startupArgument = StartupArgument.EnableLOBAndEnableSPP;
else if (LOBCheckBox.Checked)
startupArgument = StartupArgument.EnableLOBAndDisableSPP;
else if (SPPCheckBox.Checked)
startupArgument = StartupArgument.DisableLOBAndEnableSPP;
else
startupArgument = StartupArgument.DisableLOBAndDisableSPP;
string commandLine = CombineArguments(new string[] { Application.ExecutablePath, StartupArguments.GetStartupArgumentString(startupArgument) });
SetSetupParameter("CmdLine", commandLine, RegistryValueKind.String);
SetSetupType(1);
DialogResult result = MessageBox.Show("Sideloading will be enabled after a reboot. Would you like to reboot now?", "Reboot?", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
switch (result)
{
case DialogResult.Yes:
Rebooter.Reboot();
break;
case DialogResult.Cancel:
SetSetupType(0);
break;
}
}
private void JailbreakButton_Click(object sender, EventArgs e)
{ {
try try
{ {
@@ -145,12 +100,19 @@ namespace MetroUnlocker
return; return;
LOBManager.ActivateZeroCID(); LOBManager.ActivateZeroCID();
LOBEnabled = true;
DevelopmentEnabled = true;
MessageBox.Show(this, "Sideloading activated!", "Success!", MessageBoxButtons.OK, MessageBoxIcon.Information); MessageBox.Show(this, "Sideloading activated!", "Success!", MessageBoxButtons.OK, MessageBoxIcon.Information);
UpdatePolicyState(); UpdatePolicyState();
} }
catch (Exception ex) 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"> <resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </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"> <data name="developmentCheckbox.AccessibleDescription" xml:space="preserve">
<value>Allows sideloading of unpackaged apps.</value> <value>Allows sideloading of unpackaged apps.</value>
</data> </data>
<assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="developmentCheckbox.AutoSize" type="System.Boolean, mscorlib"> <data name="developmentCheckbox.AutoSize" type="System.Boolean, mscorlib">
<value>True</value> <value>True</value>
</data> </data>
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value> <value>True</value>
</metadata> </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"> <data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
<value>6, 13</value> <value>6, 13</value>
</data> </data>
<data name="$this.AutoSize" type="System.Boolean, mscorlib"> <data name="$this.AutoSize" type="System.Boolean, mscorlib">
<value>True</value> <value>True</value>
</data> </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"> <data name="$this.AutoSizeMode" type="System.Windows.Forms.AutoSizeMode, System.Windows.Forms">
<value>GrowAndShrink</value> <value>GrowAndShrink</value>
</data> </data>
<data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing"> <data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
<value>266, 215</value> <value>252, 200</value>
</data> </data>
<data name="Manual.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms"> <data name="disableButton.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Bottom, Left, Right</value> <value>Bottom, Left, Right</value>
</data> </data>
<data name="button2.Location" type="System.Drawing.Point, System.Drawing"> <data name="disableButton.Location" type="System.Drawing.Point, System.Drawing">
<value>7, 123</value> <value>12, 165</value>
</data> </data>
<data name="button2.Size" type="System.Drawing.Size, System.Drawing"> <data name="disableButton.Size" type="System.Drawing.Size, System.Drawing">
<value>221, 23</value> <value>228, 23</value>
</data> </data>
<data name="button2.TabIndex" type="System.Int32, mscorlib"> <data name="disableButton.TabIndex" type="System.Int32, mscorlib">
<value>1</value> <value>1</value>
</data> </data>
<data name="button2.Text" xml:space="preserve"> <data name="disableButton.Text" xml:space="preserve">
<value>Disable Sideloading</value> <value>Disable Sideloading</value>
</data> </data>
<data name="&gt;&gt;button2.Name" xml:space="preserve"> <data name="&gt;&gt;disableButton.Name" xml:space="preserve">
<value>button2</value> <value>disableButton</value>
</data> </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> <value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data> </data>
<data name="&gt;&gt;button2.Parent" xml:space="preserve"> <data name="&gt;&gt;disableButton.Parent" xml:space="preserve">
<value>tabPage1</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;button2.ZOrder" xml:space="preserve"> <data name="&gt;&gt;disableButton.ZOrder" xml:space="preserve">
<value>0</value> <value>0</value>
</data> </data>
<data name="button1.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms"> <data name="groupBox.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Bottom, Left, Right</value> <value>Bottom, Left, Right</value>
</data>
<data name="button1.Location" type="System.Drawing.Point, System.Drawing">
<value>6, 6</value>
</data>
<data name="button1.Size" type="System.Drawing.Size, System.Drawing">
<value>222, 111</value>
</data>
<data name="button1.TabIndex" type="System.Int32, mscorlib">
<value>0</value>
</data>
<data name="button1.Text" xml:space="preserve">
<value>Unlock!</value>
</data>
<data name="&gt;&gt;button1.Name" xml:space="preserve">
<value>button1</value>
</data>
<data name="&gt;&gt;button1.Type" xml:space="preserve">
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;button1.Parent" xml:space="preserve">
<value>tabPage1</value>
</data>
<data name="&gt;&gt;button1.ZOrder" xml:space="preserve">
<value>1</value>
</data>
<data name="tabPage1.Location" type="System.Drawing.Point, System.Drawing">
<value>4, 22</value>
</data>
<data name="tabPage1.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>3, 3, 3, 3</value>
</data>
<data name="tabPage1.Size" type="System.Drawing.Size, System.Drawing">
<value>234, 152</value>
</data>
<data name="tabPage1.TabIndex" type="System.Int32, mscorlib">
<value>0</value>
</data>
<data name="tabPage1.Text" xml:space="preserve">
<value>Jailbreak</value>
</data>
<data name="&gt;&gt;tabPage1.Name" xml:space="preserve">
<value>tabPage1</value>
</data>
<data name="&gt;&gt;tabPage1.Type" xml:space="preserve">
<value>System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;tabPage1.Parent" xml:space="preserve">
<value>Manual</value>
</data>
<data name="&gt;&gt;tabPage1.ZOrder" xml:space="preserve">
<value>0</value>
</data>
<data name="groupBox2.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Bottom, Left, Right</value>
</data>
<data name="LOBCheckBox.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<data name="LOBCheckBox.Location" type="System.Drawing.Point, System.Drawing">
<value>6, 19</value>
</data>
<data name="LOBCheckBox.Size" type="System.Drawing.Size, System.Drawing">
<value>81, 17</value>
</data>
<data name="LOBCheckBox.TabIndex" type="System.Int32, mscorlib">
<value>1</value>
</data>
<data name="LOBCheckBox.Text" xml:space="preserve">
<value>Sideloading</value>
</data>
<data name="&gt;&gt;LOBCheckBox.Name" xml:space="preserve">
<value>LOBCheckBox</value>
</data>
<data name="&gt;&gt;LOBCheckBox.Type" xml:space="preserve">
<value>System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;LOBCheckBox.Parent" xml:space="preserve">
<value>groupBox2</value>
</data>
<data name="&gt;&gt;LOBCheckBox.ZOrder" xml:space="preserve">
<value>0</value>
</data>
<data name="SPPCheckBox.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<data name="SPPCheckBox.Location" type="System.Drawing.Point, System.Drawing">
<value>95, 19</value>
</data>
<data name="SPPCheckBox.Size" type="System.Drawing.Size, System.Drawing">
<value>119, 17</value>
</data>
<data name="SPPCheckBox.TabIndex" type="System.Int32, mscorlib">
<value>2</value>
</data>
<data name="SPPCheckBox.Text" xml:space="preserve">
<value>Software Protection</value>
</data>
<data name="&gt;&gt;SPPCheckBox.Name" xml:space="preserve">
<value>SPPCheckBox</value>
</data>
<data name="&gt;&gt;SPPCheckBox.Type" xml:space="preserve">
<value>System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;SPPCheckBox.Parent" xml:space="preserve">
<value>groupBox2</value>
</data>
<data name="&gt;&gt;SPPCheckBox.ZOrder" xml:space="preserve">
<value>1</value>
</data>
<data name="groupBox2.Location" type="System.Drawing.Point, System.Drawing">
<value>6, 75</value>
</data>
<data name="groupBox2.Size" type="System.Drawing.Size, System.Drawing">
<value>222, 71</value>
</data>
<data name="groupBox2.TabIndex" type="System.Int32, mscorlib">
<value>8</value>
</data>
<data name="groupBox2.Text" xml:space="preserve">
<value>Product Policy</value>
</data>
<data name="&gt;&gt;groupBox2.Name" xml:space="preserve">
<value>groupBox2</value>
</data>
<data name="&gt;&gt;groupBox2.Type" xml:space="preserve">
<value>System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;groupBox2.Parent" xml:space="preserve">
<value>tabPage2</value>
</data>
<data name="&gt;&gt;groupBox2.ZOrder" xml:space="preserve">
<value>0</value>
</data>
<data name="groupBox1.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Left, Right</value>
</data> </data>
<data name="signedCheckbox.AccessibleDescription" xml:space="preserve"> <data name="signedCheckbox.AccessibleDescription" xml:space="preserve">
<value>Enables sideloading of signed apps.</value> <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> <value>System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data> </data>
<data name="&gt;&gt;signedCheckbox.Parent" xml:space="preserve"> <data name="&gt;&gt;signedCheckbox.Parent" xml:space="preserve">
<value>groupBox1</value> <value>groupBox</value>
</data> </data>
<data name="&gt;&gt;signedCheckbox.ZOrder" xml:space="preserve"> <data name="&gt;&gt;signedCheckbox.ZOrder" xml:space="preserve">
<value>0</value> <value>0</value>
@@ -373,7 +211,7 @@
<value>True</value> <value>True</value>
</data> </data>
<data name="allUsersCheckbox.Location" type="System.Drawing.Point, System.Drawing"> <data name="allUsersCheckbox.Location" type="System.Drawing.Point, System.Drawing">
<value>149, 19</value> <value>155, 19</value>
</data> </data>
<data name="allUsersCheckbox.Size" type="System.Drawing.Size, System.Drawing"> <data name="allUsersCheckbox.Size" type="System.Drawing.Size, System.Drawing">
<value>67, 17</value> <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> <value>System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data> </data>
<data name="&gt;&gt;allUsersCheckbox.Parent" xml:space="preserve"> <data name="&gt;&gt;allUsersCheckbox.Parent" xml:space="preserve">
<value>groupBox1</value> <value>groupBox</value>
</data> </data>
<data name="&gt;&gt;allUsersCheckbox.ZOrder" xml:space="preserve"> <data name="&gt;&gt;allUsersCheckbox.ZOrder" xml:space="preserve">
<value>1</value> <value>1</value>
</data> </data>
<data name="groupBox1.Location" type="System.Drawing.Point, System.Drawing"> <data name="groupBox.Location" type="System.Drawing.Point, System.Drawing">
<value>6, 6</value> <value>12, 96</value>
</data> </data>
<data name="groupBox1.Size" type="System.Drawing.Size, System.Drawing"> <data name="groupBox.Size" type="System.Drawing.Size, System.Drawing">
<value>222, 63</value> <value>228, 63</value>
</data> </data>
<data name="groupBox1.TabIndex" type="System.Int32, mscorlib"> <data name="groupBox.TabIndex" type="System.Int32, mscorlib">
<value>7</value> <value>7</value>
</data> </data>
<data name="groupBox1.Text" xml:space="preserve"> <data name="groupBox.Text" xml:space="preserve">
<value>Group Policy</value> <value>Group Policy</value>
</data> </data>
<data name="&gt;&gt;groupBox1.Name" xml:space="preserve"> <data name="&gt;&gt;groupBox.Name" xml:space="preserve">
<value>groupBox1</value> <value>groupBox</value>
</data> </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> <value>System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data> </data>
<data name="&gt;&gt;groupBox1.Parent" xml:space="preserve"> <data name="&gt;&gt;groupBox.Parent" xml:space="preserve">
<value>tabPage2</value>
</data>
<data name="&gt;&gt;groupBox1.ZOrder" xml:space="preserve">
<value>1</value>
</data>
<data name="tabPage2.Location" type="System.Drawing.Point, System.Drawing">
<value>4, 22</value>
</data>
<data name="tabPage2.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>3, 3, 3, 3</value>
</data>
<data name="tabPage2.Size" type="System.Drawing.Size, System.Drawing">
<value>234, 152</value>
</data>
<data name="tabPage2.TabIndex" type="System.Int32, mscorlib">
<value>1</value>
</data>
<data name="tabPage2.Text" xml:space="preserve">
<value>Manual</value>
</data>
<data name="&gt;&gt;tabPage2.Name" xml:space="preserve">
<value>tabPage2</value>
</data>
<data name="&gt;&gt;tabPage2.Type" xml:space="preserve">
<value>System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;tabPage2.Parent" xml:space="preserve">
<value>Manual</value>
</data>
<data name="&gt;&gt;tabPage2.ZOrder" xml:space="preserve">
<value>1</value>
</data>
<data name="Manual.Location" type="System.Drawing.Point, System.Drawing">
<value>12, 25</value>
</data>
<data name="Manual.Size" type="System.Drawing.Size, System.Drawing">
<value>242, 178</value>
</data>
<data name="Manual.TabIndex" type="System.Int32, mscorlib">
<value>9</value>
</data>
<data name="&gt;&gt;Manual.Name" xml:space="preserve">
<value>Manual</value>
</data>
<data name="&gt;&gt;Manual.Type" xml:space="preserve">
<value>System.Windows.Forms.TabControl, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;Manual.Parent" xml:space="preserve">
<value>$this</value> <value>$this</value>
</data> </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> <value>0</value>
</data> </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"> <data name="statusLabel.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value> <value>Top, Right</value>
</data> </data>
<data name="statusLabel.Location" type="System.Drawing.Point, System.Drawing"> <data name="statusLabel.Location" type="System.Drawing.Point, System.Drawing">
<value>58, 9</value> <value>44, 9</value>
</data> </data>
<data name="statusLabel.Size" type="System.Drawing.Size, System.Drawing"> <data name="statusLabel.Size" type="System.Drawing.Size, System.Drawing">
<value>196, 13</value> <value>196, 13</value>
@@ -496,7 +313,7 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;statusLabel.ZOrder" xml:space="preserve"> <data name="&gt;&gt;statusLabel.ZOrder" xml:space="preserve">
<value>1</value> <value>3</value>
</data> </data>
<data name="statusTextLabel.AutoSize" type="System.Boolean, mscorlib"> <data name="statusTextLabel.AutoSize" type="System.Boolean, mscorlib">
<value>True</value> <value>True</value>
@@ -523,7 +340,7 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;statusTextLabel.ZOrder" xml:space="preserve"> <data name="&gt;&gt;statusTextLabel.ZOrder" xml:space="preserve">
<value>2</value> <value>4</value>
</data> </data>
<data name="$this.StartPosition" type="System.Windows.Forms.FormStartPosition, System.Windows.Forms"> <data name="$this.StartPosition" type="System.Windows.Forms.FormStartPosition, System.Windows.Forms">
<value>CenterScreen</value> <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> <value>System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data> </data>
<data name="&gt;&gt;developmentCheckbox.Parent" xml:space="preserve"> <data name="&gt;&gt;developmentCheckbox.Parent" xml:space="preserve">
<value>groupBox1</value> <value>groupBox</value>
</data> </data>
<data name="&gt;&gt;developmentCheckbox.ZOrder" xml:space="preserve"> <data name="&gt;&gt;developmentCheckbox.ZOrder" xml:space="preserve">
<value>2</value> <value>2</value>

View File

@@ -14,7 +14,7 @@ using MetroUnlocker.LibTSForge.SPP;
// Common.cs // Common.cs
namespace MetroUnlocker namespace MetroUnlocker
{ {
public enum PSVersion public enum PhysicalStoreVersion
{ {
Win8Early, Win8Early,
Win8, Win8,
@@ -33,7 +33,7 @@ namespace MetroUnlocker
public static class Constants public static class Constants
{ {
public static readonly string ZeroCID = new string('0', 48); 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, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -146,8 +146,6 @@ namespace MetroUnlocker
throw new InvalidOperationException("Unable to access sppsvc: " + ex.Message); throw new InvalidOperationException("Unable to access sppsvc: " + ex.Message);
} }
//Logger.WriteLine("Stopping sppsvc...");
bool stopped = false; bool stopped = false;
for (int i = 0; stopped == false && i < 60; i++) for (int i = 0; stopped == false && i < 60; i++)
@@ -174,19 +172,14 @@ namespace MetroUnlocker
if (!stopped) if (!stopped)
throw new System.TimeoutException("Failed to stop sppsvc"); 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; int build = Environment.OSVersion.Version.Build;
if (build >= 9600) return PSVersion.WinModern; if (build >= 9600) return PhysicalStoreVersion.WinModern;
//if (build >= 6000 && build <= 6003) return PSVersion.Vista; if (build == 9200) return PhysicalStoreVersion.Win8;
//if (build >= 7600 && build <= 7602) return PSVersion.Win7;
if (build == 9200) return PSVersion.Win8;
throw new NotSupportedException("This version of Windows is not supported. (build " + build + ")"); throw new NotSupportedException("This version of Windows is not supported. (build " + build + ")");
} }
@@ -196,15 +189,9 @@ namespace MetroUnlocker
SLApi.RefreshLicenseStatus(); SLApi.RefreshLicenseStatus();
using (RegistryKey wpaKey = Registry.LocalMachine.OpenSubKey(@"SYSTEM\WPA")) using (RegistryKey wpaKey = Registry.LocalMachine.OpenSubKey(@"SYSTEM\WPA"))
{
foreach (string subKey in wpaKey.GetSubKeyNames()) foreach (string subKey in wpaKey.GetSubKeyNames())
{
if (subKey.StartsWith("8DEC0AF1") && subKey.EndsWith("-1")) if (subKey.StartsWith("8DEC0AF1") && subKey.EndsWith("-1"))
{
return subKey.Contains("P"); return subKey.Contains("P");
}
}
}
throw new FileNotFoundException("Failed to autodetect key type, specify physical store key with /prod or /test arguments."); throw new FileNotFoundException("Failed to autodetect key type, specify physical store key with /prod or /test arguments.");
} }
@@ -230,6 +217,10 @@ namespace MetroUnlocker
public string Name; public string Name;
public Dictionary<string, string> Data = new Dictionary<string, string>(); 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() public byte[] Serialize()
{ {
BinaryWriter writer = new BinaryWriter(new MemoryStream()); BinaryWriter writer = new BinaryWriter(new MemoryStream());
@@ -267,15 +258,5 @@ namespace MetroUnlocker
Data[key] = value; 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.Threading.Tasks;
using System.IO; using System.IO;
using MetroUnlocker.ProductPolicy;
using MetroUnlocker; using MetroUnlocker;
using MetroUnlocker.LibTSForge.PhysicalStore; using MetroUnlocker.LibTSForge.SPP;
using MetroUnlocker.LibTSForge.Modifiers; using MetroUnlocker.LibTSForge.Modifiers;
using MetroUnlocker.LibTSForge.TokenStore; using MetroUnlocker.LibTSForge.TokenStore;
using MetroUnlocker.LibTSForge.SPP; using MetroUnlocker.LibTSForge.PhysicalStore;
namespace MetroUnlocker namespace MetroUnlocker
{ {
@@ -22,19 +21,25 @@ namespace MetroUnlocker
public static void ActivateZeroCID() public static void ActivateZeroCID()
{ {
PSVersion version = Utils.DetectVersion(); PhysicalStoreVersion version = Utils.DetectVersion();
bool production = Utils.DetectCurrentKey(); bool production = Utils.DetectCurrentKey();
if (Backup) BackupPhysicalStore(); if (Backup) BackupPhysicalStore();
GenPKeyInstall.InstallGenPKey(version, production, ActivationId); ProductKeyInstaller.InstallGeneratedProductKey(version, production, ActivationId);
ZeroCID.Activate(version, production, ActivationId); ZeroCID.Activate(version, production, ActivationId);
} }
public static Guid GetInstalledSideloadingKeyId() 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) public static bool IsSideloadingKeyInstalled(out Guid sideloadingKeyId)
@@ -80,28 +85,5 @@ namespace MetroUnlocker
File.Copy(physicalStore, GetUniqueFileName(backupFileName), false); 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

@@ -72,9 +72,7 @@ namespace MetroUnlocker.LibTSForge.Crypto
byte[] hash; byte[] hash;
using (SHA1 sha1 = SHA1.Create()) using (SHA1 sha1 = SHA1.Create())
{
hash = sha1.ComputeHash(data); hash = sha1.ComputeHash(data);
}
return formatter.CreateSignature(hash); return formatter.CreateSignature(hash);
} }
@@ -90,9 +88,7 @@ namespace MetroUnlocker.LibTSForge.Crypto
byte[] hash; byte[] hash;
using (SHA1 sha1 = SHA1.Create()) using (SHA1 sha1 = SHA1.Create())
{
hash = sha1.ComputeHash(data); hash = sha1.ComputeHash(data);
}
return deformatter.VerifySignature(hash, signature); return deformatter.VerifySignature(hash, signature);
} }
@@ -113,9 +109,7 @@ namespace MetroUnlocker.LibTSForge.Crypto
public static byte[] SHA256Hash(byte[] data) public static byte[] SHA256Hash(byte[] data)
{ {
using (SHA256 sha256 = SHA256.Create()) using (SHA256 sha256 = SHA256.Create())
{
return sha256.ComputeHash(data); return sha256.ComputeHash(data);
}
} }
} }
} }

View File

@@ -2,7 +2,7 @@ namespace MetroUnlocker.LibTSForge.Crypto
{ {
public static class Keys 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, 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, 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, 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 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, 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, 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, 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) 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)); BinaryReader br = new BinaryReader(new MemoryStream(data));
br.BaseStream.Seek(0x10, SeekOrigin.Begin); br.BaseStream.Seek(0x10, SeekOrigin.Begin);
byte[] aesKeySig = br.ReadBytes(0x80); byte[] aesKeySig = br.ReadBytes(0x80);
@@ -33,16 +33,16 @@ namespace MetroUnlocker.LibTSForge.Crypto
return psData; 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}, {PhysicalStoreVersion.Win8, 1},
{PSVersion.WinBlue, 2}, {PhysicalStoreVersion.WinBlue, 2},
{PSVersion.WinModern, 3} {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[] aesKey = Encoding.UTF8.GetBytes("Boop Foxyz nose!");
byte[] hmacKey = CryptoUtils.GenerateRandomKey(0x10); byte[] hmacKey = CryptoUtils.GenerateRandomKey(0x10);

View File

@@ -1,33 +1,25 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using MetroUnlocker.LibTSForge.SPP;
using System.Text;
namespace MetroUnlocker.LibTSForge.Modifiers namespace MetroUnlocker.LibTSForge.Modifiers
{ {
using System; public static class ProductKeyInstaller
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) public static void InstallGeneratedProductKey(PhysicalStoreVersion version, bool production, Guid actId)
{ {
PKeyConfig pkc = new PKeyConfig(); ProductKeyConfig keyConfig = new ProductKeyConfig();
pkc.LoadConfig(actId); keyConfig.LoadConfig(actId);
ProductConfig config; ProductConfig config;
pkc.Products.TryGetValue(actId, out config); keyConfig.Products.TryGetValue(actId, out config);
if (config == null) throw new ArgumentException("Activation ID " + actId + " not found in PKeyConfig."); if (config == null) throw new ArgumentException("Activation ID " + actId + " not found in ProductKeyConfig.");
ProductKey pkey = config.GetRandomKey(); ProductKey pkey = config.GetRandomKey();
Guid instPkeyId = SLApi.GetInstalledPkeyId(actId); Guid instPkeyId = SLApi.GetInstalledProductKeyId(actId);
if (instPkeyId != Guid.Empty) SLApi.UninstallProductKey(instPkeyId); if (instPkeyId != Guid.Empty) SLApi.UninstallProductKey(instPkeyId);
if (pkey.Algorithm != PKeyAlgorithm.PKEY2009) if (pkey.Algorithm != PKeyAlgorithm.PKEY2009)

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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO; using System.IO;
namespace MetroUnlocker.LibTSForge.PhysicalStore namespace MetroUnlocker.LibTSForge.PhysicalStore
{ {
public enum CRCBlockType : uint public enum CRCBlockType : uint
{ {
UINT = 1 << 0, UInt = 1 << 0,
STRING = 1 << 1, String = 1 << 1,
BINARY = 1 << 2 Binary = 1 << 2
} }
public class CRCBlock public class CRCBlock : BasicBlock
{ {
public CRCBlockType DataType; public CRCBlockType DataType;
public byte[] Key;
public string KeyAsStr public CRCBlock() { }
public CRCBlock(BinaryReader reader)
{ {
get uint crc = reader.ReadUInt32();
{ uint type = reader.ReadUInt32();
return Utils.DecodeString(Key); uint lenName = reader.ReadUInt32();
} uint lenVal = reader.ReadUInt32();
set
{ byte[] key = reader.ReadBytes((int)lenName);
Key = Utils.EncodeString(value);
} reader.Align(8);
}
public byte[] Value; byte[] value = reader.ReadBytes((int)lenVal);
public string ValueAsStr reader.Align(8);
{
get DataType = (CRCBlockType)type;
{ Key = key;
return Utils.DecodeString(Value); Value = value;
}
set if (CRC() != crc)
{ throw new InvalidDataException("Invalid CRC in variable bag.");
Value = Utils.EncodeString(value);
}
}
public uint ValueAsInt
{
get
{
return BitConverter.ToUInt32(Value, 0);
}
set
{
Value = BitConverter.GetBytes(value);
}
} }
public void Encode(BinaryWriter writer) public void Encode(BinaryWriter writer)
@@ -67,45 +54,16 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore
writer.Align(8); 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() public uint CRC()
{ {
BinaryWriter wtemp = new BinaryWriter(new MemoryStream()); BinaryWriter writer = new BinaryWriter(new MemoryStream());
wtemp.Write(0); writer.Write(0);
wtemp.Write((uint)DataType); writer.Write((uint)DataType);
wtemp.Write(Key.Length); writer.Write(Key.Length);
wtemp.Write(Value.Length); writer.Write(Value.Length);
wtemp.Write(Key); writer.Write(Key);
wtemp.Write(Value); writer.Write(Value);
return Utils.CRC32(((MemoryStream)wtemp.BaseStream).ToArray()); return Utils.CRC32(((MemoryStream)writer.BaseStream).ToArray());
} }
} }
} }

View File

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

View File

@@ -16,7 +16,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore
private byte[] PreHeaderBytes = new byte[] { }; private byte[] PreHeaderBytes = new byte[] { };
private readonly Dictionary<string, List<ModernBlock>> Data = new Dictionary<string, List<ModernBlock>>(); private readonly Dictionary<string, List<ModernBlock>> Data = new Dictionary<string, List<ModernBlock>>();
private readonly FileStream TSFile; private readonly FileStream TSFile;
private readonly PSVersion Version; private readonly PhysicalStoreVersion Version;
private readonly bool Production; private readonly bool Production;
public byte[] Serialize() public byte[] Serialize()
@@ -66,7 +66,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore
for (int j = 0; j < numValues; j++) for (int j = 0; j < numValues; j++)
{ {
Data[keyName].Add(ModernBlock.Decode(reader)); Data[keyName].Add(new ModernBlock(reader));
reader.Align(4); reader.Align(4);
} }
} }
@@ -75,12 +75,10 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore
public void AddBlock(ModernBlock block) public void AddBlock(ModernBlock block)
{ {
if (!Data.ContainsKey(block.KeyAsStr)) if (!Data.ContainsKey(block.KeyAsString))
{ Data[block.KeyAsString] = new List<ModernBlock>();
Data[block.KeyAsStr] = new List<ModernBlock>();
}
Data[block.KeyAsStr].Add(new ModernBlock Data[block.KeyAsString].Add(new ModernBlock
{ {
Type = block.Type, Type = block.Type,
Flags = block.Flags, Flags = block.Flags,
@@ -104,7 +102,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore
foreach (ModernBlock block in blocks) foreach (ModernBlock block in blocks)
{ {
if (block.ValueAsStr == value) if (block.ValueAsString == value)
{ {
return new ModernBlock return new ModernBlock
{ {
@@ -126,7 +124,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore
foreach (ModernBlock block in blocks) foreach (ModernBlock block in blocks)
{ {
if (block.ValueAsInt == value) if (block.ValueAsInteger == value)
{ {
return new ModernBlock return new ModernBlock
{ {
@@ -150,7 +148,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore
{ {
ModernBlock block = blocks[i]; ModernBlock block = blocks[i];
if (block.ValueAsStr == value) if (block.ValueAsString == value)
{ {
block.Data = data; block.Data = data;
blocks[i] = block; blocks[i] = block;
@@ -169,7 +167,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore
{ {
ModernBlock block = blocks[i]; ModernBlock block = blocks[i];
if (block.ValueAsInt == value) if (block.ValueAsInteger == value)
{ {
block.Data = data; block.Data = data;
blocks[i] = block; blocks[i] = block;
@@ -208,7 +206,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore
foreach (ModernBlock block in blocks) foreach (ModernBlock block in blocks)
{ {
if (block.ValueAsStr == value) if (block.ValueAsString == value)
{ {
blocks.Remove(block); blocks.Remove(block);
break; break;
@@ -227,7 +225,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore
foreach (ModernBlock block in blocks) foreach (ModernBlock block in blocks)
{ {
if (block.ValueAsInt == value) if (block.ValueAsInteger == value)
{ {
blocks.Remove(block); blocks.Remove(block);
break; break;
@@ -245,7 +243,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore
return Path.Combine(Environment.ExpandEnvironmentVariables(sppRoot), "data.dat"); return Path.Combine(Environment.ExpandEnvironmentVariables(sppRoot), "data.dat");
} }
public PhysicalStore(PSVersion version, bool production) public PhysicalStore(PhysicalStoreVersion version, bool production)
{ {
Version = version; Version = version;
Production = production; Production = production;

View File

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

View File

@@ -74,7 +74,7 @@ namespace MetroUnlocker.LibTSForge.SPP
} }
} }
public class PKeyConfig public class ProductKeyConfig
{ {
public Dictionary<Guid, ProductConfig> Products = new Dictionary<Guid, ProductConfig>(); public Dictionary<Guid, ProductConfig> Products = new Dictionary<Guid, ProductConfig>();
private List<Guid> loadedPkeyConfigs = new List<Guid>(); private List<Guid> loadedPkeyConfigs = new List<Guid>();
@@ -194,7 +194,7 @@ namespace MetroUnlocker.LibTSForge.SPP
throw new FileNotFoundException("Failed to find product matching supplied product key parameters."); throw new FileNotFoundException("Failed to find product matching supplied product key parameters.");
} }
public PKeyConfig() public ProductKeyConfig()
{ {
} }

View File

@@ -70,21 +70,21 @@ namespace MetroUnlocker.LibTSForge.SPP
{ {
new CRCBlock new CRCBlock
{ {
DataType = CRCBlockType.STRING, DataType = CRCBlockType.String,
KeyAsStr = "SppPkeyBindingProductKey", KeyAsString = "SppPkeyBindingProductKey",
ValueAsStr = ToString() ValueAsString = ToString()
}, },
new CRCBlock new CRCBlock
{ {
DataType = CRCBlockType.BINARY, DataType = CRCBlockType.Binary,
KeyAsStr = "SppPkeyBindingMiscData", KeyAsString = "SppPkeyBindingMiscData",
Value = new byte[] { } Value = new byte[] { }
}, },
new CRCBlock new CRCBlock
{ {
DataType = CRCBlockType.STRING, DataType = CRCBlockType.String,
KeyAsStr = "SppPkeyBindingAlgorithm", KeyAsString = "SppPkeyBindingAlgorithm",
ValueAsStr = GetAlgoUri() ValueAsString = GetAlgoUri()
} }
}); });
@@ -245,7 +245,7 @@ namespace MetroUnlocker.LibTSForge.SPP
); );
} }
public byte[] GetPhoneData(PSVersion version) public byte[] GetPhoneData(PhysicalStoreVersion version)
{ {
int serialHigh = Serial / 1000000; int serialHigh = Serial / 1000000;
int serialLow = Serial % 1000000; int serialLow = Serial % 1000000;

View File

@@ -13,12 +13,12 @@ namespace MetroUnlocker.LibTSForge.SPP
{ {
public static class SLApi public static class SLApi
{ {
private enum SLIDTYPE private enum SLIDType
{ {
SL_ID_APPLICATION, SLIDApplication,
SL_ID_PRODUCT_SKU, SLIDProductSku,
SL_ID_LICENSE_FILE, SLIDLicenseFile,
SL_ID_LICENSE, SLIDLicense,
SL_ID_PKEY, SL_ID_PKEY,
SL_ID_ALL_LICENSES, SL_ID_ALL_LICENSES,
SL_ID_ALL_LICENSE_FILES, SL_ID_ALL_LICENSE_FILES,
@@ -26,7 +26,7 @@ namespace MetroUnlocker.LibTSForge.SPP
SL_ID_LAST SL_ID_LAST
} }
private enum SLDATATYPE private enum SLDataType
{ {
SL_DATA_NONE, SL_DATA_NONE,
SL_DATA_SZ, SL_DATA_SZ,
@@ -37,7 +37,7 @@ namespace MetroUnlocker.LibTSForge.SPP
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
private struct SL_LICENSING_STATUS private struct SLLicensingStatus
{ {
public Guid SkuId; public Guid SkuId;
public uint eStatus; public uint eStatus;
@@ -47,8 +47,6 @@ namespace MetroUnlocker.LibTSForge.SPP
public ulong qwValidityExpiration; 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)] [DllImport("sppc.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
private static extern void SLOpen(out IntPtr hSLC); private static extern void SLOpen(out IntPtr hSLC);
@@ -65,7 +63,7 @@ namespace MetroUnlocker.LibTSForge.SPP
private static extern uint SLUninstallProofOfPurchase(IntPtr hSLC, ref Guid PKeyId); private static extern uint SLUninstallProofOfPurchase(IntPtr hSLC, ref Guid PKeyId);
[DllImport("sppc.dll", CharSet = CharSet.Unicode)] [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); 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)] [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); private static extern uint SLActivateProduct(IntPtr hSLC, ref Guid pProductSkuId, byte[] cbAppSpecificData, byte[] pvAppSpecificData, byte[] pActivationInfo, string pwszProxyServer, ushort wProxyPort);
@@ -77,7 +75,7 @@ namespace MetroUnlocker.LibTSForge.SPP
private static extern uint SLDepositOfflineConfirmationId(IntPtr hSLC, ref Guid pProductSkuId, string pwszInstallationId, string pwszConfirmationId); private static extern uint SLDepositOfflineConfirmationId(IntPtr hSLC, ref Guid pProductSkuId, string pwszInstallationId, string pwszConfirmationId);
[DllImport("sppc.dll", CharSet = CharSet.Unicode)] [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); 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)] [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); private static extern void SLGetLicensingStatusInformation(IntPtr hSLC, ref Guid pAppID, IntPtr pProductSkuId, string pwszRightName, out uint pnStatusCount, out IntPtr ppLicensingStatus);
@@ -89,7 +87,7 @@ namespace MetroUnlocker.LibTSForge.SPP
private static extern uint SLConsumeWindowsRight(uint unknown); private static extern uint SLConsumeWindowsRight(uint unknown);
[DllImport("slc.dll", CharSet = CharSet.Unicode)] [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); 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)] [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); private static extern uint SLGetProductSkuInformation(IntPtr hSLC, ref Guid pProductSkuId, string pwszValueName, IntPtr peDataType, out uint pcbValue, out IntPtr ppbValue);
@@ -128,7 +126,7 @@ namespace MetroUnlocker.LibTSForge.SPP
{ {
using (SLContext sl = new SLContext()) using (SLContext sl = new SLContext())
{ {
SLDATATYPE type; SLDataType type;
uint len; uint len;
IntPtr ppReturnLics; IntPtr ppReturnLics;
@@ -144,17 +142,17 @@ namespace MetroUnlocker.LibTSForge.SPP
} }
} }
public static Guid GetLicenseFileId(Guid licId) public static Guid GetLicenseFileId(Guid licenseId)
{ {
using (SLContext sl = new SLContext()) using (SLContext sl = new SLContext())
{ {
uint status; uint status;
uint count; 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 = SLGetSLIDList(sl.Handle, SLIDType.SLIDLicense, ref licenseId, SLIDType.SLIDLicenseFile, 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;//new Guid(Marshal.PtrToStringAuto(returnLicenses));
} }
} }
@@ -168,9 +166,7 @@ namespace MetroUnlocker.LibTSForge.SPP
IntPtr dataPtr; IntPtr dataPtr;
if (SLGetLicense(sl.Handle, ref fileId, out dataLen, out dataPtr) != 0) if (SLGetLicense(sl.Handle, ref fileId, out dataLen, out dataPtr) != 0)
{
return null; return null;
}
byte[] data = new byte[dataLen]; byte[] data = new byte[dataLen];
Marshal.Copy(dataPtr, data, 0, (int)dataLen); Marshal.Copy(dataPtr, data, 0, (int)dataLen);
@@ -180,22 +176,20 @@ namespace MetroUnlocker.LibTSForge.SPP
} }
} }
public static string GetMetaStr(Guid actId, string value) public static string GetMetaStr(Guid productSkuId, string value)
{ {
using (SLContext sl = new SLContext()) using (SLContext sl = new SLContext())
{ {
uint len; uint length;
SLDATATYPE type; SLDataType type;
IntPtr ppbValue; IntPtr binaryValue;
uint status = SLGetProductSkuInformation(sl.Handle, ref actId, value, out type, out len, out ppbValue); uint status = 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.SL_DATA_SZ)
{
return null; return null;
}
return Marshal.PtrToStringAuto(ppbValue); return Marshal.PtrToStringAuto(binaryValue);
} }
} }
@@ -213,18 +207,17 @@ namespace MetroUnlocker.LibTSForge.SPP
} }
} }
public static Guid GetInstalledPkeyId(Guid actId) public static Guid GetInstalledProductKeyId(Guid actId)
{ {
using (SLContext sl = new SLContext()) using (SLContext sl = new SLContext())
{ {
uint status; uint status;
uint count; uint count;
IntPtr pProductKeyIds; IntPtr productKeyIds;
status = SLGetInstalledProductKeyIds(sl.Handle, ref actId, out count, out pProductKeyIds); status = SLGetInstalledProductKeyIds(sl.Handle, ref actId, out count, out productKeyIds);
//unsafe { return *(Guid*)pProductKeyIds; } return (status == 0 && count != 0) ? (Guid)Marshal.PtrToStructure(productKeyIds, typeof(Guid)) : Guid.Empty;
return (status == 0 && count != 0) ? (Guid)Marshal.PtrToStructure(pProductKeyIds, typeof(Guid)) : Guid.Empty;
} }
} }
@@ -243,7 +236,7 @@ namespace MetroUnlocker.LibTSForge.SPP
{ {
using (SLContext sl = new SLContext()) using (SLContext sl = new SLContext())
{ {
SLDATATYPE type; SLDataType type;
uint count; uint count;
IntPtr ppbValue; IntPtr ppbValue;
@@ -255,9 +248,7 @@ namespace MetroUnlocker.LibTSForge.SPP
public static void FireStateChangedEvent(Guid appId) public static void FireStateChangedEvent(Guid appId)
{ {
using (SLContext sl = new SLContext()) using (SLContext sl = new SLContext())
{
SLFireEvent(sl.Handle, "msft:rm/event/licensingstatechanged", ref appId); SLFireEvent(sl.Handle, "msft:rm/event/licensingstatechanged", ref appId);
}
} }
public static Guid GetAppId(Guid actId) public static Guid GetAppId(Guid actId)
@@ -267,7 +258,7 @@ namespace MetroUnlocker.LibTSForge.SPP
uint count; uint count;
IntPtr pAppIds; IntPtr pAppIds;
uint status = SLGetSLIDList(sl.Handle, SLIDTYPE.SL_ID_PRODUCT_SKU, ref actId, SLIDTYPE.SL_ID_APPLICATION, out count, out pAppIds); uint status = SLGetSLIDList(sl.Handle, SLIDType.SLIDProductSku, ref actId, SLIDType.SLIDApplication, out count, out pAppIds);
if (status != 0 || count == 0) if (status != 0 || count == 0)
return Guid.Empty; return Guid.Empty;
@@ -281,7 +272,7 @@ namespace MetroUnlocker.LibTSForge.SPP
using (SLContext sl = new SLContext()) using (SLContext sl = new SLContext())
{ {
uint count; uint count;
SLDATATYPE type; SLDataType type;
IntPtr ppbValue; IntPtr ppbValue;
uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "DependsOn", out type, out count, out ppbValue); uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "DependsOn", out type, out count, out ppbValue);

View File

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

View File

@@ -4,8 +4,9 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.IO; using System.IO;
using Microsoft.Win32; using System.Runtime.InteropServices;
using Microsoft.Win32;
using MetroUnlocker.LibTSForge.SPP; using MetroUnlocker.LibTSForge.SPP;
using MetroUnlocker.LibTSForge.PhysicalStore; using MetroUnlocker.LibTSForge.PhysicalStore;
@@ -21,39 +22,37 @@ namespace MetroUnlocker
uint status = SLApi.DepositConfirmationId(actId, instId, Constants.ZeroCID); uint status = SLApi.DepositConfirmationId(actId, instId, Constants.ZeroCID);
if (status != 0) 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); string instId = SLApi.GetInstallationId(activationId);
Guid pkeyId = SLApi.GetInstalledPkeyId(actId); Guid pkeyId = SLApi.GetInstalledProductKeyId(activationId);
Utils.KillSPP(); Utils.KillSPP();
using (PhysicalStore store = new PhysicalStore(version, production)) 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)); 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()); ModernBlock keyBlock = store.GetBlock(key, pkeyId.ToString());
if (keyBlock == null) if (keyBlock == null)
{ throw new InvalidDataException("Failed to get product key data for activation ID: 0x" + activationId + ".");
throw new InvalidDataException("Failed to get product key data for activation ID: 0x" + actId + ".");
}
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"); keyBag.DeleteBlock("SppPkeyVirtual");
store.SetBlock(key, pkeyId.ToString(), pkb.Serialize()); store.SetBlock(key, pkeyId.ToString(), keyBag.Serialize());
BinaryWriter writer = new BinaryWriter(new MemoryStream()); BinaryWriter writer = new BinaryWriter(new MemoryStream());
writer.Write(0x20); writer.Write(0x20);
@@ -69,27 +68,15 @@ namespace MetroUnlocker
writer.Write(pkeyData); writer.Write(pkeyData);
byte[] tsPkeyInfoData = Utils.GetBytes(writer); byte[] tsPkeyInfoData = Utils.GetBytes(writer);
string path = "msft:Windows/7.0/Phone/Cached/";
store.AddBlocks(new ModernBlock[] { store.AddBlocks(new ModernBlock[] {
new ModernBlock new ModernBlock(key, path + "HwidBlock/" + pkeyId, tsHwidData),
{ new ModernBlock(key, path + "PKeyInfo/" + pkeyId, tsPkeyInfoData)
Type = BlockType.NAMED,
Flags = 0,
KeyAsStr = key,
ValueAsStr = "msft:Windows/7.0/Phone/Cached/HwidBlock/" + pkeyId,
Data = tsHwidData
},
new ModernBlock
{
Type = BlockType.NAMED,
Flags = 0,
KeyAsStr = key,
ValueAsStr = "msft:Windows/7.0/Phone/Cached/PKeyInfo/" + pkeyId,
Data = tsPkeyInfoData
}
}); });
} }
Deposit(actId, instId); Deposit(activationId, instId);
SLApi.RefreshLicenseStatus(); SLApi.RefreshLicenseStatus();
SLApi.FireStateChangedEvent(appId); SLApi.FireStateChangedEvent(appId);

View File

@@ -57,11 +57,12 @@
<Compile Include="App.Designer.cs"> <Compile Include="App.Designer.cs">
<DependentUpon>App.cs</DependentUpon> <DependentUpon>App.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="LibTSForge\Common.cs" /> <Compile Include="Common.cs" />
<Compile Include="LibTSForge\Crypto\CryptoUtils.cs" /> <Compile Include="LibTSForge\Crypto\CryptoUtils.cs" />
<Compile Include="LibTSForge\Crypto\Keys.cs" /> <Compile Include="LibTSForge\Crypto\Keys.cs" />
<Compile Include="LibTSForge\Crypto\PhysicalStoreCrypto.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\CRCBlock.cs" />
<Compile Include="LibTSForge\PhysicalStore\ModernBlock.cs" /> <Compile Include="LibTSForge\PhysicalStore\ModernBlock.cs" />
<Compile Include="LibTSForge\PhysicalStore\PhysicalStore.cs" /> <Compile Include="LibTSForge\PhysicalStore\PhysicalStore.cs" />
@@ -74,13 +75,9 @@
<Compile Include="LibTSForge\ZeroCID.cs" /> <Compile Include="LibTSForge\ZeroCID.cs" />
<Compile Include="LOBManager.cs" /> <Compile Include="LOBManager.cs" />
<Compile Include="ProductPolicy\ProductPolicy.cs" /> <Compile Include="ProductPolicy\ProductPolicy.cs" />
<Compile Include="ProductPolicy\ProductPolicyEditor.cs" /> <Compile Include="ProductPolicy\ProductPolicyReader.cs" />
<Compile Include="ProductPolicy\Tools.cs" />
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Rebooter.cs" />
<Compile Include="SPPManager.cs" />
<Compile Include="StartupArguments.cs" />
<EmbeddedResource Include="App.resx"> <EmbeddedResource Include="App.resx">
<DependentUpon>App.cs</DependentUpon> <DependentUpon>App.cs</DependentUpon>
</EmbeddedResource> </EmbeddedResource>
@@ -93,7 +90,9 @@
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon> <DependentUpon>Resources.resx</DependentUpon>
</Compile> </Compile>
<None Include="app.manifest" /> <None Include="app.manifest">
<SubType>Designer</SubType>
</None>
<None Include="Properties\Settings.settings"> <None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator> <Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput> <LastGenOutput>Settings.Designer.cs</LastGenOutput>

View File

@@ -7,57 +7,20 @@ using System.Runtime.InteropServices;
using Microsoft.Win32; using Microsoft.Win32;
namespace MetroUnlocker.ProductPolicy namespace MetroUnlocker.ProductPolicy
{ {
//public struct ProductPolicyData
//{
// public string String;
// public byte[] Bytes;
// public uint DWord;
//};
class ProductPolicy class ProductPolicy
{ {
public bool Modified { get; set; }
public ProductPolicyValue Header { get; set; } public ProductPolicyValue Header { get; set; }
public string Name { 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 byte[] Bytes { get; set; }
public string StringValue public string StringValue { get { return Encoding.Unicode.GetString(Bytes); } }
{ public uint DWordValue { get { return BitConverter.ToUInt32(Bytes, 0); } }
get
{
return Encoding.Unicode.GetString(Bytes);
}
set {
Bytes = Encoding.Unicode.GetBytes(value);
}
}
public uint DWordValue
{
get
{
return BitConverter.ToUInt32(Bytes, 0);
}
set
{
Bytes = BitConverter.GetBytes(value);
}
}
public RegistryValueKind Type public RegistryValueKind Type
{ {
get get { return (RegistryValueKind)Header.DataType; }
{
return (RegistryValueKind)Header.DataType;
}
} }
private void NameFromBin(ref byte[] PolicyBlob, int offset) private void NameFromBin(ref byte[] PolicyBlob, int offset)
@@ -74,12 +37,10 @@ namespace MetroUnlocker.ProductPolicy
public void FromBin(ref byte[] PolicyBlob, int offset) public void FromBin(ref byte[] PolicyBlob, int offset)
{ {
Header = Tools.BytesToStruct<ProductPolicyValue>(PolicyBlob, typeof(ProductPolicyValue), offset); Header = ProductPolicyReader.BytesToStruct<ProductPolicyValue>(PolicyBlob, offset);
if ((Header.Data + Header.Name + Marshal.SizeOf(Header)) > Header.Size || if ((Header.Data + Header.Name + Marshal.SizeOf(Header)) > Header.Size || (offset + Header.Size) > PolicyBlob.Length)
(offset + Header.Size) > PolicyBlob.Length) throw new Exception("Invalid data Header format");
{
throw new Exception("Invalid _data Header format");
}
NameFromBin(ref PolicyBlob, offset); NameFromBin(ref PolicyBlob, offset);
ValFromBin(ref PolicyBlob, offset); ValFromBin(ref PolicyBlob, offset);
} }
@@ -97,57 +58,6 @@ namespace MetroUnlocker.ProductPolicy
} }
} }
public int Size() public int Size() { return Bytes.Length; }
{
//switch (Type)
//{
// case RegistryValueKind.String:
// return StringValue.Length * 2;
// case RegistryValueKind.DWord:
// return 4;
// default:
// return Bytes.Length;
//}
return Bytes.Length;
}
//public byte[] ToBinary()
//{
// switch (Type)
// {
// case RegistryValueKind.String:
// return Encoding.Unicode.GetBytes(_data.String);
// case RegistryValueKind.DWord:
// return Tools.StructToBytes(DWordVq);
// default:
// return Bytes;
// }
//}
public byte[] ToBin()
{
ProductPolicyValue value = new ProductPolicyValue();
value.Name = (UInt16)(2 * Name.Length);
value.Data = (UInt16)Size();
int datablocksize = Marshal.SizeOf(Header) + value.Name + value.Data;
int suffixLength = 4 - (datablocksize % 4);
value.Size = (UInt16)(Marshal.SizeOf(Header) + value.Name + value.Data + suffixLength);
value.DataType = Header.DataType;
value.Unknown1 = Header.Unknown1;
value.Unknown2 = Header.Unknown2;
byte[] bytes = Tools.StructToBytes(value);
Tools.AppendBytes(ref bytes, Encoding.Unicode.GetBytes(Name));
Tools.AppendBytes(ref bytes, Bytes);
Tools.PaddingAppend(ref bytes, suffixLength);
return bytes;
}
// I would like to not split the data into dword and string on parsing but on getting.
//public void SetDWordValue(uint value)
//{
// Data = new ProductPolicyData { DWord = value };
//}
} }
} }

View File

@@ -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,16 +1,25 @@
# MetroUnlocker # Sideloading Unlocker
![Preview](MetroUnlocker.png "Sideloading Unlocker")
## Unlock signed sideloading on: ## Unlock signed sideloading on:
- Windows 8.0 and up - 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 takes a while to activate. If it doesn't happen automatically, use Product Policy Editor to disable SPPSVC, set the system clock to 2026, try sideloading until it activates and revert the clock and enable SPPSVC again. Development sideloading might take a while to activate. If it doesn't happen fast enough, use Product Policy Editor to disable SPPSVC, set the system clock to 2026, try sideloading until it activates, revert the clock and enable SPPSVC again.
Known bug:
If you have 0 bytes free on your disk, it might fail to write the new tokens, leaving the tokens file empty and when SPPSVC starts, it will recreate the file but everything will be deactivated including Windows itself.
MetroUnlocker always tries to make a backup of your tokens before modifying them. Just make sure you have at least 30MB free before trying to activate sideloading. If something goes wrong, just restore the tokens.dat from the backup to `C:\Windows\System32\spp\store\2.0\`. In worst case you can just reactivate what you want 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! Huge thanks to [TSForge](https://github.com/massgravel/TSforge) for making this possible by reverse engineering SPPSVC!