From f90695dfda5694d02a510bf4bc143b675c9ee57a Mon Sep 17 00:00:00 2001 From: Mona Lassa Date: Thu, 22 May 2025 01:31:03 +0200 Subject: [PATCH] First release build. --- MetroUnlocker.png | Bin 0 -> 17363 bytes MetroUnlocker/App.Designer.cs | 131 ++------ MetroUnlocker/App.cs | 80 ++--- MetroUnlocker/App.resx | 313 ++++-------------- MetroUnlocker/{LibTSForge => }/Common.cs | 37 +-- MetroUnlocker/LOBManager.cs | 40 +-- .../LibTSForge/Crypto/CryptoUtils.cs | 6 - MetroUnlocker/LibTSForge/Crypto/Keys.cs | 4 +- .../LibTSForge/Crypto/PhysicalStoreCrypto.cs | 14 +- ...nPKeyInstall.cs => ProductKeyInstaller.cs} | 26 +- .../LibTSForge/PhysicalStore/BasicBlock.cs | 29 ++ .../LibTSForge/PhysicalStore/CRCBlock.cs | 110 ++---- .../LibTSForge/PhysicalStore/ModernBlock.cs | 94 ++---- .../LibTSForge/PhysicalStore/PhysicalStore.cs | 26 +- .../LibTSForge/PhysicalStore/VariableBag.cs | 40 +-- MetroUnlocker/LibTSForge/SPP/PKeyConfig.cs | 4 +- MetroUnlocker/LibTSForge/SPP/ProductKey.cs | 18 +- MetroUnlocker/LibTSForge/SPP/SLAPI.cs | 67 ++-- .../LibTSForge/TokenStore/TokenEntry.cs | 17 +- .../LibTSForge/TokenStore/TokenStore.cs | 123 ++----- MetroUnlocker/LibTSForge/ZeroCID.cs | 51 ++- MetroUnlocker/MetroUnlocker.csproj | 15 +- MetroUnlocker/ProductPolicy/ProductPolicy.cs | 106 +----- .../ProductPolicy/ProductPolicyEditor.cs | 157 --------- .../ProductPolicy/ProductPolicyReader.cs | 101 ++++++ MetroUnlocker/ProductPolicy/Tools.cs | 82 ----- MetroUnlocker/Rebooter.cs | 33 -- MetroUnlocker/SPPManager.cs | 100 ------ MetroUnlocker/StartupArguments.cs | 49 --- README.md | 15 +- 30 files changed, 499 insertions(+), 1389 deletions(-) create mode 100644 MetroUnlocker.png rename MetroUnlocker/{LibTSForge => }/Common.cs (91%) rename MetroUnlocker/LibTSForge/Modifiers/{GenPKeyInstall.cs => ProductKeyInstaller.cs} (51%) create mode 100644 MetroUnlocker/LibTSForge/PhysicalStore/BasicBlock.cs delete mode 100644 MetroUnlocker/ProductPolicy/ProductPolicyEditor.cs create mode 100644 MetroUnlocker/ProductPolicy/ProductPolicyReader.cs delete mode 100644 MetroUnlocker/ProductPolicy/Tools.cs delete mode 100644 MetroUnlocker/Rebooter.cs delete mode 100644 MetroUnlocker/SPPManager.cs delete mode 100644 MetroUnlocker/StartupArguments.cs diff --git a/MetroUnlocker.png b/MetroUnlocker.png new file mode 100644 index 0000000000000000000000000000000000000000..87c7924a84d1d9dbf10ff8a27effe4f761163548 GIT binary patch literal 17363 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 P00000NkvXXu0mjfZ8-Df literal 0 HcmV?d00001 diff --git a/MetroUnlocker/App.Designer.cs b/MetroUnlocker/App.Designer.cs index b0b60a5..b090dc1 100644 --- a/MetroUnlocker/App.Designer.cs +++ b/MetroUnlocker/App.Designer.cs @@ -29,35 +29,17 @@ private void InitializeComponent() { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(App)); - this.temporaryButton = new System.Windows.Forms.Button(); this.developmentCheckbox = new System.Windows.Forms.CheckBox(); this.signedCheckbox = new System.Windows.Forms.CheckBox(); this.allUsersCheckbox = new System.Windows.Forms.CheckBox(); this.statusTextLabel = new System.Windows.Forms.Label(); this.statusLabel = new System.Windows.Forms.Label(); - this.LOBCheckBox = new System.Windows.Forms.CheckBox(); - this.SPPCheckBox = new System.Windows.Forms.CheckBox(); - this.groupBox1 = new System.Windows.Forms.GroupBox(); - this.groupBox2 = new System.Windows.Forms.GroupBox(); - this.Manual = new System.Windows.Forms.TabControl(); - this.tabPage1 = new System.Windows.Forms.TabPage(); - this.button1 = new System.Windows.Forms.Button(); - this.tabPage2 = new System.Windows.Forms.TabPage(); - this.button2 = new System.Windows.Forms.Button(); - this.groupBox1.SuspendLayout(); - this.groupBox2.SuspendLayout(); - this.Manual.SuspendLayout(); - this.tabPage1.SuspendLayout(); - this.tabPage2.SuspendLayout(); + this.groupBox = new System.Windows.Forms.GroupBox(); + this.disableButton = new System.Windows.Forms.Button(); + this.unlockButton = new System.Windows.Forms.Button(); + this.groupBox.SuspendLayout(); this.SuspendLayout(); // - // temporaryButton - // - resources.ApplyResources(this.temporaryButton, "temporaryButton"); - this.temporaryButton.Name = "temporaryButton"; - this.temporaryButton.UseVisualStyleBackColor = true; - this.temporaryButton.Click += new System.EventHandler(this.button1_Click); - // // developmentCheckbox // resources.ApplyResources(this.developmentCheckbox, "developmentCheckbox"); @@ -89,79 +71,36 @@ resources.ApplyResources(this.statusLabel, "statusLabel"); this.statusLabel.Name = "statusLabel"; // - // LOBCheckBox + // groupBox // - resources.ApplyResources(this.LOBCheckBox, "LOBCheckBox"); - this.LOBCheckBox.Name = "LOBCheckBox"; - this.LOBCheckBox.UseVisualStyleBackColor = true; + resources.ApplyResources(this.groupBox, "groupBox"); + this.groupBox.Controls.Add(this.signedCheckbox); + this.groupBox.Controls.Add(this.allUsersCheckbox); + this.groupBox.Controls.Add(this.developmentCheckbox); + this.groupBox.Name = "groupBox"; + this.groupBox.TabStop = false; // - // SPPCheckBox + // disableButton // - resources.ApplyResources(this.SPPCheckBox, "SPPCheckBox"); - this.SPPCheckBox.Name = "SPPCheckBox"; - this.SPPCheckBox.UseVisualStyleBackColor = true; + resources.ApplyResources(this.disableButton, "disableButton"); + this.disableButton.Name = "disableButton"; + this.disableButton.UseVisualStyleBackColor = true; + this.disableButton.Click += new System.EventHandler(this.Uninstall); // - // groupBox1 + // unlockButton // - resources.ApplyResources(this.groupBox1, "groupBox1"); - this.groupBox1.Controls.Add(this.signedCheckbox); - this.groupBox1.Controls.Add(this.allUsersCheckbox); - this.groupBox1.Controls.Add(this.developmentCheckbox); - this.groupBox1.Name = "groupBox1"; - this.groupBox1.TabStop = false; - // - // groupBox2 - // - resources.ApplyResources(this.groupBox2, "groupBox2"); - this.groupBox2.Controls.Add(this.LOBCheckBox); - this.groupBox2.Controls.Add(this.SPPCheckBox); - this.groupBox2.Controls.Add(this.temporaryButton); - this.groupBox2.Name = "groupBox2"; - this.groupBox2.TabStop = false; - // - // Manual - // - resources.ApplyResources(this.Manual, "Manual"); - this.Manual.Controls.Add(this.tabPage1); - this.Manual.Controls.Add(this.tabPage2); - this.Manual.Name = "Manual"; - this.Manual.SelectedIndex = 0; - // - // tabPage1 - // - this.tabPage1.Controls.Add(this.button2); - this.tabPage1.Controls.Add(this.button1); - resources.ApplyResources(this.tabPage1, "tabPage1"); - this.tabPage1.Name = "tabPage1"; - this.tabPage1.UseVisualStyleBackColor = true; - // - // button1 - // - resources.ApplyResources(this.button1, "button1"); - this.button1.Name = "button1"; - this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.JailbreakButton_Click); - // - // tabPage2 - // - this.tabPage2.Controls.Add(this.groupBox2); - this.tabPage2.Controls.Add(this.groupBox1); - resources.ApplyResources(this.tabPage2, "tabPage2"); - this.tabPage2.Name = "tabPage2"; - this.tabPage2.UseVisualStyleBackColor = true; - // - // button2 - // - resources.ApplyResources(this.button2, "button2"); - this.button2.Name = "button2"; - this.button2.UseVisualStyleBackColor = true; - this.button2.Click += new System.EventHandler(this.Uninstall); + resources.ApplyResources(this.unlockButton, "unlockButton"); + this.unlockButton.Name = "unlockButton"; + this.unlockButton.UseVisualStyleBackColor = true; + this.unlockButton.Click += new System.EventHandler(this.Jailbreak); // // App // resources.ApplyResources(this, "$this"); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.Controls.Add(this.Manual); + this.Controls.Add(this.disableButton); + this.Controls.Add(this.groupBox); + this.Controls.Add(this.unlockButton); this.Controls.Add(this.statusLabel); this.Controls.Add(this.statusTextLabel); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; @@ -171,13 +110,8 @@ this.ShowIcon = false; this.ShowInTaskbar = false; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.groupBox1.ResumeLayout(false); - this.groupBox1.PerformLayout(); - this.groupBox2.ResumeLayout(false); - this.groupBox2.PerformLayout(); - this.Manual.ResumeLayout(false); - this.tabPage1.ResumeLayout(false); - this.tabPage2.ResumeLayout(false); + this.groupBox.ResumeLayout(false); + this.groupBox.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -185,21 +119,14 @@ #endregion - private System.Windows.Forms.Button temporaryButton; private System.Windows.Forms.CheckBox developmentCheckbox; private System.Windows.Forms.CheckBox signedCheckbox; private System.Windows.Forms.CheckBox allUsersCheckbox; private System.Windows.Forms.Label statusTextLabel; private System.Windows.Forms.Label statusLabel; - private System.Windows.Forms.GroupBox groupBox2; - private System.Windows.Forms.CheckBox LOBCheckBox; - private System.Windows.Forms.CheckBox SPPCheckBox; - private System.Windows.Forms.GroupBox groupBox1; - private System.Windows.Forms.TabControl Manual; - private System.Windows.Forms.TabPage tabPage1; - private System.Windows.Forms.Button button1; - private System.Windows.Forms.TabPage tabPage2; - private System.Windows.Forms.Button button2; + private System.Windows.Forms.GroupBox groupBox; + private System.Windows.Forms.Button unlockButton; + private System.Windows.Forms.Button disableButton; } } diff --git a/MetroUnlocker/App.cs b/MetroUnlocker/App.cs index 41a94d5..341dcb3 100644 --- a/MetroUnlocker/App.cs +++ b/MetroUnlocker/App.cs @@ -6,6 +6,7 @@ using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; +using System.Runtime.InteropServices; using System.Diagnostics; using Microsoft.Win32; @@ -60,82 +61,36 @@ namespace MetroUnlocker public void UpdatePolicyState() { - var productPolicyEditor = new ProductPolicyEditor(); + var productPolicyEditor = new ProductPolicyReader(); var policyState = productPolicyEditor.GetPolicyStateByName("WSLicensingService-LOBSideloadingActivated"); var isSideloadingKeyInstalled = LOBManager.IsSideloadingKeyInstalled(); + statusLabel.ForeColor = isSideloadingKeyInstalled ? Color.DarkGreen: Color.DarkOrange; + disableButton.Enabled = isSideloadingKeyInstalled; + switch (policyState) { case PolicyState.Disabled: - statusLabel.Text = "Disabled"; - statusLabel.ForeColor = Color.DarkRed; - break; - case PolicyState.Enabled: if (isSideloadingKeyInstalled) - { - statusLabel.Text = "Sideloading enabled"; - statusLabel.ForeColor = Color.DarkGreen; - } + statusLabel.Text = "Enabling..."; else { - statusLabel.Text = "Sideloading will be disabled soon"; - statusLabel.ForeColor = Color.DarkOrange; + statusLabel.Text = "Disabled"; + statusLabel.ForeColor = Color.DarkRed; } break; - case PolicyState.Unknown: + case PolicyState.Enabled: + statusLabel.Text = isSideloadingKeyInstalled ? "Sideloading enabled" : "Disabling..."; + break; + default: statusLabel.Text = "Unknown"; statusLabel.ForeColor = Color.Black; break; } } - private string CombineArguments(params string[] arguments) - { - return string.Join(" ", arguments); - } - - private void SetSetupParameter(string key, object value, RegistryValueKind valueKind) - { - Registry.SetValue("HKEY_LOCAL_MACHINE\\SYSTEM\\Setup", key, value, valueKind); - } - - private void SetSetupType(int type) - { - SetSetupParameter("SetupType", type, RegistryValueKind.DWord); - } - - private void button1_Click(object sender, EventArgs e) - { - StartupArgument startupArgument; - - if (LOBCheckBox.Checked && SPPCheckBox.Checked) - startupArgument = StartupArgument.EnableLOBAndEnableSPP; - else if (LOBCheckBox.Checked) - startupArgument = StartupArgument.EnableLOBAndDisableSPP; - else if (SPPCheckBox.Checked) - startupArgument = StartupArgument.DisableLOBAndEnableSPP; - else - startupArgument = StartupArgument.DisableLOBAndDisableSPP; - - string commandLine = CombineArguments(new string[] { Application.ExecutablePath, StartupArguments.GetStartupArgumentString(startupArgument) }); - - SetSetupParameter("CmdLine", commandLine, RegistryValueKind.String); - SetSetupType(1); - DialogResult result = MessageBox.Show("Sideloading will be enabled after a reboot. Would you like to reboot now?", "Reboot?", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question); - - switch (result) - { - case DialogResult.Yes: - Rebooter.Reboot(); - break; - case DialogResult.Cancel: - SetSetupType(0); - break; - } - } - - private void JailbreakButton_Click(object sender, EventArgs e) + private void Jailbreak(object sender, EventArgs e) { try { @@ -145,12 +100,19 @@ namespace MetroUnlocker return; LOBManager.ActivateZeroCID(); + + LOBEnabled = true; + DevelopmentEnabled = true; + MessageBox.Show(this, "Sideloading activated!", "Success!", MessageBoxButtons.OK, MessageBoxIcon.Information); + UpdatePolicyState(); } catch (Exception ex) { - MessageBox.Show(this, ex.Message, "Error while activating sideloading!", MessageBoxButtons.OK, MessageBoxIcon.Error); + if (ex is COMException && ((uint)((COMException)ex).ErrorCode) == 0xC004F014) + MessageBox.Show(this, "You likely ran out of storage or something else caused your tokens.dat to get corrupted. SPPSVC will recreate it. Try rebooting to let Windows reactivate itself before trying again. Make sure you have at least 30MB free before using Sideloading Unlocker.", "The key was recognised but I can't activate it.", MessageBoxButtons.OK, MessageBoxIcon.Error); + else MessageBox.Show(this, ex.Message, "Error while activating sideloading!", MessageBoxButtons.OK, MessageBoxIcon.Error); } } diff --git a/MetroUnlocker/App.resx b/MetroUnlocker/App.resx index 29e7d62..e90e407 100644 --- a/MetroUnlocker/App.resx +++ b/MetroUnlocker/App.resx @@ -117,221 +117,59 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Bottom, Left, Right - - - - 6, 42 - - - 210, 23 - - - - 0 - - - Reboot to Apply - - - temporaryButton - - - System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - groupBox2 - - - 2 - Allows sideloading of unpackaged apps. + True True + 6, 13 True + GrowAndShrink - 266, 215 + 252, 200 - - Top, Bottom, Left, Right + + Bottom, Left, Right - - 7, 123 + + 12, 165 - - 221, 23 + + 228, 23 - + 1 - + Disable Sideloading - - button2 + + disableButton - + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - tabPage1 + + $this - + 0 - - Top, Bottom, Left, Right - - - 6, 6 - - - 222, 111 - - - 0 - - - Unlock! - - - button1 - - - System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tabPage1 - - - 1 - - - 4, 22 - - - 3, 3, 3, 3 - - - 234, 152 - - - 0 - - - Jailbreak - - - tabPage1 - - - System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Manual - - - 0 - - - Top, Bottom, Left, Right - - - True - - - 6, 19 - - - 81, 17 - - - 1 - - - Sideloading - - - LOBCheckBox - - - System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - groupBox2 - - - 0 - - - True - - - 95, 19 - - - 119, 17 - - - 2 - - - Software Protection - - - SPPCheckBox - - - System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - groupBox2 - - - 1 - - - 6, 75 - - - 222, 71 - - - 8 - - - Product Policy - - - groupBox2 - - - System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tabPage2 - - - 0 - - - Top, Left, Right + + Bottom, Left, Right Enables sideloading of signed apps. @@ -358,7 +196,7 @@ System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - groupBox1 + groupBox 0 @@ -373,7 +211,7 @@ True - 149, 19 + 155, 19 67, 17 @@ -391,88 +229,67 @@ System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - groupBox1 + groupBox 1 - - 6, 6 + + 12, 96 - - 222, 63 + + 228, 63 - + 7 - + Group Policy - - groupBox1 + + groupBox - + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - tabPage2 - - - 1 - - - 4, 22 - - - 3, 3, 3, 3 - - - 234, 152 - - - 1 - - - Manual - - - tabPage2 - - - System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Manual - - - 1 - - - 12, 25 - - - 242, 178 - - - 9 - - - Manual - - - System.Windows.Forms.TabControl, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - + $this - + + 1 + + + Top, Bottom, Left, Right + + + 12, 25 + + + 228, 65 + + 0 + + Unlock! + + + unlockButton + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + Top, Right - 58, 9 + 44, 9 196, 13 @@ -496,7 +313,7 @@ $this - 1 + 3 True @@ -523,7 +340,7 @@ $this - 2 + 4 CenterScreen @@ -556,7 +373,7 @@ System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - groupBox1 + groupBox 2 diff --git a/MetroUnlocker/LibTSForge/Common.cs b/MetroUnlocker/Common.cs similarity index 91% rename from MetroUnlocker/LibTSForge/Common.cs rename to MetroUnlocker/Common.cs index ad842de..b506ecb 100644 --- a/MetroUnlocker/LibTSForge/Common.cs +++ b/MetroUnlocker/Common.cs @@ -14,7 +14,7 @@ using MetroUnlocker.LibTSForge.SPP; // Common.cs namespace MetroUnlocker { - public enum PSVersion + public enum PhysicalStoreVersion { Win8Early, Win8, @@ -33,7 +33,7 @@ namespace MetroUnlocker public static class Constants { public static readonly string ZeroCID = new string('0', 48); - public static readonly byte[] UniversalHWIDBlock = + public static readonly byte[] UniversalHardwareIdBlock = { 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -146,8 +146,6 @@ namespace MetroUnlocker throw new InvalidOperationException("Unable to access sppsvc: " + ex.Message); } - //Logger.WriteLine("Stopping sppsvc..."); - bool stopped = false; for (int i = 0; stopped == false && i < 60; i++) @@ -174,19 +172,14 @@ namespace MetroUnlocker if (!stopped) throw new System.TimeoutException("Failed to stop sppsvc"); - - //Logger.WriteLine("sppsvc stopped successfully."); - } - public static PSVersion DetectVersion() + public static PhysicalStoreVersion DetectVersion() { int build = Environment.OSVersion.Version.Build; - if (build >= 9600) return PSVersion.WinModern; - //if (build >= 6000 && build <= 6003) return PSVersion.Vista; - //if (build >= 7600 && build <= 7602) return PSVersion.Win7; - if (build == 9200) return PSVersion.Win8; + if (build >= 9600) return PhysicalStoreVersion.WinModern; + if (build == 9200) return PhysicalStoreVersion.Win8; throw new NotSupportedException("This version of Windows is not supported. (build " + build + ")"); } @@ -196,15 +189,9 @@ namespace MetroUnlocker SLApi.RefreshLicenseStatus(); using (RegistryKey wpaKey = Registry.LocalMachine.OpenSubKey(@"SYSTEM\WPA")) - { foreach (string subKey in wpaKey.GetSubKeyNames()) - { if (subKey.StartsWith("8DEC0AF1") && subKey.EndsWith("-1")) - { return subKey.Contains("P"); - } - } - } throw new FileNotFoundException("Failed to autodetect key type, specify physical store key with /prod or /test arguments."); } @@ -230,6 +217,10 @@ namespace MetroUnlocker public string Name; public Dictionary Data = new Dictionary(); + public TokenMeta() { } + public TokenMeta(string name) { Name = name; } + public TokenMeta(byte[] data) { Deserialize(data); } + public byte[] Serialize() { BinaryWriter writer = new BinaryWriter(new MemoryStream()); @@ -267,15 +258,5 @@ namespace MetroUnlocker Data[key] = value; } } - - public TokenMeta(byte[] data) - { - Deserialize(data); - } - - public TokenMeta() - { - - } } } diff --git a/MetroUnlocker/LOBManager.cs b/MetroUnlocker/LOBManager.cs index 10995b0..54cc1d5 100644 --- a/MetroUnlocker/LOBManager.cs +++ b/MetroUnlocker/LOBManager.cs @@ -5,12 +5,11 @@ using System.Text; using System.Threading.Tasks; using System.IO; -using MetroUnlocker.ProductPolicy; using MetroUnlocker; -using MetroUnlocker.LibTSForge.PhysicalStore; +using MetroUnlocker.LibTSForge.SPP; using MetroUnlocker.LibTSForge.Modifiers; using MetroUnlocker.LibTSForge.TokenStore; -using MetroUnlocker.LibTSForge.SPP; +using MetroUnlocker.LibTSForge.PhysicalStore; namespace MetroUnlocker { @@ -22,19 +21,25 @@ namespace MetroUnlocker public static void ActivateZeroCID() { - PSVersion version = Utils.DetectVersion(); + PhysicalStoreVersion version = Utils.DetectVersion(); bool production = Utils.DetectCurrentKey(); if (Backup) BackupPhysicalStore(); - GenPKeyInstall.InstallGenPKey(version, production, ActivationId); + ProductKeyInstaller.InstallGeneratedProductKey(version, production, ActivationId); ZeroCID.Activate(version, production, ActivationId); } public static Guid GetInstalledSideloadingKeyId() { - return SLApi.GetInstalledPkeyId(ActivationId); + return SLApi.GetInstalledProductKeyId(ActivationId); + } + + public static bool IsSideloadingKeyInstalled() + { + Guid sideloadingKeyId; + return IsSideloadingKeyInstalled(out sideloadingKeyId); } public static bool IsSideloadingKeyInstalled(out Guid sideloadingKeyId) @@ -80,28 +85,5 @@ namespace MetroUnlocker File.Copy(physicalStore, GetUniqueFileName(backupFileName), false); } - - public static bool SetPolicyState(PolicyState state) - { - ProductPolicyEditor policyEditor = new ProductPolicyEditor(); - policyEditor.SetPolicyStateByName("WSLicensingService-LOBSideloadingActivated", state); - return policyEditor.Save(); - } - - public static bool Enable() - { - return SetPolicyState(PolicyState.Enabled); - } - - public static bool Disable() - { - return SetPolicyState(PolicyState.Disabled); - } - - public static bool IsSideloadingKeyInstalled() - { - Guid sideloadingKeyId; - return IsSideloadingKeyInstalled(out sideloadingKeyId); - } } } diff --git a/MetroUnlocker/LibTSForge/Crypto/CryptoUtils.cs b/MetroUnlocker/LibTSForge/Crypto/CryptoUtils.cs index 95ab11b..0615aa9 100644 --- a/MetroUnlocker/LibTSForge/Crypto/CryptoUtils.cs +++ b/MetroUnlocker/LibTSForge/Crypto/CryptoUtils.cs @@ -72,9 +72,7 @@ namespace MetroUnlocker.LibTSForge.Crypto byte[] hash; using (SHA1 sha1 = SHA1.Create()) - { hash = sha1.ComputeHash(data); - } return formatter.CreateSignature(hash); } @@ -90,9 +88,7 @@ namespace MetroUnlocker.LibTSForge.Crypto byte[] hash; using (SHA1 sha1 = SHA1.Create()) - { hash = sha1.ComputeHash(data); - } return deformatter.VerifySignature(hash, signature); } @@ -113,9 +109,7 @@ namespace MetroUnlocker.LibTSForge.Crypto public static byte[] SHA256Hash(byte[] data) { using (SHA256 sha256 = SHA256.Create()) - { return sha256.ComputeHash(data); - } } } } diff --git a/MetroUnlocker/LibTSForge/Crypto/Keys.cs b/MetroUnlocker/LibTSForge/Crypto/Keys.cs index 43b9d9c..581536f 100644 --- a/MetroUnlocker/LibTSForge/Crypto/Keys.cs +++ b/MetroUnlocker/LibTSForge/Crypto/Keys.cs @@ -2,7 +2,7 @@ namespace MetroUnlocker.LibTSForge.Crypto { public static class Keys { - public static readonly byte[] PRODUCTION = { + public static readonly byte[] Production = { 0x07, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x29, 0x87, 0xBA, 0x3F, 0x52, 0x90, 0x57, 0xD8, 0x12, 0x26, 0x6B, 0x38, 0xB2, 0x3B, 0xF9, 0x67, 0x08, 0x4F, 0xDD, 0x8B, 0xF5, 0xE3, 0x11, 0xB8, 0x61, 0x3A, 0x33, 0x42, @@ -43,7 +43,7 @@ namespace MetroUnlocker.LibTSForge.Crypto 0x81, 0x44, 0x38, 0xBF }; - public static readonly byte[] TEST = { + public static readonly byte[] Test = { 0x07, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x0F, 0xBE, 0x77, 0xB8, 0xDD, 0x54, 0x36, 0xDD, 0x67, 0xD4, 0x17, 0x66, 0xC4, 0x13, 0xD1, 0x3F, 0x1E, 0x16, 0x0C, 0x16, 0x35, 0xAB, 0x6D, 0x3D, 0x34, 0x51, 0xED, 0x3F, diff --git a/MetroUnlocker/LibTSForge/Crypto/PhysicalStoreCrypto.cs b/MetroUnlocker/LibTSForge/Crypto/PhysicalStoreCrypto.cs index 6fb3a2b..523ca38 100644 --- a/MetroUnlocker/LibTSForge/Crypto/PhysicalStoreCrypto.cs +++ b/MetroUnlocker/LibTSForge/Crypto/PhysicalStoreCrypto.cs @@ -12,7 +12,7 @@ namespace MetroUnlocker.LibTSForge.Crypto { public static byte[] DecryptPhysicalStore(byte[] data, bool production) { - byte[] rsaKey = production ? Keys.PRODUCTION : Keys.TEST; + byte[] rsaKey = production ? Keys.Production : Keys.Test; BinaryReader br = new BinaryReader(new MemoryStream(data)); br.BaseStream.Seek(0x10, SeekOrigin.Begin); byte[] aesKeySig = br.ReadBytes(0x80); @@ -33,16 +33,16 @@ namespace MetroUnlocker.LibTSForge.Crypto return psData; } - public static byte[] EncryptPhysicalStore(byte[] data, bool production, PSVersion version) + public static byte[] EncryptPhysicalStore(byte[] data, bool production, PhysicalStoreVersion version) { - Dictionary versionTable = new Dictionary + Dictionary versionTable = new Dictionary { - {PSVersion.Win8, 1}, - {PSVersion.WinBlue, 2}, - {PSVersion.WinModern, 3} + {PhysicalStoreVersion.Win8, 1}, + {PhysicalStoreVersion.WinBlue, 2}, + {PhysicalStoreVersion.WinModern, 3} }; - byte[] rsaKey = production ? Keys.PRODUCTION : Keys.TEST; + byte[] rsaKey = production ? Keys.Production : Keys.Test; byte[] aesKey = Encoding.UTF8.GetBytes("Boop Foxyz nose!"); byte[] hmacKey = CryptoUtils.GenerateRandomKey(0x10); diff --git a/MetroUnlocker/LibTSForge/Modifiers/GenPKeyInstall.cs b/MetroUnlocker/LibTSForge/Modifiers/ProductKeyInstaller.cs similarity index 51% rename from MetroUnlocker/LibTSForge/Modifiers/GenPKeyInstall.cs rename to MetroUnlocker/LibTSForge/Modifiers/ProductKeyInstaller.cs index 2267da5..859f04b 100644 --- a/MetroUnlocker/LibTSForge/Modifiers/GenPKeyInstall.cs +++ b/MetroUnlocker/LibTSForge/Modifiers/ProductKeyInstaller.cs @@ -1,33 +1,25 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + +using MetroUnlocker.LibTSForge.SPP; namespace MetroUnlocker.LibTSForge.Modifiers { - using System; - using System.IO; - using Microsoft.Win32; - using MetroUnlocker.LibTSForge.PhysicalStore; - using MetroUnlocker.LibTSForge.SPP; - using MetroUnlocker.LibTSForge.TokenStore; - - public static class GenPKeyInstall + public static class ProductKeyInstaller { - 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; - 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(); - Guid instPkeyId = SLApi.GetInstalledPkeyId(actId); + Guid instPkeyId = SLApi.GetInstalledProductKeyId(actId); if (instPkeyId != Guid.Empty) SLApi.UninstallProductKey(instPkeyId); if (pkey.Algorithm != PKeyAlgorithm.PKEY2009) diff --git a/MetroUnlocker/LibTSForge/PhysicalStore/BasicBlock.cs b/MetroUnlocker/LibTSForge/PhysicalStore/BasicBlock.cs new file mode 100644 index 0000000..c2845b1 --- /dev/null +++ b/MetroUnlocker/LibTSForge/PhysicalStore/BasicBlock.cs @@ -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); } + } + } +} diff --git a/MetroUnlocker/LibTSForge/PhysicalStore/CRCBlock.cs b/MetroUnlocker/LibTSForge/PhysicalStore/CRCBlock.cs index a62daec..f7b86d8 100644 --- a/MetroUnlocker/LibTSForge/PhysicalStore/CRCBlock.cs +++ b/MetroUnlocker/LibTSForge/PhysicalStore/CRCBlock.cs @@ -1,55 +1,42 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using System.IO; namespace MetroUnlocker.LibTSForge.PhysicalStore { public enum CRCBlockType : uint { - UINT = 1 << 0, - STRING = 1 << 1, - BINARY = 1 << 2 + UInt = 1 << 0, + String = 1 << 1, + Binary = 1 << 2 } - public class CRCBlock + public class CRCBlock : BasicBlock { public CRCBlockType DataType; - public byte[] Key; - public string KeyAsStr + + public CRCBlock() { } + + public CRCBlock(BinaryReader reader) { - get - { - return Utils.DecodeString(Key); - } - set - { - Key = Utils.EncodeString(value); - } - } - public byte[] Value; - public string ValueAsStr - { - get - { - return Utils.DecodeString(Value); - } - set - { - Value = Utils.EncodeString(value); - } - } - public uint ValueAsInt - { - get - { - return BitConverter.ToUInt32(Value, 0); - } - set - { - Value = BitConverter.GetBytes(value); - } + uint crc = reader.ReadUInt32(); + uint type = reader.ReadUInt32(); + uint lenName = reader.ReadUInt32(); + uint lenVal = reader.ReadUInt32(); + + byte[] key = reader.ReadBytes((int)lenName); + + reader.Align(8); + + byte[] value = reader.ReadBytes((int)lenVal); + reader.Align(8); + + DataType = (CRCBlockType)type; + Key = key; + Value = value; + + if (CRC() != crc) + throw new InvalidDataException("Invalid CRC in variable bag."); } public void Encode(BinaryWriter writer) @@ -67,45 +54,16 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore writer.Align(8); } - public static CRCBlock Decode(BinaryReader reader) - { - uint crc = reader.ReadUInt32(); - uint type = reader.ReadUInt32(); - uint lenName = reader.ReadUInt32(); - uint lenVal = reader.ReadUInt32(); - - byte[] key = reader.ReadBytes((int)lenName); - - reader.Align(8); - - byte[] value = reader.ReadBytes((int)lenVal); - reader.Align(8); - - CRCBlock block = new CRCBlock - { - DataType = (CRCBlockType)type, - Key = key, - Value = value, - }; - - if (block.CRC() != crc) - { - throw new InvalidDataException("Invalid CRC in variable bag."); - } - - return block; - } - public uint CRC() { - BinaryWriter wtemp = new BinaryWriter(new MemoryStream()); - wtemp.Write(0); - wtemp.Write((uint)DataType); - wtemp.Write(Key.Length); - wtemp.Write(Value.Length); - wtemp.Write(Key); - wtemp.Write(Value); - return Utils.CRC32(((MemoryStream)wtemp.BaseStream).ToArray()); + BinaryWriter writer = new BinaryWriter(new MemoryStream()); + writer.Write(0); + writer.Write((uint)DataType); + writer.Write(Key.Length); + writer.Write(Value.Length); + writer.Write(Key); + writer.Write(Value); + return Utils.CRC32(((MemoryStream)writer.BaseStream).ToArray()); } } } diff --git a/MetroUnlocker/LibTSForge/PhysicalStore/ModernBlock.cs b/MetroUnlocker/LibTSForge/PhysicalStore/ModernBlock.cs index ccf605f..9bd1100 100644 --- a/MetroUnlocker/LibTSForge/PhysicalStore/ModernBlock.cs +++ b/MetroUnlocker/LibTSForge/PhysicalStore/ModernBlock.cs @@ -6,68 +6,41 @@ using System.IO; namespace MetroUnlocker.LibTSForge.PhysicalStore { - public class ModernBlock + public class ModernBlock : BasicBlock { public BlockType Type; public uint Flags; public uint Unknown; - public byte[] Key; - public string KeyAsStr - { - get - { - return Utils.DecodeString(Key); - } - set - { - Key = Utils.EncodeString(value); - } - } - public byte[] Value; - public string ValueAsStr - { - get - { - return Utils.DecodeString(Value); - } - set - { - Value = Utils.EncodeString(value); - } - } - public uint ValueAsInt - { - get - { - return BitConverter.ToUInt32(Value, 0); - } - set - { - Value = BitConverter.GetBytes(value); - } - } + public byte[] Data; - public string DataAsStr + public string DataAsString { - get - { - return Utils.DecodeString(Data); - } - set - { - Data = Utils.EncodeString(value); - } + get { return Utils.DecodeString(Data); } + set { Data = Utils.EncodeString(value); } } + public uint DataAsInt { - get - { - return BitConverter.ToUInt32(Data, 0); - } - set - { - Data = BitConverter.GetBytes(value); - } + get { return BitConverter.ToUInt32(Data, 0); } + set { Data = BitConverter.GetBytes(value); } + } + + public ModernBlock() { } + public ModernBlock(string key, string value, byte[] data, BlockType type = BlockType.NAMED, uint flags = 0) + { + Type = type; + Flags = flags; + KeyAsString = key; + ValueAsString = value; + Data = data; + } + public ModernBlock(ModernBlock block) + { + Type = block.Type; + Flags = block.Flags; + Unknown = block.Unknown; + Value = block.Value; + Data = block.Data; } public void Encode(BinaryWriter writer) @@ -81,7 +54,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore writer.Write(Data); } - public static ModernBlock Decode(BinaryReader reader) + public ModernBlock(BinaryReader reader) { uint type = reader.ReadUInt32(); uint flags = reader.ReadUInt32(); @@ -93,14 +66,11 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore byte[] value = reader.ReadBytes((int)valueLen); byte[] data = reader.ReadBytes((int)dataLen); - return new ModernBlock - { - Type = (BlockType)type, - Flags = flags, - Unknown = unk3, - Value = value, - Data = data, - }; + Type = (BlockType)type; + Flags = flags; + Unknown = unk3; + Value = value; + Data = data; } } } diff --git a/MetroUnlocker/LibTSForge/PhysicalStore/PhysicalStore.cs b/MetroUnlocker/LibTSForge/PhysicalStore/PhysicalStore.cs index a00bd56..eb053bb 100644 --- a/MetroUnlocker/LibTSForge/PhysicalStore/PhysicalStore.cs +++ b/MetroUnlocker/LibTSForge/PhysicalStore/PhysicalStore.cs @@ -16,7 +16,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore private byte[] PreHeaderBytes = new byte[] { }; private readonly Dictionary> Data = new Dictionary>(); private readonly FileStream TSFile; - private readonly PSVersion Version; + private readonly PhysicalStoreVersion Version; private readonly bool Production; public byte[] Serialize() @@ -66,7 +66,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore for (int j = 0; j < numValues; j++) { - Data[keyName].Add(ModernBlock.Decode(reader)); + Data[keyName].Add(new ModernBlock(reader)); reader.Align(4); } } @@ -75,12 +75,10 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore public void AddBlock(ModernBlock block) { - if (!Data.ContainsKey(block.KeyAsStr)) - { - Data[block.KeyAsStr] = new List(); - } + if (!Data.ContainsKey(block.KeyAsString)) + Data[block.KeyAsString] = new List(); - Data[block.KeyAsStr].Add(new ModernBlock + Data[block.KeyAsString].Add(new ModernBlock { Type = block.Type, Flags = block.Flags, @@ -104,7 +102,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore foreach (ModernBlock block in blocks) { - if (block.ValueAsStr == value) + if (block.ValueAsString == value) { return new ModernBlock { @@ -126,7 +124,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore foreach (ModernBlock block in blocks) { - if (block.ValueAsInt == value) + if (block.ValueAsInteger == value) { return new ModernBlock { @@ -150,7 +148,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore { ModernBlock block = blocks[i]; - if (block.ValueAsStr == value) + if (block.ValueAsString == value) { block.Data = data; blocks[i] = block; @@ -169,7 +167,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore { ModernBlock block = blocks[i]; - if (block.ValueAsInt == value) + if (block.ValueAsInteger == value) { block.Data = data; blocks[i] = block; @@ -208,7 +206,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore foreach (ModernBlock block in blocks) { - if (block.ValueAsStr == value) + if (block.ValueAsString == value) { blocks.Remove(block); break; @@ -227,7 +225,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore foreach (ModernBlock block in blocks) { - if (block.ValueAsInt == value) + if (block.ValueAsInteger == value) { blocks.Remove(block); break; @@ -245,7 +243,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore return Path.Combine(Environment.ExpandEnvironmentVariables(sppRoot), "data.dat"); } - public PhysicalStore(PSVersion version, bool production) + public PhysicalStore(PhysicalStoreVersion version, bool production) { Version = version; Production = production; diff --git a/MetroUnlocker/LibTSForge/PhysicalStore/VariableBag.cs b/MetroUnlocker/LibTSForge/PhysicalStore/VariableBag.cs index 24aa100..4b3fccd 100644 --- a/MetroUnlocker/LibTSForge/PhysicalStore/VariableBag.cs +++ b/MetroUnlocker/LibTSForge/PhysicalStore/VariableBag.cs @@ -10,10 +10,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore public List Blocks = new List(); public VariableBag() { } - public VariableBag(byte[] data) - { - Deserialize(data); - } + public VariableBag(byte[] data) { Deserialize(data); } public void Deserialize(byte[] data) { @@ -22,9 +19,7 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore BinaryReader reader = new BinaryReader(new MemoryStream(data)); while (reader.BaseStream.Position < len - 0x10) - { - Blocks.Add(CRCBlock.Decode(reader)); - } + Blocks.Add(new CRCBlock(reader)); } public byte[] Serialize() @@ -39,40 +34,19 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore public CRCBlock GetBlock(string key) { - foreach (CRCBlock block in Blocks) - { - if (block.KeyAsStr == key) - { - return block; - } - } - - return null; + return Blocks.Find(block => block.KeyAsString == key); } public void SetBlock(string key, byte[] value) { - for (int i = 0; i < Blocks.Count; i++) - { - CRCBlock block = Blocks[i]; - - if (block.KeyAsStr == key) - { - block.Value = value; - Blocks[i] = block; - break; - } - } + int index = Blocks.FindIndex(block => block.KeyAsString == key); + if (index != -1) Blocks[index].Value = value; } public void DeleteBlock(string key) { - foreach (CRCBlock block in Blocks) - if (block.KeyAsStr == key) - { - Blocks.Remove(block); - return; - } + CRCBlock block = GetBlock(key); + if (block != null) Blocks.Remove(block); } } } diff --git a/MetroUnlocker/LibTSForge/SPP/PKeyConfig.cs b/MetroUnlocker/LibTSForge/SPP/PKeyConfig.cs index 111d1e0..1f56655 100644 --- a/MetroUnlocker/LibTSForge/SPP/PKeyConfig.cs +++ b/MetroUnlocker/LibTSForge/SPP/PKeyConfig.cs @@ -74,7 +74,7 @@ namespace MetroUnlocker.LibTSForge.SPP } } - public class PKeyConfig + public class ProductKeyConfig { public Dictionary Products = new Dictionary(); private List loadedPkeyConfigs = new List(); @@ -194,7 +194,7 @@ namespace MetroUnlocker.LibTSForge.SPP throw new FileNotFoundException("Failed to find product matching supplied product key parameters."); } - public PKeyConfig() + public ProductKeyConfig() { } diff --git a/MetroUnlocker/LibTSForge/SPP/ProductKey.cs b/MetroUnlocker/LibTSForge/SPP/ProductKey.cs index 9bce22d..efb8bd1 100644 --- a/MetroUnlocker/LibTSForge/SPP/ProductKey.cs +++ b/MetroUnlocker/LibTSForge/SPP/ProductKey.cs @@ -70,21 +70,21 @@ namespace MetroUnlocker.LibTSForge.SPP { new CRCBlock { - DataType = CRCBlockType.STRING, - KeyAsStr = "SppPkeyBindingProductKey", - ValueAsStr = ToString() + DataType = CRCBlockType.String, + KeyAsString = "SppPkeyBindingProductKey", + ValueAsString = ToString() }, new CRCBlock { - DataType = CRCBlockType.BINARY, - KeyAsStr = "SppPkeyBindingMiscData", + DataType = CRCBlockType.Binary, + KeyAsString = "SppPkeyBindingMiscData", Value = new byte[] { } }, new CRCBlock { - DataType = CRCBlockType.STRING, - KeyAsStr = "SppPkeyBindingAlgorithm", - ValueAsStr = GetAlgoUri() + DataType = CRCBlockType.String, + KeyAsString = "SppPkeyBindingAlgorithm", + ValueAsString = GetAlgoUri() } }); @@ -245,7 +245,7 @@ namespace MetroUnlocker.LibTSForge.SPP ); } - public byte[] GetPhoneData(PSVersion version) + public byte[] GetPhoneData(PhysicalStoreVersion version) { int serialHigh = Serial / 1000000; int serialLow = Serial % 1000000; diff --git a/MetroUnlocker/LibTSForge/SPP/SLAPI.cs b/MetroUnlocker/LibTSForge/SPP/SLAPI.cs index 29dfb37..fb404ba 100644 --- a/MetroUnlocker/LibTSForge/SPP/SLAPI.cs +++ b/MetroUnlocker/LibTSForge/SPP/SLAPI.cs @@ -13,12 +13,12 @@ namespace MetroUnlocker.LibTSForge.SPP { public static class SLApi { - private enum SLIDTYPE + private enum SLIDType { - SL_ID_APPLICATION, - SL_ID_PRODUCT_SKU, - SL_ID_LICENSE_FILE, - SL_ID_LICENSE, + SLIDApplication, + SLIDProductSku, + SLIDLicenseFile, + SLIDLicense, SL_ID_PKEY, SL_ID_ALL_LICENSES, SL_ID_ALL_LICENSE_FILES, @@ -26,7 +26,7 @@ namespace MetroUnlocker.LibTSForge.SPP SL_ID_LAST } - private enum SLDATATYPE + private enum SLDataType { SL_DATA_NONE, SL_DATA_SZ, @@ -37,7 +37,7 @@ namespace MetroUnlocker.LibTSForge.SPP } [StructLayout(LayoutKind.Sequential)] - private struct SL_LICENSING_STATUS + private struct SLLicensingStatus { public Guid SkuId; public uint eStatus; @@ -47,8 +47,6 @@ namespace MetroUnlocker.LibTSForge.SPP public ulong qwValidityExpiration; } - public static readonly Guid WINDOWS_APP_ID = new Guid("55c92734-d682-4d71-983e-d6ec3f16059f"); - [DllImport("sppc.dll", CharSet = CharSet.Unicode, PreserveSig = false)] private static extern void SLOpen(out IntPtr hSLC); @@ -65,7 +63,7 @@ namespace MetroUnlocker.LibTSForge.SPP private static extern uint SLUninstallProofOfPurchase(IntPtr hSLC, ref Guid PKeyId); [DllImport("sppc.dll", CharSet = CharSet.Unicode)] - private static extern uint SLGetPKeyInformation(IntPtr hSLC, ref Guid pPKeyId, string pwszValueName, out SLDATATYPE peDataType, out uint pcbValue, out IntPtr ppbValue); + private static extern uint SLGetPKeyInformation(IntPtr hSLC, ref Guid pPKeyId, string pwszValueName, out SLDataType peDataType, out uint pcbValue, out IntPtr ppbValue); [DllImport("sppcext.dll", CharSet = CharSet.Unicode)] private static extern uint SLActivateProduct(IntPtr hSLC, ref Guid pProductSkuId, byte[] cbAppSpecificData, byte[] pvAppSpecificData, byte[] pActivationInfo, string pwszProxyServer, ushort wProxyPort); @@ -77,7 +75,7 @@ namespace MetroUnlocker.LibTSForge.SPP private static extern uint SLDepositOfflineConfirmationId(IntPtr hSLC, ref Guid pProductSkuId, string pwszInstallationId, string pwszConfirmationId); [DllImport("sppc.dll", CharSet = CharSet.Unicode)] - private static extern uint SLGetSLIDList(IntPtr hSLC, SLIDTYPE eQueryIdType, ref Guid pQueryId, SLIDTYPE eReturnIdType, out uint pnReturnIds, out IntPtr ppReturnIds); + private static extern uint SLGetSLIDList(IntPtr hSLC, SLIDType eQueryIdType, ref Guid pQueryId, SLIDType eReturnIdType, out uint pnReturnIds, out IntPtr ppReturnIds); [DllImport("sppc.dll", CharSet = CharSet.Unicode, PreserveSig = false)] private static extern void SLGetLicensingStatusInformation(IntPtr hSLC, ref Guid pAppID, IntPtr pProductSkuId, string pwszRightName, out uint pnStatusCount, out IntPtr ppLicensingStatus); @@ -89,7 +87,7 @@ namespace MetroUnlocker.LibTSForge.SPP private static extern uint SLConsumeWindowsRight(uint unknown); [DllImport("slc.dll", CharSet = CharSet.Unicode)] - private static extern uint SLGetProductSkuInformation(IntPtr hSLC, ref Guid pProductSkuId, string pwszValueName, out SLDATATYPE peDataType, out uint pcbValue, out IntPtr ppbValue); + private static extern uint SLGetProductSkuInformation(IntPtr hSLC, ref Guid pProductSkuId, string pwszValueName, out SLDataType peDataType, out uint pcbValue, out IntPtr ppbValue); [DllImport("slc.dll", CharSet = CharSet.Unicode)] private static extern uint SLGetProductSkuInformation(IntPtr hSLC, ref Guid pProductSkuId, string pwszValueName, IntPtr peDataType, out uint pcbValue, out IntPtr ppbValue); @@ -128,7 +126,7 @@ namespace MetroUnlocker.LibTSForge.SPP { using (SLContext sl = new SLContext()) { - SLDATATYPE type; + SLDataType type; uint len; 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()) { uint status; uint count; - IntPtr ppReturnLics; + IntPtr returnLicenses; - status = SLGetSLIDList(sl.Handle, SLIDTYPE.SL_ID_LICENSE, ref licId, SLIDTYPE.SL_ID_LICENSE_FILE, out count, out ppReturnLics); + status = 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; if (SLGetLicense(sl.Handle, ref fileId, out dataLen, out dataPtr) != 0) - { return null; - } byte[] data = new byte[dataLen]; Marshal.Copy(dataPtr, data, 0, (int)dataLen); @@ -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()) { - uint len; - SLDATATYPE type; - IntPtr ppbValue; + uint length; + SLDataType type; + IntPtr binaryValue; - uint status = SLGetProductSkuInformation(sl.Handle, ref actId, value, out type, out len, out ppbValue); + uint status = 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 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()) { uint status; 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(pProductKeyIds, typeof(Guid)) : Guid.Empty; + return (status == 0 && count != 0) ? (Guid)Marshal.PtrToStructure(productKeyIds, typeof(Guid)) : Guid.Empty; } } @@ -243,7 +236,7 @@ namespace MetroUnlocker.LibTSForge.SPP { using (SLContext sl = new SLContext()) { - SLDATATYPE type; + SLDataType type; uint count; IntPtr ppbValue; @@ -255,9 +248,7 @@ namespace MetroUnlocker.LibTSForge.SPP public static void FireStateChangedEvent(Guid appId) { using (SLContext sl = new SLContext()) - { SLFireEvent(sl.Handle, "msft:rm/event/licensingstatechanged", ref appId); - } } public static Guid GetAppId(Guid actId) @@ -267,7 +258,7 @@ namespace MetroUnlocker.LibTSForge.SPP uint count; 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) return Guid.Empty; @@ -281,7 +272,7 @@ namespace MetroUnlocker.LibTSForge.SPP using (SLContext sl = new SLContext()) { uint count; - SLDATATYPE type; + SLDataType type; IntPtr ppbValue; uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "DependsOn", out type, out count, out ppbValue); diff --git a/MetroUnlocker/LibTSForge/TokenStore/TokenEntry.cs b/MetroUnlocker/LibTSForge/TokenStore/TokenEntry.cs index 2e1a26e..dbe738d 100644 --- a/MetroUnlocker/LibTSForge/TokenStore/TokenEntry.cs +++ b/MetroUnlocker/LibTSForge/TokenStore/TokenEntry.cs @@ -7,9 +7,18 @@ namespace MetroUnlocker.LibTSForge.TokenStore { public class TokenEntry { - public string Name; - public string Extension; - public byte[] Data; - public bool Populated; + public string Name { get; set; } + public string Extension { get; set; } + public byte[] Data { get; set; } + public bool Populated { get; set; } + + public TokenEntry() : this("", "", new byte[] { }, false) {} + public TokenEntry(string name, string extension, byte[] data, bool populated = true) + { + Name = name; + Extension = extension; + Data = data; + Populated = populated; + } } } diff --git a/MetroUnlocker/LibTSForge/TokenStore/TokenStore.cs b/MetroUnlocker/LibTSForge/TokenStore/TokenStore.cs index 14a109f..87d11dd 100644 --- a/MetroUnlocker/LibTSForge/TokenStore/TokenStore.cs +++ b/MetroUnlocker/LibTSForge/TokenStore/TokenStore.cs @@ -10,21 +10,21 @@ namespace MetroUnlocker.LibTSForge.TokenStore public class TokenStore : IDisposable { - private static readonly uint VERSION = 3; - private static readonly int ENTRY_SIZE = 0x9E; - private static readonly int BLOCK_SIZE = 0x4020; - private static readonly int ENTRIES_PER_BLOCK = BLOCK_SIZE / ENTRY_SIZE; - private static readonly int BLOCK_PAD_SIZE = 0x66; + private static readonly uint Version = 3; + private static readonly int EntrySize = 0x9E; + private static readonly int BlockSize = 0x4020; + private static readonly int EntriesPerBlock = BlockSize / EntrySize; + private static readonly int BlockPadSize = 0x66; - private static readonly byte[] CONTS_HEADER = Enumerable.Repeat((byte)0x55, 0x20).ToArray(); - private static readonly byte[] CONTS_FOOTER = Enumerable.Repeat((byte)0xAA, 0x20).ToArray(); + private static readonly byte[] Header = Enumerable.Repeat((byte)0x55, 0x20).ToArray(); + private static readonly byte[] Footer = Enumerable.Repeat((byte)0xAA, 0x20).ToArray(); private List Entries = new List(); - public FileStream TokensFile; + public FileStream TokensFile { get; set; } public void Deserialize() { - if (TokensFile.Length < BLOCK_SIZE) return; + if (TokensFile.Length < BlockSize) return; TokensFile.Seek(0x24, SeekOrigin.Begin); uint nextBlock = 0; @@ -35,7 +35,7 @@ namespace MetroUnlocker.LibTSForge.TokenStore uint curOffset = reader.ReadUInt32(); nextBlock = reader.ReadUInt32(); - for (int i = 0; i < ENTRIES_PER_BLOCK; i++) + for (int i = 0; i < EntriesPerBlock; i++) { curOffset = reader.ReadUInt32(); bool populated = reader.ReadUInt32() == 1; @@ -50,9 +50,7 @@ namespace MetroUnlocker.LibTSForge.TokenStore uint dataLength = reader.ReadUInt32(); if (dataLength != contentLength) - { throw new FormatException("Data length in tokens content is inconsistent with entry."); - } reader.ReadBytes(0x20); contentData = reader.ReadBytes((int)contentLength); @@ -60,13 +58,7 @@ namespace MetroUnlocker.LibTSForge.TokenStore reader.BaseStream.Seek(curOffset + 0x14, SeekOrigin.Begin); - Entries.Add(new TokenEntry - { - Name = reader.ReadNullTerminatedString(0x82), - Extension = reader.ReadNullTerminatedString(0x8), - Data = contentData, - Populated = populated - }); + Entries.Add(new TokenEntry(reader.ReadNullTerminatedString(0x82), reader.ReadNullTerminatedString(0x8), contentData, populated)); } reader.BaseStream.Seek(nextBlock, SeekOrigin.Begin); @@ -79,31 +71,16 @@ namespace MetroUnlocker.LibTSForge.TokenStore using (BinaryWriter writer = new BinaryWriter(tokens)) { - writer.Write(VERSION); - writer.Write(CONTS_HEADER); + writer.Write(Version); + writer.Write(Header); int curBlockOffset = (int)writer.BaseStream.Position; int curEntryOffset = curBlockOffset + 0x8; - int curContsOffset = curBlockOffset + BLOCK_SIZE; + int curContsOffset = curBlockOffset + BlockSize; - for (int eIndex = 0; eIndex < ((Entries.Count / ENTRIES_PER_BLOCK) + 1) * ENTRIES_PER_BLOCK; eIndex++) + for (int eIndex = 0; eIndex < ((Entries.Count / EntriesPerBlock) + 1) * EntriesPerBlock; eIndex++) { - TokenEntry entry; - - if (eIndex < Entries.Count) - { - entry = Entries[eIndex]; - } - else - { - entry = new TokenEntry - { - Name = "", - Extension = "", - Populated = false, - Data = new byte[] { } - }; - } + TokenEntry entry = eIndex < Entries.Count ? entry = Entries[eIndex] : new TokenEntry(); writer.BaseStream.Seek(curBlockOffset, SeekOrigin.Begin); writer.Write(curBlockOffset); @@ -122,15 +99,15 @@ namespace MetroUnlocker.LibTSForge.TokenStore if (entry.Populated) { writer.BaseStream.Seek(curContsOffset, SeekOrigin.Begin); - writer.Write(CONTS_HEADER); + writer.Write(Header); writer.Write(entry.Data.Length); writer.Write(CryptoUtils.SHA256Hash(entry.Data)); writer.Write(entry.Data); - writer.Write(CONTS_FOOTER); + writer.Write(Footer); curContsOffset = (int)writer.BaseStream.Position; } - if ((eIndex + 1) % ENTRIES_PER_BLOCK == 0 && eIndex != 0) + if ((eIndex + 1) % EntriesPerBlock == 0 && eIndex != 0) { if (eIndex < Entries.Count) { @@ -139,21 +116,21 @@ namespace MetroUnlocker.LibTSForge.TokenStore } writer.BaseStream.Seek(curEntryOffset, SeekOrigin.Begin); - writer.WritePadding(BLOCK_PAD_SIZE); + writer.WritePadding(BlockPadSize); writer.BaseStream.Seek(curBlockOffset, SeekOrigin.Begin); byte[] blockHash; - byte[] blockData = new byte[BLOCK_SIZE - 0x20]; + byte[] blockData = new byte[BlockSize - 0x20]; - tokens.Read(blockData, 0, BLOCK_SIZE - 0x20); + tokens.Read(blockData, 0, BlockSize - 0x20); blockHash = CryptoUtils.SHA256Hash(blockData); - writer.BaseStream.Seek(curBlockOffset + BLOCK_SIZE - 0x20, SeekOrigin.Begin); + writer.BaseStream.Seek(curBlockOffset + BlockSize - 0x20, SeekOrigin.Begin); writer.Write(blockHash); curBlockOffset = curContsOffset; curEntryOffset = curBlockOffset + 0x8; - curContsOffset = curBlockOffset + BLOCK_SIZE; + curContsOffset = curBlockOffset + BlockSize; } } @@ -190,71 +167,41 @@ namespace MetroUnlocker.LibTSForge.TokenStore public void DeleteEntry(string name, string ext) { foreach (TokenEntry entry in Entries) - { if (entry.Name == name && entry.Extension == ext) { Entries.Remove(entry); return; } - } } - public void DeleteUnpopEntry(string name, string ext) + public void DeleteUnpopulatedEntry(string name, string extension) { - List delEntries = new List(); - foreach (TokenEntry entry in Entries) - { - if (entry.Name == name && entry.Extension == ext && !entry.Populated) - { - delEntries.Add(entry); - } - } - - Entries = Entries.Except(delEntries).ToList(); + Entries = Entries.FindAll(entry => entry.Name != name && entry.Extension != extension && entry.Populated); } public TokenEntry GetEntry(string name, string ext) { foreach (TokenEntry entry in Entries) - { if (entry.Name == name && entry.Extension == ext) - { - if (!entry.Populated) continue; - return entry; - } - } - + if (entry.Populated) return entry; return null; } public TokenMeta GetMetaEntry(string name) { - DeleteUnpopEntry(name, "xml"); + DeleteUnpopulatedEntry(name, "xml"); TokenEntry entry = GetEntry(name, "xml"); - TokenMeta meta; - if (entry == null) - { - meta = new TokenMeta - { - Name = name - }; - } - else - { - meta = new TokenMeta(entry.Data); - } - - return meta; + return entry == null ? new TokenMeta(name) : new TokenMeta(entry.Data); } - public void SetEntry(string name, string ext, byte[] data) + public void SetEntry(string name, string extension, byte[] data) { for (int i = 0; i < Entries.Count; i++) { TokenEntry entry = Entries[i]; - if (entry.Name == name && entry.Extension == ext && entry.Populated) + if (entry.Name == name && entry.Extension == extension && entry.Populated) { entry.Data = data; Entries[i] = entry; @@ -262,13 +209,7 @@ namespace MetroUnlocker.LibTSForge.TokenStore } } - Entries.Add(new TokenEntry - { - Populated = true, - Name = name, - Extension = ext, - Data = data - }); + Entries.Add(new TokenEntry(name, extension, data)); } public static string GetPath() diff --git a/MetroUnlocker/LibTSForge/ZeroCID.cs b/MetroUnlocker/LibTSForge/ZeroCID.cs index eb07131..b4719d2 100644 --- a/MetroUnlocker/LibTSForge/ZeroCID.cs +++ b/MetroUnlocker/LibTSForge/ZeroCID.cs @@ -4,8 +4,9 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; -using Microsoft.Win32; +using System.Runtime.InteropServices; +using Microsoft.Win32; using MetroUnlocker.LibTSForge.SPP; using MetroUnlocker.LibTSForge.PhysicalStore; @@ -21,39 +22,37 @@ namespace MetroUnlocker uint status = SLApi.DepositConfirmationId(actId, instId, Constants.ZeroCID); if (status != 0) - throw new InvalidOperationException(string.Format("Failed to deposit fake CID. Status code: 0x{0}", status.ToString("X"))); + throw new COMException(string.Format("Failed to deposit fake CID. Status code: 0x{0}", status.ToString("X")), (int)status); } - public static void Activate(PSVersion version, bool production, Guid actId) + public static void Activate(PhysicalStoreVersion version, bool production, Guid activationId) { - Guid appId = SLApi.GetAppId(actId); + Guid appId = SLApi.GetAppId(activationId); - string instId = SLApi.GetInstallationId(actId); - Guid pkeyId = SLApi.GetInstalledPkeyId(actId); + string instId = SLApi.GetInstallationId(activationId); + Guid pkeyId = SLApi.GetInstalledProductKeyId(activationId); Utils.KillSPP(); using (PhysicalStore store = new PhysicalStore(version, production)) { - byte[] hwidBlock = Constants.UniversalHWIDBlock; + byte[] hwidBlock = Constants.UniversalHardwareIdBlock; byte[] iidHash = CryptoUtils.SHA256Hash(Utils.EncodeString(instId + '\0' + Constants.ZeroCID)); - string key = string.Format("SPPSVC\\{0}\\{1}", appId, actId); + string key = string.Format("SPPSVC\\{0}\\{1}", appId, activationId); ModernBlock keyBlock = store.GetBlock(key, pkeyId.ToString()); if (keyBlock == null) - { - throw new InvalidDataException("Failed to get product key data for activation ID: 0x" + actId + "."); - } + throw new InvalidDataException("Failed to get product key data for activation ID: 0x" + activationId + "."); - VariableBag pkb = new VariableBag(keyBlock.Data); + VariableBag keyBag = new VariableBag(keyBlock.Data); - byte[] pkeyData = pkb.GetBlock("SppPkeyPhoneActivationData").Value; + byte[] pkeyData = keyBag.GetBlock("SppPkeyPhoneActivationData").Value; - pkb.DeleteBlock("SppPkeyVirtual"); - store.SetBlock(key, pkeyId.ToString(), pkb.Serialize()); + keyBag.DeleteBlock("SppPkeyVirtual"); + store.SetBlock(key, pkeyId.ToString(), keyBag.Serialize()); BinaryWriter writer = new BinaryWriter(new MemoryStream()); writer.Write(0x20); @@ -69,27 +68,15 @@ namespace MetroUnlocker writer.Write(pkeyData); byte[] tsPkeyInfoData = Utils.GetBytes(writer); + string path = "msft:Windows/7.0/Phone/Cached/"; + store.AddBlocks(new ModernBlock[] { - new ModernBlock - { - Type = BlockType.NAMED, - Flags = 0, - KeyAsStr = key, - ValueAsStr = "msft:Windows/7.0/Phone/Cached/HwidBlock/" + pkeyId, - Data = tsHwidData - }, - new ModernBlock - { - Type = BlockType.NAMED, - Flags = 0, - KeyAsStr = key, - ValueAsStr = "msft:Windows/7.0/Phone/Cached/PKeyInfo/" + pkeyId, - Data = tsPkeyInfoData - } + new ModernBlock(key, path + "HwidBlock/" + pkeyId, tsHwidData), + new ModernBlock(key, path + "PKeyInfo/" + pkeyId, tsPkeyInfoData) }); } - Deposit(actId, instId); + Deposit(activationId, instId); SLApi.RefreshLicenseStatus(); SLApi.FireStateChangedEvent(appId); diff --git a/MetroUnlocker/MetroUnlocker.csproj b/MetroUnlocker/MetroUnlocker.csproj index aea953b..6f3d686 100644 --- a/MetroUnlocker/MetroUnlocker.csproj +++ b/MetroUnlocker/MetroUnlocker.csproj @@ -57,11 +57,12 @@ App.cs - + - + + @@ -74,13 +75,9 @@ - - + - - - App.cs @@ -93,7 +90,9 @@ True Resources.resx - + + Designer + SettingsSingleFileGenerator Settings.Designer.cs diff --git a/MetroUnlocker/ProductPolicy/ProductPolicy.cs b/MetroUnlocker/ProductPolicy/ProductPolicy.cs index 14d20a0..fba5cd0 100644 --- a/MetroUnlocker/ProductPolicy/ProductPolicy.cs +++ b/MetroUnlocker/ProductPolicy/ProductPolicy.cs @@ -7,57 +7,20 @@ using System.Runtime.InteropServices; using Microsoft.Win32; - namespace MetroUnlocker.ProductPolicy { - //public struct ProductPolicyData - //{ - // public string String; - // public byte[] Bytes; - // public uint DWord; - //}; class ProductPolicy { - public bool Modified { get; set; } public ProductPolicyValue Header { get; set; } public string Name { get; set; } - //private ProductPolicyData _data; - - //public ProductPolicyData Data - //{ - // get { return _data; } - // set { _data = value; } - //} public byte[] Bytes { get; set; } - public string StringValue - { - get - { - return Encoding.Unicode.GetString(Bytes); - } - set { - Bytes = Encoding.Unicode.GetBytes(value); - } - } - public uint DWordValue - { - get - { - return BitConverter.ToUInt32(Bytes, 0); - } - set - { - Bytes = BitConverter.GetBytes(value); - } - } + public string StringValue { get { return Encoding.Unicode.GetString(Bytes); } } + public uint DWordValue { get { return BitConverter.ToUInt32(Bytes, 0); } } public RegistryValueKind Type { - get - { - return (RegistryValueKind)Header.DataType; - } + get { return (RegistryValueKind)Header.DataType; } } private void NameFromBin(ref byte[] PolicyBlob, int offset) @@ -74,12 +37,10 @@ namespace MetroUnlocker.ProductPolicy public void FromBin(ref byte[] PolicyBlob, int offset) { - Header = Tools.BytesToStruct(PolicyBlob, typeof(ProductPolicyValue), offset); - if ((Header.Data + Header.Name + Marshal.SizeOf(Header)) > Header.Size || - (offset + Header.Size) > PolicyBlob.Length) - { - throw new Exception("Invalid _data Header format"); - } + Header = ProductPolicyReader.BytesToStruct(PolicyBlob, offset); + if ((Header.Data + Header.Name + Marshal.SizeOf(Header)) > Header.Size || (offset + Header.Size) > PolicyBlob.Length) + throw new Exception("Invalid data Header format"); + NameFromBin(ref PolicyBlob, offset); ValFromBin(ref PolicyBlob, offset); } @@ -97,57 +58,6 @@ namespace MetroUnlocker.ProductPolicy } } - public int Size() - { - //switch (Type) - //{ - // case RegistryValueKind.String: - // return StringValue.Length * 2; - // case RegistryValueKind.DWord: - // return 4; - // default: - // return Bytes.Length; - //} - return Bytes.Length; - } - - //public byte[] ToBinary() - //{ - // switch (Type) - // { - // case RegistryValueKind.String: - // return Encoding.Unicode.GetBytes(_data.String); - // case RegistryValueKind.DWord: - // return Tools.StructToBytes(DWordVq); - // default: - // return Bytes; - // } - //} - - public byte[] ToBin() - { - ProductPolicyValue value = new ProductPolicyValue(); - value.Name = (UInt16)(2 * Name.Length); - value.Data = (UInt16)Size(); - int datablocksize = Marshal.SizeOf(Header) + value.Name + value.Data; - int suffixLength = 4 - (datablocksize % 4); - value.Size = (UInt16)(Marshal.SizeOf(Header) + value.Name + value.Data + suffixLength); - value.DataType = Header.DataType; - value.Unknown1 = Header.Unknown1; - value.Unknown2 = Header.Unknown2; - byte[] bytes = Tools.StructToBytes(value); - - Tools.AppendBytes(ref bytes, Encoding.Unicode.GetBytes(Name)); - Tools.AppendBytes(ref bytes, Bytes); - Tools.PaddingAppend(ref bytes, suffixLength); - - return bytes; - } - - // I would like to not split the data into dword and string on parsing but on getting. - //public void SetDWordValue(uint value) - //{ - // Data = new ProductPolicyData { DWord = value }; - //} + public int Size() { return Bytes.Length; } } } diff --git a/MetroUnlocker/ProductPolicy/ProductPolicyEditor.cs b/MetroUnlocker/ProductPolicy/ProductPolicyEditor.cs deleted file mode 100644 index 28451fc..0000000 --- a/MetroUnlocker/ProductPolicy/ProductPolicyEditor.cs +++ /dev/null @@ -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 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 FromBinary() - { - return FromBinary(_policyBytes); - } - - public List FromBinary(byte[] policyBlob) - { - var header = Tools.BytesToStruct(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(); - - 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; - } - } -} diff --git a/MetroUnlocker/ProductPolicy/ProductPolicyReader.cs b/MetroUnlocker/ProductPolicy/ProductPolicyReader.cs new file mode 100644 index 0000000..c1f551e --- /dev/null +++ b/MetroUnlocker/ProductPolicy/ProductPolicyReader.cs @@ -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 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(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 FromBinary(byte[] policyBlob) + { + var header = BytesToStruct(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(); + + 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; + } + } +} diff --git a/MetroUnlocker/ProductPolicy/Tools.cs b/MetroUnlocker/ProductPolicy/Tools.cs deleted file mode 100644 index 2e8a9a6..0000000 --- a/MetroUnlocker/ProductPolicy/Tools.cs +++ /dev/null @@ -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(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' 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; - } - } -} diff --git a/MetroUnlocker/Rebooter.cs b/MetroUnlocker/Rebooter.cs deleted file mode 100644 index c487216..0000000 --- a/MetroUnlocker/Rebooter.cs +++ /dev/null @@ -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().First().InvokeMethod("Win32Shutdown", mboShutdownParams, null); - } - } -} diff --git a/MetroUnlocker/SPPManager.cs b/MetroUnlocker/SPPManager.cs deleted file mode 100644 index dff8830..0000000 --- a/MetroUnlocker/SPPManager.cs +++ /dev/null @@ -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; } - } - } -} diff --git a/MetroUnlocker/StartupArguments.cs b/MetroUnlocker/StartupArguments.cs deleted file mode 100644 index e8c9c71..0000000 --- a/MetroUnlocker/StartupArguments.cs +++ /dev/null @@ -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 KnownArguments = new Dictionary() - { - {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; - } - } -} diff --git a/README.md b/README.md index 21229d6..c2aa72d 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,25 @@ -# MetroUnlocker +# Sideloading Unlocker + +![Preview](MetroUnlocker.png "Sideloading Unlocker") ## Unlock signed sideloading on: - Windows 8.0 and up -## Unlock development sideloading on: +## Unlock full sideloading on: - Windows 8.1 Pro and up -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! \ No newline at end of file