Archived
1
1

Refactor and cleanup

This commit is contained in:
Mona Lassa
2025-05-22 02:52:38 +02:00
parent f90695dfda
commit 5ae6b4da9a
12 changed files with 215 additions and 333 deletions

View File

@@ -5,6 +5,11 @@ VisualStudioVersion = 12.0.40629.0
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MetroUnlocker", "MetroUnlocker\MetroUnlocker.csproj", "{D27EB145-0B58-43AD-BB94-BE000D236D38}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MetroUnlocker", "MetroUnlocker\MetroUnlocker.csproj", "{D27EB145-0B58-43AD-BB94-BE000D236D38}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C9C14067-F9A1-4D85-A1D2-162E91B71CC3}"
ProjectSection(SolutionItems) = preProject
DependencyGraph.dgml = DependencyGraph.dgml
EndProjectSection
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU

View File

@@ -17,38 +17,38 @@ namespace MetroUnlocker
{ {
public partial class App : Form public partial class App : Form
{ {
public const string AppxKey = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Policies\\Microsoft\\Windows\\Appx"; public const string AppxRegistryKey = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Policies\\Microsoft\\Windows\\Appx";
string trustedAppsPolicyName = "AllowAllTrustedApps"; string TrustedAppsPolicyName = "AllowAllTrustedApps";
string developmentPolicyName = "AllowDevelopmentWithoutDevLicense"; string DevelopmentPolicyName = "AllowDevelopmentWithoutDevLicense";
string specialProfilesPolicyName = "AllowDeploymentInSpecialProfiles"; string SpecialProfilesPolicyName = "AllowDeploymentInSpecialProfiles";
public bool LOBEnabled public bool LOBEnabled
{ {
get { return GetGroupPolicy(trustedAppsPolicyName); } get { return GetGroupPolicy(TrustedAppsPolicyName); }
set { SetGroupPolicy(trustedAppsPolicyName, value); } set { SetGroupPolicy(TrustedAppsPolicyName, value); }
} }
public bool DevelopmentEnabled public bool DevelopmentEnabled
{ {
get { return GetGroupPolicy(developmentPolicyName); } get { return GetGroupPolicy(DevelopmentPolicyName); }
set { SetGroupPolicy(developmentPolicyName, value); } set { SetGroupPolicy(DevelopmentPolicyName, value); }
} }
public bool SpecialProfilesEnabled public bool SpecialProfilesEnabled
{ {
get { return GetGroupPolicy(specialProfilesPolicyName); } get { return GetGroupPolicy(SpecialProfilesPolicyName); }
set { SetGroupPolicy(specialProfilesPolicyName, value); } set { SetGroupPolicy(SpecialProfilesPolicyName, value); }
} }
public void SetGroupPolicy(string policyName, bool enabled) public void SetGroupPolicy(string policyName, bool enabled)
{ {
Registry.SetValue(AppxKey, policyName, enabled ? 1 : 0, RegistryValueKind.DWord); Registry.SetValue(AppxRegistryKey, policyName, enabled ? 1 : 0, RegistryValueKind.DWord);
} }
public bool GetGroupPolicy(string policyName) public bool GetGroupPolicy(string policyName)
{ {
object value = Registry.GetValue(AppxKey, policyName, 0); object value = Registry.GetValue(AppxRegistryKey, policyName, 0);
return value is int ? (int)value == 1 : false; return value is int ? (int)value == 1 : false;
} }

View File

@@ -45,9 +45,6 @@ namespace MetroUnlocker
public static class Utils public static class Utils
{ {
[DllImport("kernel32.dll")]
public static extern uint GetSystemDefaultLCID();
public static string GetArchitecture() public static string GetArchitecture()
{ {
string arch = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE", EnvironmentVariableTarget.Machine).ToUpperInvariant(); string arch = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE", EnvironmentVariableTarget.Machine).ToUpperInvariant();

View File

@@ -6,13 +6,13 @@ namespace MetroUnlocker.LibTSForge.Crypto
{ {
public static class CryptoUtils public static class CryptoUtils
{ {
public static byte[] GenerateRandomKey(int len) public static byte[] GenerateRandomKey(int length)
{ {
byte[] rand = new byte[len]; byte[] randomKey = new byte[length];
Random r = new Random(); Random random = new Random();
r.NextBytes(rand); random.NextBytes(randomKey);
return rand; return randomKey;
} }
public static byte[] AESEncrypt(byte[] data, byte[] key) public static byte[] AESEncrypt(byte[] data, byte[] key)

View File

@@ -47,19 +47,19 @@ namespace MetroUnlocker.LibTSForge.Crypto
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);
byte[] encAesKey = CryptoUtils.RSAEncrypt(rsaKey, aesKey); byte[] encryptedAesKey = CryptoUtils.RSAEncrypt(rsaKey, aesKey);
byte[] aesKeySig = CryptoUtils.RSASign(rsaKey, encAesKey); byte[] aesKeySignature = CryptoUtils.RSASign(rsaKey, encryptedAesKey);
byte[] hmacSig = CryptoUtils.HMACSign(hmacKey, data); byte[] hmacSignature = CryptoUtils.HMACSign(hmacKey, data);
byte[] decData = new byte[] { }; byte[] decData = new byte[] { };
decData = decData.Concat(hmacKey).Concat(hmacSig).Concat(BitConverter.GetBytes(0)).Concat(data).ToArray(); decData = decData.Concat(hmacKey).Concat(hmacSignature).Concat(BitConverter.GetBytes(0)).Concat(data).ToArray();
byte[] encData = CryptoUtils.AESEncrypt(decData, aesKey); byte[] encData = CryptoUtils.AESEncrypt(decData, aesKey);
BinaryWriter bw = new BinaryWriter(new MemoryStream()); BinaryWriter bw = new BinaryWriter(new MemoryStream());
bw.Write(versionTable[version]); bw.Write(versionTable[version]);
bw.Write(Encoding.UTF8.GetBytes("UNTRUSTSTORE")); bw.Write(Encoding.UTF8.GetBytes("UNTRUSTSTORE"));
bw.Write(aesKeySig); bw.Write(aesKeySignature);
bw.Write(encAesKey); bw.Write(encryptedAesKey);
bw.Write(encData); bw.Write(encData);
return bw.GetBytes(); return bw.GetBytes();

View File

@@ -22,7 +22,7 @@ namespace MetroUnlocker.LibTSForge.Modifiers
Guid instPkeyId = SLApi.GetInstalledProductKeyId(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 != ProductKeyAlgorithm.ProductKey2009)
throw new Exception("The key algorithm isn't 2009"); throw new Exception("The key algorithm isn't 2009");
uint status = SLApi.InstallProductKey(pkey); uint status = SLApi.InstallProductKey(pkey);

View File

@@ -90,92 +90,33 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore
public void AddBlocks(IEnumerable<ModernBlock> blocks) public void AddBlocks(IEnumerable<ModernBlock> blocks)
{ {
foreach (ModernBlock block in blocks) foreach (ModernBlock block in blocks) AddBlock(block);
{
AddBlock(block);
}
} }
public ModernBlock GetBlock(string key, string value) public ModernBlock GetBlock(string key, string value)
{ {
List<ModernBlock> blocks = Data[key]; if (!Data.ContainsKey(key)) return null;
return Data[key].Find(block => block.ValueAsString == value);
foreach (ModernBlock block in blocks)
{
if (block.ValueAsString == value)
{
return new ModernBlock
{
Type = block.Type,
Flags = block.Flags,
Key = Utils.EncodeString(key),
Value = block.Value,
Data = block.Data
};
}
}
return null;
} }
public ModernBlock GetBlock(string key, uint value) public ModernBlock GetBlock(string key, uint value)
{ {
List<ModernBlock> blocks = Data[key]; if (!Data.ContainsKey(key)) return null;
return Data[key].Find(block => block.ValueAsInteger == value);
foreach (ModernBlock block in blocks)
{
if (block.ValueAsInteger == value)
{
return new ModernBlock
{
Type = block.Type,
Flags = block.Flags,
Key = Utils.EncodeString(key),
Value = block.Value,
Data = block.Data
};
}
}
return null;
} }
public void SetBlock(string key, string value, byte[] data) public void SetBlock(string key, string value, byte[] data)
{ {
List<ModernBlock> blocks = Data[key]; if (!Data.ContainsKey(key)) return;
int index = Data[key].FindIndex(block => block.ValueAsString == value);
for (int i = 0; i < blocks.Count; i++) Data[key][index].Data = data;
{
ModernBlock block = blocks[i];
if (block.ValueAsString == value)
{
block.Data = data;
blocks[i] = block;
break;
}
}
Data[key] = blocks;
} }
public void SetBlock(string key, uint value, byte[] data) public void SetBlock(string key, uint value, byte[] data)
{ {
List<ModernBlock> blocks = Data[key]; if (!Data.ContainsKey(key)) return;
int index = Data[key].FindIndex(block => block.ValueAsInteger == value);
for (int i = 0; i < blocks.Count; i++) Data[key][index].Data = data;
{
ModernBlock block = blocks[i];
if (block.ValueAsInteger == value)
{
block.Data = data;
blocks[i] = block;
break;
}
}
Data[key] = blocks;
} }
public void SetBlock(string key, string value, string data) public void SetBlock(string key, string value, string data)
@@ -200,40 +141,12 @@ namespace MetroUnlocker.LibTSForge.PhysicalStore
public void DeleteBlock(string key, string value) public void DeleteBlock(string key, string value)
{ {
if (Data.ContainsKey(key)) Data[key].Remove(GetBlock(key, value));
{
List<ModernBlock> blocks = Data[key];
foreach (ModernBlock block in blocks)
{
if (block.ValueAsString == value)
{
blocks.Remove(block);
break;
}
}
Data[key] = blocks;
}
} }
public void DeleteBlock(string key, uint value) public void DeleteBlock(string key, uint value)
{ {
if (Data.ContainsKey(key)) Data[key].Remove(GetBlock(key, value));
{
List<ModernBlock> blocks = Data[key];
foreach (ModernBlock block in blocks)
{
if (block.ValueAsInteger == value)
{
blocks.Remove(block);
break;
}
}
Data[key] = blocks;
}
} }
public static string GetPath() public static string GetPath()

View File

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

View File

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

View File

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

View File

@@ -3,142 +3,42 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
namespace MetroUnlocker.LibTSForge.SPP namespace MetroUnlocker.LibTSForge.SPP
{ {
public static class SLApi public static class SLApi
{ {
private enum SLIDType
{
SLIDApplication,
SLIDProductSku,
SLIDLicenseFile,
SLIDLicense,
SL_ID_PKEY,
SL_ID_ALL_LICENSES,
SL_ID_ALL_LICENSE_FILES,
SL_ID_STORE_TOKEN,
SL_ID_LAST
}
private enum SLDataType
{
SL_DATA_NONE,
SL_DATA_SZ,
SL_DATA_DWORD,
SL_DATA_BINARY,
SL_DATA_MULTI_SZ,
SL_DATA_SUM
}
[StructLayout(LayoutKind.Sequential)]
private struct SLLicensingStatus
{
public Guid SkuId;
public uint eStatus;
public uint dwGraceTime;
public uint dwTotalGraceDays;
public uint hrReason;
public ulong qwValidityExpiration;
}
[DllImport("sppc.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
private static extern void SLOpen(out IntPtr hSLC);
[DllImport("sppc.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
private static extern void SLClose(IntPtr hSLC);
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLGetWindowsInformationDWORD(string ValueName, ref int Value);
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLInstallProofOfPurchase(IntPtr hSLC, string pwszPKeyAlgorithm, string pwszPKeyString, uint cbPKeySpecificData, byte[] pbPKeySpecificData, ref Guid PKeyId);
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLUninstallProofOfPurchase(IntPtr hSLC, ref Guid PKeyId);
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLGetPKeyInformation(IntPtr hSLC, ref Guid pPKeyId, string pwszValueName, out SLDataType peDataType, out uint pcbValue, out IntPtr ppbValue);
[DllImport("sppcext.dll", CharSet = CharSet.Unicode)]
private static extern uint SLActivateProduct(IntPtr hSLC, ref Guid pProductSkuId, byte[] cbAppSpecificData, byte[] pvAppSpecificData, byte[] pActivationInfo, string pwszProxyServer, ushort wProxyPort);
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLGenerateOfflineInstallationId(IntPtr hSLC, ref Guid pProductSkuId, ref string ppwszInstallationId);
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLDepositOfflineConfirmationId(IntPtr hSLC, ref Guid pProductSkuId, string pwszInstallationId, string pwszConfirmationId);
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLGetSLIDList(IntPtr hSLC, SLIDType eQueryIdType, ref Guid pQueryId, SLIDType eReturnIdType, out uint pnReturnIds, out IntPtr ppReturnIds);
[DllImport("sppc.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
private static extern void SLGetLicensingStatusInformation(IntPtr hSLC, ref Guid pAppID, IntPtr pProductSkuId, string pwszRightName, out uint pnStatusCount, out IntPtr ppLicensingStatus);
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLGetInstalledProductKeyIds(IntPtr hSLC, ref Guid pProductSkuId, out uint pnProductKeyIds, out IntPtr ppProductKeyIds);
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLConsumeWindowsRight(uint unknown);
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLGetProductSkuInformation(IntPtr hSLC, ref Guid pProductSkuId, string pwszValueName, out SLDataType peDataType, out uint pcbValue, out IntPtr ppbValue);
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLGetProductSkuInformation(IntPtr hSLC, ref Guid pProductSkuId, string pwszValueName, IntPtr peDataType, out uint pcbValue, out IntPtr ppbValue);
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLGetLicense(IntPtr hSLC, ref Guid pLicenseFileId, out uint pcbLicenseFile, out IntPtr ppbLicenseFile);
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLSetCurrentProductKey(IntPtr hSLC, ref Guid pProductSkuId, ref Guid pProductKeyId);
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLFireEvent(IntPtr hSLC, string pwszEventId, ref Guid pApplicationId);
public class SLContext : IDisposable public class SLContext : IDisposable
{ {
public readonly IntPtr Handle; public readonly IntPtr Handle;
public SLContext() public SLContext() { NativeMethods.SLOpen(out Handle); }
{
SLOpen(out Handle);
}
public void Dispose() public void Dispose()
{ {
SLClose(Handle); NativeMethods.SLClose(Handle);
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
~SLContext() ~SLContext() { Dispose(); }
{
Dispose();
}
} }
public static Guid GetPkeyConfigFileId(Guid actId) public static Guid GetProductKeyConfigFileId(Guid activationId)
{ {
using (SLContext sl = new SLContext()) using (SLContext sl = new SLContext())
{ {
SLDataType type; SLDataType type;
uint len; uint length;
IntPtr ppReturnLics; IntPtr fileIdPointer;
uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "pkeyConfigLicenseId", out type, out len, out ppReturnLics); uint status = NativeMethods.SLGetProductSkuInformation(sl.Handle, ref activationId, "pkeyConfigLicenseId", out type, out length, out fileIdPointer);
if (status != 0 || len == 0) if (status != 0 || length == 0)
{
return Guid.Empty; return Guid.Empty;
}
Guid pkcId = new Guid(Marshal.PtrToStringAuto(ppReturnLics)); Guid configLicenseId = new Guid(Marshal.PtrToStringAuto(fileIdPointer));
return GetLicenseFileId(pkcId); return GetLicenseFileId(configLicenseId);
} }
} }
@@ -150,9 +50,9 @@ namespace MetroUnlocker.LibTSForge.SPP
uint count; uint count;
IntPtr returnLicenses; IntPtr returnLicenses;
status = SLGetSLIDList(sl.Handle, SLIDType.SLIDLicense, ref licenseId, SLIDType.SLIDLicenseFile, out count, out returnLicenses); status = NativeMethods.SLGetSLIDList(sl.Handle, SLIDType.License, ref licenseId, SLIDType.LicenseFile, out count, out returnLicenses);
return (status == 0 && count != 0) ? (Guid)Marshal.PtrToStructure(returnLicenses, typeof(Guid)) : Guid.Empty;//new Guid(Marshal.PtrToStringAuto(returnLicenses)); return (status == 0 && count != 0) ? (Guid)Marshal.PtrToStructure(returnLicenses, typeof(Guid)) : Guid.Empty;
} }
} }
@@ -162,14 +62,14 @@ namespace MetroUnlocker.LibTSForge.SPP
using (SLContext sl = new SLContext()) using (SLContext sl = new SLContext())
{ {
uint dataLen; uint length;
IntPtr dataPtr; IntPtr dataPointer;
if (SLGetLicense(sl.Handle, ref fileId, out dataLen, out dataPtr) != 0) if (NativeMethods.SLGetLicense(sl.Handle, ref fileId, out length, out dataPointer) != 0)
return null; return null;
byte[] data = new byte[dataLen]; byte[] data = new byte[length];
Marshal.Copy(dataPtr, data, 0, (int)dataLen); Marshal.Copy(dataPointer, data, 0, (int)length);
data = data.Skip(Array.IndexOf(data, (byte)'<')).ToArray(); data = data.Skip(Array.IndexOf(data, (byte)'<')).ToArray();
return Encoding.UTF8.GetString(data); return Encoding.UTF8.GetString(data);
@@ -184,9 +84,9 @@ namespace MetroUnlocker.LibTSForge.SPP
SLDataType type; SLDataType type;
IntPtr binaryValue; IntPtr binaryValue;
uint status = SLGetProductSkuInformation(sl.Handle, ref productSkuId, value, out type, out length, out binaryValue); uint status = NativeMethods.SLGetProductSkuInformation(sl.Handle, ref productSkuId, value, out type, out length, out binaryValue);
if (status != 0 || length == 0 || type != SLDataType.SL_DATA_SZ) if (status != 0 || length == 0 || type != SLDataType.String)
return null; return null;
return Marshal.PtrToStringAuto(binaryValue); return Marshal.PtrToStringAuto(binaryValue);
@@ -198,7 +98,7 @@ namespace MetroUnlocker.LibTSForge.SPP
using (SLContext sl = new SLContext()) using (SLContext sl = new SLContext())
{ {
string installationId = null; string installationId = null;
var status = SLGenerateOfflineInstallationId(sl.Handle, ref actId, ref installationId); var status = NativeMethods.SLGenerateOfflineInstallationId(sl.Handle, ref actId, ref installationId);
if (status != 0) if (status != 0)
throw new Exception(string.Format("Failed to get installation ID: 0x{0}. Your data.dat is probably corrupt at the moment. Try again later.", status.ToString("X"))); throw new Exception(string.Format("Failed to get installation ID: 0x{0}. Your data.dat is probably corrupt at the moment. Try again later.", status.ToString("X")));
@@ -215,7 +115,7 @@ namespace MetroUnlocker.LibTSForge.SPP
uint count; uint count;
IntPtr productKeyIds; IntPtr productKeyIds;
status = SLGetInstalledProductKeyIds(sl.Handle, ref actId, out count, out productKeyIds); status = NativeMethods.SLGetInstalledProductKeyIds(sl.Handle, ref actId, out count, out productKeyIds);
return (status == 0 && count != 0) ? (Guid)Marshal.PtrToStructure(productKeyIds, typeof(Guid)) : Guid.Empty; return (status == 0 && count != 0) ? (Guid)Marshal.PtrToStructure(productKeyIds, typeof(Guid)) : Guid.Empty;
} }
@@ -224,12 +124,12 @@ namespace MetroUnlocker.LibTSForge.SPP
public static uint DepositConfirmationId(Guid actId, string installationId, string confirmationId) public static uint DepositConfirmationId(Guid actId, string installationId, string confirmationId)
{ {
using (SLContext sl = new SLContext()) using (SLContext sl = new SLContext())
return SLDepositOfflineConfirmationId(sl.Handle, ref actId, installationId, confirmationId); return NativeMethods.SLDepositOfflineConfirmationId(sl.Handle, ref actId, installationId, confirmationId);
} }
public static void RefreshLicenseStatus() public static void RefreshLicenseStatus()
{ {
SLConsumeWindowsRight(0); NativeMethods.SLConsumeWindowsRight(0);
} }
public static bool RefreshTrustedTime(Guid actId) public static bool RefreshTrustedTime(Guid actId)
@@ -240,7 +140,7 @@ namespace MetroUnlocker.LibTSForge.SPP
uint count; uint count;
IntPtr ppbValue; IntPtr ppbValue;
uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "TrustedTime", out type, out count, out ppbValue); uint status = NativeMethods.SLGetProductSkuInformation(sl.Handle, ref actId, "TrustedTime", out type, out count, out ppbValue);
return (int)status >= 0 && status != 0xC004F012; return (int)status >= 0 && status != 0xC004F012;
} }
} }
@@ -248,22 +148,22 @@ 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); NativeMethods.SLFireEvent(sl.Handle, "msft:rm/event/licensingstatechanged", ref appId);
} }
public static Guid GetAppId(Guid actId) public static Guid GetAppId(Guid activationId)
{ {
using (SLContext sl = new SLContext()) using (SLContext sl = new SLContext())
{ {
uint count; uint count;
IntPtr pAppIds; IntPtr appIdPointer;
uint status = SLGetSLIDList(sl.Handle, SLIDType.SLIDProductSku, ref actId, SLIDType.SLIDApplication, out count, out pAppIds); uint status = NativeMethods.SLGetSLIDList(sl.Handle, SLIDType.ProductSku, ref activationId, SLIDType.Application, out count, out appIdPointer);
if (status != 0 || count == 0) if (status != 0 || count == 0)
return Guid.Empty; return Guid.Empty;
return (Guid)Marshal.PtrToStructure(pAppIds, typeof(Guid)); return (Guid)Marshal.PtrToStructure(appIdPointer, typeof(Guid));
} }
} }
@@ -275,7 +175,7 @@ namespace MetroUnlocker.LibTSForge.SPP
SLDataType type; SLDataType type;
IntPtr ppbValue; IntPtr ppbValue;
uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "DependsOn", out type, out count, out ppbValue); uint status = NativeMethods.SLGetProductSkuInformation(sl.Handle, ref actId, "DependsOn", out type, out count, out ppbValue);
return (int)status >= 0 && status != 0xC004F012; return (int)status >= 0 && status != 0xC004F012;
} }
} }
@@ -284,15 +184,15 @@ namespace MetroUnlocker.LibTSForge.SPP
{ {
using (SLContext sl = new SLContext()) using (SLContext sl = new SLContext())
{ {
Guid pkeyId = Guid.Empty; Guid productKeyId = Guid.Empty;
return SLInstallProofOfPurchase(sl.Handle, pkey.GetAlgoUri(), pkey.ToString(), 0, null, ref pkeyId); return NativeMethods.SLInstallProofOfPurchase(sl.Handle, pkey.GetAlgoUri(), pkey.ToString(), 0, null, ref productKeyId);
} }
} }
public static uint UninstallProductKey(Guid pkeyId) public static uint UninstallProductKey(Guid productKeyId)
{ {
using (SLContext sl = new SLContext()) using (SLContext sl = new SLContext())
return SLUninstallProofOfPurchase(sl.Handle, ref pkeyId); return NativeMethods.SLUninstallProofOfPurchase(sl.Handle, ref productKeyId);
} }
} }
} }

View File

@@ -67,7 +67,8 @@
<Compile Include="LibTSForge\PhysicalStore\ModernBlock.cs" /> <Compile Include="LibTSForge\PhysicalStore\ModernBlock.cs" />
<Compile Include="LibTSForge\PhysicalStore\PhysicalStore.cs" /> <Compile Include="LibTSForge\PhysicalStore\PhysicalStore.cs" />
<Compile Include="LibTSForge\PhysicalStore\VariableBag.cs" /> <Compile Include="LibTSForge\PhysicalStore\VariableBag.cs" />
<Compile Include="LibTSForge\SPP\PKeyConfig.cs" /> <Compile Include="LibTSForge\SPP\NativeMethods.cs" />
<Compile Include="LibTSForge\SPP\ProductKeyConfig.cs" />
<Compile Include="LibTSForge\SPP\ProductKey.cs" /> <Compile Include="LibTSForge\SPP\ProductKey.cs" />
<Compile Include="LibTSForge\SPP\SLApi.cs" /> <Compile Include="LibTSForge\SPP\SLApi.cs" />
<Compile Include="LibTSForge\TokenStore\TokenEntry.cs" /> <Compile Include="LibTSForge\TokenStore\TokenEntry.cs" />