From 0d59561bee4cf7db10d53a8aa58952ae65e856b5 Mon Sep 17 00:00:00 2001 From: Wither OrNot Date: Thu, 13 Feb 2025 09:49:35 -0500 Subject: Initial commit Co-authored-by: neko <109633131+nekoppai@users.noreply.github.com> Co-authored-by: Lyssa <75037904+thecatontheceiling@users.noreply.github.com> Co-authored-by: abbodi1406 <33669284+abbodi1406@users.noreply.github.com> --- LibTSforge/SPP/PKeyConfig.cs | 215 ++++++++++++++++++++++ LibTSforge/SPP/ProductKey.cs | 313 ++++++++++++++++++++++++++++++++ LibTSforge/SPP/SLAPI.cs | 417 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 945 insertions(+) create mode 100644 LibTSforge/SPP/PKeyConfig.cs create mode 100644 LibTSforge/SPP/ProductKey.cs create mode 100644 LibTSforge/SPP/SLAPI.cs (limited to 'LibTSforge/SPP') 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 Ranges; + public Guid ActivationId; + + private List GetPkeyRanges() + { + if (Ranges.Count == 0) + { + throw new ArgumentException("No key ranges."); + } + + if (Algorithm == PKeyAlgorithm.PKEY2005) + { + return Ranges; + } + + List 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 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 Products = new Dictionary(); + private List loadedPkeyConfigs = new List(); + + 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 algorithms = new Dictionary(); + Dictionary> ranges = new Dictionary>(); + + Dictionary algoConv = new Dictionary + { + { "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 = 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 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 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 result = new List(); + + 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); + } + } + } +} -- cgit v1.2.3