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>
This commit is contained in:
215
LibTSforge/SPP/PKeyConfig.cs
Normal file
215
LibTSforge/SPP/PKeyConfig.cs
Normal file
@ -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()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
313
LibTSforge/SPP/ProductKey.cs
Normal file
313
LibTSforge/SPP/ProductKey.cs
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
417
LibTSforge/SPP/SLAPI.cs
Normal file
417
LibTSforge/SPP/SLAPI.cs
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user