summaryrefslogtreecommitdiff
path: root/LibTSforge/SPP
diff options
context:
space:
mode:
Diffstat (limited to 'LibTSforge/SPP')
-rw-r--r--LibTSforge/SPP/PKeyConfig.cs215
-rw-r--r--LibTSforge/SPP/ProductKey.cs313
-rw-r--r--LibTSforge/SPP/SLAPI.cs417
3 files changed, 945 insertions, 0 deletions
diff --git a/LibTSforge/SPP/PKeyConfig.cs b/LibTSforge/SPP/PKeyConfig.cs
new file mode 100644
index 0000000..a608608
--- /dev/null
+++ b/LibTSforge/SPP/PKeyConfig.cs
@@ -0,0 +1,215 @@
+namespace LibTSforge.SPP
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Linq;
+ using System.Text;
+ using System.Xml;
+
+ public enum PKeyAlgorithm
+ {
+ PKEY2005,
+ PKEY2009
+ }
+
+ public class KeyRange
+ {
+ public int Start;
+ public int End;
+ public string EulaType;
+ public string PartNumber;
+ public bool Valid;
+
+ public bool Contains(int n)
+ {
+ return Start <= n && End <= n;
+ }
+ }
+
+ public class ProductConfig
+ {
+ public int GroupId;
+ public string Edition;
+ public string Description;
+ public string Channel;
+ public bool Randomized;
+ public PKeyAlgorithm Algorithm;
+ public List<KeyRange> Ranges;
+ public Guid ActivationId;
+
+ private List<KeyRange> GetPkeyRanges()
+ {
+ if (Ranges.Count == 0)
+ {
+ throw new ArgumentException("No key ranges.");
+ }
+
+ if (Algorithm == PKeyAlgorithm.PKEY2005)
+ {
+ return Ranges;
+ }
+
+ List<KeyRange> FilteredRanges = Ranges.Where(r => !r.EulaType.Contains("WAU")).ToList();
+
+ if (FilteredRanges.Count == 0)
+ {
+ throw new NotSupportedException("Specified Activation ID is usable only for Windows Anytime Upgrade. Please use a non-WAU Activation ID instead.");
+ }
+
+ return FilteredRanges;
+ }
+
+ public ProductKey GetRandomKey()
+ {
+ List<KeyRange> KeyRanges = GetPkeyRanges();
+ Random rnd = new Random();
+
+ KeyRange range = KeyRanges[rnd.Next(KeyRanges.Count)];
+ int serial = rnd.Next(range.Start, range.End);
+
+ return new ProductKey(serial, 0, false, Algorithm, this, range);
+ }
+ }
+
+ public class PKeyConfig
+ {
+ public Dictionary<Guid, ProductConfig> Products = new Dictionary<Guid, ProductConfig>();
+ private List<Guid> loadedPkeyConfigs = new List<Guid>();
+
+ public void LoadConfig(Guid actId)
+ {
+ string pkcData;
+ Guid pkcFileId = SLApi.GetPkeyConfigFileId(actId);
+
+ if (loadedPkeyConfigs.Contains(pkcFileId)) return;
+
+ string licConts = SLApi.GetLicenseContents(pkcFileId);
+
+ using (TextReader tr = new StringReader(licConts))
+ {
+ XmlDocument lic = new XmlDocument();
+ lic.Load(tr);
+
+ XmlNamespaceManager nsmgr = new XmlNamespaceManager(lic.NameTable);
+ nsmgr.AddNamespace("rg", "urn:mpeg:mpeg21:2003:01-REL-R-NS");
+ nsmgr.AddNamespace("r", "urn:mpeg:mpeg21:2003:01-REL-R-NS");
+ nsmgr.AddNamespace("tm", "http://www.microsoft.com/DRM/XrML2/TM/v2");
+
+ XmlNode root = lic.DocumentElement;
+ XmlNode pkcDataNode = root.SelectSingleNode("/rg:licenseGroup/r:license/r:otherInfo/tm:infoTables/tm:infoList/tm:infoBin[@name=\"pkeyConfigData\"]", nsmgr);
+ pkcData = Encoding.UTF8.GetString(Convert.FromBase64String(pkcDataNode.InnerText));
+ }
+
+ using (TextReader tr = new StringReader(pkcData))
+ {
+ XmlDocument lic = new XmlDocument();
+ lic.Load(tr);
+
+ XmlNamespaceManager nsmgr = new XmlNamespaceManager(lic.NameTable);
+ nsmgr.AddNamespace("p", "http://www.microsoft.com/DRM/PKEY/Configuration/2.0");
+ XmlNodeList configNodes = lic.SelectNodes("//p:ProductKeyConfiguration/p:Configurations/p:Configuration", nsmgr);
+ XmlNodeList rangeNodes = lic.SelectNodes("//p:ProductKeyConfiguration/p:KeyRanges/p:KeyRange", nsmgr);
+ XmlNodeList pubKeyNodes = lic.SelectNodes("//p:ProductKeyConfiguration/p:PublicKeys/p:PublicKey", nsmgr);
+
+ Dictionary<int, PKeyAlgorithm> algorithms = new Dictionary<int, PKeyAlgorithm>();
+ Dictionary<string, List<KeyRange>> ranges = new Dictionary<string, List<KeyRange>>();
+
+ Dictionary<string, PKeyAlgorithm> algoConv = new Dictionary<string, PKeyAlgorithm>
+ {
+ { "msft:rm/algorithm/pkey/2005", PKeyAlgorithm.PKEY2005 },
+ { "msft:rm/algorithm/pkey/2009", PKeyAlgorithm.PKEY2009 }
+ };
+
+ foreach (XmlNode pubKeyNode in pubKeyNodes)
+ {
+ int group = int.Parse(pubKeyNode.SelectSingleNode("./p:GroupId", nsmgr).InnerText);
+ algorithms[group] = algoConv[pubKeyNode.SelectSingleNode("./p:AlgorithmId", nsmgr).InnerText];
+ }
+
+ foreach (XmlNode rangeNode in rangeNodes)
+ {
+ string refActIdStr = rangeNode.SelectSingleNode("./p:RefActConfigId", nsmgr).InnerText;
+
+ if (!ranges.ContainsKey(refActIdStr))
+ {
+ ranges[refActIdStr] = new List<KeyRange>();
+ }
+
+ KeyRange keyRange = new KeyRange();
+ keyRange.Start = int.Parse(rangeNode.SelectSingleNode("./p:Start", nsmgr).InnerText);
+ keyRange.End = int.Parse(rangeNode.SelectSingleNode("./p:End", nsmgr).InnerText);
+ keyRange.EulaType = rangeNode.SelectSingleNode("./p:EulaType", nsmgr).InnerText;
+ keyRange.PartNumber = rangeNode.SelectSingleNode("./p:PartNumber", nsmgr).InnerText;
+ keyRange.Valid = rangeNode.SelectSingleNode("./p:IsValid", nsmgr).InnerText.ToLower() == "true";
+
+ ranges[refActIdStr].Add(keyRange);
+ }
+
+ foreach (XmlNode configNode in configNodes)
+ {
+ string refActIdStr = configNode.SelectSingleNode("./p:ActConfigId", nsmgr).InnerText;
+ Guid refActId = new Guid(refActIdStr);
+ int group = int.Parse(configNode.SelectSingleNode("./p:RefGroupId", nsmgr).InnerText);
+ List<KeyRange> keyRanges = ranges[refActIdStr];
+
+ if (keyRanges.Count > 0 && !Products.ContainsKey(refActId))
+ {
+ ProductConfig productConfig = new ProductConfig();
+ productConfig.GroupId = group;
+ productConfig.Edition = configNode.SelectSingleNode("./p:EditionId", nsmgr).InnerText;
+ productConfig.Description = configNode.SelectSingleNode("./p:ProductDescription", nsmgr).InnerText;
+ productConfig.Channel = configNode.SelectSingleNode("./p:ProductKeyType", nsmgr).InnerText;
+ productConfig.Randomized = configNode.SelectSingleNode("./p:ProductKeyType", nsmgr).InnerText.ToLower() == "true";
+ productConfig.Algorithm = algorithms[group];
+ productConfig.Ranges = keyRanges;
+ productConfig.ActivationId = refActId;
+
+ Products[refActId] = productConfig;
+ }
+ }
+ }
+
+ loadedPkeyConfigs.Add(pkcFileId);
+ }
+
+ public ProductConfig MatchParams(int group, int serial)
+ {
+ foreach (ProductConfig config in Products.Values)
+ {
+ if (config.GroupId == group)
+ {
+ foreach (KeyRange range in config.Ranges)
+ {
+ if (range.Contains(serial))
+ {
+ return config;
+ }
+ }
+ }
+ }
+
+ throw new FileNotFoundException("Failed to find product matching supplied product key parameters.");
+ }
+
+ public void LoadAllConfigs(Guid appId)
+ {
+ foreach (Guid actId in SLApi.GetActivationIds(appId))
+ {
+ try
+ {
+ LoadConfig(actId);
+ }
+ catch (ArgumentException)
+ {
+
+ }
+ }
+ }
+
+ public PKeyConfig()
+ {
+
+ }
+ }
+}
diff --git a/LibTSforge/SPP/ProductKey.cs b/LibTSforge/SPP/ProductKey.cs
new file mode 100644
index 0000000..7a933da
--- /dev/null
+++ b/LibTSforge/SPP/ProductKey.cs
@@ -0,0 +1,313 @@
+namespace LibTSforge.SPP
+{
+ using System;
+ using System.IO;
+ using System.Linq;
+ using LibTSforge.Crypto;
+ using LibTSforge.PhysicalStore;
+
+ public class ProductKey
+ {
+ private static readonly string ALPHABET = "BCDFGHJKMPQRTVWXY2346789";
+
+ private readonly ulong klow;
+ private readonly ulong khigh;
+
+ public int Group;
+ public int Serial;
+ public ulong Security;
+ public bool Upgrade;
+ public PKeyAlgorithm Algorithm;
+ public string EulaType;
+ public string PartNumber;
+ public string Edition;
+ public string Channel;
+ public Guid ActivationId;
+
+ private string mpc;
+ private string pid2;
+
+ public byte[] KeyBytes
+ {
+ get { return BitConverter.GetBytes(klow).Concat(BitConverter.GetBytes(khigh)).ToArray(); }
+ }
+
+ public ProductKey(int serial, ulong security, bool upgrade, PKeyAlgorithm algorithm, ProductConfig config, KeyRange range)
+ {
+ Group = config.GroupId;
+ Serial = serial;
+ Security = security;
+ Upgrade = upgrade;
+ Algorithm = algorithm;
+ EulaType = range.EulaType;
+ PartNumber = range.PartNumber.Split(':', ';')[0];
+ Edition = config.Edition;
+ Channel = config.Channel;
+ ActivationId = config.ActivationId;
+
+ klow = ((security & 0x3fff) << 50 | ((ulong)serial & 0x3fffffff) << 20 | ((ulong)Group & 0xfffff));
+ khigh = ((upgrade ? (ulong)1 : 0) << 49 | ((security >> 14) & 0x7fffffffff));
+
+ uint checksum = Utils.CRC32(KeyBytes) & 0x3ff;
+
+ khigh |= ((ulong)checksum << 39);
+ }
+
+ public string GetAlgoUri()
+ {
+ return "msft:rm/algorithm/pkey/" + (Algorithm == PKeyAlgorithm.PKEY2005 ? "2005" : (Algorithm == PKeyAlgorithm.PKEY2009 ? "2009" : "Unknown"));
+ }
+
+ public Guid GetPkeyId()
+ {
+ VariableBag pkb = new VariableBag();
+ pkb.Blocks.AddRange(new CRCBlock[]
+ {
+ new CRCBlock
+ {
+ DataType = CRCBlockType.STRING,
+ KeyAsStr = "SppPkeyBindingProductKey",
+ ValueAsStr = ToString()
+ },
+ new CRCBlock
+ {
+ DataType = CRCBlockType.BINARY,
+ KeyAsStr = "SppPkeyBindingMiscData",
+ Value = new byte[] { }
+ },
+ new CRCBlock
+ {
+ DataType = CRCBlockType.STRING,
+ KeyAsStr = "SppPkeyBindingAlgorithm",
+ ValueAsStr = GetAlgoUri()
+ }
+ });
+
+ return new Guid(CryptoUtils.SHA256Hash(pkb.Serialize()).Take(16).ToArray());
+ }
+
+ public string GetDefaultMPC()
+ {
+ int build = Environment.OSVersion.Version.Build;
+ string defaultMPC = build >= 10240 ? "03612" :
+ build >= 9600 ? "06401" :
+ build >= 9200 ? "05426" :
+ "55041";
+ return defaultMPC;
+ }
+
+ public string GetMPC()
+ {
+ if (mpc != null)
+ {
+ return mpc;
+ }
+
+ mpc = GetDefaultMPC();
+
+ // setup.cfg doesn't exist in Windows 8+
+ string setupcfg = string.Format("{0}\\oobe\\{1}", Environment.SystemDirectory, "setup.cfg");
+
+ if (!File.Exists(setupcfg) || Edition.Contains(";"))
+ {
+ return mpc;
+ }
+
+ string mpcKey = string.Format("{0}.{1}=", Utils.GetArchitecture(), Edition);
+ string localMPC = File.ReadAllLines(setupcfg).FirstOrDefault(line => line.Contains(mpcKey));
+ if (localMPC != null)
+ {
+ mpc = localMPC.Split('=')[1].Trim();
+ }
+
+ return mpc;
+ }
+
+ public string GetPid2()
+ {
+ if (pid2 != null)
+ {
+ return pid2;
+ }
+
+ pid2 = "";
+
+ if (Algorithm == PKeyAlgorithm.PKEY2005)
+ {
+ string mpc = GetMPC();
+ string serialHigh;
+ int serialLow;
+ int lastPart;
+
+ if (EulaType == "OEM")
+ {
+ serialHigh = "OEM";
+ serialLow = ((Group / 2) % 100) * 10000 + (Serial / 100000);
+ lastPart = Serial % 100000;
+ }
+ else
+ {
+ serialHigh = (Serial / 1000000).ToString("D3");
+ serialLow = Serial % 1000000;
+ lastPart = ((Group / 2) % 100) * 1000 + new Random().Next(1000);
+ }
+
+ int checksum = 0;
+
+ foreach (char c in serialLow.ToString())
+ {
+ checksum += int.Parse(c.ToString());
+ }
+ checksum = 7 - (checksum % 7);
+
+ pid2 = string.Format("{0}-{1}-{2:D6}{3}-{4:D5}", mpc, serialHigh, serialLow, checksum, lastPart);
+ }
+
+ return pid2;
+ }
+
+ public byte[] GetPid3()
+ {
+ BinaryWriter writer = new BinaryWriter(new MemoryStream());
+ writer.Write(0xA4);
+ writer.Write(0x3);
+ writer.WriteFixedString(GetPid2(), 24);
+ writer.Write(Group);
+ writer.WriteFixedString(PartNumber, 16);
+ writer.WritePadding(0x6C);
+ byte[] data = writer.GetBytes();
+ byte[] crc = BitConverter.GetBytes(~Utils.CRC32(data.Reverse().ToArray())).Reverse().ToArray();
+ writer.Write(crc);
+
+ return writer.GetBytes();
+ }
+
+ public byte[] GetPid4()
+ {
+ BinaryWriter writer = new BinaryWriter(new MemoryStream());
+ writer.Write(0x4F8);
+ writer.Write(0x4);
+ writer.WriteFixedString16(GetExtendedPid(), 0x80);
+ writer.WriteFixedString16(ActivationId.ToString(), 0x80);
+ writer.WritePadding(0x10);
+ writer.WriteFixedString16(Edition, 0x208);
+ writer.Write(Upgrade ? (ulong)1 : 0);
+ writer.WritePadding(0x50);
+ writer.WriteFixedString16(PartNumber, 0x80);
+ writer.WriteFixedString16(Channel, 0x80);
+ writer.WriteFixedString16(EulaType, 0x80);
+
+ return writer.GetBytes();
+ }
+
+ public string GetExtendedPid()
+ {
+ string mpc = GetMPC();
+ int serialHigh = Serial / 1000000;
+ int serialLow = Serial % 1000000;
+ int licenseType;
+ uint lcid = Utils.GetSystemDefaultLCID();
+ int build = Environment.OSVersion.Version.Build;
+ int dayOfYear = DateTime.Now.DayOfYear;
+ int year = DateTime.Now.Year;
+
+ switch (EulaType)
+ {
+ case "OEM":
+ licenseType = 2;
+ break;
+
+ case "Volume":
+ licenseType = 3;
+ break;
+
+ default:
+ licenseType = 0;
+ break;
+ }
+
+ return string.Format(
+ "{0}-{1:D5}-{2:D3}-{3:D6}-{4:D2}-{5:D4}-{6:D4}.0000-{7:D3}{8:D4}",
+ mpc,
+ Group,
+ serialHigh,
+ serialLow,
+ licenseType,
+ lcid,
+ build,
+ dayOfYear,
+ year
+ );
+ }
+
+ public byte[] GetPhoneData(PSVersion version)
+ {
+ if (version == PSVersion.Win7)
+ {
+ Random rnd = new Random(Group * 1000000000 + Serial);
+ byte[] data = new byte[8];
+ rnd.NextBytes(data);
+ return data;
+ }
+
+ int serialHigh = Serial / 1000000;
+ int serialLow = Serial % 1000000;
+
+ BinaryWriter writer = new BinaryWriter(new MemoryStream());
+ writer.Write(new Guid("B8731595-A2F6-430B-A799-FBFFB81A8D73").ToByteArray());
+ writer.Write(Group);
+ writer.Write(serialHigh);
+ writer.Write(serialLow);
+ writer.Write(Upgrade ? 1 : 0);
+ writer.Write(Security);
+
+ return writer.GetBytes();
+ }
+
+ public override string ToString()
+ {
+ string keyStr = "";
+ Random rnd = new Random(Group * 1000000000 + Serial);
+
+ if (Algorithm == PKeyAlgorithm.PKEY2005)
+ {
+ keyStr = "H4X3DH4X3DH4X3DH4X3D";
+
+ for (int i = 0; i < 5; i++)
+ {
+ keyStr += ALPHABET[rnd.Next(24)];
+ }
+ }
+ else if (Algorithm == PKeyAlgorithm.PKEY2009)
+ {
+ int last = 0;
+ byte[] bKey = KeyBytes;
+
+ for (int i = 24; i >= 0; i--)
+ {
+ int current = 0;
+
+ for (int j = 14; j >= 0; j--)
+ {
+ current *= 0x100;
+ current += bKey[j];
+ bKey[j] = (byte)(current / 24);
+ current %= 24;
+ last = current;
+ }
+
+ keyStr = ALPHABET[current] + keyStr;
+ }
+
+ keyStr = keyStr.Substring(1, last) + "N" + keyStr.Substring(last + 1, keyStr.Length - last - 1);
+ }
+
+ for (int i = 5; i < keyStr.Length; i += 6)
+ {
+ keyStr = keyStr.Insert(i, "-");
+ }
+
+ return keyStr;
+ }
+ }
+}
diff --git a/LibTSforge/SPP/SLAPI.cs b/LibTSforge/SPP/SLAPI.cs
new file mode 100644
index 0000000..cfd7dc5
--- /dev/null
+++ b/LibTSforge/SPP/SLAPI.cs
@@ -0,0 +1,417 @@
+namespace LibTSforge.SPP
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Runtime.InteropServices;
+ using System.Text;
+
+ public static class SLApi
+ {
+ private enum SLIDTYPE
+ {
+ SL_ID_APPLICATION,
+ SL_ID_PRODUCT_SKU,
+ SL_ID_LICENSE_FILE,
+ SL_ID_LICENSE,
+ SL_ID_PKEY,
+ SL_ID_ALL_LICENSES,
+ SL_ID_ALL_LICENSE_FILES,
+ SL_ID_STORE_TOKEN,
+ SL_ID_LAST
+ }
+
+ private enum SLDATATYPE
+ {
+ SL_DATA_NONE,
+ SL_DATA_SZ,
+ SL_DATA_DWORD,
+ SL_DATA_BINARY,
+ SL_DATA_MULTI_SZ,
+ SL_DATA_SUM
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct SL_LICENSING_STATUS
+ {
+ public Guid SkuId;
+ public uint eStatus;
+ public uint dwGraceTime;
+ public uint dwTotalGraceDays;
+ public uint hrReason;
+ public ulong qwValidityExpiration;
+ }
+
+ public static readonly Guid WINDOWS_APP_ID = new Guid("55c92734-d682-4d71-983e-d6ec3f16059f");
+
+ [DllImport("sppc.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
+ private static extern void SLOpen(out IntPtr hSLC);
+
+ [DllImport("sppc.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
+ private static extern void SLClose(IntPtr hSLC);
+
+ [DllImport("slc.dll", CharSet = CharSet.Unicode)]
+ private static extern uint SLGetWindowsInformationDWORD(string ValueName, ref int Value);
+
+ [DllImport("sppc.dll", CharSet = CharSet.Unicode)]
+ private static extern uint SLInstallProofOfPurchase(IntPtr hSLC, string pwszPKeyAlgorithm, string pwszPKeyString, uint cbPKeySpecificData, byte[] pbPKeySpecificData, ref Guid PKeyId);
+
+ [DllImport("sppc.dll", CharSet = CharSet.Unicode)]
+ private static extern uint SLUninstallProofOfPurchase(IntPtr hSLC, ref Guid PKeyId);
+
+ [DllImport("sppc.dll", CharSet = CharSet.Unicode)]
+ private static extern uint SLGetPKeyInformation(IntPtr hSLC, ref Guid pPKeyId, string pwszValueName, out SLDATATYPE peDataType, out uint pcbValue, out IntPtr ppbValue);
+
+ [DllImport("sppcext.dll", CharSet = CharSet.Unicode)]
+ private static extern uint SLActivateProduct(IntPtr hSLC, ref Guid pProductSkuId, byte[] cbAppSpecificData, byte[] pvAppSpecificData, byte[] pActivationInfo, string pwszProxyServer, ushort wProxyPort);
+
+ [DllImport("sppc.dll", CharSet = CharSet.Unicode)]
+ private static extern uint SLGenerateOfflineInstallationId(IntPtr hSLC, ref Guid pProductSkuId, ref string ppwszInstallationId);
+
+ [DllImport("sppc.dll", CharSet = CharSet.Unicode)]
+ private static extern uint SLDepositOfflineConfirmationId(IntPtr hSLC, ref Guid pProductSkuId, string pwszInstallationId, string pwszConfirmationId);
+
+ [DllImport("sppc.dll", CharSet = CharSet.Unicode)]
+ private static extern uint SLGetSLIDList(IntPtr hSLC, SLIDTYPE eQueryIdType, ref Guid pQueryId, SLIDTYPE eReturnIdType, out uint pnReturnIds, out IntPtr ppReturnIds);
+
+ [DllImport("sppc.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
+ private static extern void SLGetLicensingStatusInformation(IntPtr hSLC, ref Guid pAppID, IntPtr pProductSkuId, string pwszRightName, out uint pnStatusCount, out IntPtr ppLicensingStatus);
+
+ [DllImport("sppc.dll", CharSet = CharSet.Unicode)]
+ private static extern uint SLGetInstalledProductKeyIds(IntPtr hSLC, ref Guid pProductSkuId, out uint pnProductKeyIds, out IntPtr ppProductKeyIds);
+
+ [DllImport("slc.dll", CharSet = CharSet.Unicode)]
+ private static extern uint SLConsumeWindowsRight(uint unknown);
+
+ [DllImport("slc.dll", CharSet = CharSet.Unicode)]
+ private static extern uint SLGetProductSkuInformation(IntPtr hSLC, ref Guid pProductSkuId, string pwszValueName, out SLDATATYPE peDataType, out uint pcbValue, out IntPtr ppbValue);
+
+ [DllImport("slc.dll", CharSet = CharSet.Unicode)]
+ private static extern uint SLGetProductSkuInformation(IntPtr hSLC, ref Guid pProductSkuId, string pwszValueName, IntPtr peDataType, out uint pcbValue, out IntPtr ppbValue);
+
+ [DllImport("slc.dll", CharSet = CharSet.Unicode)]
+ private static extern uint SLGetLicense(IntPtr hSLC, ref Guid pLicenseFileId, out uint pcbLicenseFile, out IntPtr ppbLicenseFile);
+
+ [DllImport("slc.dll", CharSet = CharSet.Unicode)]
+ private static extern uint SLSetCurrentProductKey(IntPtr hSLC, ref Guid pProductSkuId, ref Guid pProductKeyId);
+
+ [DllImport("slc.dll", CharSet = CharSet.Unicode)]
+ private static extern uint SLFireEvent(IntPtr hSLC, string pwszEventId, ref Guid pApplicationId);
+
+ public class SLContext : IDisposable
+ {
+ public readonly IntPtr Handle;
+
+ public SLContext()
+ {
+ SLOpen(out Handle);
+ }
+
+ public void Dispose()
+ {
+ SLClose(Handle);
+ GC.SuppressFinalize(this);
+ }
+
+ ~SLContext()
+ {
+ Dispose();
+ }
+ }
+
+ public static Guid GetDefaultActivationID(Guid appId, bool includeActivated)
+ {
+ using (SLContext sl = new SLContext())
+ {
+ uint count;
+ IntPtr pLicStat;
+
+ SLGetLicensingStatusInformation(sl.Handle, ref appId, IntPtr.Zero, null, out count, out pLicStat);
+
+ unsafe
+ {
+ SL_LICENSING_STATUS* licensingStatuses = (SL_LICENSING_STATUS*)pLicStat;
+ for (int i = 0; i < count; i++)
+ {
+ SL_LICENSING_STATUS slStatus = licensingStatuses[i];
+
+ Guid actId = slStatus.SkuId;
+ if (GetInstalledPkeyID(actId) == Guid.Empty) continue;
+ if (IsAddon(actId)) continue;
+ if (!includeActivated && (slStatus.eStatus == 1)) continue;
+
+ return actId;
+ }
+ }
+
+ return Guid.Empty;
+ }
+ }
+
+ public static string GetInstallationID(Guid actId)
+ {
+ using (SLContext sl = new SLContext())
+ {
+ string installationId = null;
+ return SLGenerateOfflineInstallationId(sl.Handle, ref actId, ref installationId) == 0 ? installationId : null;
+ }
+ }
+
+ public static Guid GetInstalledPkeyID(Guid actId)
+ {
+ using (SLContext sl = new SLContext())
+ {
+ uint status;
+ uint count;
+ IntPtr pProductKeyIds;
+
+ status = SLGetInstalledProductKeyIds(sl.Handle, ref actId, out count, out pProductKeyIds);
+
+ if (status != 0 || count == 0)
+ {
+ return Guid.Empty;
+ }
+
+ unsafe { return *(Guid*)pProductKeyIds; }
+ }
+ }
+
+ public static uint DepositConfirmationID(Guid actId, string installationId, string confirmationId)
+ {
+ using (SLContext sl = new SLContext())
+ {
+ return SLDepositOfflineConfirmationId(sl.Handle, ref actId, installationId, confirmationId);
+ }
+ }
+
+ public static void RefreshLicenseStatus()
+ {
+ SLConsumeWindowsRight(0);
+ }
+
+ public static bool RefreshTrustedTime(Guid actId)
+ {
+ using (SLContext sl = new SLContext())
+ {
+ SLDATATYPE type;
+ uint count;
+ IntPtr ppbValue;
+
+ uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "TrustedTime", out type, out count, out ppbValue);
+ return (int)status >= 0 && status != 0xC004F012;
+ }
+ }
+
+ public static void FireStateChangedEvent(Guid appId)
+ {
+ using (SLContext sl = new SLContext())
+ {
+ SLFireEvent(sl.Handle, "msft:rm/event/licensingstatechanged", ref appId);
+ }
+ }
+
+ public static Guid GetAppId(Guid actId)
+ {
+ using (SLContext sl = new SLContext())
+ {
+ uint status;
+ uint count;
+ IntPtr pAppIds;
+
+ status = SLGetSLIDList(sl.Handle, SLIDTYPE.SL_ID_PRODUCT_SKU, ref actId, SLIDTYPE.SL_ID_APPLICATION, out count, out pAppIds);
+
+ if (status != 0 || count == 0)
+ {
+ return Guid.Empty;
+ }
+
+ unsafe { return *(Guid*)pAppIds; }
+ }
+ }
+
+ public static bool IsAddon(Guid actId)
+ {
+ using (SLContext sl = new SLContext())
+ {
+ uint count;
+ SLDATATYPE type;
+ IntPtr ppbValue;
+
+ uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "DependsOn", out type, out count, out ppbValue);
+ return (int)status >= 0 && status != 0xC004F012;
+ }
+ }
+
+ public static Guid GetLicenseFileId(Guid licId)
+ {
+ using (SLContext sl = new SLContext())
+ {
+ uint status;
+ uint count;
+ IntPtr ppReturnLics;
+
+ status = SLGetSLIDList(sl.Handle, SLIDTYPE.SL_ID_LICENSE, ref licId, SLIDTYPE.SL_ID_LICENSE_FILE, out count, out ppReturnLics);
+
+ if (status != 0 || count == 0)
+ {
+ return Guid.Empty;
+ }
+
+ unsafe { return *(Guid*)ppReturnLics; }
+ }
+ }
+
+ public static Guid GetPkeyConfigFileId(Guid actId)
+ {
+ using (SLContext sl = new SLContext())
+ {
+ SLDATATYPE type;
+ uint len;
+ IntPtr ppReturnLics;
+
+ uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "pkeyConfigLicenseId", out type, out len, out ppReturnLics);
+
+ if (status != 0 || len == 0)
+ {
+ return Guid.Empty;
+ }
+
+ Guid pkcId = new Guid(Marshal.PtrToStringAuto(ppReturnLics));
+ return GetLicenseFileId(pkcId);
+ }
+ }
+
+ public static string GetLicenseContents(Guid fileId)
+ {
+ if (fileId == Guid.Empty) throw new ArgumentException("License contents could not be retrieved.");
+
+ using (SLContext sl = new SLContext())
+ {
+ uint dataLen;
+ IntPtr dataPtr;
+
+ if (SLGetLicense(sl.Handle, ref fileId, out dataLen, out dataPtr) != 0)
+ {
+ return null;
+ }
+
+ byte[] data = new byte[dataLen];
+ Marshal.Copy(dataPtr, data, 0, (int)dataLen);
+
+ data = data.Skip(Array.IndexOf(data, (byte)'<')).ToArray();
+ return Encoding.UTF8.GetString(data);
+ }
+ }
+
+ public static bool IsPhoneActivatable(Guid actId)
+ {
+ using (SLContext sl = new SLContext())
+ {
+ uint count;
+ SLDATATYPE type;
+ IntPtr ppbValue;
+
+ uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "msft:sl/EUL/PHONE/PUBLIC", out type, out count, out ppbValue);
+ return status >= 0 && status != 0xC004F012;
+ }
+ }
+
+ public static string GetPKeyChannel(Guid pkeyId)
+ {
+ using (SLContext sl = new SLContext())
+ {
+ SLDATATYPE type;
+ uint len;
+ IntPtr ppbValue;
+
+ uint status = SLGetPKeyInformation(sl.Handle, ref pkeyId, "Channel", out type, out len, out ppbValue);
+
+ if (status != 0 || len == 0)
+ {
+ return null;
+ }
+
+ return Marshal.PtrToStringAuto(ppbValue);
+ }
+ }
+
+ public static string GetMetaStr(Guid actId, string value)
+ {
+ using (SLContext sl = new SLContext())
+ {
+ uint len;
+ SLDATATYPE type;
+ IntPtr ppbValue;
+
+ uint status = SLGetProductSkuInformation(sl.Handle, ref actId, value, out type, out len, out ppbValue);
+
+ if (status != 0 || len == 0 || type != SLDATATYPE.SL_DATA_SZ)
+ {
+ return null;
+ }
+
+ return Marshal.PtrToStringAuto(ppbValue);
+ }
+ }
+
+ public static List<Guid> GetActivationIds(Guid appId)
+ {
+ using (SLContext sl = new SLContext())
+ {
+ uint count;
+ IntPtr pLicStat;
+
+ SLGetLicensingStatusInformation(sl.Handle, ref appId, IntPtr.Zero, null, out count, out pLicStat);
+
+ List<Guid> result = new List<Guid>();
+
+ unsafe
+ {
+ SL_LICENSING_STATUS* licensingStatuses = (SL_LICENSING_STATUS*)pLicStat;
+ for (int i = 0; i < count; i++)
+ {
+ result.Add(licensingStatuses[i].SkuId);
+ }
+ }
+
+ return result;
+ }
+ }
+
+ public static uint SetCurrentProductKey(Guid actId, Guid pkeyId)
+ {
+ using (SLContext sl = new SLContext())
+ {
+ return SLSetCurrentProductKey(sl.Handle, ref actId, ref pkeyId);
+ }
+ }
+
+ public static uint InstallProductKey(ProductKey pkey)
+ {
+ using (SLContext sl = new SLContext())
+ {
+ Guid pkeyId = Guid.Empty;
+ return SLInstallProofOfPurchase(sl.Handle, pkey.GetAlgoUri(), pkey.ToString(), 0, null, ref pkeyId);
+ }
+ }
+
+ public static uint UninstallProductKey(Guid pkeyId)
+ {
+ using (SLContext sl = new SLContext())
+ {
+ return SLUninstallProofOfPurchase(sl.Handle, ref pkeyId);
+ }
+ }
+
+ public static void UninstallAllProductKeys(Guid appId)
+ {
+ foreach (Guid actId in GetActivationIds(appId))
+ {
+ Guid pkeyId = GetInstalledPkeyID(actId);
+ if (pkeyId == Guid.Empty) continue;
+ if (IsAddon(actId)) continue;
+ UninstallProductKey(pkeyId);
+ }
+ }
+ }
+}