Merge pull request #5 from massgravel/longhorn

Longhorn
This commit is contained in:
WitherOrNot 2025-04-24 12:13:10 -04:00 committed by GitHub
commit f81edcb317
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 1526 additions and 663 deletions

2
.gitignore vendored
View File

@ -361,3 +361,5 @@ MigrationBackup/
# Fody - auto-generated XML schema # Fody - auto-generated XML schema
FodyWeavers.xsd FodyWeavers.xsd
launchSettings.json

View File

@ -1,14 +1,14 @@
namespace LibTSforge.Activators namespace LibTSforge.Activators
{ {
using System; using System;
using LibTSforge.PhysicalStore; using PhysicalStore;
using LibTSforge.SPP; using SPP;
public static class AVMA4k public static class AVMA4k
{ {
public static void Activate(PSVersion version, bool production, Guid actId) public static void Activate(PSVersion version, bool production, Guid actId)
{ {
if (version != PSVersion.WinModern) if (version != PSVersion.WinModern && version != PSVersion.WinBlue)
{ {
throw new NotSupportedException("AVMA licenses are not available for this product."); throw new NotSupportedException("AVMA licenses are not available for this product.");
} }
@ -34,46 +34,41 @@ namespace LibTSforge.Activators
throw new NotSupportedException("Non-VT:IA product key installed."); throw new NotSupportedException("Non-VT:IA product key installed.");
} }
Utils.KillSPP(); SPPUtils.KillSPP(version);
Logger.WriteLine("Writing TrustedStore data..."); Logger.WriteLine("Writing TrustedStore data...");
using (IPhysicalStore store = Utils.GetStore(version, production)) using (IPhysicalStore store = SPPUtils.GetStore(version, production))
{ {
string key = string.Format("SPPSVC\\{0}\\{1}", appId, actId); string key = string.Format("SPPSVC\\{0}\\{1}", appId, actId);
ulong unknown = 0;
ulong time1;
ulong crcBindTime = (ulong)DateTime.UtcNow.ToFileTime();
ulong timerTime;
ulong expiry = Constants.TimerMax;
long creationTime = BitConverter.ToInt64(store.GetBlock("__##USERSEP##\\$$_RESERVED_$$\\NAMESPACE__", "__##USERSEP-RESERVED##__$$GLOBAL-CREATION-TIME$$").Data, 0); long creationTime = BitConverter.ToInt64(store.GetBlock("__##USERSEP##\\$$_RESERVED_$$\\NAMESPACE__", "__##USERSEP-RESERVED##__$$GLOBAL-CREATION-TIME$$").Data, 0);
long tickCount = BitConverter.ToInt64(store.GetBlock("__##USERSEP##\\$$_RESERVED_$$\\NAMESPACE__", "__##USERSEP-RESERVED##__$$GLOBAL-TICKCOUNT-UPTIME$$").Data, 0); long tickCount = BitConverter.ToInt64(store.GetBlock("__##USERSEP##\\$$_RESERVED_$$\\NAMESPACE__", "__##USERSEP-RESERVED##__$$GLOBAL-TICKCOUNT-UPTIME$$").Data, 0);
long deltaTime = BitConverter.ToInt64(store.GetBlock(key, "__##USERSEP-RESERVED##__$$UP-TIME-DELTA$$").Data, 0); long deltaTime = BitConverter.ToInt64(store.GetBlock(key, "__##USERSEP-RESERVED##__$$UP-TIME-DELTA$$").Data, 0);
time1 = (ulong)(creationTime + tickCount + deltaTime); const ulong unknown = 0;
timerTime = crcBindTime / 10000; ulong time1 = (ulong)(creationTime + tickCount + deltaTime);
expiry /= 10000; ulong crcBindTime = (ulong)DateTime.UtcNow.ToFileTime();
ulong timerTime = crcBindTime / 10000;
ulong expiry = Constants.TimerMax / 10000;
VariableBag avmaBinding = new VariableBag(); VariableBag avmaBinding = new VariableBag(version);
avmaBinding.Blocks.AddRange(new CRCBlock[] avmaBinding.Blocks.AddRange(new[]
{ {
new CRCBlock new CRCBlockModern
{ {
DataType = CRCBlockType.BINARY, DataType = CRCBlockType.BINARY,
Key = new byte[] { }, Key = new byte[] { },
Value = BitConverter.GetBytes(crcBindTime), Value = BitConverter.GetBytes(crcBindTime),
}, },
new CRCBlock new CRCBlockModern
{ {
DataType = CRCBlockType.STRING, DataType = CRCBlockType.STRING,
Key = new byte[] { }, Key = new byte[] { },
ValueAsStr = "AVMA4K", ValueAsStr = "AVMA4K",
}, },
new CRCBlock new CRCBlockModern
{ {
DataType = CRCBlockType.STRING, DataType = CRCBlockType.STRING,
Key = new byte[] { }, Key = new byte[] { },
@ -97,7 +92,7 @@ namespace LibTSforge.Activators
store.DeleteBlock(key, storeVal); store.DeleteBlock(key, storeVal);
store.DeleteBlock(key, timerVal); store.DeleteBlock(key, timerVal);
store.AddBlocks(new PSBlock[] store.AddBlocks(new[]
{ {
new PSBlock new PSBlock
{ {

View File

@ -1,8 +1,9 @@
namespace LibTSforge.Activators namespace LibTSforge.Activators
{ {
using System; using System;
using LibTSforge.PhysicalStore; using System.IO;
using LibTSforge.SPP; using PhysicalStore;
using SPP;
public class KMS4k public class KMS4k
{ {
@ -29,11 +30,11 @@ namespace LibTSforge.Activators
throw new NotSupportedException("Non-Volume:GVLK product key installed."); throw new NotSupportedException("Non-Volume:GVLK product key installed.");
} }
Utils.KillSPP(); SPPUtils.KillSPP(version);
Logger.WriteLine("Writing TrustedStore data..."); Logger.WriteLine("Writing TrustedStore data...");
using (IPhysicalStore store = Utils.GetStore(version, production)) using (IPhysicalStore store = SPPUtils.GetStore(version, production))
{ {
string key = string.Format("SPPSVC\\{0}\\{1}", appId, actId); string key = string.Format("SPPSVC\\{0}\\{1}", appId, actId);
@ -42,7 +43,7 @@ namespace LibTSforge.Activators
ulong time2 = (ulong)DateTime.UtcNow.ToFileTime(); ulong time2 = (ulong)DateTime.UtcNow.ToFileTime();
ulong expiry = Constants.TimerMax; ulong expiry = Constants.TimerMax;
if (version == PSVersion.Win7) if (version == PSVersion.Vista || version == PSVersion.Win7)
{ {
unknown = 0x800000000; unknown = 0x800000000;
time1 = 0; time1 = 0;
@ -58,86 +59,127 @@ namespace LibTSforge.Activators
expiry /= 10000; expiry /= 10000;
} }
byte[] hwidBlock = Constants.UniversalHWIDBlock; if (version == PSVersion.Vista)
byte[] kmsResp;
switch (version)
{ {
case PSVersion.Win7: VistaTimer vistaTimer = new VistaTimer
kmsResp = Constants.KMSv4Response; {
break; Time = time2,
case PSVersion.Win8: Expiry = Constants.TimerMax
kmsResp = Constants.KMSv5Response; };
break;
case PSVersion.WinBlue: string vistaTimerName = string.Format("msft:sl/timer/VLExpiration/VOLUME/{0}/{1}", appId, actId);
case PSVersion.WinModern:
kmsResp = Constants.KMSv6Response; store.DeleteBlock(key, vistaTimerName);
break; store.DeleteBlock(key, actId.ToString());
default:
throw new NotSupportedException("Unsupported PSVersion."); BinaryWriter writer = new BinaryWriter(new MemoryStream());
writer.Write(Constants.KMSv4Response.Length);
writer.Write(Constants.KMSv4Response);
writer.Write(Constants.UniversalHWIDBlock);
byte[] kmsData = writer.GetBytes();
store.AddBlocks(new[]
{
new PSBlock
{
Type = BlockType.TIMER,
Flags = 0,
KeyAsStr = key,
ValueAsStr = vistaTimerName,
Data = vistaTimer.CastToArray()
},
new PSBlock
{
Type = BlockType.NAMED,
Flags = 0,
KeyAsStr = key,
ValueAsStr = actId.ToString(),
Data = kmsData
}
});
} }
else
VariableBag kmsBinding = new VariableBag();
kmsBinding.Blocks.AddRange(new CRCBlock[]
{ {
new CRCBlock byte[] hwidBlock = Constants.UniversalHWIDBlock;
byte[] kmsResp;
switch (version)
{
case PSVersion.Win7:
kmsResp = Constants.KMSv4Response;
break;
case PSVersion.Win8:
kmsResp = Constants.KMSv5Response;
break;
case PSVersion.WinBlue:
case PSVersion.WinModern:
kmsResp = Constants.KMSv6Response;
break;
default:
throw new NotSupportedException("Unsupported PSVersion.");
}
VariableBag kmsBinding = new VariableBag(version);
kmsBinding.Blocks.AddRange(new[]
{
new CRCBlockModern
{ {
DataType = CRCBlockType.BINARY, DataType = CRCBlockType.BINARY,
Key = new byte[] { }, Key = new byte[] { },
Value = kmsResp Value = kmsResp
}, },
new CRCBlock new CRCBlockModern
{ {
DataType = CRCBlockType.STRING, DataType = CRCBlockType.STRING,
Key = new byte[] { }, Key = new byte[] { },
ValueAsStr = "msft:rm/algorithm/hwid/4.0" ValueAsStr = "msft:rm/algorithm/hwid/4.0"
}, },
new CRCBlock new CRCBlockModern
{ {
DataType = CRCBlockType.BINARY, DataType = CRCBlockType.BINARY,
KeyAsStr = "SppBindingLicenseData", KeyAsStr = "SppBindingLicenseData",
Value = hwidBlock Value = hwidBlock
} }
}); });
if (version == PSVersion.WinModern) if (version == PSVersion.WinModern)
{
kmsBinding.Blocks.AddRange(new CRCBlock[]
{ {
new CRCBlock kmsBinding.Blocks.AddRange(new[]
{
new CRCBlockModern
{ {
DataType = CRCBlockType.STRING, DataType = CRCBlockType.STRING,
Key = new byte[] { }, Key = new byte[] { },
ValueAsStr = "massgrave.dev" ValueAsStr = "massgrave.dev"
}, },
new CRCBlock new CRCBlockModern
{ {
DataType = CRCBlockType.STRING, DataType = CRCBlockType.STRING,
Key = new byte[] { }, Key = new byte[] { },
ValueAsStr = "6969" ValueAsStr = "6969"
} }
}); });
} }
byte[] kmsBindingData = kmsBinding.Serialize(); byte[] kmsBindingData = kmsBinding.Serialize();
Timer kmsTimer = new Timer Timer kmsTimer = new Timer
{ {
Unknown = unknown, Unknown = unknown,
Time1 = time1, Time1 = time1,
Time2 = time2, Time2 = time2,
Expiry = expiry Expiry = expiry
}; };
string storeVal = string.Format("msft:spp/kms/bind/2.0/store/{0}/{1}", appId, actId); string storeVal = string.Format("msft:spp/kms/bind/2.0/store/{0}/{1}", appId, actId);
string timerVal = string.Format("msft:spp/kms/bind/2.0/timer/{0}/{1}", appId, actId); string timerVal = string.Format("msft:spp/kms/bind/2.0/timer/{0}/{1}", appId, actId);
store.DeleteBlock(key, storeVal); store.DeleteBlock(key, storeVal);
store.DeleteBlock(key, timerVal); store.DeleteBlock(key, timerVal);
store.AddBlocks(new PSBlock[] store.AddBlocks(new[]
{ {
new PSBlock new PSBlock
{ {
Type = BlockType.NAMED, Type = BlockType.NAMED,
@ -154,10 +196,11 @@ namespace LibTSforge.Activators
ValueAsStr = timerVal, ValueAsStr = timerVal,
Data = kmsTimer.CastToArray() Data = kmsTimer.CastToArray()
} }
}); });
}
} }
SLApi.RefreshLicenseStatus(); SPPUtils.RestartSPP(version);
SLApi.FireStateChangedEvent(appId); SLApi.FireStateChangedEvent(appId);
Logger.WriteLine("Activated using KMS4k successfully."); Logger.WriteLine("Activated using KMS4k successfully.");
} }

View File

@ -2,13 +2,14 @@ namespace LibTSforge.Activators
{ {
using System; using System;
using System.IO; using System.IO;
using LibTSforge.Crypto; using System.Linq;
using LibTSforge.PhysicalStore; using Crypto;
using LibTSforge.SPP; using PhysicalStore;
using SPP;
public static class ZeroCID public static class ZeroCID
{ {
public static void Deposit(Guid actId, string instId) private static void Deposit(Guid actId, string instId)
{ {
uint status = SLApi.DepositConfirmationID(actId, instId, Constants.ZeroCID); uint status = SLApi.DepositConfirmationID(actId, instId, Constants.ZeroCID);
Logger.WriteLine(string.Format("Depositing fake CID status {0:X}", status)); Logger.WriteLine(string.Format("Depositing fake CID status {0:X}", status));
@ -46,16 +47,16 @@ namespace LibTSforge.Activators
string instId = SLApi.GetInstallationID(actId); string instId = SLApi.GetInstallationID(actId);
Guid pkeyId = SLApi.GetInstalledPkeyID(actId); Guid pkeyId = SLApi.GetInstalledPkeyID(actId);
if (version == PSVersion.Win7) if (version == PSVersion.Vista || version == PSVersion.Win7)
{ {
Deposit(actId, instId); Deposit(actId, instId);
} }
Utils.KillSPP(); SPPUtils.KillSPP(version);
Logger.WriteLine("Writing TrustedStore data..."); Logger.WriteLine("Writing TrustedStore data...");
using (IPhysicalStore store = Utils.GetStore(version, production)) using (IPhysicalStore store = SPPUtils.GetStore(version, production))
{ {
byte[] hwidBlock = Constants.UniversalHWIDBlock; byte[] hwidBlock = Constants.UniversalHWIDBlock;
@ -65,7 +66,11 @@ namespace LibTSforge.Activators
byte[] iidHash; byte[] iidHash;
if (version == PSVersion.Win7) if (version == PSVersion.Vista)
{
iidHash = CryptoUtils.SHA256Hash(Utils.EncodeString(instId)).Take(0x10).ToArray();
}
else if (version == PSVersion.Win7)
{ {
iidHash = CryptoUtils.SHA256Hash(Utils.EncodeString(instId)); iidHash = CryptoUtils.SHA256Hash(Utils.EncodeString(instId));
} }
@ -82,11 +87,39 @@ namespace LibTSforge.Activators
throw new InvalidDataException("Failed to get product key data for activation ID " + actId + "."); throw new InvalidDataException("Failed to get product key data for activation ID " + actId + ".");
} }
VariableBag pkb = new VariableBag(keyBlock.Data); VariableBag pkb = new VariableBag(keyBlock.Data, version);
byte[] pkeyData; byte[] pkeyData;
if (version == PSVersion.Win7) if (version == PSVersion.Vista)
{
pkeyData = pkb.GetBlock("PKeyBasicInfo").Value;
string uniqueId = Utils.DecodeString(pkeyData.Skip(0x120).Take(0x80).ToArray());
string extPid = Utils.DecodeString(pkeyData.Skip(0x1A0).Take(0x80).ToArray());
uint group;
uint.TryParse(extPid.Split('-')[1], out group);
if (group == 0)
{
throw new FormatException("Extended PID has invalid format.");
}
ulong shortauth;
try
{
shortauth = BitConverter.ToUInt64(Convert.FromBase64String(uniqueId.Split('&')[1]), 0);
}
catch
{
throw new FormatException("Key Unique ID has invalid format.");
}
shortauth |= (ulong)group << 41;
pkeyData = BitConverter.GetBytes(shortauth);
}
else if (version == PSVersion.Win7)
{ {
pkeyData = pkb.GetBlock("SppPkeyShortAuthenticator").Value; pkeyData = pkb.GetBlock("SppPkeyShortAuthenticator").Value;
} }
@ -99,26 +132,34 @@ namespace LibTSforge.Activators
store.SetBlock(key, pkeyId.ToString(), pkb.Serialize()); store.SetBlock(key, pkeyId.ToString(), pkb.Serialize());
BinaryWriter writer = new BinaryWriter(new MemoryStream()); BinaryWriter writer = new BinaryWriter(new MemoryStream());
writer.Write(0x20); writer.Write(iidHash.Length);
writer.Write(iidHash); writer.Write(iidHash);
writer.Write(hwidBlock.Length); writer.Write(hwidBlock.Length);
writer.Write(hwidBlock); writer.Write(hwidBlock);
byte[] tsHwidData = writer.GetBytes(); byte[] tsHwidData = writer.GetBytes();
writer = new BinaryWriter(new MemoryStream()); writer = new BinaryWriter(new MemoryStream());
writer.Write(0x20); writer.Write(iidHash.Length);
writer.Write(iidHash); writer.Write(iidHash);
writer.Write(pkeyData.Length); writer.Write(pkeyData.Length);
writer.Write(pkeyData); writer.Write(pkeyData);
byte[] tsPkeyInfoData = writer.GetBytes(); byte[] tsPkeyInfoData = writer.GetBytes();
store.AddBlocks(new PSBlock[] { string phoneVersion = version == PSVersion.Vista ? "6.0" : "7.0";
Guid indexSlid = version == PSVersion.Vista ? actId : pkeyId;
string hwidBlockName = string.Format("msft:Windows/{0}/Phone/Cached/HwidBlock/{1}", phoneVersion, indexSlid);
string pkeyInfoName = string.Format("msft:Windows/{0}/Phone/Cached/PKeyInfo/{1}", phoneVersion, indexSlid);
store.DeleteBlock(key, hwidBlockName);
store.DeleteBlock(key, pkeyInfoName);
store.AddBlocks(new[] {
new PSBlock new PSBlock
{ {
Type = BlockType.NAMED, Type = BlockType.NAMED,
Flags = 0, Flags = 0,
KeyAsStr = key, KeyAsStr = key,
ValueAsStr = "msft:Windows/7.0/Phone/Cached/HwidBlock/" + pkeyId, ValueAsStr = hwidBlockName,
Data = tsHwidData Data = tsHwidData
}, },
new PSBlock new PSBlock
@ -126,18 +167,18 @@ namespace LibTSforge.Activators
Type = BlockType.NAMED, Type = BlockType.NAMED,
Flags = 0, Flags = 0,
KeyAsStr = key, KeyAsStr = key,
ValueAsStr = "msft:Windows/7.0/Phone/Cached/PKeyInfo/" + pkeyId, ValueAsStr = pkeyInfoName,
Data = tsPkeyInfoData Data = tsPkeyInfoData
} }
}); });
} }
if (version != PSVersion.Win7) if (version != PSVersion.Vista && version != PSVersion.Win7)
{ {
Deposit(actId, instId); Deposit(actId, instId);
} }
SLApi.RefreshLicenseStatus(); SPPUtils.RestartSPP(version);
SLApi.FireStateChangedEvent(appId); SLApi.FireStateChangedEvent(appId);
Logger.WriteLine("Activated using ZeroCID successfully."); Logger.WriteLine("Activated using ZeroCID successfully.");
} }

View File

@ -1,22 +1,15 @@
namespace LibTSforge namespace LibTSforge
{ {
using Microsoft.Win32;
using System; using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.ServiceProcess;
using System.Text; using System.Text;
using LibTSforge.Crypto;
using LibTSforge.PhysicalStore;
using LibTSforge.SPP;
using LibTSforge.TokenStore;
public enum PSVersion public enum PSVersion
{ {
Vista, Vista,
Win7, Win7,
Win8Early,
Win8, Win8,
WinBlue, WinBlue,
WinModern WinModern
@ -87,8 +80,8 @@ namespace LibTSforge
0x92, 0xA6, 0x56, 0x96 0x92, 0xA6, 0x56, 0x96
}; };
// 2^31 - 1 minutes // 2^31 - 8 minutes
public static ulong TimerMax = (ulong)TimeSpan.FromMinutes(2147483647).Ticks; public static readonly ulong TimerMax = (ulong)TimeSpan.FromMinutes(2147483640).Ticks;
public static readonly string ZeroCID = new string('0', 48); public static readonly string ZeroCID = new string('0', 48);
} }
@ -156,20 +149,6 @@ namespace LibTSforge
} }
return result; return result;
} }
public static T CastToStruct<T>(this byte[] data) where T : struct
{
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
try
{
IntPtr ptr = handle.AddrOfPinnedObject();
return (T)Marshal.PtrToStructure(ptr, typeof(T));
}
finally
{
handle.Free();
}
}
} }
public static class FileStreamExt public static class FileStreamExt
@ -190,6 +169,12 @@ namespace LibTSforge
public static class Utils public static class Utils
{ {
[DllImport("kernel32.dll")]
public static extern uint GetSystemDefaultLCID();
[DllImport("kernel32.dll")]
public static extern bool Wow64EnableWow64FsRedirection(bool Wow64FsEnableRedirection);
public static string DecodeString(byte[] data) public static string DecodeString(byte[] data)
{ {
return Encoding.Unicode.GetString(data).Trim('\0'); return Encoding.Unicode.GetString(data).Trim('\0');
@ -200,9 +185,6 @@ namespace LibTSforge
return Encoding.Unicode.GetBytes(str + '\0'); return Encoding.Unicode.GetBytes(str + '\0');
} }
[DllImport("kernel32.dll")]
public static extern uint GetSystemDefaultLCID();
public static uint CRC32(byte[] data) public static uint CRC32(byte[] data)
{ {
const uint polynomial = 0x04C11DB7; const uint polynomial = 0x04C11DB7;
@ -226,157 +208,6 @@ namespace LibTSforge
return ~crc; return ~crc;
} }
public static void KillSPP()
{
ServiceController sc;
try
{
sc = new ServiceController("sppsvc");
if (sc.Status == ServiceControllerStatus.Stopped)
return;
}
catch (InvalidOperationException ex)
{
throw new InvalidOperationException("Unable to access sppsvc: " + ex.Message);
}
Logger.WriteLine("Stopping sppsvc...");
bool stopped = false;
for (int i = 0; stopped == false && i < 60; i++)
{
try
{
if (sc.Status != ServiceControllerStatus.StopPending)
sc.Stop();
sc.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromMilliseconds(500));
}
catch (System.ServiceProcess.TimeoutException)
{
continue;
}
catch (InvalidOperationException)
{
System.Threading.Thread.Sleep(500);
continue;
}
stopped = true;
}
if (!stopped)
throw new System.TimeoutException("Failed to stop sppsvc");
Logger.WriteLine("sppsvc stopped successfully.");
}
public static string GetPSPath(PSVersion version)
{
switch (version)
{
case PSVersion.Win7:
return Directory.GetFiles(
Environment.GetFolderPath(Environment.SpecialFolder.System),
"7B296FB0-376B-497e-B012-9C450E1B7327-*.C7483456-A289-439d-8115-601632D005A0")
.FirstOrDefault() ?? "";
case PSVersion.Win8Early:
case PSVersion.WinBlue:
case PSVersion.Win8:
case PSVersion.WinModern:
return Path.Combine(
Environment.ExpandEnvironmentVariables(
(string)Registry.GetValue(
@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform",
"TokenStore",
string.Empty
)
),
"data.dat"
);
default:
return "";
}
}
public static string GetTokensPath(PSVersion version)
{
switch (version)
{
case PSVersion.Win7:
return Path.Combine(
Environment.ExpandEnvironmentVariables("%WINDIR%"),
@"ServiceProfiles\NetworkService\AppData\Roaming\Microsoft\SoftwareProtectionPlatform\tokens.dat"
);
case PSVersion.Win8Early:
case PSVersion.WinBlue:
case PSVersion.Win8:
case PSVersion.WinModern:
return Path.Combine(
Environment.ExpandEnvironmentVariables(
(string)Registry.GetValue(
@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform",
"TokenStore",
string.Empty
)
),
"tokens.dat"
);
default:
return "";
}
}
public static IPhysicalStore GetStore(PSVersion version, bool production)
{
string psPath;
try
{
psPath = GetPSPath(version);
}
catch
{
throw new FileNotFoundException("Failed to get path of physical store.");
}
if (string.IsNullOrEmpty(psPath) || !File.Exists(psPath))
{
throw new FileNotFoundException(string.Format("Physical store not found at expected path {0}.", psPath));
}
if (version == PSVersion.Vista)
{
throw new NotSupportedException("Physical store editing is not supported for Windows Vista.");
}
return version == PSVersion.Win7 ? new PhysicalStoreWin7(psPath, production) : (IPhysicalStore)new PhysicalStoreModern(psPath, production, version);
}
public static ITokenStore GetTokenStore(PSVersion version)
{
string tokPath;
try
{
tokPath = GetTokensPath(version);
}
catch
{
throw new FileNotFoundException("Failed to get path of physical store.");
}
if (string.IsNullOrEmpty(tokPath) || !File.Exists(tokPath))
{
throw new FileNotFoundException(string.Format("Token store not found at expected path {0}.", tokPath));
}
return new TokenStoreModern(tokPath);
}
public static string GetArchitecture() public static string GetArchitecture()
{ {
string arch = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE", EnvironmentVariableTarget.Machine).ToUpperInvariant(); string arch = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE", EnvironmentVariableTarget.Machine).ToUpperInvariant();
@ -392,65 +223,7 @@ namespace LibTSforge
if (build >= 7600 && build <= 7602) return PSVersion.Win7; if (build >= 7600 && build <= 7602) return PSVersion.Win7;
if (build == 9200) return PSVersion.Win8; if (build == 9200) return PSVersion.Win8;
throw new NotSupportedException("Unable to auto-detect version info, please specify one manually using the /ver argument."); throw new NotSupportedException("Unable to auto-detect version info");
}
public static bool DetectCurrentKey()
{
SLApi.RefreshLicenseStatus();
using (RegistryKey wpaKey = Registry.LocalMachine.OpenSubKey(@"SYSTEM\WPA"))
{
foreach (string subKey in wpaKey.GetSubKeyNames())
{
if (subKey.StartsWith("8DEC0AF1") && subKey.EndsWith("-1"))
{
return subKey.Contains("P");
}
}
}
throw new FileNotFoundException("Failed to autodetect key type, specify physical store key with /prod or /test arguments.");
}
public static void DumpStore(PSVersion version, bool production, string filePath, string encrFilePath)
{
if (encrFilePath == null)
{
encrFilePath = GetPSPath(version);
}
if (string.IsNullOrEmpty(encrFilePath) || !File.Exists(encrFilePath))
{
throw new FileNotFoundException("Store does not exist at expected path '" + encrFilePath + "'.");
}
KillSPP();
using (FileStream fs = File.Open(encrFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
{
byte[] encrData = fs.ReadAllBytes();
File.WriteAllBytes(filePath, PhysStoreCrypto.DecryptPhysicalStore(encrData, production));
}
Logger.WriteLine("Store dumped successfully to '" + filePath + "'.");
}
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();
using (IPhysicalStore store = GetStore(version, production))
{
store.WriteRaw(File.ReadAllBytes(filePath));
}
Logger.WriteLine("Loaded store file succesfully.");
} }
} }

View File

@ -106,10 +106,21 @@ namespace LibTSforge.Crypto
public static bool HMACVerify(byte[] key, byte[] data, byte[] signature) public static bool HMACVerify(byte[] key, byte[] data, byte[] signature)
{ {
HMACSHA1 hmac = new HMACSHA1(key);
return Enumerable.SequenceEqual(signature, HMACSign(key, data)); return Enumerable.SequenceEqual(signature, HMACSign(key, data));
} }
public static byte[] SaltSHASum(byte[] salt, byte[] data)
{
SHA1 sha1 = SHA1.Create();
byte[] sha_data = salt.Concat(data).ToArray();
return sha1.ComputeHash(sha_data);
}
public static bool SaltSHAVerify(byte[] salt, byte[] data, byte[] checksum)
{
return Enumerable.SequenceEqual(checksum, SaltSHASum(salt, data));
}
public static byte[] SHA256Hash(byte[] data) public static byte[] SHA256Hash(byte[] data)
{ {
using (SHA256 sha256 = SHA256.Create()) using (SHA256 sha256 = SHA256.Create())

View File

@ -8,7 +8,7 @@ namespace LibTSforge.Crypto
public static class PhysStoreCrypto public static class PhysStoreCrypto
{ {
public static byte[] DecryptPhysicalStore(byte[] data, bool production) public static byte[] DecryptPhysicalStore(byte[] data, bool production, PSVersion version)
{ {
byte[] rsaKey = production ? Keys.PRODUCTION : Keys.TEST; byte[] rsaKey = production ? Keys.PRODUCTION : Keys.TEST;
BinaryReader br = new BinaryReader(new MemoryStream(data)); BinaryReader br = new BinaryReader(new MemoryStream(data));
@ -16,29 +16,40 @@ namespace LibTSforge.Crypto
byte[] aesKeySig = br.ReadBytes(0x80); byte[] aesKeySig = br.ReadBytes(0x80);
byte[] encAesKey = br.ReadBytes(0x80); byte[] encAesKey = br.ReadBytes(0x80);
if (CryptoUtils.RSAVerifySignature(rsaKey, encAesKey, aesKeySig)) if (!CryptoUtils.RSAVerifySignature(rsaKey, encAesKey, aesKeySig))
{ {
byte[] aesKey = CryptoUtils.RSADecrypt(rsaKey, encAesKey); throw new Exception("Failed to decrypt physical store.");
byte[] decData = CryptoUtils.AESDecrypt(br.ReadBytes((int)br.BaseStream.Length - 0x110), aesKey);
byte[] hmacKey = decData.Take(0x10).ToArray();
byte[] hmacSig = decData.Skip(0x10).Take(0x14).ToArray();
byte[] psData = decData.Skip(0x28).ToArray();
if (!CryptoUtils.HMACVerify(hmacKey, psData, hmacSig))
{
Logger.WriteLine("Warning: Failed to verify HMAC. Physical store is either corrupt or in Vista format.");
}
return psData;
} }
throw new Exception("Failed to decrypt physical store."); byte[] aesKey = CryptoUtils.RSADecrypt(rsaKey, encAesKey);
byte[] decData = CryptoUtils.AESDecrypt(br.ReadBytes((int)br.BaseStream.Length - 0x110), aesKey);
byte[] hmacKey = decData.Take(0x10).ToArray(); // SHA-1 salt on Vista
byte[] hmacSig = decData.Skip(0x10).Take(0x14).ToArray(); // SHA-1 hash on Vista
byte[] psData = decData.Skip(0x28).ToArray();
if (version != PSVersion.Vista)
{
if (!CryptoUtils.HMACVerify(hmacKey, psData, hmacSig))
{
throw new InvalidDataException("Failed to verify HMAC. Physical store is corrupt.");
}
}
else
{
if (!CryptoUtils.SaltSHAVerify(hmacKey, psData, hmacSig))
{
throw new InvalidDataException("Failed to verify checksum. Physical store is corrupt.");
}
}
return psData;
} }
public static byte[] EncryptPhysicalStore(byte[] data, bool production, PSVersion version) public static byte[] EncryptPhysicalStore(byte[] data, bool production, PSVersion version)
{ {
Dictionary<PSVersion, int> versionTable = new Dictionary<PSVersion, int> Dictionary<PSVersion, int> versionTable = new Dictionary<PSVersion, int>
{ {
{PSVersion.Vista, 2},
{PSVersion.Win7, 5}, {PSVersion.Win7, 5},
{PSVersion.Win8, 1}, {PSVersion.Win8, 1},
{PSVersion.WinBlue, 2}, {PSVersion.WinBlue, 2},
@ -52,9 +63,9 @@ namespace LibTSforge.Crypto
byte[] encAesKey = CryptoUtils.RSAEncrypt(rsaKey, aesKey); byte[] encAesKey = CryptoUtils.RSAEncrypt(rsaKey, aesKey);
byte[] aesKeySig = CryptoUtils.RSASign(rsaKey, encAesKey); byte[] aesKeySig = CryptoUtils.RSASign(rsaKey, encAesKey);
byte[] hmacSig = CryptoUtils.HMACSign(hmacKey, data); byte[] hmacSig = version != PSVersion.Vista ? CryptoUtils.HMACSign(hmacKey, data) : CryptoUtils.SaltSHASum(hmacKey, data);
byte[] decData = new byte[] { }; byte[] decData = { };
decData = decData.Concat(hmacKey).Concat(hmacSig).Concat(BitConverter.GetBytes(0)).Concat(data).ToArray(); decData = decData.Concat(hmacKey).Concat(hmacSig).Concat(BitConverter.GetBytes(0)).Concat(data).ToArray();
byte[] encData = CryptoUtils.AESEncrypt(decData, aesKey); byte[] encData = CryptoUtils.AESEncrypt(decData, aesKey);

View File

@ -7,6 +7,7 @@
<LangVersion>3</LangVersion> <LangVersion>3</LangVersion>
<PackageReadmeFile>README.md</PackageReadmeFile> <PackageReadmeFile>README.md</PackageReadmeFile>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion> <IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">

View File

@ -3,9 +3,9 @@ namespace LibTSforge.Modifiers
using System; using System;
using System.IO; using System.IO;
using Microsoft.Win32; using Microsoft.Win32;
using LibTSforge.PhysicalStore; using PhysicalStore;
using LibTSforge.SPP; using SPP;
using LibTSforge.TokenStore; using TokenStore;
public static class GenPKeyInstall public static class GenPKeyInstall
{ {
@ -31,6 +31,7 @@ namespace LibTSforge.Modifiers
public static void InstallGenPKey(PSVersion version, bool production, Guid actId) public static void InstallGenPKey(PSVersion version, bool production, Guid actId)
{ {
if (version == PSVersion.Vista) throw new NotSupportedException("This feature is not supported on Windows Vista/Server 2008.");
if (actId == Guid.Empty) throw new ArgumentException("Activation ID must be specified for generated product key install."); if (actId == Guid.Empty) throw new ArgumentException("Activation ID must be specified for generated product key install.");
PKeyConfig pkc = new PKeyConfig(); PKeyConfig pkc = new PKeyConfig();
@ -57,7 +58,7 @@ namespace LibTSforge.Modifiers
if (pkey.Algorithm == PKeyAlgorithm.PKEY2009) if (pkey.Algorithm == PKeyAlgorithm.PKEY2009)
{ {
uint status = SLApi.InstallProductKey(pkey); uint status = SLApi.InstallProductKey(pkey);
Logger.WriteLine(string.Format("Installing generated product key {0} status {1:X}", pkey.ToString(), status)); Logger.WriteLine(string.Format("Installing generated product key {0} status {1:X}", pkey, status));
if ((int)status < 0) if ((int)status < 0)
{ {
@ -72,57 +73,57 @@ namespace LibTSforge.Modifiers
if (pkey.Channel == "Volume:GVLK" && version == PSVersion.Win7) throw new NotSupportedException("Fake GVLK generation is not supported on Windows 7."); if (pkey.Channel == "Volume:GVLK" && version == PSVersion.Win7) throw new NotSupportedException("Fake GVLK generation is not supported on Windows 7.");
VariableBag pkb = new VariableBag(); VariableBag pkb = new VariableBag(version);
pkb.Blocks.AddRange(new CRCBlock[] pkb.Blocks.AddRange(new[]
{ {
new CRCBlock new CRCBlockModern
{ {
DataType = CRCBlockType.STRING, DataType = CRCBlockType.STRING,
KeyAsStr = "SppPkeyBindingProductKey", KeyAsStr = "SppPkeyBindingProductKey",
ValueAsStr = pkey.ToString() ValueAsStr = pkey.ToString()
}, },
new CRCBlock new CRCBlockModern
{ {
DataType = CRCBlockType.STRING, DataType = CRCBlockType.STRING,
KeyAsStr = "SppPkeyBindingMPC", KeyAsStr = "SppPkeyBindingMPC",
ValueAsStr = pkey.GetMPC() ValueAsStr = pkey.GetMPC()
}, },
new CRCBlock { new CRCBlockModern {
DataType = CRCBlockType.BINARY, DataType = CRCBlockType.BINARY,
KeyAsStr = "SppPkeyBindingPid2", KeyAsStr = "SppPkeyBindingPid2",
ValueAsStr = pkey.GetPid2() ValueAsStr = pkey.GetPid2()
}, },
new CRCBlock new CRCBlockModern
{ {
DataType = CRCBlockType.BINARY, DataType = CRCBlockType.BINARY,
KeyAsStr = "SppPkeyBindingPid3", KeyAsStr = "SppPkeyBindingPid3",
Value = pkey.GetPid3() Value = pkey.GetPid3()
}, },
new CRCBlock new CRCBlockModern
{ {
DataType = CRCBlockType.BINARY, DataType = CRCBlockType.BINARY,
KeyAsStr = "SppPkeyBindingPid4", KeyAsStr = "SppPkeyBindingPid4",
Value = pkey.GetPid4() Value = pkey.GetPid4()
}, },
new CRCBlock new CRCBlockModern
{ {
DataType = CRCBlockType.STRING, DataType = CRCBlockType.STRING,
KeyAsStr = "SppPkeyChannelId", KeyAsStr = "SppPkeyChannelId",
ValueAsStr = pkey.Channel ValueAsStr = pkey.Channel
}, },
new CRCBlock new CRCBlockModern
{ {
DataType = CRCBlockType.STRING, DataType = CRCBlockType.STRING,
KeyAsStr = "SppPkeyBindingEditionId", KeyAsStr = "SppPkeyBindingEditionId",
ValueAsStr = pkey.Edition ValueAsStr = pkey.Edition
}, },
new CRCBlock new CRCBlockModern
{ {
DataType = CRCBlockType.BINARY, DataType = CRCBlockType.BINARY,
KeyAsStr = (version == PSVersion.Win7) ? "SppPkeyShortAuthenticator" : "SppPkeyPhoneActivationData", KeyAsStr = (version == PSVersion.Win7) ? "SppPkeyShortAuthenticator" : "SppPkeyPhoneActivationData",
Value = pkey.GetPhoneData(version) Value = pkey.GetPhoneData(version)
}, },
new CRCBlock new CRCBlockModern
{ {
DataType = CRCBlockType.BINARY, DataType = CRCBlockType.BINARY,
KeyAsStr = "SppPkeyBindingMiscData", KeyAsStr = "SppPkeyBindingMiscData",
@ -140,11 +141,11 @@ namespace LibTSforge.Modifiers
SLApi.UninstallAllProductKeys(appId); SLApi.UninstallAllProductKeys(appId);
} }
Utils.KillSPP(); SPPUtils.KillSPP(version);
using (IPhysicalStore ps = Utils.GetStore(version, production)) using (IPhysicalStore ps = SPPUtils.GetStore(version, production))
{ {
using (ITokenStore tks = Utils.GetTokenStore(version)) using (ITokenStore tks = SPPUtils.GetTokenStore(version))
{ {
Logger.WriteLine("Writing to physical store and token store..."); Logger.WriteLine("Writing to physical store and token store...");
@ -168,7 +169,7 @@ namespace LibTSforge.Modifiers
uriMap.Data[pkeyId] = pkey.GetAlgoUri(); uriMap.Data[pkeyId] = pkey.GetAlgoUri();
tks.SetEntry(uriMapName, "xml", uriMap.Serialize()); tks.SetEntry(uriMapName, "xml", uriMap.Serialize());
string skuMetaName = actId.ToString() + metSuffix; string skuMetaName = actId + metSuffix;
TokenMeta skuMeta = tks.GetMetaEntry(skuMetaName); TokenMeta skuMeta = tks.GetMetaEntry(skuMetaName);
foreach (string k in skuMeta.Data.Keys) foreach (string k in skuMeta.Data.Keys)
@ -195,7 +196,7 @@ namespace LibTSforge.Modifiers
Data = pkb.Serialize() Data = pkb.Serialize()
}); });
string cachePath = Utils.GetTokensPath(version).Replace("tokens.dat", @"cache\cache.dat"); string cachePath = SPPUtils.GetTokensPath(version).Replace("tokens.dat", @"cache\cache.dat");
if (File.Exists(cachePath)) File.Delete(cachePath); if (File.Exists(cachePath)) File.Delete(cachePath);
} }
} }

View File

@ -1,18 +1,18 @@
namespace LibTSforge.Modifiers namespace LibTSforge.Modifiers
{ {
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using LibTSforge.PhysicalStore; using PhysicalStore;
using SPP;
public static class GracePeriodReset public static class GracePeriodReset
{ {
public static void Reset(PSVersion version, bool production) public static void Reset(PSVersion version, bool production)
{ {
Utils.KillSPP(); SPPUtils.KillSPP(version);
Logger.WriteLine("Writing TrustedStore data..."); Logger.WriteLine("Writing TrustedStore data...");
using (IPhysicalStore store = Utils.GetStore(version, production)) using (IPhysicalStore store = SPPUtils.GetStore(version, production))
{ {
string value = "msft:sl/timer"; string value = "msft:sl/timer";
List<PSBlock> blocks = store.FindBlocks(value).ToList(); List<PSBlock> blocks = store.FindBlocks(value).ToList();
@ -23,6 +23,7 @@ namespace LibTSforge.Modifiers
} }
} }
SPPUtils.RestartSPP(version);
Logger.WriteLine("Successfully reset all grace and evaluation period timers."); Logger.WriteLine("Successfully reset all grace and evaluation period timers.");
} }
} }

View File

@ -2,12 +2,12 @@ namespace LibTSforge.Modifiers
{ {
using System; using System;
using System.IO; using System.IO;
using LibTSforge.PhysicalStore; using PhysicalStore;
using LibTSforge.SPP; using SPP;
public static class KMSHostCharge public static class KMSHostCharge
{ {
public static void Charge(PSVersion version, Guid actId, bool production) public static void Charge(PSVersion version, bool production, Guid actId)
{ {
if (actId == Guid.Empty) if (actId == Guid.Empty)
{ {
@ -31,76 +31,113 @@ namespace LibTSforge.Modifiers
string key = string.Format("SPPSVC\\{0}", appId); string key = string.Format("SPPSVC\\{0}", appId);
long ldapTimestamp = DateTime.Now.ToFileTime(); long ldapTimestamp = DateTime.Now.ToFileTime();
byte[] cmidGuids = { };
byte[] reqCounts = { };
byte[] kmsChargeData = { };
BinaryWriter writer = new BinaryWriter(new MemoryStream()); BinaryWriter writer = new BinaryWriter(new MemoryStream());
for (int i = 0; i < currClients; i++) if (version == PSVersion.Vista)
{ {
writer.Write(ldapTimestamp - (10 * (i + 1))); writer.Write(new byte[44]);
writer.Write(Guid.NewGuid().ToByteArray()); writer.Seek(0, SeekOrigin.Begin);
writer.Write(totalClients);
writer.Write(43200);
writer.Write(32);
writer.Seek(20, SeekOrigin.Begin);
writer.Write((byte)currClients);
writer.Seek(32, SeekOrigin.Begin);
writer.Write((byte)currClients);
writer.Seek(0, SeekOrigin.End);
for (int i = 0; i < currClients; i++)
{
writer.Write(Guid.NewGuid().ToByteArray());
writer.Write(ldapTimestamp - (10 * (i + 1)));
}
kmsChargeData = writer.GetBytes();
}
else
{
for (int i = 0; i < currClients; i++)
{
writer.Write(ldapTimestamp - (10 * (i + 1)));
writer.Write(Guid.NewGuid().ToByteArray());
}
cmidGuids = writer.GetBytes();
writer = new BinaryWriter(new MemoryStream());
writer.Write(new byte[40]);
writer.Seek(4, SeekOrigin.Begin);
writer.Write((byte)currClients);
writer.Seek(24, SeekOrigin.Begin);
writer.Write((byte)currClients);
reqCounts = writer.GetBytes();
} }
byte[] cmidGuids = writer.GetBytes(); SPPUtils.KillSPP(version);
writer = new BinaryWriter(new MemoryStream());
writer.Write(new byte[40]);
writer.Seek(4, SeekOrigin.Begin);
writer.Write((byte)currClients);
writer.Seek(24, SeekOrigin.Begin);
writer.Write((byte)currClients);
byte[] reqCounts = writer.GetBytes();
Utils.KillSPP();
Logger.WriteLine("Writing TrustedStore data..."); Logger.WriteLine("Writing TrustedStore data...");
using (IPhysicalStore store = Utils.GetStore(version, production)) using (IPhysicalStore store = SPPUtils.GetStore(version, production))
{ {
VariableBag kmsCountData = new VariableBag(); if (version != PSVersion.Vista)
kmsCountData.Blocks.AddRange(new CRCBlock[]
{ {
new CRCBlock VariableBag kmsCountData = new VariableBag(version);
kmsCountData.Blocks.AddRange(new[]
{ {
DataType = CRCBlockType.BINARY, new CRCBlockModern
KeyAsStr = "SppBindingLicenseData", {
Value = hwidBlock DataType = CRCBlockType.BINARY,
}, KeyAsStr = "SppBindingLicenseData",
new CRCBlock Value = hwidBlock
{ },
DataType = CRCBlockType.UINT, new CRCBlockModern
Key = new byte[] { }, {
ValueAsInt = (uint)totalClients DataType = CRCBlockType.UINT,
}, Key = new byte[] { },
new CRCBlock ValueAsInt = (uint)totalClients
{ },
DataType = CRCBlockType.UINT, new CRCBlockModern
Key = new byte[] { }, {
ValueAsInt = 1051200000 DataType = CRCBlockType.UINT,
}, Key = new byte[] { },
new CRCBlock ValueAsInt = 1051200000
{ },
DataType = CRCBlockType.UINT, new CRCBlockModern
Key = new byte[] { }, {
ValueAsInt = (uint)currClients DataType = CRCBlockType.UINT,
}, Key = new byte[] { },
new CRCBlock ValueAsInt = (uint)currClients
{ },
DataType = CRCBlockType.BINARY, new CRCBlockModern
Key = new byte[] { }, {
Value = cmidGuids DataType = CRCBlockType.BINARY,
}, Key = new byte[] { },
new CRCBlock Value = cmidGuids
{ },
DataType = CRCBlockType.BINARY, new CRCBlockModern
Key = new byte[] { }, {
Value = reqCounts DataType = CRCBlockType.BINARY,
} Key = new byte[] { },
}); Value = reqCounts
}
});
byte[] kmsChargeData = kmsCountData.Serialize(); kmsChargeData = kmsCountData.Serialize();
string countVal = string.Format("msft:spp/kms/host/2.0/store/counters/{0}", appId); }
string countVal = version == PSVersion.Vista ? "C8F6FFF1-79CE-404C-B150-F97991273DF1" : string.Format("msft:spp/kms/host/2.0/store/counters/{0}", appId);
store.DeleteBlock(key, countVal); store.DeleteBlock(key, countVal);
store.AddBlock(new PSBlock store.AddBlock(new PSBlock
@ -114,6 +151,8 @@ namespace LibTSforge.Modifiers
Logger.WriteLine(string.Format("Set charge count to {0} successfully.", currClients)); Logger.WriteLine(string.Format("Set charge count to {0} successfully.", currClients));
} }
SPPUtils.RestartSPP(version);
} }
} }
} }

View File

@ -2,15 +2,19 @@ namespace LibTSforge.Modifiers
{ {
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using LibTSforge.PhysicalStore; using PhysicalStore;
using LibTSforge; using SPP;
using System;
public static class KeyChangeLockDelete public static class KeyChangeLockDelete
{ {
public static void Delete(PSVersion version, bool production) public static void Delete(PSVersion version, bool production)
{ {
Utils.KillSPP(); if (version == PSVersion.Vista) throw new NotSupportedException("This feature is not supported on Windows Vista/Server 2008.");
SPPUtils.KillSPP(version);
Logger.WriteLine("Writing TrustedStore data..."); Logger.WriteLine("Writing TrustedStore data...");
using (IPhysicalStore store = Utils.GetStore(version, production)) using (IPhysicalStore store = SPPUtils.GetStore(version, production))
{ {
List<string> values = new List<string> List<string> values = new List<string>
{ {

View File

@ -1,23 +1,27 @@
namespace LibTSforge.Modifiers namespace LibTSforge.Modifiers
{ {
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using LibTSforge.PhysicalStore; using PhysicalStore;
using SPP;
public static class RearmReset public static class RearmReset
{ {
public static void Reset(PSVersion version, bool production) public static void Reset(PSVersion version, bool production)
{ {
Utils.KillSPP(); SPPUtils.KillSPP(version);
Logger.WriteLine("Writing TrustedStore data..."); Logger.WriteLine("Writing TrustedStore data...");
using (IPhysicalStore store = Utils.GetStore(version, production)) using (IPhysicalStore store = SPPUtils.GetStore(version, production))
{ {
List<PSBlock> blocks; List<PSBlock> blocks;
if (version == PSVersion.Win7) if (version == PSVersion.Vista)
{
blocks = store.FindBlocks("740D70D8-6448-4b2f-9063-4A7A463600C5").ToList();
}
else if (version == PSVersion.Win7)
{ {
blocks = store.FindBlocks(0xA0000).ToList(); blocks = store.FindBlocks(0xA0000).ToList();
} }
@ -28,7 +32,11 @@ namespace LibTSforge.Modifiers
foreach (PSBlock block in blocks) foreach (PSBlock block in blocks)
{ {
if (version == PSVersion.Win7) if (version == PSVersion.Vista)
{
store.DeleteBlock(block.KeyAsStr, block.ValueAsStr);
}
else if (version == PSVersion.Win7)
{ {
store.SetBlock(block.KeyAsStr, block.ValueAsInt, new byte[8]); store.SetBlock(block.KeyAsStr, block.ValueAsInt, new byte[8]);
} }

View File

@ -0,0 +1,66 @@
namespace LibTSforge.Modifiers
{
using PhysicalStore;
using SPP;
using System.IO;
using System;
public static class SetIIDParams
{
public static void SetParams(PSVersion version, bool production, Guid actId, PKeyAlgorithm algorithm, int group, int serial, ulong security)
{
if (version == PSVersion.Vista) throw new NotSupportedException("This feature is not supported on Windows Vista/Server 2008.");
Guid appId;
if (actId == Guid.Empty)
{
appId = SLApi.WINDOWS_APP_ID;
actId = SLApi.GetDefaultActivationID(appId, true);
if (actId == Guid.Empty)
{
throw new Exception("No applicable activation IDs found.");
}
}
else
{
appId = SLApi.GetAppId(actId);
}
Guid pkeyId = SLApi.GetInstalledPkeyID(actId);
SPPUtils.KillSPP(version);
Logger.WriteLine("Writing TrustedStore data...");
using (IPhysicalStore store = SPPUtils.GetStore(version, production))
{
string key = string.Format("SPPSVC\\{0}\\{1}", appId, actId);
PSBlock keyBlock = store.GetBlock(key, pkeyId.ToString());
if (keyBlock == null)
{
throw new InvalidDataException("Failed to get product key data for activation ID " + actId + ".");
}
VariableBag pkb = new VariableBag(keyBlock.Data, version);
ProductKey pkey = new ProductKey
{
Group = group,
Serial = serial,
Security = security,
Algorithm = algorithm,
Upgrade = false
};
string blockName = version == PSVersion.Win7 ? "SppPkeyShortAuthenticator" : "SppPkeyPhoneActivationData";
pkb.SetBlock(blockName, pkey.GetPhoneData(version));
store.SetBlock(key, pkeyId.ToString(), pkb.Serialize());
}
Logger.WriteLine("Successfully set IID parameters.");
}
}
}

View File

@ -1,34 +1,37 @@
namespace LibTSforge.Modifiers namespace LibTSforge.Modifiers
{ {
using System;
using System.Linq; using System.Linq;
using LibTSforge.PhysicalStore; using PhysicalStore;
using SPP;
public static class TamperedFlagsDelete public static class TamperedFlagsDelete
{ {
public static void DeleteTamperFlags(PSVersion version, bool production) public static void DeleteTamperFlags(PSVersion version, bool production)
{ {
Utils.KillSPP(); SPPUtils.KillSPP(version);
Logger.WriteLine("Writing TrustedStore data..."); Logger.WriteLine("Writing TrustedStore data...");
using (IPhysicalStore store = Utils.GetStore(version, production)) using (IPhysicalStore store = SPPUtils.GetStore(version, production))
{ {
if (version != PSVersion.Win7) if (version == PSVersion.Vista)
{ {
string recreatedFlag = "__##USERSEP-RESERVED##__$$RECREATED-FLAG$$"; DeleteFlag(store, "6BE8425B-E3CF-4e86-A6AF-5863E3DCB606");
string recoveredFlag = "__##USERSEP-RESERVED##__$$RECOVERED-FLAG$$"; }
else if (version == PSVersion.Win7)
DeleteFlag(store, recreatedFlag); {
DeleteFlag(store, recoveredFlag); SetFlag(store, 0xA0001);
} }
else else
{ {
SetFlag(store, 0xA0001); DeleteFlag(store, "__##USERSEP-RESERVED##__$$RECREATED-FLAG$$");
DeleteFlag(store, "__##USERSEP-RESERVED##__$$RECOVERED-FLAG$$");
} }
Logger.WriteLine("Successfully cleared the tamper state."); Logger.WriteLine("Successfully cleared the tamper state.");
} }
SPPUtils.RestartSPP(version);
} }
private static void DeleteFlag(IPhysicalStore store, string flag) private static void DeleteFlag(IPhysicalStore store, string flag)

View File

@ -1,13 +1,15 @@
namespace LibTSforge.Modifiers namespace LibTSforge.Modifiers
{ {
using System; using System;
using LibTSforge.PhysicalStore; using PhysicalStore;
using LibTSforge.SPP; using SPP;
public static class UniqueIdDelete public static class UniqueIdDelete
{ {
public static void DeleteUniqueId(PSVersion version, bool production, Guid actId) public static void DeleteUniqueId(PSVersion version, bool production, Guid actId)
{ {
if (version == PSVersion.Vista) throw new NotSupportedException("This feature is not supported on Windows Vista/Server 2008.");
Guid appId; Guid appId;
if (actId == Guid.Empty) if (actId == Guid.Empty)
@ -25,14 +27,13 @@ namespace LibTSforge.Modifiers
appId = SLApi.GetAppId(actId); appId = SLApi.GetAppId(actId);
} }
string instId = SLApi.GetInstallationID(actId);
Guid pkeyId = SLApi.GetInstalledPkeyID(actId); Guid pkeyId = SLApi.GetInstalledPkeyID(actId);
Utils.KillSPP(); SPPUtils.KillSPP(version);
Logger.WriteLine("Writing TrustedStore data..."); Logger.WriteLine("Writing TrustedStore data...");
using (IPhysicalStore store = Utils.GetStore(version, production)) using (IPhysicalStore store = SPPUtils.GetStore(version, production))
{ {
string key = string.Format("SPPSVC\\{0}\\{1}", appId, actId); string key = string.Format("SPPSVC\\{0}\\{1}", appId, actId);
PSBlock keyBlock = store.GetBlock(key, pkeyId.ToString()); PSBlock keyBlock = store.GetBlock(key, pkeyId.ToString());
@ -42,7 +43,7 @@ namespace LibTSforge.Modifiers
throw new Exception("No product key found."); throw new Exception("No product key found.");
} }
VariableBag pkb = new VariableBag(keyBlock.Data); VariableBag pkb = new VariableBag(keyBlock.Data, version);
pkb.DeleteBlock("SppPkeyUniqueIdToken"); pkb.DeleteBlock("SppPkeyUniqueIdToken");

View File

@ -18,4 +18,11 @@ namespace LibTSforge.PhysicalStore
public ulong Time2; public ulong Time2;
public ulong Expiry; public ulong Expiry;
} }
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct VistaTimer
{
public ulong Time;
public ulong Expiry;
}
} }

View File

@ -3,7 +3,7 @@ namespace LibTSforge.PhysicalStore
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using LibTSforge.Crypto; using Crypto;
public class ModernBlock public class ModernBlock
{ {
@ -93,7 +93,7 @@ namespace LibTSforge.PhysicalStore
public sealed class PhysicalStoreModern : IPhysicalStore public sealed class PhysicalStoreModern : IPhysicalStore
{ {
private byte[] PreHeaderBytes = new byte[] { }; private byte[] PreHeaderBytes = { };
private readonly Dictionary<string, List<ModernBlock>> Data = new Dictionary<string, List<ModernBlock>>(); private readonly Dictionary<string, List<ModernBlock>> Data = new Dictionary<string, List<ModernBlock>>();
private readonly FileStream TSFile; private readonly FileStream TSFile;
private readonly PSVersion Version; private readonly PSVersion Version;
@ -281,46 +281,50 @@ namespace LibTSforge.PhysicalStore
public void DeleteBlock(string key, string value) public void DeleteBlock(string key, string value)
{ {
if (Data.ContainsKey(key)) if (!Data.ContainsKey(key))
{ {
List<ModernBlock> blocks = Data[key]; return;
foreach (ModernBlock block in blocks)
{
if (block.ValueAsStr == value)
{
blocks.Remove(block);
break;
}
}
Data[key] = blocks;
} }
List<ModernBlock> blocks = Data[key];
foreach (ModernBlock block in blocks)
{
if (block.ValueAsStr == value)
{
blocks.Remove(block);
break;
}
}
Data[key] = blocks;
} }
public void DeleteBlock(string key, uint value) public void DeleteBlock(string key, uint value)
{ {
if (Data.ContainsKey(key)) if (!Data.ContainsKey(key))
{ {
List<ModernBlock> blocks = Data[key]; return;
foreach (ModernBlock block in blocks)
{
if (block.ValueAsInt == value)
{
blocks.Remove(block);
break;
}
}
Data[key] = blocks;
} }
List<ModernBlock> blocks = Data[key];
foreach (ModernBlock block in blocks)
{
if (block.ValueAsInt == value)
{
blocks.Remove(block);
break;
}
}
Data[key] = blocks;
} }
public PhysicalStoreModern(string tsPath, bool production, PSVersion version) public PhysicalStoreModern(string tsPath, bool production, PSVersion version)
{ {
TSFile = File.Open(tsPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); TSFile = File.Open(tsPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
Deserialize(PhysStoreCrypto.DecryptPhysicalStore(TSFile.ReadAllBytes(), production)); Deserialize(PhysStoreCrypto.DecryptPhysicalStore(TSFile.ReadAllBytes(), production, version));
TSFile.Seek(0, SeekOrigin.Begin); TSFile.Seek(0, SeekOrigin.Begin);
Version = version; Version = version;
Production = production; Production = production;
@ -340,7 +344,7 @@ namespace LibTSforge.PhysicalStore
public byte[] ReadRaw() public byte[] ReadRaw()
{ {
byte[] data = PhysStoreCrypto.DecryptPhysicalStore(TSFile.ReadAllBytes(), Production); byte[] data = PhysStoreCrypto.DecryptPhysicalStore(TSFile.ReadAllBytes(), Production, Version);
TSFile.Seek(0, SeekOrigin.Begin); TSFile.Seek(0, SeekOrigin.Begin);
return data; return data;
} }

View File

@ -0,0 +1,356 @@
namespace LibTSforge.PhysicalStore
{
using System;
using System.Collections.Generic;
using System.IO;
using Crypto;
public class VistaBlock
{
public BlockType Type;
public uint Flags;
public byte[] Value;
public string ValueAsStr
{
get
{
return Utils.DecodeString(Value);
}
set
{
Value = Utils.EncodeString(value);
}
}
public uint ValueAsInt
{
get
{
return BitConverter.ToUInt32(Value, 0);
}
set
{
Value = BitConverter.GetBytes(value);
}
}
public byte[] Data;
public string DataAsStr
{
get
{
return Utils.DecodeString(Data);
}
set
{
Data = Utils.EncodeString(value);
}
}
public uint DataAsInt
{
get
{
return BitConverter.ToUInt32(Data, 0);
}
set
{
Data = BitConverter.GetBytes(value);
}
}
internal void Encode(BinaryWriter writer)
{
writer.Write((uint)Type);
writer.Write(Flags);
writer.Write(Value.Length);
writer.Write(Data.Length);
writer.Write(Value);
writer.Write(Data);
}
internal static VistaBlock Decode(BinaryReader reader)
{
uint type = reader.ReadUInt32();
uint flags = reader.ReadUInt32();
int valueLen = reader.ReadInt32();
int dataLen = reader.ReadInt32();
byte[] value = reader.ReadBytes(valueLen);
byte[] data = reader.ReadBytes(dataLen);
return new VistaBlock
{
Type = (BlockType)type,
Flags = flags,
Value = value,
Data = data,
};
}
}
public sealed class PhysicalStoreVista : IPhysicalStore
{
private byte[] PreHeaderBytes = { };
private readonly List<VistaBlock> Blocks = new List<VistaBlock>();
private readonly FileStream TSPrimary;
private readonly FileStream TSSecondary;
private readonly bool Production;
public byte[] Serialize()
{
BinaryWriter writer = new BinaryWriter(new MemoryStream());
writer.Write(PreHeaderBytes);
foreach (VistaBlock block in Blocks)
{
block.Encode(writer);
writer.Align(4);
}
return writer.GetBytes();
}
public void Deserialize(byte[] data)
{
int len = data.Length;
BinaryReader reader = new BinaryReader(new MemoryStream(data));
PreHeaderBytes = reader.ReadBytes(8);
while (reader.BaseStream.Position < len - 0x14)
{
Blocks.Add(VistaBlock.Decode(reader));
reader.Align(4);
}
}
public void AddBlock(PSBlock block)
{
Blocks.Add(new VistaBlock
{
Type = block.Type,
Flags = block.Flags,
Value = block.Value,
Data = block.Data
});
}
public void AddBlocks(IEnumerable<PSBlock> blocks)
{
foreach (PSBlock block in blocks)
{
AddBlock(block);
}
}
public PSBlock GetBlock(string key, string value)
{
foreach (VistaBlock block in Blocks)
{
if (block.ValueAsStr == value)
{
return new PSBlock
{
Type = block.Type,
Flags = block.Flags,
Key = new byte[0],
Value = block.Value,
Data = block.Data
};
}
}
return null;
}
public PSBlock GetBlock(string key, uint value)
{
foreach (VistaBlock block in Blocks)
{
if (block.ValueAsInt == value)
{
return new PSBlock
{
Type = block.Type,
Flags = block.Flags,
Key = new byte[0],
Value = block.Value,
Data = block.Data
};
}
}
return null;
}
public void SetBlock(string key, string value, byte[] data)
{
for (int i = 0; i < Blocks.Count; i++)
{
VistaBlock block = Blocks[i];
if (block.ValueAsStr == value)
{
block.Data = data;
Blocks[i] = block;
break;
}
}
}
public void SetBlock(string key, uint value, byte[] data)
{
for (int i = 0; i < Blocks.Count; i++)
{
VistaBlock block = Blocks[i];
if (block.ValueAsInt == value)
{
block.Data = data;
Blocks[i] = block;
break;
}
}
}
public void SetBlock(string key, string value, string data)
{
SetBlock(key, value, Utils.EncodeString(data));
}
public void SetBlock(string key, string value, uint data)
{
SetBlock(key, value, BitConverter.GetBytes(data));
}
public void SetBlock(string key, uint value, string data)
{
SetBlock(key, value, Utils.EncodeString(data));
}
public void SetBlock(string key, uint value, uint data)
{
SetBlock(key, value, BitConverter.GetBytes(data));
}
public void DeleteBlock(string key, string value)
{
foreach (VistaBlock block in Blocks)
{
if (block.ValueAsStr == value)
{
Blocks.Remove(block);
return;
}
}
}
public void DeleteBlock(string key, uint value)
{
foreach (VistaBlock block in Blocks)
{
if (block.ValueAsInt == value)
{
Blocks.Remove(block);
return;
}
}
}
public PhysicalStoreVista(string primaryPath, bool production)
{
TSPrimary = File.Open(primaryPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
TSSecondary = File.Open(primaryPath.Replace("-0.", "-1."), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
Production = production;
Deserialize(PhysStoreCrypto.DecryptPhysicalStore(TSPrimary.ReadAllBytes(), production, PSVersion.Vista));
TSPrimary.Seek(0, SeekOrigin.Begin);
}
public void Dispose()
{
if (TSPrimary.CanWrite && TSSecondary.CanWrite)
{
byte[] data = PhysStoreCrypto.EncryptPhysicalStore(Serialize(), Production, PSVersion.Vista);
TSPrimary.SetLength(data.LongLength);
TSSecondary.SetLength(data.LongLength);
TSPrimary.Seek(0, SeekOrigin.Begin);
TSSecondary.Seek(0, SeekOrigin.Begin);
TSPrimary.WriteAllBytes(data);
TSSecondary.WriteAllBytes(data);
TSPrimary.Close();
TSSecondary.Close();
}
}
public byte[] ReadRaw()
{
byte[] data = PhysStoreCrypto.DecryptPhysicalStore(TSPrimary.ReadAllBytes(), Production, PSVersion.Vista);
TSPrimary.Seek(0, SeekOrigin.Begin);
return data;
}
public void WriteRaw(byte[] data)
{
byte[] encrData = PhysStoreCrypto.EncryptPhysicalStore(data, Production, PSVersion.Vista);
TSPrimary.SetLength(encrData.LongLength);
TSSecondary.SetLength(encrData.LongLength);
TSPrimary.Seek(0, SeekOrigin.Begin);
TSSecondary.Seek(0, SeekOrigin.Begin);
TSPrimary.WriteAllBytes(encrData);
TSSecondary.WriteAllBytes(encrData);
TSPrimary.Close();
TSSecondary.Close();
}
public IEnumerable<PSBlock> FindBlocks(string valueSearch)
{
List<PSBlock> results = new List<PSBlock>();
foreach (VistaBlock block in Blocks)
{
if (block.ValueAsStr.Contains(valueSearch))
{
results.Add(new PSBlock
{
Type = block.Type,
Flags = block.Flags,
Key = new byte[0],
Value = block.Value,
Data = block.Data
});
}
}
return results;
}
public IEnumerable<PSBlock> FindBlocks(uint valueSearch)
{
List<PSBlock> results = new List<PSBlock>();
foreach (VistaBlock block in Blocks)
{
if (block.ValueAsInt == valueSearch)
{
results.Add(new PSBlock
{
Type = block.Type,
Flags = block.Flags,
Key = new byte[0],
Value = block.Value,
Data = block.Data
});
}
}
return results;
}
}
}

View File

@ -3,7 +3,7 @@ namespace LibTSforge.PhysicalStore
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using LibTSforge.Crypto; using Crypto;
public class Win7Block public class Win7Block
{ {
@ -105,7 +105,7 @@ namespace LibTSforge.PhysicalStore
public sealed class PhysicalStoreWin7 : IPhysicalStore public sealed class PhysicalStoreWin7 : IPhysicalStore
{ {
private byte[] PreHeaderBytes = new byte[] { }; private byte[] PreHeaderBytes = { };
private readonly List<Win7Block> Blocks = new List<Win7Block>(); private readonly List<Win7Block> Blocks = new List<Win7Block>();
private readonly FileStream TSPrimary; private readonly FileStream TSPrimary;
private readonly FileStream TSSecondary; private readonly FileStream TSSecondary;
@ -279,7 +279,7 @@ namespace LibTSforge.PhysicalStore
TSSecondary = File.Open(primaryPath.Replace("-0.", "-1."), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); TSSecondary = File.Open(primaryPath.Replace("-0.", "-1."), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
Production = production; Production = production;
Deserialize(PhysStoreCrypto.DecryptPhysicalStore(TSPrimary.ReadAllBytes(), production)); Deserialize(PhysStoreCrypto.DecryptPhysicalStore(TSPrimary.ReadAllBytes(), production, PSVersion.Win7));
TSPrimary.Seek(0, SeekOrigin.Begin); TSPrimary.Seek(0, SeekOrigin.Begin);
} }
@ -305,7 +305,7 @@ namespace LibTSforge.PhysicalStore
public byte[] ReadRaw() public byte[] ReadRaw()
{ {
byte[] data = PhysStoreCrypto.DecryptPhysicalStore(TSPrimary.ReadAllBytes(), Production); byte[] data = PhysStoreCrypto.DecryptPhysicalStore(TSPrimary.ReadAllBytes(), Production, PSVersion.Win7);
TSPrimary.Seek(0, SeekOrigin.Begin); TSPrimary.Seek(0, SeekOrigin.Begin);
return data; return data;
} }

View File

@ -11,7 +11,7 @@ namespace LibTSforge.PhysicalStore
BINARY = 1 << 2 BINARY = 1 << 2
} }
public class CRCBlock public abstract class CRCBlock
{ {
public CRCBlockType DataType; public CRCBlockType DataType;
public byte[] Key; public byte[] Key;
@ -50,7 +50,57 @@ namespace LibTSforge.PhysicalStore
} }
} }
public void Encode(BinaryWriter writer) public abstract void Encode(BinaryWriter writer);
public abstract void Decode(BinaryReader reader);
public abstract uint CRC();
}
public class CRCBlockVista : CRCBlock
{
public override void Encode(BinaryWriter writer)
{
uint crc = CRC();
writer.Write((uint)DataType);
writer.Write(0);
writer.Write(Key.Length);
writer.Write(Value.Length);
writer.Write(crc);
writer.Write(Key);
writer.Write(Value);
}
public override void Decode(BinaryReader reader)
{
uint type = reader.ReadUInt32();
reader.ReadUInt32();
uint lenName = reader.ReadUInt32();
uint lenVal = reader.ReadUInt32();
uint crc = reader.ReadUInt32();
byte[] key = reader.ReadBytes((int)lenName);
byte[] value = reader.ReadBytes((int)lenVal);
DataType = (CRCBlockType)type;
Key = key;
Value = value;
if (CRC() != crc)
{
throw new InvalidDataException("Invalid CRC in variable bag.");
}
}
public override uint CRC()
{
return Utils.CRC32(Value);
}
}
public class CRCBlockModern : CRCBlock
{
public override void Encode(BinaryWriter writer)
{ {
uint crc = CRC(); uint crc = CRC();
writer.Write(crc); writer.Write(crc);
@ -65,7 +115,7 @@ namespace LibTSforge.PhysicalStore
writer.Align(8); writer.Align(8);
} }
public static CRCBlock Decode(BinaryReader reader) public override void Decode(BinaryReader reader)
{ {
uint crc = reader.ReadUInt32(); uint crc = reader.ReadUInt32();
uint type = reader.ReadUInt32(); uint type = reader.ReadUInt32();
@ -78,22 +128,17 @@ namespace LibTSforge.PhysicalStore
byte[] value = reader.ReadBytes((int)lenVal); byte[] value = reader.ReadBytes((int)lenVal);
reader.Align(8); reader.Align(8);
CRCBlock block = new CRCBlock DataType = (CRCBlockType)type;
{ Key = key;
DataType = (CRCBlockType)type, Value = value;
Key = key,
Value = value,
};
if (block.CRC() != crc) if (CRC() != crc)
{ {
throw new InvalidDataException("Invalid CRC in variable bag."); throw new InvalidDataException("Invalid CRC in variable bag.");
} }
return block;
} }
public uint CRC() public override uint CRC()
{ {
BinaryWriter wtemp = new BinaryWriter(new MemoryStream()); BinaryWriter wtemp = new BinaryWriter(new MemoryStream());
wtemp.Write(0); wtemp.Write(0);
@ -109,8 +154,9 @@ namespace LibTSforge.PhysicalStore
public class VariableBag public class VariableBag
{ {
public List<CRCBlock> Blocks = new List<CRCBlock>(); public List<CRCBlock> Blocks = new List<CRCBlock>();
private readonly PSVersion Version;
public void Deserialize(byte[] data) private void Deserialize(byte[] data)
{ {
int len = data.Length; int len = data.Length;
@ -118,7 +164,19 @@ namespace LibTSforge.PhysicalStore
while (reader.BaseStream.Position < len - 0x10) while (reader.BaseStream.Position < len - 0x10)
{ {
Blocks.Add(CRCBlock.Decode(reader)); CRCBlock block;
if (Version == PSVersion.Vista)
{
block = new CRCBlockVista();
}
else
{
block = new CRCBlockModern();
}
block.Decode(reader);
Blocks.Add(block);
} }
} }
@ -128,7 +186,13 @@ namespace LibTSforge.PhysicalStore
foreach (CRCBlock block in Blocks) foreach (CRCBlock block in Blocks)
{ {
block.Encode(writer); if (Version == PSVersion.Vista)
{
((CRCBlockVista)block).Encode(writer);
} else
{
((CRCBlockModern)block).Encode(writer);
}
} }
return writer.GetBytes(); return writer.GetBytes();
@ -174,14 +238,15 @@ namespace LibTSforge.PhysicalStore
} }
} }
public VariableBag(byte[] data) public VariableBag(byte[] data, PSVersion version)
{ {
Version = version;
Deserialize(data); Deserialize(data);
} }
public VariableBag() public VariableBag(PSVersion version)
{ {
Version = version;
} }
} }
} }

View File

@ -74,8 +74,8 @@ namespace LibTSforge.SPP
public class PKeyConfig public class PKeyConfig
{ {
public Dictionary<Guid, ProductConfig> Products = new Dictionary<Guid, ProductConfig>(); public readonly Dictionary<Guid, ProductConfig> Products = new Dictionary<Guid, ProductConfig>();
private List<Guid> loadedPkeyConfigs = new List<Guid>(); private readonly List<Guid> loadedPkeyConfigs = new List<Guid>();
public void LoadConfig(Guid actId) public void LoadConfig(Guid actId)
{ {
@ -136,12 +136,14 @@ namespace LibTSforge.SPP
ranges[refActIdStr] = new List<KeyRange>(); ranges[refActIdStr] = new List<KeyRange>();
} }
KeyRange keyRange = new KeyRange(); KeyRange keyRange = new KeyRange
keyRange.Start = int.Parse(rangeNode.SelectSingleNode("./p:Start", nsmgr).InnerText); {
keyRange.End = int.Parse(rangeNode.SelectSingleNode("./p:End", nsmgr).InnerText); Start = int.Parse(rangeNode.SelectSingleNode("./p:Start", nsmgr).InnerText),
keyRange.EulaType = rangeNode.SelectSingleNode("./p:EulaType", nsmgr).InnerText; End = int.Parse(rangeNode.SelectSingleNode("./p:End", nsmgr).InnerText),
keyRange.PartNumber = rangeNode.SelectSingleNode("./p:PartNumber", nsmgr).InnerText; EulaType = rangeNode.SelectSingleNode("./p:EulaType", nsmgr).InnerText,
keyRange.Valid = rangeNode.SelectSingleNode("./p:IsValid", nsmgr).InnerText.ToLower() == "true"; PartNumber = rangeNode.SelectSingleNode("./p:PartNumber", nsmgr).InnerText,
Valid = rangeNode.SelectSingleNode("./p:IsValid", nsmgr).InnerText.ToLower() == "true"
};
ranges[refActIdStr].Add(keyRange); ranges[refActIdStr].Add(keyRange);
} }
@ -155,15 +157,17 @@ namespace LibTSforge.SPP
if (keyRanges.Count > 0 && !Products.ContainsKey(refActId)) if (keyRanges.Count > 0 && !Products.ContainsKey(refActId))
{ {
ProductConfig productConfig = new ProductConfig(); ProductConfig productConfig = new ProductConfig
productConfig.GroupId = group; {
productConfig.Edition = configNode.SelectSingleNode("./p:EditionId", nsmgr).InnerText; GroupId = group,
productConfig.Description = configNode.SelectSingleNode("./p:ProductDescription", nsmgr).InnerText; Edition = configNode.SelectSingleNode("./p:EditionId", nsmgr).InnerText,
productConfig.Channel = configNode.SelectSingleNode("./p:ProductKeyType", nsmgr).InnerText; Description = configNode.SelectSingleNode("./p:ProductDescription", nsmgr).InnerText,
productConfig.Randomized = configNode.SelectSingleNode("./p:ProductKeyType", nsmgr).InnerText.ToLower() == "true"; Channel = configNode.SelectSingleNode("./p:ProductKeyType", nsmgr).InnerText,
productConfig.Algorithm = algorithms[group]; Randomized = configNode.SelectSingleNode("./p:ProductKeyType", nsmgr).InnerText.ToLower() == "true",
productConfig.Ranges = keyRanges; Algorithm = algorithms[group],
productConfig.ActivationId = refActId; Ranges = keyRanges,
ActivationId = refActId
};
Products[refActId] = productConfig; Products[refActId] = productConfig;
} }
@ -206,10 +210,5 @@ namespace LibTSforge.SPP
} }
} }
} }
public PKeyConfig()
{
}
} }
} }

View File

@ -3,8 +3,8 @@ namespace LibTSforge.SPP
using System; using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using LibTSforge.Crypto; using Crypto;
using LibTSforge.PhysicalStore; using PhysicalStore;
public class ProductKey public class ProductKey
{ {
@ -18,11 +18,11 @@ namespace LibTSforge.SPP
public ulong Security; public ulong Security;
public bool Upgrade; public bool Upgrade;
public PKeyAlgorithm Algorithm; public PKeyAlgorithm Algorithm;
public string EulaType; public readonly string EulaType;
public string PartNumber; public readonly string PartNumber;
public string Edition; public readonly string Edition;
public string Channel; public readonly string Channel;
public Guid ActivationId; public readonly Guid ActivationId;
private string mpc; private string mpc;
private string pid2; private string pid2;
@ -32,6 +32,11 @@ namespace LibTSforge.SPP
get { return BitConverter.GetBytes(klow).Concat(BitConverter.GetBytes(khigh)).ToArray(); } 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) public ProductKey(int serial, ulong security, bool upgrade, PKeyAlgorithm algorithm, ProductConfig config, KeyRange range)
{ {
Group = config.GroupId; Group = config.GroupId;
@ -60,22 +65,22 @@ namespace LibTSforge.SPP
public Guid GetPkeyId() public Guid GetPkeyId()
{ {
VariableBag pkb = new VariableBag(); VariableBag pkb = new VariableBag(PSVersion.WinModern);
pkb.Blocks.AddRange(new CRCBlock[] pkb.Blocks.AddRange(new[]
{ {
new CRCBlock new CRCBlockModern
{ {
DataType = CRCBlockType.STRING, DataType = CRCBlockType.STRING,
KeyAsStr = "SppPkeyBindingProductKey", KeyAsStr = "SppPkeyBindingProductKey",
ValueAsStr = ToString() ValueAsStr = ToString()
}, },
new CRCBlock new CRCBlockModern
{ {
DataType = CRCBlockType.BINARY, DataType = CRCBlockType.BINARY,
KeyAsStr = "SppPkeyBindingMiscData", KeyAsStr = "SppPkeyBindingMiscData",
Value = new byte[] { } Value = new byte[] { }
}, },
new CRCBlock new CRCBlockModern
{ {
DataType = CRCBlockType.STRING, DataType = CRCBlockType.STRING,
KeyAsStr = "SppPkeyBindingAlgorithm", KeyAsStr = "SppPkeyBindingAlgorithm",
@ -86,16 +91,6 @@ namespace LibTSforge.SPP
return new Guid(CryptoUtils.SHA256Hash(pkb.Serialize()).Take(16).ToArray()); 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() public string GetMPC()
{ {
if (mpc != null) if (mpc != null)
@ -103,10 +98,15 @@ namespace LibTSforge.SPP
return mpc; 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+ // 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(";")) if (!File.Exists(setupcfg) || Edition.Contains(";"))
{ {
@ -244,17 +244,17 @@ namespace LibTSforge.SPP
{ {
if (version == PSVersion.Win7) if (version == PSVersion.Win7)
{ {
Random rnd = new Random(Group * 1000000000 + Serial); ulong shortauth = ((ulong)Group << 41) | (Security << 31) | ((ulong)Serial << 1) | (Upgrade ? (ulong)1 : 0);
byte[] data = new byte[8]; return BitConverter.GetBytes(shortauth);
rnd.NextBytes(data);
return data;
} }
int serialHigh = Serial / 1000000; int serialHigh = Serial / 1000000;
int serialLow = Serial % 1000000; int serialLow = Serial % 1000000;
BinaryWriter writer = new BinaryWriter(new MemoryStream()); 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(Group);
writer.Write(serialHigh); writer.Write(serialHigh);
writer.Write(serialLow); writer.Write(serialLow);

View File

@ -44,40 +44,40 @@ namespace LibTSforge.SPP
public static readonly Guid WINDOWS_APP_ID = new Guid("55c92734-d682-4d71-983e-d6ec3f16059f"); 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); 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); private static extern void SLClose(IntPtr hSLC);
[DllImport("slc.dll", CharSet = CharSet.Unicode)] [DllImport("slc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLGetWindowsInformationDWORD(string ValueName, ref int Value); 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); 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); 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); 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); 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); 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); 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); 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); 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); private static extern uint SLGetInstalledProductKeyIds(IntPtr hSLC, ref Guid pProductSkuId, out uint pnProductKeyIds, out IntPtr ppProductKeyIds);
[DllImport("slc.dll", CharSet = CharSet.Unicode)] [DllImport("slc.dll", CharSet = CharSet.Unicode)]
@ -86,9 +86,6 @@ namespace LibTSforge.SPP
[DllImport("slc.dll", CharSet = CharSet.Unicode)] [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); 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)] [DllImport("slc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLGetLicense(IntPtr hSLC, ref Guid pLicenseFileId, out uint pcbLicenseFile, out IntPtr ppbLicenseFile); private static extern uint SLGetLicense(IntPtr hSLC, ref Guid pLicenseFileId, out uint pcbLicenseFile, out IntPtr ppbLicenseFile);
@ -98,7 +95,7 @@ namespace LibTSforge.SPP
[DllImport("slc.dll", CharSet = CharSet.Unicode)] [DllImport("slc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLFireEvent(IntPtr hSLC, string pwszEventId, ref Guid pApplicationId); private static extern uint SLFireEvent(IntPtr hSLC, string pwszEventId, ref Guid pApplicationId);
public class SLContext : IDisposable private class SLContext : IDisposable
{ {
public readonly IntPtr Handle; public readonly IntPtr Handle;
@ -161,11 +158,10 @@ namespace LibTSforge.SPP
{ {
using (SLContext sl = new SLContext()) using (SLContext sl = new SLContext())
{ {
uint status;
uint count; uint count;
IntPtr pProductKeyIds; 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) if (status != 0 || count == 0)
{ {
@ -189,7 +185,7 @@ namespace LibTSforge.SPP
SLConsumeWindowsRight(0); SLConsumeWindowsRight(0);
} }
public static bool RefreshTrustedTime(Guid actId) public static void RefreshTrustedTime(Guid actId)
{ {
using (SLContext sl = new SLContext()) using (SLContext sl = new SLContext())
{ {
@ -197,8 +193,7 @@ namespace LibTSforge.SPP
uint count; uint count;
IntPtr ppbValue; IntPtr ppbValue;
uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "TrustedTime", out type, out count, out ppbValue); SLGetProductSkuInformation(sl.Handle, ref actId, "TrustedTime", out type, out count, out ppbValue);
return (int)status >= 0 && status != 0xC004F012;
} }
} }
@ -214,11 +209,10 @@ namespace LibTSforge.SPP
{ {
using (SLContext sl = new SLContext()) using (SLContext sl = new SLContext())
{ {
uint status;
uint count; uint count;
IntPtr pAppIds; 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) if (status != 0 || count == 0)
{ {
@ -246,11 +240,10 @@ namespace LibTSforge.SPP
{ {
using (SLContext sl = new SLContext()) using (SLContext sl = new SLContext())
{ {
uint status;
uint count; uint count;
IntPtr ppReturnLics; 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) if (status != 0 || count == 0)
{ {
@ -312,7 +305,7 @@ namespace LibTSforge.SPP
IntPtr ppbValue; IntPtr ppbValue;
uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "msft:sl/EUL/PHONE/PUBLIC", out type, out count, out 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()) using (SLContext sl = new SLContext())
{ {
return SLUninstallProofOfPurchase(sl.Handle, ref pkeyId); SLUninstallProofOfPurchase(sl.Handle, ref pkeyId);
} }
} }

334
LibTSforge/SPP/SPPUtils.cs Normal file
View File

@ -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.");
}
}
}

44
LibTSforge/SPP/SPSys.cs Normal file
View File

@ -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;
}
}
}

View File

@ -14,7 +14,7 @@ namespace LibTSforge.TokenStore
public class TokenMeta public class TokenMeta
{ {
public string Name; public string Name;
public Dictionary<string, string> Data = new Dictionary<string, string>(); public readonly Dictionary<string, string> Data = new Dictionary<string, string>();
public byte[] Serialize() public byte[] Serialize()
{ {
@ -37,7 +37,7 @@ namespace LibTSforge.TokenStore
return writer.GetBytes(); return writer.GetBytes();
} }
public void Deserialize(byte[] data) private void Deserialize(byte[] data)
{ {
BinaryReader reader = new BinaryReader(new MemoryStream(data)); BinaryReader reader = new BinaryReader(new MemoryStream(data));
reader.ReadInt32(); reader.ReadInt32();

View File

@ -4,7 +4,7 @@ namespace LibTSforge.TokenStore
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using LibTSforge.Crypto; using Crypto;
public class TokenStoreModern : ITokenStore public class TokenStoreModern : ITokenStore
{ {
@ -18,29 +18,29 @@ namespace LibTSforge.TokenStore
private static readonly byte[] CONTS_FOOTER = Enumerable.Repeat((byte)0xAA, 0x20).ToArray(); private static readonly byte[] CONTS_FOOTER = Enumerable.Repeat((byte)0xAA, 0x20).ToArray();
private List<TokenEntry> Entries = new List<TokenEntry>(); private List<TokenEntry> Entries = new List<TokenEntry>();
public FileStream TokensFile; private readonly FileStream TokensFile;
public void Deserialize() public void Deserialize()
{ {
if (TokensFile.Length < BLOCK_SIZE) return; if (TokensFile.Length < BLOCK_SIZE) return;
TokensFile.Seek(0x24, SeekOrigin.Begin); TokensFile.Seek(0x24, SeekOrigin.Begin);
uint nextBlock = 0; uint nextBlock;
BinaryReader reader = new BinaryReader(TokensFile); BinaryReader reader = new BinaryReader(TokensFile);
do do
{ {
uint curOffset = reader.ReadUInt32(); reader.ReadUInt32();
nextBlock = reader.ReadUInt32(); nextBlock = reader.ReadUInt32();
for (int i = 0; i < ENTRIES_PER_BLOCK; i++) for (int i = 0; i < ENTRIES_PER_BLOCK; i++)
{ {
curOffset = reader.ReadUInt32(); uint curOffset = reader.ReadUInt32();
bool populated = reader.ReadUInt32() == 1; bool populated = reader.ReadUInt32() == 1;
uint contentOffset = reader.ReadUInt32(); uint contentOffset = reader.ReadUInt32();
uint contentLength = reader.ReadUInt32(); uint contentLength = reader.ReadUInt32();
uint allocLength = reader.ReadUInt32(); uint allocLength = reader.ReadUInt32();
byte[] contentData = new byte[] { }; byte[] contentData = { };
if (populated) if (populated)
{ {
@ -140,11 +140,10 @@ namespace LibTSforge.TokenStore
writer.WritePadding(BLOCK_PAD_SIZE); writer.WritePadding(BLOCK_PAD_SIZE);
writer.BaseStream.Seek(curBlockOffset, SeekOrigin.Begin); writer.BaseStream.Seek(curBlockOffset, SeekOrigin.Begin);
byte[] blockHash;
byte[] blockData = new byte[BLOCK_SIZE - 0x20]; byte[] blockData = new byte[BLOCK_SIZE - 0x20];
tokens.Read(blockData, 0, BLOCK_SIZE - 0x20); tokens.Read(blockData, 0, BLOCK_SIZE - 0x20);
blockHash = CryptoUtils.SHA256Hash(blockData); byte[] blockHash = CryptoUtils.SHA256Hash(blockData);
writer.BaseStream.Seek(curBlockOffset + BLOCK_SIZE - 0x20, SeekOrigin.Begin); writer.BaseStream.Seek(curBlockOffset + BLOCK_SIZE - 0x20, SeekOrigin.Begin);
writer.Write(blockHash); writer.Write(blockHash);
@ -275,11 +274,6 @@ namespace LibTSforge.TokenStore
Deserialize(); Deserialize();
} }
public TokenStoreModern()
{
}
public void Dispose() public void Dispose()
{ {
Serialize(); Serialize();

View File

@ -20,29 +20,31 @@ Included methods and tools:
- KMS Charger - Charge an existing KMS server to allow immediate use for activation - KMS Charger - Charge an existing KMS server to allow immediate use for activation
- Clear Tamper State - Clear the tamper state set due to store corruption or deletion - Clear Tamper State - Clear the tamper state set due to store corruption or deletion
- Remove Evaluation Key Lock - Remove the product key change lock set for evaluation product keys - Remove Evaluation Key Lock - Remove the product key change lock set for evaluation product keys
- Set IID Parameters - Set parameters for IID independently of installed key
## Usage ## Usage
``` ```
Usage: TSforge [/dump <filePath> (<encrFilePath>)] [/load <filePath>] [/kms4k] [/avma4k] [/zcid] [/rtmr] [/duid] [/igpk] [/kmsc] [/ctpr] [/revl] [/prod] [/test] [<activation id>] [/ver <version override>] Usage: TSforge [/dump <filePath> (<encrFilePath>)] [/load <filePath>] [/kms4k] [/avma4k] [/zcid] [/rtmr] [/duid] [/igpk] [/kmsc] [/ctpr] [/revl] [/siid <5/9> <group> <serial> <security>] [/prod] [/test] [<activation id>] [/ver <version override>]
Options: Options:
/dump <filePath> (<encrFilePath>) Dump and decrypt the physical store to the specified path. /dump <filePath> (<encrFilePath>) Dump and decrypt the physical store to the specified path.
/load <filePath> Load and re-encrypt the physical store from the specified path. /load <filePath> Load and re-encrypt the physical store from the specified path.
/kms4k Activate using KMS4k. Only supports KMS-activatable editions. /kms4k Activate using KMS4k. Only supports KMS-activatable editions.
/avma4k Activate using AVMA4k. Only supports Windows Server 2012 R2+. /avma4k Activate using AVMA4k. Only supports Windows Server 2012 R2+.
/zcid Activate using ZeroCID. Only supports phone-activatable editions. /zcid Activate using ZeroCID. Only supports phone-activatable editions.
/rtmr Reset grace/evaluation period timers. /rtmr Reset grace/evaluation period timers.
/rrmc Reset the rearm count. /rrmc Reset the rearm count.
/duid Delete product key Unique ID used in online key validation. /duid Delete product key Unique ID used in online key validation.
/igpk Install auto-generated/fake product key according to the specified Activation ID. /igpk Install auto-generated/fake product key according to the specified Activation ID
/kmsc Reset the charged count on the local KMS server to 25. Requires an activated KMS host. /kmsc Reset the charged count on the local KMS server to 25. Requires an activated KMS host.
/ctpr Clear the physical store tamper state. /ctpr Remove the tamper flags that get set in the physical store when sppsvc detects an attempt to tamper with it.
/revl Remove the key change lock in evaluation edition store. /revl Remove the key change lock in evaluation edition store.
/prod Use SPP production key. /siid <5/9> <group> <serial> <security> Set Installation ID parameters independently of installed key. 5/9 argument specifies PKEY200[5/9] key algorithm.
/test Use SPP test key. /prod Use SPP production key.
/ver <version> Override the detected version. Available versions: vista, 7, 8early, 8, blue, modern. /test Use SPP test key.
<activation id> A specific activation ID. Useful if you want to activate specific addons like ESU. /ver <version> Override the detected version. Available versions: vista, 7, 8, blue, modern.
/? Display this help message. <activation id> A specific activation ID. Useful if you want to activate specific addons like ESU.
/? Display this help message.
``` ```
## FAQ ## FAQ
@ -73,9 +75,27 @@ You can use the `/igpk` switch in TSforge in order to install licenses by only u
You can use the `/igpk` and `/zcid` options with the activation ID of the KMS Host SKU to be activated. You can then use the `/kmsc` option with this activation ID to charge the KMS server with 25 clients. Please note that KMS servers will maintain their client counts for a maximum of 30 days. You can use the `/igpk` and `/zcid` options with the activation ID of the KMS Host SKU to be activated. You can then use the `/kmsc` option with this activation ID to charge the KMS server with 25 clients. Please note that KMS servers will maintain their client counts for a maximum of 30 days.
### Why is Windows Vista not supported by any activation methods? ### What features are implemented in Windows Vista?
Windows Vista contains a driver which holds a permanent [handle](https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/object-handles) to the physical store, even when SLSvc is stopped after initial startup. This prevents TSforge from writing new trusted store data while the system is booted. There are theoretical workarounds to this issue, but they require an extraordinary amount of bug-prone, specialized code specific to Vista. For these reasons, we do not plan to support Vista/Server 2008. The following options are implemented:
- `/dump`
- `/load`
- `/zcid`
- `/kms4k`
- `/rtmr`
- `/rrmc`
- `/kmsc`
- `/ctpr`
The following options are NOT implemented:
- `/duid` - Key Unique ID is not removable from Vista physical store
- `/igpk` - Product key data is derived directly from the key string, preventing forgery
- `/siid` - IID is also derived directly from the key string
- `/revl` - Eval key lock is not present on Vista
Effectively, this means that a product key must be provided to activate a given SKU. Additionally, ZeroCID on Vista/Server 2008 lacks protection against deactivation due to the WGA update KB929391, though this update is no longer offered via Windows Update.
### How do I prevent de-activation due to WAT on Windows 7? ### How do I prevent de-activation due to WAT on Windows 7?
@ -85,6 +105,10 @@ If generic keys are installed, you need to run `TSforge.exe /duid` to remove the
Windows doesn't support AVMA activation under VM software that fails to provide [Hyper-V Enlightenments](https://www.qemu.org/docs/master/system/i386/hyperv.html). This primarily means that AVMA4k is only supported on VMs running under a [correctly configured QEMU instance](https://blog.wikichoon.com/2014/07/enabling-hyper-v-enlightenments-with-kvm.html) or Hyper-V. If your VM's activation status is `Notification` with the status code `0xC004FD01` after using AVMA4k, you will need to use another activation method. Windows doesn't support AVMA activation under VM software that fails to provide [Hyper-V Enlightenments](https://www.qemu.org/docs/master/system/i386/hyperv.html). This primarily means that AVMA4k is only supported on VMs running under a [correctly configured QEMU instance](https://blog.wikichoon.com/2014/07/enabling-hyper-v-enlightenments-with-kvm.html) or Hyper-V. If your VM's activation status is `Notification` with the status code `0xC004FD01` after using AVMA4k, you will need to use another activation method.
### Does TSforge support beta versions of Windows?
It can, though we do not provide official support for these versions. TSforge works on most insider/beta builds of Windows past Windows 8.1. Beta builds prior to build 9600 are likely to face issues, as the internal data formats used by SPP were constantly changing during this period of development. Builds with similar licensing behavior to retail versions are the most likely to work with the current TSforge codebase. For other builds, you may need to manually edit the source code of LibTSforge to get it to work.
### How do I remove this activation? ### How do I remove this activation?
Run [Microsoft Activation Scripts](https://massgrave.dev), select `Troubleshoot` > `Fix Licensing`. This will reset the physical store and revert any changes made by TSforge. Run [Microsoft Activation Scripts](https://massgrave.dev), select `Troubleshoot` > `Fix Licensing`. This will reset the physical store and revert any changes made by TSforge.
@ -116,7 +140,7 @@ Probably not. If they do, please tell us so we can laugh to ourselves like a bun
### Other Contributions ### Other Contributions
- SpCreatePackaedLicense - Tool development, testing - Emma (IPG) - Vista SPSys IOCTLs and physical store format
- May - Code formatting, build setup - May - Code formatting, build setup
### Special Thanks ### Special Thanks

View File

@ -4,36 +4,44 @@ namespace TSforgeCLI
using LibTSforge; using LibTSforge;
using LibTSforge.Activators; using LibTSforge.Activators;
using LibTSforge.Modifiers; using LibTSforge.Modifiers;
using LibTSforge.SPP;
public class Program public class Program
{ {
private class Options private class Options
{ {
public bool Dump = false; public bool Dump;
public string DumpFilePath = "dump.dat"; public string DumpFilePath = "dump.dat";
public string EncrFilePath = null; public string EncrFilePath;
public bool Load = false; public bool Load;
public string LoadFilePath = "load.dat"; public string LoadFilePath = "load.dat";
public bool KMS4k = false; public bool KMS4k;
public bool AVMA4k = false; public bool AVMA4k;
public bool ZCID = false; public bool ZCID;
public bool TimerReset = false; public bool TimerReset;
public bool RearmReset = false; public bool RearmReset;
public bool DeleteUniqueId = false; public bool DeleteUniqueId;
public bool InstallGenPKey = false; public bool InstallGenPKey;
public bool KMSHostCharge = false; public bool KMSHostCharge;
public bool TamperedFlagsDelete = false; public bool TamperedFlagsDelete;
public bool KeyChangeLockDelete = false; public bool KeyChangeLockDelete;
public bool? Production = null; public bool SetIIDParams;
public PSVersion? Version = null; public bool? Production;
public PSVersion? Version;
public Guid ActivationId = Guid.Empty; public Guid ActivationId = Guid.Empty;
public bool ShowHelp = false; public bool ShowHelp;
public PKeyAlgorithm? Algorithm;
public int Group;
public int Serial;
public ulong Security;
} }
public static void Main(string[] args) public static void Main(string[] args)
{ {
Logger.WriteLine("TSforge (c) MASSGRAVE 2025"); Logger.WriteLine("TSforge (c) MASSGRAVE 2025");
Utils.Wow64EnableWow64FsRedirection(false);
try try
{ {
if (args.Length == 0) if (args.Length == 0)
@ -51,15 +59,15 @@ namespace TSforgeCLI
} }
PSVersion version = options.Version ?? Utils.DetectVersion(); PSVersion version = options.Version ?? Utils.DetectVersion();
bool production = options.Production ?? Utils.DetectCurrentKey(); bool production = options.Production ?? SPPUtils.DetectCurrentKey();
if (options.Dump) if (options.Dump)
{ {
Utils.DumpStore(version, production, options.DumpFilePath, options.EncrFilePath); SPPUtils.DumpStore(version, production, options.DumpFilePath, options.EncrFilePath);
} }
else if (options.Load) else if (options.Load)
{ {
Utils.LoadStore(version, production, options.LoadFilePath); SPPUtils.LoadStore(version, production, options.LoadFilePath);
} }
else if (options.KMS4k) else if (options.KMS4k)
{ {
@ -91,7 +99,7 @@ namespace TSforgeCLI
} }
else if (options.KMSHostCharge) else if (options.KMSHostCharge)
{ {
KMSHostCharge.Charge(version, options.ActivationId, production); KMSHostCharge.Charge(version, production, options.ActivationId);
} }
else if (options.TamperedFlagsDelete) else if (options.TamperedFlagsDelete)
{ {
@ -101,6 +109,10 @@ namespace TSforgeCLI
{ {
KeyChangeLockDelete.Delete(version, production); KeyChangeLockDelete.Delete(version, production);
} }
else if (options.SetIIDParams)
{
SetIIDParams.SetParams(version, production, options.ActivationId, options.Algorithm.Value, options.Group, options.Serial, options.Security);
}
else else
{ {
DisplayUsage(); DisplayUsage();
@ -184,6 +196,38 @@ namespace TSforgeCLI
break; break;
case "/revl": case "/revl":
options.KeyChangeLockDelete = true; options.KeyChangeLockDelete = true;
break;
case "/siid":
options.SetIIDParams = true;
if (args.Length - i - 1 < 4) throw new ArgumentException("Not enough arguments specified.");
string algoType = args[++i];
if (algoType == "5")
{
options.Algorithm = PKeyAlgorithm.PKEY2005;
}
else if (algoType == "9")
{
options.Algorithm = PKeyAlgorithm.PKEY2009;
}
else
{
throw new ArgumentException("Invalid key algorithm specified.");
}
try
{
options.Group = int.Parse(args[++i]);
options.Serial = int.Parse(args[++i]);
options.Security = ulong.Parse(args[++i]);
}
catch
{
throw new ArgumentException("Failed to parse key parameters.");
}
break; break;
default: default:
try try
@ -194,7 +238,6 @@ namespace TSforgeCLI
{ {
Logger.WriteLine("Argument doesn't exist or the specified activation ID is invalid."); Logger.WriteLine("Argument doesn't exist or the specified activation ID is invalid.");
options.ShowHelp = true; options.ShowHelp = true;
break;
} }
break; break;
} }
@ -206,25 +249,26 @@ namespace TSforgeCLI
private static void DisplayUsage() private static void DisplayUsage()
{ {
string exeName = typeof(Program).Namespace; string exeName = typeof(Program).Namespace;
Logger.WriteLine("Usage: " + exeName + " [/dump <filePath> (<encrFilePath>)] [/load <filePath>] [/kms4k] [/avma4k] [/zcid] [/rtmr] [/duid] [/igpk] [/kmsc] [/ctpr] [/revl] [/prod] [/test] [<activation id>] [/ver <version override>]"); Logger.WriteLine("Usage: " + exeName + " [/dump <filePath> (<encrFilePath>)] [/load <filePath>] [/kms4k] [/avma4k] [/zcid] [/rtmr] [/duid] [/igpk] [/kmsc] [/ctpr] [/revl] [/siid <5/9> <group> <serial> <security>] [/prod] [/test] [<activation id>] [/ver <version override>]");
Logger.WriteLine("Options:"); Logger.WriteLine("Options:");
Logger.WriteLine("\t/dump <filePath> (<encrFilePath>) Dump and decrypt the physical store to the specified path."); Logger.WriteLine("\t/dump <filePath> (<encrFilePath>) Dump and decrypt the physical store to the specified path.");
Logger.WriteLine("\t/load <filePath> Load and re-encrypt the physical store from the specified path."); Logger.WriteLine("\t/load <filePath> Load and re-encrypt the physical store from the specified path.");
Logger.WriteLine("\t/kms4k Activate using KMS4k. Only supports KMS-activatable editions."); Logger.WriteLine("\t/kms4k Activate using KMS4k. Only supports KMS-activatable editions.");
Logger.WriteLine("\t/avma4k Activate using AVMA4k. Only supports Windows Server 2012 R2+."); Logger.WriteLine("\t/avma4k Activate using AVMA4k. Only supports Windows Server 2012 R2+.");
Logger.WriteLine("\t/zcid Activate using ZeroCID. Only supports phone-activatable editions."); Logger.WriteLine("\t/zcid Activate using ZeroCID. Only supports phone-activatable editions.");
Logger.WriteLine("\t/rtmr Reset grace/evaluation period timers."); Logger.WriteLine("\t/rtmr Reset grace/evaluation period timers.");
Logger.WriteLine("\t/rrmc Reset the rearm count."); Logger.WriteLine("\t/rrmc Reset the rearm count.");
Logger.WriteLine("\t/duid Delete product key Unique ID used in online key validation."); Logger.WriteLine("\t/duid Delete product key Unique ID used in online key validation.");
Logger.WriteLine("\t/igpk Install auto-generated/fake product key according to the specified Activation ID"); Logger.WriteLine("\t/igpk Install auto-generated/fake product key according to the specified Activation ID");
Logger.WriteLine("\t/kmsc Reset the charged count on the local KMS server to 25. Requires an activated KMS host."); Logger.WriteLine("\t/kmsc Reset the charged count on the local KMS server to 25. Requires an activated KMS host.");
Logger.WriteLine("\t/ctpr Remove the tamper flags that get set in the physical store when sppsvc detects an attempt to tamper with it."); Logger.WriteLine("\t/ctpr Remove the tamper flags that get set in the physical store when sppsvc detects an attempt to tamper with it.");
Logger.WriteLine("\t/revl Remove the key change lock in evaluation edition store."); Logger.WriteLine("\t/revl Remove the key change lock in evaluation edition store.");
Logger.WriteLine("\t/prod Use SPP production key."); Logger.WriteLine("\t/siid <5/9> <group> <serial> <security> Set Installation ID parameters independently of installed key. 5/9 argument specifies PKEY200[5/9] key algorithm.");
Logger.WriteLine("\t/test Use SPP test key."); Logger.WriteLine("\t/prod Use SPP production key.");
Logger.WriteLine("\t/ver <version> Override the detected version. Available versions: vista, 7, 8early, 8, blue, modern."); Logger.WriteLine("\t/test Use SPP test key.");
Logger.WriteLine("\t<activation id> A specific activation ID. Useful if you want to activate specific addons like ESU."); Logger.WriteLine("\t/ver <version> Override the detected version. Available versions: vista, 7, 8, blue, modern.");
Logger.WriteLine("\t/? Display this help message."); Logger.WriteLine("\t<activation id> A specific activation ID. Useful if you want to activate specific addons like ESU.");
Logger.WriteLine("\t/? Display this help message.");
} }
private static PSVersion ParseVersion(string ver) private static PSVersion ParseVersion(string ver)
@ -233,7 +277,6 @@ namespace TSforgeCLI
{ {
case "vista": return PSVersion.Vista; case "vista": return PSVersion.Vista;
case "7": return PSVersion.Win7; case "7": return PSVersion.Win7;
case "8early": return PSVersion.Win8Early;
case "8": return PSVersion.Win8; case "8": return PSVersion.Win8;
case "blue": return PSVersion.WinBlue; case "blue": return PSVersion.WinBlue;
case "modern": return PSVersion.WinModern; case "modern": return PSVersion.WinModern;