summaryrefslogtreecommitdiff
path: root/LibTSforge/SPP
diff options
context:
space:
mode:
authorWitherOrNot2025-04-24 16:13:10 +0000
committerGitHub2025-04-24 16:13:10 +0000
commitf81edcb3171d1f80da1c67abdf7193d871b18378 (patch)
tree993d3ea250c9d264c61252dd388fee5e5447e218 /LibTSforge/SPP
parent8aa1f9078d786a7b20d2b92bbeefdd77a93dd828 (diff)
parent912f83c11b75c93f38b7966d7b727144eee7f23d (diff)
downloadTSforge-f81edcb3171d1f80da1c67abdf7193d871b18378.zip
Merge pull request #5 from massgravel/longhorn1.1.0
Longhorn
Diffstat (limited to 'LibTSforge/SPP')
-rw-r--r--LibTSforge/SPP/PKeyConfig.cs43
-rw-r--r--LibTSforge/SPP/ProductKey.cs58
-rw-r--r--LibTSforge/SPP/SLAPI.cs47
-rw-r--r--LibTSforge/SPP/SPPUtils.cs334
-rw-r--r--LibTSforge/SPP/SPSys.cs44
5 files changed, 448 insertions, 78 deletions
diff --git a/LibTSforge/SPP/PKeyConfig.cs b/LibTSforge/SPP/PKeyConfig.cs
index a608608..83fc981 100644
--- a/LibTSforge/SPP/PKeyConfig.cs
+++ b/LibTSforge/SPP/PKeyConfig.cs
@@ -74,8 +74,8 @@ namespace LibTSforge.SPP
public class PKeyConfig
{
- public Dictionary<Guid, ProductConfig> Products = new Dictionary<Guid, ProductConfig>();
- private List<Guid> loadedPkeyConfigs = new List<Guid>();
+ public readonly Dictionary<Guid, ProductConfig> Products = new Dictionary<Guid, ProductConfig>();
+ private readonly List<Guid> loadedPkeyConfigs = new List<Guid>();
public void LoadConfig(Guid actId)
{
@@ -136,12 +136,14 @@ namespace LibTSforge.SPP
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";
+ KeyRange keyRange = new KeyRange
+ {
+ Start = int.Parse(rangeNode.SelectSingleNode("./p:Start", nsmgr).InnerText),
+ End = int.Parse(rangeNode.SelectSingleNode("./p:End", nsmgr).InnerText),
+ EulaType = rangeNode.SelectSingleNode("./p:EulaType", nsmgr).InnerText,
+ PartNumber = rangeNode.SelectSingleNode("./p:PartNumber", nsmgr).InnerText,
+ Valid = rangeNode.SelectSingleNode("./p:IsValid", nsmgr).InnerText.ToLower() == "true"
+ };
ranges[refActIdStr].Add(keyRange);
}
@@ -155,15 +157,17 @@ namespace LibTSforge.SPP
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;
+ ProductConfig productConfig = new ProductConfig
+ {
+ GroupId = group,
+ Edition = configNode.SelectSingleNode("./p:EditionId", nsmgr).InnerText,
+ Description = configNode.SelectSingleNode("./p:ProductDescription", nsmgr).InnerText,
+ Channel = configNode.SelectSingleNode("./p:ProductKeyType", nsmgr).InnerText,
+ Randomized = configNode.SelectSingleNode("./p:ProductKeyType", nsmgr).InnerText.ToLower() == "true",
+ Algorithm = algorithms[group],
+ Ranges = keyRanges,
+ ActivationId = refActId
+ };
Products[refActId] = productConfig;
}
@@ -206,10 +210,5 @@ namespace LibTSforge.SPP
}
}
}
-
- public PKeyConfig()
- {
-
- }
}
}
diff --git a/LibTSforge/SPP/ProductKey.cs b/LibTSforge/SPP/ProductKey.cs
index 7a933da..03eb729 100644
--- a/LibTSforge/SPP/ProductKey.cs
+++ b/LibTSforge/SPP/ProductKey.cs
@@ -3,8 +3,8 @@ namespace LibTSforge.SPP
using System;
using System.IO;
using System.Linq;
- using LibTSforge.Crypto;
- using LibTSforge.PhysicalStore;
+ using Crypto;
+ using PhysicalStore;
public class ProductKey
{
@@ -18,11 +18,11 @@ namespace LibTSforge.SPP
public ulong Security;
public bool Upgrade;
public PKeyAlgorithm Algorithm;
- public string EulaType;
- public string PartNumber;
- public string Edition;
- public string Channel;
- public Guid ActivationId;
+ public readonly string EulaType;
+ public readonly string PartNumber;
+ public readonly string Edition;
+ public readonly string Channel;
+ public readonly Guid ActivationId;
private string mpc;
private string pid2;
@@ -32,6 +32,11 @@ namespace LibTSforge.SPP
get { return BitConverter.GetBytes(klow).Concat(BitConverter.GetBytes(khigh)).ToArray(); }
}
+ public ProductKey()
+ {
+
+ }
+
public ProductKey(int serial, ulong security, bool upgrade, PKeyAlgorithm algorithm, ProductConfig config, KeyRange range)
{
Group = config.GroupId;
@@ -60,22 +65,22 @@ namespace LibTSforge.SPP
public Guid GetPkeyId()
{
- VariableBag pkb = new VariableBag();
- pkb.Blocks.AddRange(new CRCBlock[]
+ VariableBag pkb = new VariableBag(PSVersion.WinModern);
+ pkb.Blocks.AddRange(new[]
{
- new CRCBlock
+ new CRCBlockModern
{
DataType = CRCBlockType.STRING,
KeyAsStr = "SppPkeyBindingProductKey",
ValueAsStr = ToString()
},
- new CRCBlock
+ new CRCBlockModern
{
DataType = CRCBlockType.BINARY,
KeyAsStr = "SppPkeyBindingMiscData",
Value = new byte[] { }
},
- new CRCBlock
+ new CRCBlockModern
{
DataType = CRCBlockType.STRING,
KeyAsStr = "SppPkeyBindingAlgorithm",
@@ -86,16 +91,6 @@ namespace LibTSforge.SPP
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)
@@ -103,10 +98,15 @@ namespace LibTSforge.SPP
return mpc;
}
- mpc = GetDefaultMPC();
+ int build = Environment.OSVersion.Version.Build;
+
+ mpc = build >= 10240 ? "03612" :
+ build >= 9600 ? "06401" :
+ build >= 9200 ? "05426" :
+ "55041";
// setup.cfg doesn't exist in Windows 8+
- string setupcfg = string.Format("{0}\\oobe\\{1}", Environment.SystemDirectory, "setup.cfg");
+ string setupcfg = string.Format(@"{0}\oobe\{1}", Environment.SystemDirectory, "setup.cfg");
if (!File.Exists(setupcfg) || Edition.Contains(";"))
{
@@ -244,17 +244,17 @@ namespace LibTSforge.SPP
{
if (version == PSVersion.Win7)
{
- Random rnd = new Random(Group * 1000000000 + Serial);
- byte[] data = new byte[8];
- rnd.NextBytes(data);
- return data;
+ ulong shortauth = ((ulong)Group << 41) | (Security << 31) | ((ulong)Serial << 1) | (Upgrade ? (ulong)1 : 0);
+ return BitConverter.GetBytes(shortauth);
}
int serialHigh = Serial / 1000000;
int serialLow = Serial % 1000000;
BinaryWriter writer = new BinaryWriter(new MemoryStream());
- writer.Write(new Guid("B8731595-A2F6-430B-A799-FBFFB81A8D73").ToByteArray());
+ string algoId = Algorithm == PKeyAlgorithm.PKEY2005 ? "B8731595-A2F6-430B-A799-FBFFB81A8D73" : "660672EF-7809-4CFD-8D54-41B7FB738988";
+
+ writer.Write(new Guid(algoId).ToByteArray());
writer.Write(Group);
writer.Write(serialHigh);
writer.Write(serialLow);
diff --git a/LibTSforge/SPP/SLAPI.cs b/LibTSforge/SPP/SLAPI.cs
index cfd7dc5..ec27381 100644
--- a/LibTSforge/SPP/SLAPI.cs
+++ b/LibTSforge/SPP/SLAPI.cs
@@ -44,40 +44,40 @@ namespace LibTSforge.SPP
public static readonly Guid WINDOWS_APP_ID = new Guid("55c92734-d682-4d71-983e-d6ec3f16059f");
- [DllImport("sppc.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
+ [DllImport("slc.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
private static extern void SLOpen(out IntPtr hSLC);
- [DllImport("sppc.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
+ [DllImport("slc.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)]
+ [DllImport("slc.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)]
+ [DllImport("slc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLUninstallProofOfPurchase(IntPtr hSLC, ref Guid PKeyId);
- [DllImport("sppc.dll", CharSet = CharSet.Unicode)]
+ [DllImport("slc.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)]
+ [DllImport("slcext.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)]
+ [DllImport("slc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLGenerateOfflineInstallationId(IntPtr hSLC, ref Guid pProductSkuId, ref string ppwszInstallationId);
- [DllImport("sppc.dll", CharSet = CharSet.Unicode)]
+ [DllImport("slc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLDepositOfflineConfirmationId(IntPtr hSLC, ref Guid pProductSkuId, string pwszInstallationId, string pwszConfirmationId);
- [DllImport("sppc.dll", CharSet = CharSet.Unicode)]
+ [DllImport("slc.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)]
+ [DllImport("slc.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)]
+ [DllImport("slc.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)]
@@ -87,9 +87,6 @@ namespace LibTSforge.SPP
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)]
@@ -98,7 +95,7 @@ namespace LibTSforge.SPP
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLFireEvent(IntPtr hSLC, string pwszEventId, ref Guid pApplicationId);
- public class SLContext : IDisposable
+ private class SLContext : IDisposable
{
public readonly IntPtr Handle;
@@ -161,11 +158,10 @@ namespace LibTSforge.SPP
{
using (SLContext sl = new SLContext())
{
- uint status;
uint count;
IntPtr pProductKeyIds;
- status = SLGetInstalledProductKeyIds(sl.Handle, ref actId, out count, out pProductKeyIds);
+ uint status = SLGetSLIDList(sl.Handle, SLIDTYPE.SL_ID_PRODUCT_SKU, ref actId, SLIDTYPE.SL_ID_PKEY, out count, out pProductKeyIds);
if (status != 0 || count == 0)
{
@@ -189,7 +185,7 @@ namespace LibTSforge.SPP
SLConsumeWindowsRight(0);
}
- public static bool RefreshTrustedTime(Guid actId)
+ public static void RefreshTrustedTime(Guid actId)
{
using (SLContext sl = new SLContext())
{
@@ -197,8 +193,7 @@ namespace LibTSforge.SPP
uint count;
IntPtr ppbValue;
- uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "TrustedTime", out type, out count, out ppbValue);
- return (int)status >= 0 && status != 0xC004F012;
+ SLGetProductSkuInformation(sl.Handle, ref actId, "TrustedTime", out type, out count, out ppbValue);
}
}
@@ -214,11 +209,10 @@ namespace LibTSforge.SPP
{
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);
+ uint status = SLGetSLIDList(sl.Handle, SLIDTYPE.SL_ID_PRODUCT_SKU, ref actId, SLIDTYPE.SL_ID_APPLICATION, out count, out pAppIds);
if (status != 0 || count == 0)
{
@@ -246,11 +240,10 @@ namespace LibTSforge.SPP
{
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);
+ uint status = SLGetSLIDList(sl.Handle, SLIDTYPE.SL_ID_LICENSE, ref licId, SLIDTYPE.SL_ID_LICENSE_FILE, out count, out ppReturnLics);
if (status != 0 || count == 0)
{
@@ -312,7 +305,7 @@ namespace LibTSforge.SPP
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;
+ return status != 0xC004F012;
}
}
@@ -395,11 +388,11 @@ namespace LibTSforge.SPP
}
}
- public static uint UninstallProductKey(Guid pkeyId)
+ public static void UninstallProductKey(Guid pkeyId)
{
using (SLContext sl = new SLContext())
{
- return SLUninstallProofOfPurchase(sl.Handle, ref pkeyId);
+ SLUninstallProofOfPurchase(sl.Handle, ref pkeyId);
}
}
diff --git a/LibTSforge/SPP/SPPUtils.cs b/LibTSforge/SPP/SPPUtils.cs
new file mode 100644
index 0000000..fc4967b
--- /dev/null
+++ b/LibTSforge/SPP/SPPUtils.cs
@@ -0,0 +1,334 @@
+namespace LibTSforge.SPP
+{
+ using Microsoft.Win32;
+ using System;
+ using System.IO;
+ using System.Linq;
+ using System.ServiceProcess;
+ using Crypto;
+ using PhysicalStore;
+ using TokenStore;
+
+ public static class SPPUtils
+ {
+ public static void KillSPP(PSVersion version)
+ {
+ ServiceController sc;
+
+ string svcName = version == PSVersion.Vista ? "slsvc" : "sppsvc";
+
+ try
+ {
+ sc = new ServiceController(svcName);
+
+ if (sc.Status == ServiceControllerStatus.Stopped)
+ return;
+ }
+ catch (InvalidOperationException ex)
+ {
+ throw new InvalidOperationException(string.Format("Unable to access {0}: ", svcName) + ex.Message);
+ }
+
+ Logger.WriteLine(string.Format("Stopping {0}...", svcName));
+
+ bool stopped = false;
+
+ for (int i = 0; stopped == false && i < 1080; i++)
+ {
+ try
+ {
+ if (sc.Status != ServiceControllerStatus.StopPending)
+ sc.Stop();
+
+ sc.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromMilliseconds(500));
+ }
+ catch (System.ServiceProcess.TimeoutException)
+ {
+ continue;
+ }
+ catch (InvalidOperationException ex)
+ {
+ Logger.WriteLine("Warning: Stopping sppsvc failed, retrying. Details: " + ex.Message);
+ System.Threading.Thread.Sleep(500);
+ continue;
+ }
+
+ stopped = true;
+ }
+
+ if (!stopped)
+ throw new System.TimeoutException(string.Format("Failed to stop {0}", svcName));
+
+ Logger.WriteLine(string.Format("{0} stopped successfully.", svcName));
+
+ if (version == PSVersion.Vista && SPSys.IsSpSysRunning())
+ {
+ Logger.WriteLine("Unloading spsys...");
+
+ int status = SPSys.ControlSpSys(false);
+
+ if (status < 0)
+ {
+ throw new IOException("Failed to unload spsys");
+ }
+
+ Logger.WriteLine("spsys unloaded successfully.");
+ }
+ }
+
+ public static void RestartSPP(PSVersion version)
+ {
+ if (version == PSVersion.Vista)
+ {
+ ServiceController sc;
+
+ try
+ {
+ sc = new ServiceController("slsvc");
+
+ if (sc.Status == ServiceControllerStatus.Running)
+ return;
+ }
+ catch (InvalidOperationException ex)
+ {
+ throw new InvalidOperationException("Unable to access slsvc: " + ex.Message);
+ }
+
+ Logger.WriteLine("Starting slsvc...");
+
+ bool started = false;
+
+ for (int i = 0; started == false && i < 360; i++)
+ {
+ try
+ {
+ if (sc.Status != ServiceControllerStatus.StartPending)
+ sc.Start();
+
+ sc.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromMilliseconds(500));
+ }
+ catch (System.ServiceProcess.TimeoutException)
+ {
+ continue;
+ }
+ catch (InvalidOperationException ex)
+ {
+ Logger.WriteLine("Warning: Starting slsvc failed, retrying. Details: " + ex.Message);
+ System.Threading.Thread.Sleep(500);
+ continue;
+ }
+
+ started = true;
+ }
+
+ if (!started)
+ throw new System.TimeoutException("Failed to start slsvc");
+
+ Logger.WriteLine("slsvc started successfully.");
+ }
+
+ SLApi.RefreshLicenseStatus();
+ }
+
+ public static bool DetectCurrentKey()
+ {
+ SLApi.RefreshLicenseStatus();
+
+ using (RegistryKey wpaKey = Registry.LocalMachine.OpenSubKey(@"SYSTEM\WPA"))
+ {
+ foreach (string subKey in wpaKey.GetSubKeyNames())
+ {
+ if (subKey.StartsWith("8DEC0AF1"))
+ {
+ return subKey.Contains("P");
+ }
+ }
+ }
+
+ throw new FileNotFoundException("Failed to autodetect key type, specify physical store key with /prod or /test arguments.");
+ }
+
+ public static string GetPSPath(PSVersion version)
+ {
+ switch (version)
+ {
+ case PSVersion.Vista:
+ case PSVersion.Win7:
+ return Directory.GetFiles(
+ Environment.GetFolderPath(Environment.SpecialFolder.System),
+ "7B296FB0-376B-497e-B012-9C450E1B7327-*.C7483456-A289-439d-8115-601632D005A0")
+ .FirstOrDefault() ?? "";
+ default:
+ string psDir = Environment.ExpandEnvironmentVariables(
+ (string)Registry.GetValue(
+ @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform",
+ "TokenStore",
+ ""
+ )
+ );
+ string psPath = Path.Combine(psDir, "data.dat");
+
+ if (string.IsNullOrEmpty(psDir) || !File.Exists(psPath))
+ {
+ string[] psDirs =
+ {
+ @"spp\store",
+ @"spp\store\2.0",
+ @"spp\store_test",
+ @"spp\store_test\2.0"
+ };
+
+ foreach (string dir in psDirs)
+ {
+ psPath = Path.Combine(
+ Path.Combine(
+ Environment.GetFolderPath(Environment.SpecialFolder.System),
+ dir
+ ),
+ "data.dat"
+ );
+
+ if (File.Exists(psPath)) return psPath;
+ }
+ }
+ else
+ {
+ return psPath;
+ }
+
+ throw new FileNotFoundException("Failed to locate physical store.");
+ }
+ }
+
+ public static string GetTokensPath(PSVersion version)
+ {
+ switch (version)
+ {
+ case PSVersion.Vista:
+ return Path.Combine(
+ Environment.ExpandEnvironmentVariables("%WINDIR%"),
+ @"ServiceProfiles\NetworkService\AppData\Roaming\Microsoft\SoftwareLicensing\tokens.dat"
+ );
+ case PSVersion.Win7:
+ return Path.Combine(
+ Environment.ExpandEnvironmentVariables("%WINDIR%"),
+ @"ServiceProfiles\NetworkService\AppData\Roaming\Microsoft\SoftwareProtectionPlatform\tokens.dat"
+ );
+ default:
+ string tokDir = Environment.ExpandEnvironmentVariables(
+ (string)Registry.GetValue(
+ @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform",
+ "TokenStore",
+ ""
+ )
+ );
+ string tokPath = Path.Combine(tokDir, "tokens.dat");
+
+ if (string.IsNullOrEmpty(tokDir) || !File.Exists(tokPath))
+ {
+ string[] tokDirs =
+ {
+ @"spp\store",
+ @"spp\store\2.0",
+ @"spp\store_test",
+ @"spp\store_test\2.0"
+ };
+
+ foreach (string dir in tokDirs)
+ {
+ tokPath = Path.Combine(
+ Path.Combine(
+ Environment.GetFolderPath(Environment.SpecialFolder.System),
+ dir
+ ),
+ "tokens.dat"
+ );
+
+ if (File.Exists(tokPath)) return tokPath;
+ }
+ }
+ else
+ {
+ return tokPath;
+ }
+
+ throw new FileNotFoundException("Failed to locate token store.");
+ }
+ }
+
+ public static IPhysicalStore GetStore(PSVersion version, bool production)
+ {
+ string psPath = GetPSPath(version);
+
+ switch (version)
+ {
+ case PSVersion.Vista:
+ return new PhysicalStoreVista(psPath, production);
+ case PSVersion.Win7:
+ return new PhysicalStoreWin7(psPath, production);
+ default:
+ return new PhysicalStoreModern(psPath, production, version);
+ }
+ }
+
+ public static ITokenStore GetTokenStore(PSVersion version)
+ {
+ string tokPath = GetTokensPath(version);
+
+ return new TokenStoreModern(tokPath);
+ }
+
+ public static void DumpStore(PSVersion version, bool production, string filePath, string encrFilePath)
+ {
+ bool manageSpp = false;
+
+ if (encrFilePath == null)
+ {
+ encrFilePath = GetPSPath(version);
+ manageSpp = true;
+ KillSPP(version);
+ }
+
+ if (string.IsNullOrEmpty(encrFilePath) || !File.Exists(encrFilePath))
+ {
+ throw new FileNotFoundException("Store does not exist at expected path '" + encrFilePath + "'.");
+ }
+
+ try
+ {
+ using (FileStream fs = File.Open(encrFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
+ {
+ byte[] encrData = fs.ReadAllBytes();
+ File.WriteAllBytes(filePath, PhysStoreCrypto.DecryptPhysicalStore(encrData, production, version));
+ }
+ Logger.WriteLine("Store dumped successfully to '" + filePath + "'.");
+ }
+ finally
+ {
+ if (manageSpp)
+ {
+ RestartSPP(version);
+ }
+ }
+ }
+
+ public static void LoadStore(PSVersion version, bool production, string filePath)
+ {
+ if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath))
+ {
+ throw new FileNotFoundException("Store file '" + filePath + "' does not exist.");
+ }
+
+ KillSPP(version);
+
+ using (IPhysicalStore store = GetStore(version, production))
+ {
+ store.WriteRaw(File.ReadAllBytes(filePath));
+ }
+
+ RestartSPP(version);
+
+ Logger.WriteLine("Loaded store file successfully.");
+ }
+ }
+}
diff --git a/LibTSforge/SPP/SPSys.cs b/LibTSforge/SPP/SPSys.cs
new file mode 100644
index 0000000..ecc331c
--- /dev/null
+++ b/LibTSforge/SPP/SPSys.cs
@@ -0,0 +1,44 @@
+namespace LibTSforge.SPP
+{
+ using Microsoft.Win32.SafeHandles;
+ using System;
+ using System.Runtime.InteropServices;
+
+ public class SPSys
+ {
+ [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ private static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);
+ private static SafeFileHandle CreateFileSafe(string device)
+ {
+ return new SafeFileHandle(CreateFile(device, 0xC0000000, 0, IntPtr.Zero, 3, 0, IntPtr.Zero), true);
+ }
+
+ [return: MarshalAs(UnmanagedType.Bool)]
+ [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ private static extern bool DeviceIoControl([In] SafeFileHandle hDevice, [In] uint dwIoControlCode, [In] IntPtr lpInBuffer, [In] int nInBufferSize, [Out] IntPtr lpOutBuffer, [In] int nOutBufferSize, out int lpBytesReturned, [In] IntPtr lpOverlapped);
+
+ public static bool IsSpSysRunning()
+ {
+ SafeFileHandle file = CreateFileSafe(@"\\.\SpDevice");
+ IntPtr buffer = Marshal.AllocHGlobal(1);
+ int bytesReturned;
+ DeviceIoControl(file, 0x80006008, IntPtr.Zero, 0, buffer, 1, out bytesReturned, IntPtr.Zero);
+ bool running = Marshal.ReadByte(buffer) != 0;
+ Marshal.FreeHGlobal(buffer);
+ file.Close();
+ return running;
+ }
+
+ public static int ControlSpSys(bool start)
+ {
+ SafeFileHandle file = CreateFileSafe(@"\\.\SpDevice");
+ IntPtr buffer = Marshal.AllocHGlobal(4);
+ int bytesReturned;
+ DeviceIoControl(file, start ? 0x8000a000 : 0x8000a004, IntPtr.Zero, 0, buffer, 4, out bytesReturned, IntPtr.Zero);
+ int result = Marshal.ReadInt32(buffer);
+ Marshal.FreeHGlobal(buffer);
+ file.Close();
+ return result;
+ }
+ }
+}