From 372eb73a02260cf4bc6fd424bcc6216fa8a15be2 Mon Sep 17 00:00:00 2001 From: WindowsAddict Date: Thu, 17 Apr 2025 01:47:13 +0530 Subject: [PATCH] Add updated TSforge code --- MAS/All-In-One-Version-KL/MAS_AIO.cmd | 4165 ++++++++++------- .../Activators/TSforge_Activation.cmd | 4165 ++++++++++------- 2 files changed, 5056 insertions(+), 3274 deletions(-) diff --git a/MAS/All-In-One-Version-KL/MAS_AIO.cmd b/MAS/All-In-One-Version-KL/MAS_AIO.cmd index cce246a..f180db7 100644 --- a/MAS/All-In-One-Version-KL/MAS_AIO.cmd +++ b/MAS/All-In-One-Version-KL/MAS_AIO.cmd @@ -4951,23 +4951,16 @@ $src = @' // Common.cs namespace LibTSforge { - using Microsoft.Win32; using System; using System.IO; using System.Linq; using System.Runtime.InteropServices; - using System.ServiceProcess; using System.Text; - using LibTSforge.Crypto; - using LibTSforge.PhysicalStore; - using LibTSforge.SPP; - using LibTSforge.TokenStore; public enum PSVersion { Vista, Win7, - Win8Early, Win8, WinBlue, WinModern @@ -5038,8 +5031,8 @@ namespace LibTSforge 0x92, 0xA6, 0x56, 0x96 }; - // 2^31 - 1 minutes - public static ulong TimerMax = (ulong)TimeSpan.FromMinutes(2147483647).Ticks; + // 2^31 - 8 minutes + public static readonly ulong TimerMax = (ulong)TimeSpan.FromMinutes(2147483640).Ticks; public static readonly string ZeroCID = new string('0', 48); } @@ -5107,20 +5100,6 @@ namespace LibTSforge } return result; } - - public static T CastToStruct(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 @@ -5141,6 +5120,12 @@ namespace LibTSforge 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) { return Encoding.Unicode.GetString(data).Trim('\0'); @@ -5151,9 +5136,6 @@ namespace LibTSforge return Encoding.Unicode.GetBytes(str + '\0'); } - [DllImport("kernel32.dll")] - public static extern uint GetSystemDefaultLCID(); - public static uint CRC32(byte[] data) { const uint polynomial = 0x04C11DB7; @@ -5177,157 +5159,6 @@ namespace LibTSforge 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() { string arch = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE", EnvironmentVariableTarget.Machine).ToUpperInvariant(); @@ -5343,65 +5174,7 @@ namespace LibTSforge if (build >= 7600 && build <= 7602) return PSVersion.Win7; if (build == 9200) return PSVersion.Win8; - throw new NotSupportedException("Unable to auto-detect version info, please specify one manually using the /ver argument."); - } - - 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."); + throw new NotSupportedException("Unable to auto-detect version info"); } } @@ -5494,8 +5267,8 @@ namespace LibTSforge.SPP public class PKeyConfig { - public Dictionary Products = new Dictionary(); - private List loadedPkeyConfigs = new List(); + public readonly Dictionary Products = new Dictionary(); + private readonly List loadedPkeyConfigs = new List(); public void LoadConfig(Guid actId) { @@ -5556,12 +5329,14 @@ namespace LibTSforge.SPP ranges[refActIdStr] = new List(); } - KeyRange keyRange = new KeyRange(); - keyRange.Start = int.Parse(rangeNode.SelectSingleNode("./p:Start", nsmgr).InnerText); - keyRange.End = int.Parse(rangeNode.SelectSingleNode("./p:End", nsmgr).InnerText); - keyRange.EulaType = rangeNode.SelectSingleNode("./p:EulaType", nsmgr).InnerText; - keyRange.PartNumber = rangeNode.SelectSingleNode("./p:PartNumber", nsmgr).InnerText; - keyRange.Valid = rangeNode.SelectSingleNode("./p:IsValid", nsmgr).InnerText.ToLower() == "true"; + KeyRange keyRange = new KeyRange + { + Start = int.Parse(rangeNode.SelectSingleNode("./p:Start", nsmgr).InnerText), + End = int.Parse(rangeNode.SelectSingleNode("./p:End", nsmgr).InnerText), + EulaType = rangeNode.SelectSingleNode("./p:EulaType", nsmgr).InnerText, + PartNumber = rangeNode.SelectSingleNode("./p:PartNumber", nsmgr).InnerText, + Valid = rangeNode.SelectSingleNode("./p:IsValid", nsmgr).InnerText.ToLower() == "true" + }; ranges[refActIdStr].Add(keyRange); } @@ -5575,15 +5350,17 @@ namespace LibTSforge.SPP if (keyRanges.Count > 0 && !Products.ContainsKey(refActId)) { - ProductConfig productConfig = new ProductConfig(); - productConfig.GroupId = group; - productConfig.Edition = configNode.SelectSingleNode("./p:EditionId", nsmgr).InnerText; - productConfig.Description = configNode.SelectSingleNode("./p:ProductDescription", nsmgr).InnerText; - productConfig.Channel = configNode.SelectSingleNode("./p:ProductKeyType", nsmgr).InnerText; - productConfig.Randomized = configNode.SelectSingleNode("./p:ProductKeyType", nsmgr).InnerText.ToLower() == "true"; - productConfig.Algorithm = algorithms[group]; - productConfig.Ranges = keyRanges; - productConfig.ActivationId = refActId; + ProductConfig productConfig = new ProductConfig + { + GroupId = group, + Edition = configNode.SelectSingleNode("./p:EditionId", nsmgr).InnerText, + Description = configNode.SelectSingleNode("./p:ProductDescription", nsmgr).InnerText, + Channel = configNode.SelectSingleNode("./p:ProductKeyType", nsmgr).InnerText, + Randomized = configNode.SelectSingleNode("./p:ProductKeyType", nsmgr).InnerText.ToLower() == "true", + Algorithm = algorithms[group], + Ranges = keyRanges, + ActivationId = refActId + }; Products[refActId] = productConfig; } @@ -5626,11 +5403,6 @@ namespace LibTSforge.SPP } } } - - public PKeyConfig() - { - - } } } @@ -5641,8 +5413,8 @@ namespace LibTSforge.SPP using System; using System.IO; using System.Linq; - using LibTSforge.Crypto; - using LibTSforge.PhysicalStore; + using Crypto; + using PhysicalStore; public class ProductKey { @@ -5656,11 +5428,11 @@ namespace LibTSforge.SPP public ulong Security; public bool Upgrade; public PKeyAlgorithm Algorithm; - public string EulaType; - public string PartNumber; - public string Edition; - public string Channel; - public Guid ActivationId; + public readonly string EulaType; + public readonly string PartNumber; + public readonly string Edition; + public readonly string Channel; + public readonly Guid ActivationId; private string mpc; private string pid2; @@ -5670,6 +5442,11 @@ namespace LibTSforge.SPP get { return BitConverter.GetBytes(klow).Concat(BitConverter.GetBytes(khigh)).ToArray(); } } + public ProductKey() + { + + } + public ProductKey(int serial, ulong security, bool upgrade, PKeyAlgorithm algorithm, ProductConfig config, KeyRange range) { Group = config.GroupId; @@ -5698,22 +5475,22 @@ namespace LibTSforge.SPP public Guid GetPkeyId() { - VariableBag pkb = new VariableBag(); - pkb.Blocks.AddRange(new CRCBlock[] + VariableBag pkb = new VariableBag(PSVersion.WinModern); + pkb.Blocks.AddRange(new[] { - new CRCBlock + new CRCBlockModern { DataType = CRCBlockType.STRING, KeyAsStr = "SppPkeyBindingProductKey", ValueAsStr = ToString() }, - new CRCBlock + new CRCBlockModern { DataType = CRCBlockType.BINARY, KeyAsStr = "SppPkeyBindingMiscData", Value = new byte[] { } }, - new CRCBlock + new CRCBlockModern { DataType = CRCBlockType.STRING, KeyAsStr = "SppPkeyBindingAlgorithm", @@ -5724,16 +5501,6 @@ namespace LibTSforge.SPP return new Guid(CryptoUtils.SHA256Hash(pkb.Serialize()).Take(16).ToArray()); } - public string GetDefaultMPC() - { - int build = Environment.OSVersion.Version.Build; - string defaultMPC = build >= 10240 ? "03612" : - build >= 9600 ? "06401" : - build >= 9200 ? "05426" : - "55041"; - return defaultMPC; - } - public string GetMPC() { if (mpc != null) @@ -5741,10 +5508,15 @@ namespace LibTSforge.SPP return mpc; } - mpc = GetDefaultMPC(); + int build = Environment.OSVersion.Version.Build; + + mpc = build >= 10240 ? "03612" : + build >= 9600 ? "06401" : + build >= 9200 ? "05426" : + "55041"; // setup.cfg doesn't exist in Windows 8+ - string setupcfg = string.Format("{0}\\oobe\\{1}", Environment.SystemDirectory, "setup.cfg"); + string setupcfg = string.Format(@"{0}\oobe\{1}", Environment.SystemDirectory, "setup.cfg"); if (!File.Exists(setupcfg) || Edition.Contains(";")) { @@ -5882,17 +5654,17 @@ namespace LibTSforge.SPP { if (version == PSVersion.Win7) { - Random rnd = new Random(Group * 1000000000 + Serial); - byte[] data = new byte[8]; - rnd.NextBytes(data); - return data; + ulong shortauth = ((ulong)Group << 41) | (Security << 31) | ((ulong)Serial << 1) | (Upgrade ? (ulong)1 : 0); + return BitConverter.GetBytes(shortauth); } int serialHigh = Serial / 1000000; int serialLow = Serial % 1000000; BinaryWriter writer = new BinaryWriter(new MemoryStream()); - writer.Write(new Guid("B8731595-A2F6-430B-A799-FBFFB81A8D73").ToByteArray()); + string algoId = Algorithm == PKeyAlgorithm.PKEY2005 ? "B8731595-A2F6-430B-A799-FBFFB81A8D73" : "660672EF-7809-4CFD-8D54-41B7FB738988"; + + writer.Write(new Guid(algoId).ToByteArray()); writer.Write(Group); writer.Write(serialHigh); writer.Write(serialLow); @@ -5998,40 +5770,40 @@ namespace LibTSforge.SPP public static readonly Guid WINDOWS_APP_ID = new Guid("55c92734-d682-4d71-983e-d6ec3f16059f"); - [DllImport("sppc.dll", CharSet = CharSet.Unicode, PreserveSig = false)] + [DllImport("slc.dll", CharSet = CharSet.Unicode, PreserveSig = false)] private static extern void SLOpen(out IntPtr hSLC); - [DllImport("sppc.dll", CharSet = CharSet.Unicode, PreserveSig = false)] + [DllImport("slc.dll", CharSet = CharSet.Unicode, PreserveSig = false)] private static extern void SLClose(IntPtr hSLC); [DllImport("slc.dll", CharSet = CharSet.Unicode)] private static extern uint SLGetWindowsInformationDWORD(string ValueName, ref int Value); - [DllImport("sppc.dll", CharSet = CharSet.Unicode)] + [DllImport("slc.dll", CharSet = CharSet.Unicode)] private static extern uint SLInstallProofOfPurchase(IntPtr hSLC, string pwszPKeyAlgorithm, string pwszPKeyString, uint cbPKeySpecificData, byte[] pbPKeySpecificData, ref Guid PKeyId); - [DllImport("sppc.dll", CharSet = CharSet.Unicode)] + [DllImport("slc.dll", CharSet = CharSet.Unicode)] private static extern uint SLUninstallProofOfPurchase(IntPtr hSLC, ref Guid PKeyId); - [DllImport("sppc.dll", CharSet = CharSet.Unicode)] + [DllImport("slc.dll", CharSet = CharSet.Unicode)] private static extern uint SLGetPKeyInformation(IntPtr hSLC, ref Guid pPKeyId, string pwszValueName, out SLDATATYPE peDataType, out uint pcbValue, out IntPtr ppbValue); - [DllImport("sppcext.dll", CharSet = CharSet.Unicode)] + [DllImport("slcext.dll", CharSet = CharSet.Unicode)] private static extern uint SLActivateProduct(IntPtr hSLC, ref Guid pProductSkuId, byte[] cbAppSpecificData, byte[] pvAppSpecificData, byte[] pActivationInfo, string pwszProxyServer, ushort wProxyPort); - [DllImport("sppc.dll", CharSet = CharSet.Unicode)] + [DllImport("slc.dll", CharSet = CharSet.Unicode)] private static extern uint SLGenerateOfflineInstallationId(IntPtr hSLC, ref Guid pProductSkuId, ref string ppwszInstallationId); - [DllImport("sppc.dll", CharSet = CharSet.Unicode)] + [DllImport("slc.dll", CharSet = CharSet.Unicode)] private static extern uint SLDepositOfflineConfirmationId(IntPtr hSLC, ref Guid pProductSkuId, string pwszInstallationId, string pwszConfirmationId); - [DllImport("sppc.dll", CharSet = CharSet.Unicode)] + [DllImport("slc.dll", CharSet = CharSet.Unicode)] private static extern uint SLGetSLIDList(IntPtr hSLC, SLIDTYPE eQueryIdType, ref Guid pQueryId, SLIDTYPE eReturnIdType, out uint pnReturnIds, out IntPtr ppReturnIds); - [DllImport("sppc.dll", CharSet = CharSet.Unicode, PreserveSig = false)] + [DllImport("slc.dll", CharSet = CharSet.Unicode, PreserveSig = false)] private static extern void SLGetLicensingStatusInformation(IntPtr hSLC, ref Guid pAppID, IntPtr pProductSkuId, string pwszRightName, out uint pnStatusCount, out IntPtr ppLicensingStatus); - [DllImport("sppc.dll", CharSet = CharSet.Unicode)] + [DllImport("slc.dll", CharSet = CharSet.Unicode)] private static extern uint SLGetInstalledProductKeyIds(IntPtr hSLC, ref Guid pProductSkuId, out uint pnProductKeyIds, out IntPtr ppProductKeyIds); [DllImport("slc.dll", CharSet = CharSet.Unicode)] @@ -6040,9 +5812,6 @@ namespace LibTSforge.SPP [DllImport("slc.dll", CharSet = CharSet.Unicode)] private static extern uint SLGetProductSkuInformation(IntPtr hSLC, ref Guid pProductSkuId, string pwszValueName, out SLDATATYPE peDataType, out uint pcbValue, out IntPtr ppbValue); - [DllImport("slc.dll", CharSet = CharSet.Unicode)] - private static extern uint SLGetProductSkuInformation(IntPtr hSLC, ref Guid pProductSkuId, string pwszValueName, IntPtr peDataType, out uint pcbValue, out IntPtr ppbValue); - [DllImport("slc.dll", CharSet = CharSet.Unicode)] private static extern uint SLGetLicense(IntPtr hSLC, ref Guid pLicenseFileId, out uint pcbLicenseFile, out IntPtr ppbLicenseFile); @@ -6052,7 +5821,7 @@ namespace LibTSforge.SPP [DllImport("slc.dll", CharSet = CharSet.Unicode)] private static extern uint SLFireEvent(IntPtr hSLC, string pwszEventId, ref Guid pApplicationId); - public class SLContext : IDisposable + private class SLContext : IDisposable { public readonly IntPtr Handle; @@ -6115,11 +5884,10 @@ namespace LibTSforge.SPP { using (SLContext sl = new SLContext()) { - uint status; uint count; IntPtr pProductKeyIds; - status = SLGetInstalledProductKeyIds(sl.Handle, ref actId, out count, out pProductKeyIds); + uint status = SLGetSLIDList(sl.Handle, SLIDTYPE.SL_ID_PRODUCT_SKU, ref actId, SLIDTYPE.SL_ID_PKEY, out count, out pProductKeyIds); if (status != 0 || count == 0) { @@ -6143,7 +5911,7 @@ namespace LibTSforge.SPP SLConsumeWindowsRight(0); } - public static bool RefreshTrustedTime(Guid actId) + public static void RefreshTrustedTime(Guid actId) { using (SLContext sl = new SLContext()) { @@ -6151,8 +5919,7 @@ namespace LibTSforge.SPP uint count; IntPtr ppbValue; - uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "TrustedTime", out type, out count, out ppbValue); - return (int)status >= 0 && status != 0xC004F012; + SLGetProductSkuInformation(sl.Handle, ref actId, "TrustedTime", out type, out count, out ppbValue); } } @@ -6168,11 +5935,10 @@ namespace LibTSforge.SPP { using (SLContext sl = new SLContext()) { - uint status; uint count; IntPtr pAppIds; - status = SLGetSLIDList(sl.Handle, SLIDTYPE.SL_ID_PRODUCT_SKU, ref actId, SLIDTYPE.SL_ID_APPLICATION, out count, out pAppIds); + uint status = SLGetSLIDList(sl.Handle, SLIDTYPE.SL_ID_PRODUCT_SKU, ref actId, SLIDTYPE.SL_ID_APPLICATION, out count, out pAppIds); if (status != 0 || count == 0) { @@ -6200,11 +5966,10 @@ namespace LibTSforge.SPP { using (SLContext sl = new SLContext()) { - uint status; uint count; IntPtr ppReturnLics; - status = SLGetSLIDList(sl.Handle, SLIDTYPE.SL_ID_LICENSE, ref licId, SLIDTYPE.SL_ID_LICENSE_FILE, out count, out ppReturnLics); + uint status = SLGetSLIDList(sl.Handle, SLIDTYPE.SL_ID_LICENSE, ref licId, SLIDTYPE.SL_ID_LICENSE_FILE, out count, out ppReturnLics); if (status != 0 || count == 0) { @@ -6266,7 +6031,7 @@ namespace LibTSforge.SPP IntPtr ppbValue; uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "msft:sl/EUL/PHONE/PUBLIC", out type, out count, out ppbValue); - return status >= 0 && status != 0xC004F012; + return status != 0xC004F012; } } @@ -6349,11 +6114,11 @@ namespace LibTSforge.SPP } } - public static uint UninstallProductKey(Guid pkeyId) + public static void UninstallProductKey(Guid pkeyId) { using (SLContext sl = new SLContext()) { - return SLUninstallProofOfPurchase(sl.Handle, ref pkeyId); + SLUninstallProofOfPurchase(sl.Handle, ref pkeyId); } } @@ -6371,1509 +6136,2624 @@ namespace LibTSforge.SPP } -// Crypto/CryptoUtils.cs -namespace LibTSforge.Crypto +// SPP/SPPUtils.cs +namespace LibTSforge.SPP { + using Microsoft.Win32; using System; + using System.IO; using System.Linq; - using System.Security.Cryptography; + using System.ServiceProcess; + using Crypto; + using PhysicalStore; + using TokenStore; - public static class CryptoUtils + public static class SPPUtils { - public static byte[] GenerateRandomKey(int len) + public static void KillSPP(PSVersion version) { - byte[] rand = new byte[len]; - Random r = new Random(); - r.NextBytes(rand); + ServiceController sc; - return rand; - } + string svcName = version == PSVersion.Vista ? "slsvc" : "sppsvc"; - public static byte[] AESEncrypt(byte[] data, byte[] key) - { - using (Aes aes = Aes.Create()) + try { - aes.Key = key; - aes.Mode = CipherMode.CBC; - aes.Padding = PaddingMode.PKCS7; + sc = new ServiceController(svcName); - ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, Enumerable.Repeat((byte)0, 16).ToArray()); - byte[] encryptedData = encryptor.TransformFinalBlock(data, 0, data.Length); - return encryptedData; + if (sc.Status == ServiceControllerStatus.Stopped) + return; } - } - - public static byte[] AESDecrypt(byte[] data, byte[] key) - { - using (Aes aes = Aes.Create()) + catch (InvalidOperationException ex) { - aes.Key = key; - aes.Mode = CipherMode.CBC; - aes.Padding = PaddingMode.PKCS7; - - ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, Enumerable.Repeat((byte)0, 16).ToArray()); - byte[] decryptedData = decryptor.TransformFinalBlock(data, 0, data.Length); - return decryptedData; + throw new InvalidOperationException(string.Format("Unable to access {0}: ", svcName) + ex.Message); } - } - public static byte[] RSADecrypt(byte[] rsaKey, byte[] data) - { + Logger.WriteLine(string.Format("Stopping {0}...", svcName)); - using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) - { - rsa.ImportCspBlob(rsaKey); - return rsa.Decrypt(data, false); - } - } + bool stopped = false; - public static byte[] RSAEncrypt(byte[] rsaKey, byte[] data) - { - using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) + for (int i = 0; stopped == false && i < 1080; i++) { - rsa.ImportCspBlob(rsaKey); - return rsa.Encrypt(data, false); + 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; } - } - public static byte[] RSASign(byte[] rsaKey, byte[] data) - { - using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) + 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()) { - rsa.ImportCspBlob(rsaKey); - RSAPKCS1SignatureFormatter formatter = new RSAPKCS1SignatureFormatter(rsa); - formatter.SetHashAlgorithm("SHA1"); + Logger.WriteLine("Unloading spsys..."); - byte[] hash; - using (SHA1 sha1 = SHA1.Create()) + int status = SPSys.ControlSpSys(false); + + if (status < 0) { - hash = sha1.ComputeHash(data); + throw new IOException("Failed to unload spsys"); } - return formatter.CreateSignature(hash); + Logger.WriteLine("spsys unloaded successfully."); } } - public static bool RSAVerifySignature(byte[] rsaKey, byte[] data, byte[] signature) + public static void RestartSPP(PSVersion version) { - using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) + if (version == PSVersion.Vista) { - rsa.ImportCspBlob(rsaKey); - RSAPKCS1SignatureDeformatter deformatter = new RSAPKCS1SignatureDeformatter(rsa); - deformatter.SetHashAlgorithm("SHA1"); + ServiceController sc; - byte[] hash; - using (SHA1 sha1 = SHA1.Create()) + try { - hash = sha1.ComputeHash(data); - } + sc = new ServiceController("slsvc"); - return deformatter.VerifySignature(hash, signature); - } - } + if (sc.Status == ServiceControllerStatus.Running) + return; + } + catch (InvalidOperationException ex) + { + throw new InvalidOperationException("Unable to access slsvc: " + ex.Message); + } - public static byte[] HMACSign(byte[] key, byte[] data) - { - HMACSHA1 hmac = new HMACSHA1(key); - return hmac.ComputeHash(data); - } + Logger.WriteLine("Starting slsvc..."); - public static bool HMACVerify(byte[] key, byte[] data, byte[] signature) - { - HMACSHA1 hmac = new HMACSHA1(key); - return Enumerable.SequenceEqual(signature, HMACSign(key, data)); - } + bool started = false; - public static byte[] SHA256Hash(byte[] data) - { - using (SHA256 sha256 = SHA256.Create()) - { - return sha256.ComputeHash(data); - } - } - } -} + 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; + } -// Crypto/Keys.cs -namespace LibTSforge.Crypto -{ - public static class Keys - { - public static readonly byte[] PRODUCTION = { - 0x07, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32, 0x00, 0x04, 0x00, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x29, 0x87, 0xBA, 0x3F, 0x52, 0x90, 0x57, 0xD8, 0x12, 0x26, 0x6B, 0x38, - 0xB2, 0x3B, 0xF9, 0x67, 0x08, 0x4F, 0xDD, 0x8B, 0xF5, 0xE3, 0x11, 0xB8, 0x61, 0x3A, 0x33, 0x42, - 0x51, 0x65, 0x05, 0x86, 0x1E, 0x00, 0x41, 0xDE, 0xC5, 0xDD, 0x44, 0x60, 0x56, 0x3D, 0x14, 0x39, - 0xB7, 0x43, 0x65, 0xE9, 0xF7, 0x2B, 0xA5, 0xF0, 0xA3, 0x65, 0x68, 0xE9, 0xE4, 0x8B, 0x5C, 0x03, - 0x2D, 0x36, 0xFE, 0x28, 0x4C, 0xD1, 0x3C, 0x3D, 0xC1, 0x90, 0x75, 0xF9, 0x6E, 0x02, 0xE0, 0x58, - 0x97, 0x6A, 0xCA, 0x80, 0x02, 0x42, 0x3F, 0x6C, 0x15, 0x85, 0x4D, 0x83, 0x23, 0x6A, 0x95, 0x9E, - 0x38, 0x52, 0x59, 0x38, 0x6A, 0x99, 0xF0, 0xB5, 0xCD, 0x53, 0x7E, 0x08, 0x7C, 0xB5, 0x51, 0xD3, - 0x8F, 0xA3, 0x0D, 0xA0, 0xFA, 0x8D, 0x87, 0x3C, 0xFC, 0x59, 0x21, 0xD8, 0x2E, 0xD9, 0x97, 0x8B, - 0x40, 0x60, 0xB1, 0xD7, 0x2B, 0x0A, 0x6E, 0x60, 0xB5, 0x50, 0xCC, 0x3C, 0xB1, 0x57, 0xE4, 0xB7, - 0xDC, 0x5A, 0x4D, 0xE1, 0x5C, 0xE0, 0x94, 0x4C, 0x5E, 0x28, 0xFF, 0xFA, 0x80, 0x6A, 0x13, 0x53, - 0x52, 0xDB, 0xF3, 0x04, 0x92, 0x43, 0x38, 0xB9, 0x1B, 0xD9, 0x85, 0x54, 0x7B, 0x14, 0xC7, 0x89, - 0x16, 0x8A, 0x4B, 0x82, 0xA1, 0x08, 0x02, 0x99, 0x23, 0x48, 0xDD, 0x75, 0x9C, 0xC8, 0xC1, 0xCE, - 0xB0, 0xD7, 0x1B, 0xD8, 0xFB, 0x2D, 0xA7, 0x2E, 0x47, 0xA7, 0x18, 0x4B, 0xF6, 0x29, 0x69, 0x44, - 0x30, 0x33, 0xBA, 0xA7, 0x1F, 0xCE, 0x96, 0x9E, 0x40, 0xE1, 0x43, 0xF0, 0xE0, 0x0D, 0x0A, 0x32, - 0xB4, 0xEE, 0xA1, 0xC3, 0x5E, 0x9B, 0xC7, 0x7F, 0xF5, 0x9D, 0xD8, 0xF2, 0x0F, 0xD9, 0x8F, 0xAD, - 0x75, 0x0A, 0x00, 0xD5, 0x25, 0x43, 0xF7, 0xAE, 0x51, 0x7F, 0xB7, 0xDE, 0xB7, 0xAD, 0xFB, 0xCE, - 0x83, 0xE1, 0x81, 0xFF, 0xDD, 0xA2, 0x77, 0xFE, 0xEB, 0x27, 0x1F, 0x10, 0xFA, 0x82, 0x37, 0xF4, - 0x7E, 0xCC, 0xE2, 0xA1, 0x58, 0xC8, 0xAF, 0x1D, 0x1A, 0x81, 0x31, 0x6E, 0xF4, 0x8B, 0x63, 0x34, - 0xF3, 0x05, 0x0F, 0xE1, 0xCC, 0x15, 0xDC, 0xA4, 0x28, 0x7A, 0x9E, 0xEB, 0x62, 0xD8, 0xD8, 0x8C, - 0x85, 0xD7, 0x07, 0x87, 0x90, 0x2F, 0xF7, 0x1C, 0x56, 0x85, 0x2F, 0xEF, 0x32, 0x37, 0x07, 0xAB, - 0xB0, 0xE6, 0xB5, 0x02, 0x19, 0x35, 0xAF, 0xDB, 0xD4, 0xA2, 0x9C, 0x36, 0x80, 0xC6, 0xDC, 0x82, - 0x08, 0xE0, 0xC0, 0x5F, 0x3C, 0x59, 0xAA, 0x4E, 0x26, 0x03, 0x29, 0xB3, 0x62, 0x58, 0x41, 0x59, - 0x3A, 0x37, 0x43, 0x35, 0xE3, 0x9F, 0x34, 0xE2, 0xA1, 0x04, 0x97, 0x12, 0x9D, 0x8C, 0xAD, 0xF7, - 0xFB, 0x8C, 0xA1, 0xA2, 0xE9, 0xE4, 0xEF, 0xD9, 0xC5, 0xE5, 0xDF, 0x0E, 0xBF, 0x4A, 0xE0, 0x7A, - 0x1E, 0x10, 0x50, 0x58, 0x63, 0x51, 0xE1, 0xD4, 0xFE, 0x57, 0xB0, 0x9E, 0xD7, 0xDA, 0x8C, 0xED, - 0x7D, 0x82, 0xAC, 0x2F, 0x25, 0x58, 0x0A, 0x58, 0xE6, 0xA4, 0xF4, 0x57, 0x4B, 0xA4, 0x1B, 0x65, - 0xB9, 0x4A, 0x87, 0x46, 0xEB, 0x8C, 0x0F, 0x9A, 0x48, 0x90, 0xF9, 0x9F, 0x76, 0x69, 0x03, 0x72, - 0x77, 0xEC, 0xC1, 0x42, 0x4C, 0x87, 0xDB, 0x0B, 0x3C, 0xD4, 0x74, 0xEF, 0xE5, 0x34, 0xE0, 0x32, - 0x45, 0xB0, 0xF8, 0xAB, 0xD5, 0x26, 0x21, 0xD7, 0xD2, 0x98, 0x54, 0x8F, 0x64, 0x88, 0x20, 0x2B, - 0x14, 0xE3, 0x82, 0xD5, 0x2A, 0x4B, 0x8F, 0x4E, 0x35, 0x20, 0x82, 0x7E, 0x1B, 0xFE, 0xFA, 0x2C, - 0x79, 0x6C, 0x6E, 0x66, 0x94, 0xBB, 0x0A, 0xEB, 0xBA, 0xD9, 0x70, 0x61, 0xE9, 0x47, 0xB5, 0x82, - 0xFC, 0x18, 0x3C, 0x66, 0x3A, 0x09, 0x2E, 0x1F, 0x61, 0x74, 0xCA, 0xCB, 0xF6, 0x7A, 0x52, 0x37, - 0x1D, 0xAC, 0x8D, 0x63, 0x69, 0x84, 0x8E, 0xC7, 0x70, 0x59, 0xDD, 0x2D, 0x91, 0x1E, 0xF7, 0xB1, - 0x56, 0xED, 0x7A, 0x06, 0x9D, 0x5B, 0x33, 0x15, 0xDD, 0x31, 0xD0, 0xE6, 0x16, 0x07, 0x9B, 0xA5, - 0x94, 0x06, 0x7D, 0xC1, 0xE9, 0xD6, 0xC8, 0xAF, 0xB4, 0x1E, 0x2D, 0x88, 0x06, 0xA7, 0x63, 0xB8, - 0xCF, 0xC8, 0xA2, 0x6E, 0x84, 0xB3, 0x8D, 0xE5, 0x47, 0xE6, 0x13, 0x63, 0x8E, 0xD1, 0x7F, 0xD4, - 0x81, 0x44, 0x38, 0xBF - }; + started = true; + } - public static readonly byte[] TEST = { - 0x07, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32, 0x00, 0x04, 0x00, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x0F, 0xBE, 0x77, 0xB8, 0xDD, 0x54, 0x36, 0xDD, 0x67, 0xD4, 0x17, 0x66, - 0xC4, 0x13, 0xD1, 0x3F, 0x1E, 0x16, 0x0C, 0x16, 0x35, 0xAB, 0x6D, 0x3D, 0x34, 0x51, 0xED, 0x3F, - 0x57, 0x14, 0xB6, 0xB7, 0x08, 0xE9, 0xD9, 0x7A, 0x80, 0xB3, 0x5F, 0x9B, 0x3A, 0xFD, 0x9E, 0x37, - 0x3A, 0x53, 0x72, 0x67, 0x92, 0x60, 0xC3, 0xEF, 0xB5, 0x8E, 0x1E, 0xCF, 0x9D, 0x9C, 0xD3, 0x90, - 0xE5, 0xDD, 0xF4, 0xDB, 0xF3, 0xD6, 0x65, 0xB3, 0xC1, 0xBD, 0x69, 0xE1, 0x76, 0x95, 0xD9, 0x37, - 0xB8, 0x5E, 0xCA, 0x3D, 0x98, 0xFC, 0x50, 0x5C, 0x98, 0xAE, 0xE3, 0x7C, 0x4C, 0x27, 0xC3, 0xD0, - 0xCE, 0x78, 0x06, 0x51, 0x68, 0x23, 0xE6, 0x70, 0xF8, 0x7C, 0xAE, 0x36, 0xBE, 0x41, 0x57, 0xE2, - 0xC3, 0x2D, 0xAF, 0x21, 0xB1, 0xB3, 0x15, 0x81, 0x19, 0x26, 0x6B, 0x10, 0xB3, 0xE9, 0xD1, 0x45, - 0x21, 0x77, 0x9C, 0xF6, 0xE1, 0xDD, 0xB6, 0x78, 0x9D, 0x1D, 0x32, 0x61, 0xBC, 0x2B, 0xDB, 0x86, - 0xFB, 0x07, 0x24, 0x10, 0x19, 0x4F, 0x09, 0x6D, 0x03, 0x90, 0xD4, 0x5E, 0x30, 0x85, 0xC5, 0x58, - 0x7E, 0x5D, 0xAE, 0x9F, 0x64, 0x93, 0x04, 0x82, 0x09, 0x0E, 0x1C, 0x66, 0xA8, 0x95, 0x91, 0x51, - 0xB2, 0xED, 0x9A, 0x75, 0x04, 0x87, 0x50, 0xAC, 0xCC, 0x20, 0x06, 0x45, 0xB9, 0x7B, 0x42, 0x53, - 0x9A, 0xD1, 0x29, 0xFC, 0xEF, 0xB9, 0x47, 0x16, 0x75, 0x69, 0x05, 0x87, 0x2B, 0xCB, 0x54, 0x9C, - 0x21, 0x2D, 0x50, 0x8E, 0x12, 0xDE, 0xD3, 0x6B, 0xEC, 0x92, 0xA1, 0xB1, 0xE9, 0x4B, 0xBF, 0x6B, - 0x9A, 0x38, 0xC7, 0x13, 0xFA, 0x78, 0xA1, 0x3C, 0x1E, 0xBB, 0x38, 0x31, 0xBB, 0x0C, 0x9F, 0x70, - 0x1A, 0x31, 0x00, 0xD7, 0x5A, 0xA5, 0x84, 0x24, 0x89, 0x80, 0xF5, 0x88, 0xC2, 0x31, 0x18, 0xDC, - 0x53, 0x05, 0x5D, 0xFA, 0x81, 0xDC, 0xE1, 0xCE, 0xA4, 0xAA, 0xBA, 0x07, 0xDA, 0x28, 0x4F, 0x64, - 0x0E, 0x84, 0x9B, 0x06, 0xDE, 0xC8, 0x78, 0x66, 0x2F, 0x17, 0x25, 0xA8, 0x9C, 0x99, 0xFC, 0xBC, - 0x7D, 0x01, 0x42, 0xD7, 0x35, 0xBF, 0x19, 0xF6, 0x3F, 0x20, 0xD9, 0x98, 0x9B, 0x5D, 0xDD, 0x39, - 0xBE, 0x81, 0x00, 0x0B, 0xDE, 0x6F, 0x14, 0xCA, 0x7E, 0xF8, 0xC0, 0x26, 0xA8, 0x1D, 0xD1, 0x16, - 0x88, 0x64, 0x87, 0x36, 0x45, 0x37, 0x50, 0xDA, 0x6C, 0xEB, 0x85, 0xB5, 0x43, 0x29, 0x88, 0x6F, - 0x2F, 0xFE, 0x8D, 0x12, 0x8B, 0x72, 0xB7, 0x5A, 0xCB, 0x66, 0xC2, 0x2E, 0x1D, 0x7D, 0x42, 0xA6, - 0xF4, 0xFE, 0x26, 0x5D, 0x54, 0x9E, 0x77, 0x1D, 0x97, 0xC2, 0xF3, 0xFD, 0x60, 0xB3, 0x22, 0x88, - 0xCA, 0x27, 0x99, 0xDF, 0xC8, 0xB1, 0xD7, 0xC6, 0x54, 0xA6, 0x50, 0xB9, 0x54, 0xF5, 0xDE, 0xFE, - 0xE1, 0x81, 0xA2, 0xBE, 0x81, 0x9F, 0x48, 0xFF, 0x2F, 0xB8, 0xA4, 0xB3, 0x17, 0xD8, 0xC1, 0xB9, - 0x5D, 0x21, 0x3D, 0xA2, 0xED, 0x1C, 0x96, 0x66, 0xEE, 0x1F, 0x47, 0xCF, 0x62, 0xFA, 0xD6, 0xC1, - 0x87, 0x5B, 0xC4, 0xE5, 0xD9, 0x08, 0x38, 0x22, 0xFA, 0x21, 0xBD, 0xF2, 0x88, 0xDA, 0xE2, 0x24, - 0x25, 0x1F, 0xF1, 0x0B, 0x2D, 0xAE, 0x04, 0xBE, 0xA6, 0x7F, 0x75, 0x8C, 0xD9, 0x97, 0xE1, 0xCA, - 0x35, 0xB9, 0xFC, 0x6F, 0x01, 0x68, 0x11, 0xD3, 0x68, 0x32, 0xD0, 0xC1, 0x69, 0xA3, 0xCF, 0x9B, - 0x10, 0xE4, 0x69, 0xA7, 0xCF, 0xE1, 0xFE, 0x2A, 0x07, 0x9E, 0xC1, 0x37, 0x84, 0x68, 0xE5, 0xC5, - 0xAB, 0x25, 0xEC, 0x7D, 0x7D, 0x74, 0x6A, 0xD1, 0xD5, 0x4D, 0xD7, 0xE1, 0x7D, 0xDE, 0x30, 0x4B, - 0xE6, 0x5D, 0xCD, 0x91, 0x59, 0xF6, 0x80, 0xFD, 0xC6, 0x3C, 0xDD, 0x94, 0x7F, 0x15, 0x9D, 0xEF, - 0x2F, 0x00, 0x62, 0xD7, 0xDA, 0xB9, 0xB3, 0xD9, 0x8D, 0xE8, 0xD7, 0x3C, 0x96, 0x45, 0x5D, 0x1E, - 0x50, 0xFB, 0xAA, 0x43, 0xD3, 0x47, 0x77, 0x81, 0xE9, 0x67, 0xE4, 0xFE, 0xDF, 0x42, 0x79, 0xCB, - 0xA7, 0xAD, 0x5D, 0x48, 0xF5, 0xB7, 0x74, 0x96, 0x12, 0x23, 0x06, 0x70, 0x42, 0x68, 0x7A, 0x44, - 0xFC, 0xA0, 0x31, 0x7F, 0x68, 0xCA, 0xA2, 0x14, 0x5D, 0xA3, 0xCF, 0x42, 0x23, 0xAB, 0x47, 0xF6, - 0xB2, 0xFC, 0x6D, 0xF1 - }; - } -} + if (!started) + throw new System.TimeoutException("Failed to start slsvc"); + Logger.WriteLine("slsvc started successfully."); + } -// Crypto/PhysStoreCrypto.cs -namespace LibTSforge.Crypto -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using System.Text; + SLApi.RefreshLicenseStatus(); + } - public static class PhysStoreCrypto - { - public static byte[] DecryptPhysicalStore(byte[] data, bool production) + public static bool DetectCurrentKey() { - byte[] rsaKey = production ? Keys.PRODUCTION : Keys.TEST; - BinaryReader br = new BinaryReader(new MemoryStream(data)); - br.BaseStream.Seek(0x10, SeekOrigin.Begin); - byte[] aesKeySig = br.ReadBytes(0x80); - byte[] encAesKey = br.ReadBytes(0x80); + SLApi.RefreshLicenseStatus(); - if (CryptoUtils.RSAVerifySignature(rsaKey, encAesKey, aesKeySig)) + using (RegistryKey wpaKey = Registry.LocalMachine.OpenSubKey(@"SYSTEM\WPA")) { - byte[] aesKey = CryptoUtils.RSADecrypt(rsaKey, encAesKey); - 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)) + foreach (string subKey in wpaKey.GetSubKeyNames()) { - Logger.WriteLine("Warning: Failed to verify HMAC. Physical store is either corrupt or in Vista format."); + if (subKey.StartsWith("8DEC0AF1")) + { + return subKey.Contains("P"); + } } - - return psData; } - throw new Exception("Failed to decrypt physical store."); + throw new FileNotFoundException("Failed to autodetect key type, specify physical store key with /prod or /test arguments."); } - public static byte[] EncryptPhysicalStore(byte[] data, bool production, PSVersion version) + public static string GetPSPath(PSVersion version) { - Dictionary versionTable = new Dictionary + switch (version) { - {PSVersion.Win7, 5}, - {PSVersion.Win8, 1}, - {PSVersion.WinBlue, 2}, - {PSVersion.WinModern, 3} - }; - - byte[] rsaKey = production ? Keys.PRODUCTION : Keys.TEST; - - byte[] aesKey = Encoding.UTF8.GetBytes("massgrave.dev :3"); - byte[] hmacKey = CryptoUtils.GenerateRandomKey(0x10); - - byte[] encAesKey = CryptoUtils.RSAEncrypt(rsaKey, aesKey); - byte[] aesKeySig = CryptoUtils.RSASign(rsaKey, encAesKey); - byte[] hmacSig = CryptoUtils.HMACSign(hmacKey, data); + 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"); - byte[] decData = new byte[] { }; - decData = decData.Concat(hmacKey).Concat(hmacSig).Concat(BitConverter.GetBytes(0)).Concat(data).ToArray(); - byte[] encData = CryptoUtils.AESEncrypt(decData, aesKey); + if (string.IsNullOrEmpty(psDir) || !File.Exists(psPath)) + { + string[] psDirs = + { + @"spp\store", + @"spp\store\2.0", + @"spp\store_test", + @"spp\store_test\2.0" + }; - BinaryWriter bw = new BinaryWriter(new MemoryStream()); - bw.Write(versionTable[version]); - bw.Write(Encoding.UTF8.GetBytes("UNTRUSTSTORE")); - bw.Write(aesKeySig); - bw.Write(encAesKey); - bw.Write(encData); + 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; + } - return bw.GetBytes(); + throw new FileNotFoundException("Failed to locate physical store."); + } } - } -} - -// Modifiers/GenPKeyInstall.cs -namespace LibTSforge.Modifiers -{ - using System; - using System.IO; - using Microsoft.Win32; - using LibTSforge.PhysicalStore; - using LibTSforge.SPP; - using LibTSforge.TokenStore; - - public static class GenPKeyInstall - { - private static void WritePkey2005RegistryValues(PSVersion version, ProductKey pkey) + public static string GetTokensPath(PSVersion version) { - Logger.WriteLine("Writing registry data for Windows product key..."); - Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ProductId", pkey.GetPid2()); - Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "DigitalProductId", pkey.GetPid3()); - Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "DigitalProductId4", pkey.GetPid4()); + 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."); + } + } +} + + +// SPP/SPSys.cs +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; + } + } +} + + +// Crypto/CryptoUtils.cs +namespace LibTSforge.Crypto +{ + using System; + using System.Linq; + using System.Security.Cryptography; + + public static class CryptoUtils + { + public static byte[] GenerateRandomKey(int len) + { + byte[] rand = new byte[len]; + Random r = new Random(); + r.NextBytes(rand); + + return rand; + } + + public static byte[] AESEncrypt(byte[] data, byte[] key) + { + using (Aes aes = Aes.Create()) + { + aes.Key = key; + aes.Mode = CipherMode.CBC; + aes.Padding = PaddingMode.PKCS7; + + ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, Enumerable.Repeat((byte)0, 16).ToArray()); + byte[] encryptedData = encryptor.TransformFinalBlock(data, 0, data.Length); + return encryptedData; + } + } + + public static byte[] AESDecrypt(byte[] data, byte[] key) + { + using (Aes aes = Aes.Create()) + { + aes.Key = key; + aes.Mode = CipherMode.CBC; + aes.Padding = PaddingMode.PKCS7; + + ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, Enumerable.Repeat((byte)0, 16).ToArray()); + byte[] decryptedData = decryptor.TransformFinalBlock(data, 0, data.Length); + return decryptedData; + } + } + + public static byte[] RSADecrypt(byte[] rsaKey, byte[] data) + { + + using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) + { + rsa.ImportCspBlob(rsaKey); + return rsa.Decrypt(data, false); + } + } + + public static byte[] RSAEncrypt(byte[] rsaKey, byte[] data) + { + using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) + { + rsa.ImportCspBlob(rsaKey); + return rsa.Encrypt(data, false); + } + } + + public static byte[] RSASign(byte[] rsaKey, byte[] data) + { + using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) + { + rsa.ImportCspBlob(rsaKey); + RSAPKCS1SignatureFormatter formatter = new RSAPKCS1SignatureFormatter(rsa); + formatter.SetHashAlgorithm("SHA1"); + + byte[] hash; + using (SHA1 sha1 = SHA1.Create()) + { + hash = sha1.ComputeHash(data); + } + + return formatter.CreateSignature(hash); + } + } + + public static bool RSAVerifySignature(byte[] rsaKey, byte[] data, byte[] signature) + { + using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) + { + rsa.ImportCspBlob(rsaKey); + RSAPKCS1SignatureDeformatter deformatter = new RSAPKCS1SignatureDeformatter(rsa); + deformatter.SetHashAlgorithm("SHA1"); + + byte[] hash; + using (SHA1 sha1 = SHA1.Create()) + { + hash = sha1.ComputeHash(data); + } + + return deformatter.VerifySignature(hash, signature); + } + } + + public static byte[] HMACSign(byte[] key, byte[] data) + { + HMACSHA1 hmac = new HMACSHA1(key); + return hmac.ComputeHash(data); + } + + public static bool HMACVerify(byte[] key, byte[] data, byte[] signature) + { + 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) + { + using (SHA256 sha256 = SHA256.Create()) + { + return sha256.ComputeHash(data); + } + } + } +} + + +// Crypto/Keys.cs +namespace LibTSforge.Crypto +{ + public static class Keys + { + public static readonly byte[] PRODUCTION = { + 0x07, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32, 0x00, 0x04, 0x00, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x29, 0x87, 0xBA, 0x3F, 0x52, 0x90, 0x57, 0xD8, 0x12, 0x26, 0x6B, 0x38, + 0xB2, 0x3B, 0xF9, 0x67, 0x08, 0x4F, 0xDD, 0x8B, 0xF5, 0xE3, 0x11, 0xB8, 0x61, 0x3A, 0x33, 0x42, + 0x51, 0x65, 0x05, 0x86, 0x1E, 0x00, 0x41, 0xDE, 0xC5, 0xDD, 0x44, 0x60, 0x56, 0x3D, 0x14, 0x39, + 0xB7, 0x43, 0x65, 0xE9, 0xF7, 0x2B, 0xA5, 0xF0, 0xA3, 0x65, 0x68, 0xE9, 0xE4, 0x8B, 0x5C, 0x03, + 0x2D, 0x36, 0xFE, 0x28, 0x4C, 0xD1, 0x3C, 0x3D, 0xC1, 0x90, 0x75, 0xF9, 0x6E, 0x02, 0xE0, 0x58, + 0x97, 0x6A, 0xCA, 0x80, 0x02, 0x42, 0x3F, 0x6C, 0x15, 0x85, 0x4D, 0x83, 0x23, 0x6A, 0x95, 0x9E, + 0x38, 0x52, 0x59, 0x38, 0x6A, 0x99, 0xF0, 0xB5, 0xCD, 0x53, 0x7E, 0x08, 0x7C, 0xB5, 0x51, 0xD3, + 0x8F, 0xA3, 0x0D, 0xA0, 0xFA, 0x8D, 0x87, 0x3C, 0xFC, 0x59, 0x21, 0xD8, 0x2E, 0xD9, 0x97, 0x8B, + 0x40, 0x60, 0xB1, 0xD7, 0x2B, 0x0A, 0x6E, 0x60, 0xB5, 0x50, 0xCC, 0x3C, 0xB1, 0x57, 0xE4, 0xB7, + 0xDC, 0x5A, 0x4D, 0xE1, 0x5C, 0xE0, 0x94, 0x4C, 0x5E, 0x28, 0xFF, 0xFA, 0x80, 0x6A, 0x13, 0x53, + 0x52, 0xDB, 0xF3, 0x04, 0x92, 0x43, 0x38, 0xB9, 0x1B, 0xD9, 0x85, 0x54, 0x7B, 0x14, 0xC7, 0x89, + 0x16, 0x8A, 0x4B, 0x82, 0xA1, 0x08, 0x02, 0x99, 0x23, 0x48, 0xDD, 0x75, 0x9C, 0xC8, 0xC1, 0xCE, + 0xB0, 0xD7, 0x1B, 0xD8, 0xFB, 0x2D, 0xA7, 0x2E, 0x47, 0xA7, 0x18, 0x4B, 0xF6, 0x29, 0x69, 0x44, + 0x30, 0x33, 0xBA, 0xA7, 0x1F, 0xCE, 0x96, 0x9E, 0x40, 0xE1, 0x43, 0xF0, 0xE0, 0x0D, 0x0A, 0x32, + 0xB4, 0xEE, 0xA1, 0xC3, 0x5E, 0x9B, 0xC7, 0x7F, 0xF5, 0x9D, 0xD8, 0xF2, 0x0F, 0xD9, 0x8F, 0xAD, + 0x75, 0x0A, 0x00, 0xD5, 0x25, 0x43, 0xF7, 0xAE, 0x51, 0x7F, 0xB7, 0xDE, 0xB7, 0xAD, 0xFB, 0xCE, + 0x83, 0xE1, 0x81, 0xFF, 0xDD, 0xA2, 0x77, 0xFE, 0xEB, 0x27, 0x1F, 0x10, 0xFA, 0x82, 0x37, 0xF4, + 0x7E, 0xCC, 0xE2, 0xA1, 0x58, 0xC8, 0xAF, 0x1D, 0x1A, 0x81, 0x31, 0x6E, 0xF4, 0x8B, 0x63, 0x34, + 0xF3, 0x05, 0x0F, 0xE1, 0xCC, 0x15, 0xDC, 0xA4, 0x28, 0x7A, 0x9E, 0xEB, 0x62, 0xD8, 0xD8, 0x8C, + 0x85, 0xD7, 0x07, 0x87, 0x90, 0x2F, 0xF7, 0x1C, 0x56, 0x85, 0x2F, 0xEF, 0x32, 0x37, 0x07, 0xAB, + 0xB0, 0xE6, 0xB5, 0x02, 0x19, 0x35, 0xAF, 0xDB, 0xD4, 0xA2, 0x9C, 0x36, 0x80, 0xC6, 0xDC, 0x82, + 0x08, 0xE0, 0xC0, 0x5F, 0x3C, 0x59, 0xAA, 0x4E, 0x26, 0x03, 0x29, 0xB3, 0x62, 0x58, 0x41, 0x59, + 0x3A, 0x37, 0x43, 0x35, 0xE3, 0x9F, 0x34, 0xE2, 0xA1, 0x04, 0x97, 0x12, 0x9D, 0x8C, 0xAD, 0xF7, + 0xFB, 0x8C, 0xA1, 0xA2, 0xE9, 0xE4, 0xEF, 0xD9, 0xC5, 0xE5, 0xDF, 0x0E, 0xBF, 0x4A, 0xE0, 0x7A, + 0x1E, 0x10, 0x50, 0x58, 0x63, 0x51, 0xE1, 0xD4, 0xFE, 0x57, 0xB0, 0x9E, 0xD7, 0xDA, 0x8C, 0xED, + 0x7D, 0x82, 0xAC, 0x2F, 0x25, 0x58, 0x0A, 0x58, 0xE6, 0xA4, 0xF4, 0x57, 0x4B, 0xA4, 0x1B, 0x65, + 0xB9, 0x4A, 0x87, 0x46, 0xEB, 0x8C, 0x0F, 0x9A, 0x48, 0x90, 0xF9, 0x9F, 0x76, 0x69, 0x03, 0x72, + 0x77, 0xEC, 0xC1, 0x42, 0x4C, 0x87, 0xDB, 0x0B, 0x3C, 0xD4, 0x74, 0xEF, 0xE5, 0x34, 0xE0, 0x32, + 0x45, 0xB0, 0xF8, 0xAB, 0xD5, 0x26, 0x21, 0xD7, 0xD2, 0x98, 0x54, 0x8F, 0x64, 0x88, 0x20, 0x2B, + 0x14, 0xE3, 0x82, 0xD5, 0x2A, 0x4B, 0x8F, 0x4E, 0x35, 0x20, 0x82, 0x7E, 0x1B, 0xFE, 0xFA, 0x2C, + 0x79, 0x6C, 0x6E, 0x66, 0x94, 0xBB, 0x0A, 0xEB, 0xBA, 0xD9, 0x70, 0x61, 0xE9, 0x47, 0xB5, 0x82, + 0xFC, 0x18, 0x3C, 0x66, 0x3A, 0x09, 0x2E, 0x1F, 0x61, 0x74, 0xCA, 0xCB, 0xF6, 0x7A, 0x52, 0x37, + 0x1D, 0xAC, 0x8D, 0x63, 0x69, 0x84, 0x8E, 0xC7, 0x70, 0x59, 0xDD, 0x2D, 0x91, 0x1E, 0xF7, 0xB1, + 0x56, 0xED, 0x7A, 0x06, 0x9D, 0x5B, 0x33, 0x15, 0xDD, 0x31, 0xD0, 0xE6, 0x16, 0x07, 0x9B, 0xA5, + 0x94, 0x06, 0x7D, 0xC1, 0xE9, 0xD6, 0xC8, 0xAF, 0xB4, 0x1E, 0x2D, 0x88, 0x06, 0xA7, 0x63, 0xB8, + 0xCF, 0xC8, 0xA2, 0x6E, 0x84, 0xB3, 0x8D, 0xE5, 0x47, 0xE6, 0x13, 0x63, 0x8E, 0xD1, 0x7F, 0xD4, + 0x81, 0x44, 0x38, 0xBF + }; + + public static readonly byte[] TEST = { + 0x07, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32, 0x00, 0x04, 0x00, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x0F, 0xBE, 0x77, 0xB8, 0xDD, 0x54, 0x36, 0xDD, 0x67, 0xD4, 0x17, 0x66, + 0xC4, 0x13, 0xD1, 0x3F, 0x1E, 0x16, 0x0C, 0x16, 0x35, 0xAB, 0x6D, 0x3D, 0x34, 0x51, 0xED, 0x3F, + 0x57, 0x14, 0xB6, 0xB7, 0x08, 0xE9, 0xD9, 0x7A, 0x80, 0xB3, 0x5F, 0x9B, 0x3A, 0xFD, 0x9E, 0x37, + 0x3A, 0x53, 0x72, 0x67, 0x92, 0x60, 0xC3, 0xEF, 0xB5, 0x8E, 0x1E, 0xCF, 0x9D, 0x9C, 0xD3, 0x90, + 0xE5, 0xDD, 0xF4, 0xDB, 0xF3, 0xD6, 0x65, 0xB3, 0xC1, 0xBD, 0x69, 0xE1, 0x76, 0x95, 0xD9, 0x37, + 0xB8, 0x5E, 0xCA, 0x3D, 0x98, 0xFC, 0x50, 0x5C, 0x98, 0xAE, 0xE3, 0x7C, 0x4C, 0x27, 0xC3, 0xD0, + 0xCE, 0x78, 0x06, 0x51, 0x68, 0x23, 0xE6, 0x70, 0xF8, 0x7C, 0xAE, 0x36, 0xBE, 0x41, 0x57, 0xE2, + 0xC3, 0x2D, 0xAF, 0x21, 0xB1, 0xB3, 0x15, 0x81, 0x19, 0x26, 0x6B, 0x10, 0xB3, 0xE9, 0xD1, 0x45, + 0x21, 0x77, 0x9C, 0xF6, 0xE1, 0xDD, 0xB6, 0x78, 0x9D, 0x1D, 0x32, 0x61, 0xBC, 0x2B, 0xDB, 0x86, + 0xFB, 0x07, 0x24, 0x10, 0x19, 0x4F, 0x09, 0x6D, 0x03, 0x90, 0xD4, 0x5E, 0x30, 0x85, 0xC5, 0x58, + 0x7E, 0x5D, 0xAE, 0x9F, 0x64, 0x93, 0x04, 0x82, 0x09, 0x0E, 0x1C, 0x66, 0xA8, 0x95, 0x91, 0x51, + 0xB2, 0xED, 0x9A, 0x75, 0x04, 0x87, 0x50, 0xAC, 0xCC, 0x20, 0x06, 0x45, 0xB9, 0x7B, 0x42, 0x53, + 0x9A, 0xD1, 0x29, 0xFC, 0xEF, 0xB9, 0x47, 0x16, 0x75, 0x69, 0x05, 0x87, 0x2B, 0xCB, 0x54, 0x9C, + 0x21, 0x2D, 0x50, 0x8E, 0x12, 0xDE, 0xD3, 0x6B, 0xEC, 0x92, 0xA1, 0xB1, 0xE9, 0x4B, 0xBF, 0x6B, + 0x9A, 0x38, 0xC7, 0x13, 0xFA, 0x78, 0xA1, 0x3C, 0x1E, 0xBB, 0x38, 0x31, 0xBB, 0x0C, 0x9F, 0x70, + 0x1A, 0x31, 0x00, 0xD7, 0x5A, 0xA5, 0x84, 0x24, 0x89, 0x80, 0xF5, 0x88, 0xC2, 0x31, 0x18, 0xDC, + 0x53, 0x05, 0x5D, 0xFA, 0x81, 0xDC, 0xE1, 0xCE, 0xA4, 0xAA, 0xBA, 0x07, 0xDA, 0x28, 0x4F, 0x64, + 0x0E, 0x84, 0x9B, 0x06, 0xDE, 0xC8, 0x78, 0x66, 0x2F, 0x17, 0x25, 0xA8, 0x9C, 0x99, 0xFC, 0xBC, + 0x7D, 0x01, 0x42, 0xD7, 0x35, 0xBF, 0x19, 0xF6, 0x3F, 0x20, 0xD9, 0x98, 0x9B, 0x5D, 0xDD, 0x39, + 0xBE, 0x81, 0x00, 0x0B, 0xDE, 0x6F, 0x14, 0xCA, 0x7E, 0xF8, 0xC0, 0x26, 0xA8, 0x1D, 0xD1, 0x16, + 0x88, 0x64, 0x87, 0x36, 0x45, 0x37, 0x50, 0xDA, 0x6C, 0xEB, 0x85, 0xB5, 0x43, 0x29, 0x88, 0x6F, + 0x2F, 0xFE, 0x8D, 0x12, 0x8B, 0x72, 0xB7, 0x5A, 0xCB, 0x66, 0xC2, 0x2E, 0x1D, 0x7D, 0x42, 0xA6, + 0xF4, 0xFE, 0x26, 0x5D, 0x54, 0x9E, 0x77, 0x1D, 0x97, 0xC2, 0xF3, 0xFD, 0x60, 0xB3, 0x22, 0x88, + 0xCA, 0x27, 0x99, 0xDF, 0xC8, 0xB1, 0xD7, 0xC6, 0x54, 0xA6, 0x50, 0xB9, 0x54, 0xF5, 0xDE, 0xFE, + 0xE1, 0x81, 0xA2, 0xBE, 0x81, 0x9F, 0x48, 0xFF, 0x2F, 0xB8, 0xA4, 0xB3, 0x17, 0xD8, 0xC1, 0xB9, + 0x5D, 0x21, 0x3D, 0xA2, 0xED, 0x1C, 0x96, 0x66, 0xEE, 0x1F, 0x47, 0xCF, 0x62, 0xFA, 0xD6, 0xC1, + 0x87, 0x5B, 0xC4, 0xE5, 0xD9, 0x08, 0x38, 0x22, 0xFA, 0x21, 0xBD, 0xF2, 0x88, 0xDA, 0xE2, 0x24, + 0x25, 0x1F, 0xF1, 0x0B, 0x2D, 0xAE, 0x04, 0xBE, 0xA6, 0x7F, 0x75, 0x8C, 0xD9, 0x97, 0xE1, 0xCA, + 0x35, 0xB9, 0xFC, 0x6F, 0x01, 0x68, 0x11, 0xD3, 0x68, 0x32, 0xD0, 0xC1, 0x69, 0xA3, 0xCF, 0x9B, + 0x10, 0xE4, 0x69, 0xA7, 0xCF, 0xE1, 0xFE, 0x2A, 0x07, 0x9E, 0xC1, 0x37, 0x84, 0x68, 0xE5, 0xC5, + 0xAB, 0x25, 0xEC, 0x7D, 0x7D, 0x74, 0x6A, 0xD1, 0xD5, 0x4D, 0xD7, 0xE1, 0x7D, 0xDE, 0x30, 0x4B, + 0xE6, 0x5D, 0xCD, 0x91, 0x59, 0xF6, 0x80, 0xFD, 0xC6, 0x3C, 0xDD, 0x94, 0x7F, 0x15, 0x9D, 0xEF, + 0x2F, 0x00, 0x62, 0xD7, 0xDA, 0xB9, 0xB3, 0xD9, 0x8D, 0xE8, 0xD7, 0x3C, 0x96, 0x45, 0x5D, 0x1E, + 0x50, 0xFB, 0xAA, 0x43, 0xD3, 0x47, 0x77, 0x81, 0xE9, 0x67, 0xE4, 0xFE, 0xDF, 0x42, 0x79, 0xCB, + 0xA7, 0xAD, 0x5D, 0x48, 0xF5, 0xB7, 0x74, 0x96, 0x12, 0x23, 0x06, 0x70, 0x42, 0x68, 0x7A, 0x44, + 0xFC, 0xA0, 0x31, 0x7F, 0x68, 0xCA, 0xA2, 0x14, 0x5D, 0xA3, 0xCF, 0x42, 0x23, 0xAB, 0x47, 0xF6, + 0xB2, 0xFC, 0x6D, 0xF1 + }; + } +} + + +// Crypto/PhysStoreCrypto.cs +namespace LibTSforge.Crypto +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Text; + + public static class PhysStoreCrypto + { + public static byte[] DecryptPhysicalStore(byte[] data, bool production, PSVersion version) + { + byte[] rsaKey = production ? Keys.PRODUCTION : Keys.TEST; + BinaryReader br = new BinaryReader(new MemoryStream(data)); + br.BaseStream.Seek(0x10, SeekOrigin.Begin); + byte[] aesKeySig = br.ReadBytes(0x80); + byte[] encAesKey = br.ReadBytes(0x80); + + if (!CryptoUtils.RSAVerifySignature(rsaKey, encAesKey, aesKeySig)) + { + 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) + { + Dictionary versionTable = new Dictionary + { + {PSVersion.Vista, 2}, + {PSVersion.Win7, 5}, + {PSVersion.Win8, 1}, + {PSVersion.WinBlue, 2}, + {PSVersion.WinModern, 3} + }; + + byte[] rsaKey = production ? Keys.PRODUCTION : Keys.TEST; + + byte[] aesKey = Encoding.UTF8.GetBytes("massgrave.dev :3"); + byte[] hmacKey = CryptoUtils.GenerateRandomKey(0x10); + + byte[] encAesKey = CryptoUtils.RSAEncrypt(rsaKey, aesKey); + byte[] aesKeySig = CryptoUtils.RSASign(rsaKey, encAesKey); + byte[] hmacSig = version != PSVersion.Vista ? CryptoUtils.HMACSign(hmacKey, data) : CryptoUtils.SaltSHASum(hmacKey, data); + + byte[] decData = { }; + decData = decData.Concat(hmacKey).Concat(hmacSig).Concat(BitConverter.GetBytes(0)).Concat(data).ToArray(); + byte[] encData = CryptoUtils.AESEncrypt(decData, aesKey); + + BinaryWriter bw = new BinaryWriter(new MemoryStream()); + bw.Write(versionTable[version]); + bw.Write(Encoding.UTF8.GetBytes("UNTRUSTSTORE")); + bw.Write(aesKeySig); + bw.Write(encAesKey); + bw.Write(encData); + + return bw.GetBytes(); + } + } +} + + +// Modifiers/GenPKeyInstall.cs +namespace LibTSforge.Modifiers +{ + using System; + using System.IO; + using Microsoft.Win32; + using PhysicalStore; + using SPP; + using TokenStore; + + public static class GenPKeyInstall + { + private static void WritePkey2005RegistryValues(PSVersion version, ProductKey pkey) + { + Logger.WriteLine("Writing registry data for Windows product key..."); + Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ProductId", pkey.GetPid2()); + Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "DigitalProductId", pkey.GetPid3()); + Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "DigitalProductId4", pkey.GetPid4()); + + if (Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Registration", "ProductId", null) != null) + { + Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Registration", "ProductId", pkey.GetPid2()); + Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Registration", "DigitalProductId", pkey.GetPid3()); + Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Registration", "DigitalProductId4", pkey.GetPid4()); + } + + if (pkey.Channel == "Volume:CSVLK" && version != PSVersion.Win7) + { + Registry.SetValue(@"HKEY_USERS\S-1-5-20\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform", "KmsHostConfig", 1); + } + } + + 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."); + + PKeyConfig pkc = new PKeyConfig(); + + try + { + pkc.LoadConfig(actId); + } + catch (ArgumentException) + { + pkc.LoadAllConfigs(SLApi.GetAppId(actId)); + } + + ProductConfig config; + pkc.Products.TryGetValue(actId, out config); + + if (config == null) throw new ArgumentException("Activation ID " + actId + " not found in PKeyConfig."); + + ProductKey pkey = config.GetRandomKey(); + + Guid instPkeyId = SLApi.GetInstalledPkeyID(actId); + if (instPkeyId != Guid.Empty) SLApi.UninstallProductKey(instPkeyId); + + if (pkey.Algorithm == PKeyAlgorithm.PKEY2009) + { + uint status = SLApi.InstallProductKey(pkey); + Logger.WriteLine(string.Format("Installing generated product key {0} status {1:X}", pkey, status)); + + if ((int)status < 0) + { + throw new ApplicationException("Failed to install generated product key."); + } + + Logger.WriteLine("Successfully deposited generated product key."); + return; + } + + Logger.WriteLine("Key range is PKEY2005, creating fake key data..."); + + if (pkey.Channel == "Volume:GVLK" && version == PSVersion.Win7) throw new NotSupportedException("Fake GVLK generation is not supported on Windows 7."); + + VariableBag pkb = new VariableBag(version); + pkb.Blocks.AddRange(new[] + { + new CRCBlockModern + { + DataType = CRCBlockType.STRING, + KeyAsStr = "SppPkeyBindingProductKey", + ValueAsStr = pkey.ToString() + }, + new CRCBlockModern + { + DataType = CRCBlockType.STRING, + KeyAsStr = "SppPkeyBindingMPC", + ValueAsStr = pkey.GetMPC() + }, + new CRCBlockModern { + DataType = CRCBlockType.BINARY, + KeyAsStr = "SppPkeyBindingPid2", + ValueAsStr = pkey.GetPid2() + }, + new CRCBlockModern + { + DataType = CRCBlockType.BINARY, + KeyAsStr = "SppPkeyBindingPid3", + Value = pkey.GetPid3() + }, + new CRCBlockModern + { + DataType = CRCBlockType.BINARY, + KeyAsStr = "SppPkeyBindingPid4", + Value = pkey.GetPid4() + }, + new CRCBlockModern + { + DataType = CRCBlockType.STRING, + KeyAsStr = "SppPkeyChannelId", + ValueAsStr = pkey.Channel + }, + new CRCBlockModern + { + DataType = CRCBlockType.STRING, + KeyAsStr = "SppPkeyBindingEditionId", + ValueAsStr = pkey.Edition + }, + new CRCBlockModern + { + DataType = CRCBlockType.BINARY, + KeyAsStr = (version == PSVersion.Win7) ? "SppPkeyShortAuthenticator" : "SppPkeyPhoneActivationData", + Value = pkey.GetPhoneData(version) + }, + new CRCBlockModern + { + DataType = CRCBlockType.BINARY, + KeyAsStr = "SppPkeyBindingMiscData", + Value = new byte[] { } + } + }); + + Guid appId = SLApi.GetAppId(actId); + string pkeyId = pkey.GetPkeyId().ToString(); + bool isAddon = SLApi.IsAddon(actId); + string currEdition = SLApi.GetMetaStr(actId, "Family"); + + if (appId == SLApi.WINDOWS_APP_ID && !isAddon) + { + SLApi.UninstallAllProductKeys(appId); + } + + SPPUtils.KillSPP(version); + + using (IPhysicalStore ps = SPPUtils.GetStore(version, production)) + { + using (ITokenStore tks = SPPUtils.GetTokenStore(version)) + { + Logger.WriteLine("Writing to physical store and token store..."); + + string suffix = (version == PSVersion.Win8 || version == PSVersion.WinBlue || version == PSVersion.WinModern) ? "_--" : ""; + string metSuffix = suffix + "_met"; + + if (appId == SLApi.WINDOWS_APP_ID && !isAddon) + { + string edTokName = "msft:spp/token/windows/productkeyid/" + currEdition; + + TokenMeta edToken = tks.GetMetaEntry(edTokName); + edToken.Data["windowsComponentEditionPkeyId"] = pkeyId; + edToken.Data["windowsComponentEditionSkuId"] = actId.ToString(); + tks.SetEntry(edTokName, "xml", edToken.Serialize()); + + WritePkey2005RegistryValues(version, pkey); + } + + string uriMapName = "msft:spp/token/PKeyIdUriMapper" + metSuffix; + TokenMeta uriMap = tks.GetMetaEntry(uriMapName); + uriMap.Data[pkeyId] = pkey.GetAlgoUri(); + tks.SetEntry(uriMapName, "xml", uriMap.Serialize()); + + string skuMetaName = actId + metSuffix; + TokenMeta skuMeta = tks.GetMetaEntry(skuMetaName); + + foreach (string k in skuMeta.Data.Keys) + { + if (k.StartsWith("pkeyId_")) + { + skuMeta.Data.Remove(k); + break; + } + } + + skuMeta.Data["pkeyId"] = pkeyId; + skuMeta.Data["pkeyIdList"] = pkeyId; + tks.SetEntry(skuMetaName, "xml", skuMeta.Serialize()); + + string psKey = string.Format("SPPSVC\\{0}\\{1}", appId, actId); + ps.DeleteBlock(psKey, pkeyId); + ps.AddBlock(new PSBlock + { + Type = BlockType.NAMED, + Flags = (version == PSVersion.WinModern) ? (uint)0x402 : 0x2, + KeyAsStr = psKey, + ValueAsStr = pkeyId, + Data = pkb.Serialize() + }); + + string cachePath = SPPUtils.GetTokensPath(version).Replace("tokens.dat", @"cache\cache.dat"); + if (File.Exists(cachePath)) File.Delete(cachePath); + } + } + + SLApi.RefreshTrustedTime(actId); + Logger.WriteLine("Successfully deposited fake product key."); + } + } +} + + +// Modifiers/GracePeriodReset.cs +namespace LibTSforge.Modifiers +{ + using System.Collections.Generic; + using System.Linq; + using PhysicalStore; + using SPP; + + public static class GracePeriodReset + { + public static void Reset(PSVersion version, bool production) + { + SPPUtils.KillSPP(version); + Logger.WriteLine("Writing TrustedStore data..."); + + using (IPhysicalStore store = SPPUtils.GetStore(version, production)) + { + string value = "msft:sl/timer"; + List blocks = store.FindBlocks(value).ToList(); + + foreach (PSBlock block in blocks) + { + store.DeleteBlock(block.KeyAsStr, block.ValueAsStr); + } + } + + SPPUtils.RestartSPP(version); + Logger.WriteLine("Successfully reset all grace and evaluation period timers."); + } + } +} + + +// Modifiers/KeyChangeLockDelete.cs +namespace LibTSforge.Modifiers +{ + using System.Collections.Generic; + using System.Linq; + using PhysicalStore; + using SPP; + using System; + + public static class KeyChangeLockDelete + { + public static void Delete(PSVersion version, bool production) + { + 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..."); + using (IPhysicalStore store = SPPUtils.GetStore(version, production)) + { + List values = new List + { + "msft:spp/timebased/AB", + "msft:spp/timebased/CD" + }; + List blocks = new List(); + foreach (string value in values) + { + blocks.AddRange(store.FindBlocks(value).ToList()); + } + foreach (PSBlock block in blocks) + { + store.DeleteBlock(block.KeyAsStr, block.ValueAsStr); + } + } + Logger.WriteLine("Successfully removed the key change lock."); + } + } +} + + +// Modifiers/KMSHostCharge.cs +namespace LibTSforge.Modifiers +{ + using System; + using System.IO; + using PhysicalStore; + using SPP; + + public static class KMSHostCharge + { + public static void Charge(PSVersion version, bool production, Guid actId) + { + if (actId == Guid.Empty) + { + actId = SLApi.GetDefaultActivationID(SLApi.WINDOWS_APP_ID, true); + + if (actId == Guid.Empty) + { + throw new NotSupportedException("No applicable activation IDs found."); + } + } + + if (SLApi.GetPKeyChannel(SLApi.GetInstalledPkeyID(actId)) != "Volume:CSVLK") + { + throw new NotSupportedException("Non-Volume:CSVLK product key installed."); + } + + Guid appId = SLApi.GetAppId(actId); + int totalClients = 50; + int currClients = 25; + byte[] hwidBlock = Constants.UniversalHWIDBlock; + string key = string.Format("SPPSVC\\{0}", appId); + long ldapTimestamp = DateTime.Now.ToFileTime(); + + byte[] cmidGuids = { }; + byte[] reqCounts = { }; + byte[] kmsChargeData = { }; + + BinaryWriter writer = new BinaryWriter(new MemoryStream()); + + if (version == PSVersion.Vista) + { + writer.Write(new byte[44]); + 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(); + } + + SPPUtils.KillSPP(version); + + Logger.WriteLine("Writing TrustedStore data..."); + + using (IPhysicalStore store = SPPUtils.GetStore(version, production)) + { + if (version != PSVersion.Vista) + { + VariableBag kmsCountData = new VariableBag(version); + kmsCountData.Blocks.AddRange(new[] + { + new CRCBlockModern + { + DataType = CRCBlockType.BINARY, + KeyAsStr = "SppBindingLicenseData", + Value = hwidBlock + }, + new CRCBlockModern + { + DataType = CRCBlockType.UINT, + Key = new byte[] { }, + ValueAsInt = (uint)totalClients + }, + new CRCBlockModern + { + DataType = CRCBlockType.UINT, + Key = new byte[] { }, + ValueAsInt = 1051200000 + }, + new CRCBlockModern + { + DataType = CRCBlockType.UINT, + Key = new byte[] { }, + ValueAsInt = (uint)currClients + }, + new CRCBlockModern + { + DataType = CRCBlockType.BINARY, + Key = new byte[] { }, + Value = cmidGuids + }, + new CRCBlockModern + { + DataType = CRCBlockType.BINARY, + Key = new byte[] { }, + Value = reqCounts + } + }); + + kmsChargeData = kmsCountData.Serialize(); + } + + 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.AddBlock(new PSBlock + { + Type = BlockType.NAMED, + Flags = (version == PSVersion.WinModern) ? (uint)0x400 : 0, + KeyAsStr = key, + ValueAsStr = countVal, + Data = kmsChargeData + }); + + Logger.WriteLine(string.Format("Set charge count to {0} successfully.", currClients)); + } + + SPPUtils.RestartSPP(version); + } + } +} + + +// Modifiers/RearmReset.cs +namespace LibTSforge.Modifiers +{ + using System.Collections.Generic; + using System.Linq; + using PhysicalStore; + using SPP; + + public static class RearmReset + { + public static void Reset(PSVersion version, bool production) + { + SPPUtils.KillSPP(version); + + Logger.WriteLine("Writing TrustedStore data..."); + + using (IPhysicalStore store = SPPUtils.GetStore(version, production)) + { + List blocks; + + if (version == PSVersion.Vista) + { + blocks = store.FindBlocks("740D70D8-6448-4b2f-9063-4A7A463600C5").ToList(); + } + else if (version == PSVersion.Win7) + { + blocks = store.FindBlocks(0xA0000).ToList(); + } + else + { + blocks = store.FindBlocks("__##USERSEP-RESERVED##__$$REARM-COUNT$$").ToList(); + } + + foreach (PSBlock block in blocks) + { + if (version == PSVersion.Vista) + { + store.DeleteBlock(block.KeyAsStr, block.ValueAsStr); + } + else if (version == PSVersion.Win7) + { + store.SetBlock(block.KeyAsStr, block.ValueAsInt, new byte[8]); + } + else + { + store.SetBlock(block.KeyAsStr, block.ValueAsStr, new byte[8]); + } + } + + Logger.WriteLine("Successfully reset all rearm counters."); + } + } + } +} - if (Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Registration", "ProductId", null) != null) + +// Modifiers/SetIIDParams.cs +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."); + } + } +} + + +// Modifiers/TamperedFlagsDelete.cs +namespace LibTSforge.Modifiers +{ + using System.Linq; + using PhysicalStore; + using SPP; + + public static class TamperedFlagsDelete + { + public static void DeleteTamperFlags(PSVersion version, bool production) + { + SPPUtils.KillSPP(version); + + Logger.WriteLine("Writing TrustedStore data..."); + + using (IPhysicalStore store = SPPUtils.GetStore(version, production)) + { + if (version == PSVersion.Vista) + { + DeleteFlag(store, "6BE8425B-E3CF-4e86-A6AF-5863E3DCB606"); + } + else if (version == PSVersion.Win7) + { + SetFlag(store, 0xA0001); + } + else + { + DeleteFlag(store, "__##USERSEP-RESERVED##__$$RECREATED-FLAG$$"); + DeleteFlag(store, "__##USERSEP-RESERVED##__$$RECOVERED-FLAG$$"); + } + + Logger.WriteLine("Successfully cleared the tamper state."); + } + + SPPUtils.RestartSPP(version); + } + + private static void DeleteFlag(IPhysicalStore store, string flag) + { + store.FindBlocks(flag).ToList().ForEach(block => store.DeleteBlock(block.KeyAsStr, block.ValueAsStr)); + } + + private static void SetFlag(IPhysicalStore store, uint flag) + { + store.FindBlocks(flag).ToList().ForEach(block => store.SetBlock(block.KeyAsStr, block.ValueAsInt, new byte[8])); + } + } +} + + +// Modifiers/UniqueIdDelete.cs +namespace LibTSforge.Modifiers +{ + using System; + using PhysicalStore; + using SPP; + + public static class UniqueIdDelete + { + 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; + + 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 Exception("No product key found."); + } + + VariableBag pkb = new VariableBag(keyBlock.Data, version); + + pkb.DeleteBlock("SppPkeyUniqueIdToken"); + + store.SetBlock(key, pkeyId.ToString(), pkb.Serialize()); + } + + Logger.WriteLine("Successfully removed Unique ID for product key ID " + pkeyId); + } + } +} + + +// Activators/AVMA4K.cs +namespace LibTSforge.Activators +{ + using System; + using PhysicalStore; + using SPP; + + public static class AVMA4k + { + public static void Activate(PSVersion version, bool production, Guid actId) + { + if (version != PSVersion.WinModern && version != PSVersion.WinBlue) + { + throw new NotSupportedException("AVMA licenses are not available for this product."); + } + + Guid appId; + if (actId == Guid.Empty) + { + appId = SLApi.WINDOWS_APP_ID; + actId = SLApi.GetDefaultActivationID(appId, false); + + if (actId == Guid.Empty) + { + throw new NotSupportedException("No applicable activation IDs found."); + } + } + else + { + appId = SLApi.GetAppId(actId); + } + + if (SLApi.GetPKeyChannel(SLApi.GetInstalledPkeyID(actId)) != "VT:IA") + { + throw new NotSupportedException("Non-VT:IA product key installed."); + } + + SPPUtils.KillSPP(version); + + Logger.WriteLine("Writing TrustedStore data..."); + + using (IPhysicalStore store = SPPUtils.GetStore(version, production)) + { + string key = string.Format("SPPSVC\\{0}\\{1}", appId, actId); + + 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 deltaTime = BitConverter.ToInt64(store.GetBlock(key, "__##USERSEP-RESERVED##__$$UP-TIME-DELTA$$").Data, 0); + + const ulong unknown = 0; + ulong time1 = (ulong)(creationTime + tickCount + deltaTime); + ulong crcBindTime = (ulong)DateTime.UtcNow.ToFileTime(); + ulong timerTime = crcBindTime / 10000; + ulong expiry = Constants.TimerMax / 10000; + + VariableBag avmaBinding = new VariableBag(version); + + avmaBinding.Blocks.AddRange(new[] + { + new CRCBlockModern + { + DataType = CRCBlockType.BINARY, + Key = new byte[] { }, + Value = BitConverter.GetBytes(crcBindTime), + }, + new CRCBlockModern + { + DataType = CRCBlockType.STRING, + Key = new byte[] { }, + ValueAsStr = "AVMA4K", + }, + new CRCBlockModern + { + DataType = CRCBlockType.STRING, + Key = new byte[] { }, + ValueAsStr = "00491-50000-00001-AA666", + } + }); + + byte[] avmaBindingData = avmaBinding.Serialize(); + + Timer avmaTimer = new Timer + { + Unknown = unknown, + Time1 = time1, + Time2 = timerTime, + Expiry = expiry + }; + + string storeVal = string.Format("msft:spp/ia/bind/1.0/store/{0}/{1}", appId, actId); + string timerVal = string.Format("msft:spp/ia/bind/1.0/timer/{0}/{1}", appId, actId); + + store.DeleteBlock(key, storeVal); + store.DeleteBlock(key, timerVal); + + store.AddBlocks(new[] + { + new PSBlock + { + Type = BlockType.NAMED, + Flags = 0x400, + KeyAsStr = key, + ValueAsStr = storeVal, + Data = avmaBindingData, + }, + new PSBlock + { + Type = BlockType.TIMER, + Flags = 0x4, + KeyAsStr = key, + ValueAsStr = timerVal, + Data = avmaTimer.CastToArray() + } + }); + } + + SLApi.RefreshLicenseStatus(); + SLApi.FireStateChangedEvent(appId); + Logger.WriteLine("Activated using AVMA4k successfully."); + } + } +} + + +// Activators/ZeroCID.cs +namespace LibTSforge.Activators +{ + using System; + using System.IO; + using System.Linq; + using Crypto; + using PhysicalStore; + using SPP; + + public static class ZeroCID + { + private static void Deposit(Guid actId, string instId) + { + uint status = SLApi.DepositConfirmationID(actId, instId, Constants.ZeroCID); + Logger.WriteLine(string.Format("Depositing fake CID status {0:X}", status)); + + if (status != 0) + { + throw new InvalidOperationException("Failed to deposit fake CID."); + } + } + + public static void Activate(PSVersion version, bool production, Guid actId) + { + Guid appId; + + if (actId == Guid.Empty) + { + appId = SLApi.WINDOWS_APP_ID; + actId = SLApi.GetDefaultActivationID(appId, false); + + if (actId == Guid.Empty) + { + throw new NotSupportedException("No applicable activation IDs found."); + } + } + else { - Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Registration", "ProductId", pkey.GetPid2()); - Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Registration", "DigitalProductId", pkey.GetPid3()); - Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Registration", "DigitalProductId4", pkey.GetPid4()); + appId = SLApi.GetAppId(actId); } - if (pkey.Channel == "Volume:CSVLK" && version != PSVersion.Win7) + if (!SLApi.IsPhoneActivatable(actId)) { - Registry.SetValue(@"HKEY_USERS\S-1-5-20\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform", "KmsHostConfig", 1); + throw new NotSupportedException("Phone license is unavailable for this product."); } - } - public static void InstallGenPKey(PSVersion version, bool production, Guid actId) - { - if (actId == Guid.Empty) throw new ArgumentException("Activation ID must be specified for generated product key install."); + string instId = SLApi.GetInstallationID(actId); + Guid pkeyId = SLApi.GetInstalledPkeyID(actId); - PKeyConfig pkc = new PKeyConfig(); - - try - { - pkc.LoadConfig(actId); - } - catch (ArgumentException) + if (version == PSVersion.Vista || version == PSVersion.Win7) { - pkc.LoadAllConfigs(SLApi.GetAppId(actId)); + Deposit(actId, instId); } - ProductConfig config; - pkc.Products.TryGetValue(actId, out config); + SPPUtils.KillSPP(version); - if (config == null) throw new ArgumentException("Activation ID " + actId + " not found in PKeyConfig."); + Logger.WriteLine("Writing TrustedStore data..."); - ProductKey pkey = config.GetRandomKey(); + using (IPhysicalStore store = SPPUtils.GetStore(version, production)) + { + byte[] hwidBlock = Constants.UniversalHWIDBlock; - Guid instPkeyId = SLApi.GetInstalledPkeyID(actId); - if (instPkeyId != Guid.Empty) SLApi.UninstallProductKey(instPkeyId); + Logger.WriteLine("Activation ID: " + actId); + Logger.WriteLine("Installation ID: " + instId); + Logger.WriteLine("Product Key ID: " + pkeyId); - if (pkey.Algorithm == PKeyAlgorithm.PKEY2009) - { - uint status = SLApi.InstallProductKey(pkey); - Logger.WriteLine(string.Format("Installing generated product key {0} status {1:X}", pkey.ToString(), status)); + byte[] iidHash; - if ((int)status < 0) + if (version == PSVersion.Vista) { - throw new ApplicationException("Failed to install generated product key."); + iidHash = CryptoUtils.SHA256Hash(Utils.EncodeString(instId)).Take(0x10).ToArray(); + } + else if (version == PSVersion.Win7) + { + iidHash = CryptoUtils.SHA256Hash(Utils.EncodeString(instId)); + } + else + { + iidHash = CryptoUtils.SHA256Hash(Utils.EncodeString(instId + '\0' + Constants.ZeroCID)); } - Logger.WriteLine("Successfully deposited generated product key."); - return; - } + string key = string.Format("SPPSVC\\{0}\\{1}", appId, actId); + PSBlock keyBlock = store.GetBlock(key, pkeyId.ToString()); - Logger.WriteLine("Key range is PKEY2005, creating fake key data..."); + if (keyBlock == null) + { + throw new InvalidDataException("Failed to get product key data for activation ID " + actId + "."); + } - if (pkey.Channel == "Volume:GVLK" && version == PSVersion.Win7) throw new NotSupportedException("Fake GVLK generation is not supported on Windows 7."); + VariableBag pkb = new VariableBag(keyBlock.Data, version); - VariableBag pkb = new VariableBag(); - pkb.Blocks.AddRange(new CRCBlock[] - { - new CRCBlock - { - DataType = CRCBlockType.STRING, - KeyAsStr = "SppPkeyBindingProductKey", - ValueAsStr = pkey.ToString() - }, - new CRCBlock - { - DataType = CRCBlockType.STRING, - KeyAsStr = "SppPkeyBindingMPC", - ValueAsStr = pkey.GetMPC() - }, - new CRCBlock { - DataType = CRCBlockType.BINARY, - KeyAsStr = "SppPkeyBindingPid2", - ValueAsStr = pkey.GetPid2() - }, - new CRCBlock - { - DataType = CRCBlockType.BINARY, - KeyAsStr = "SppPkeyBindingPid3", - Value = pkey.GetPid3() - }, - new CRCBlock - { - DataType = CRCBlockType.BINARY, - KeyAsStr = "SppPkeyBindingPid4", - Value = pkey.GetPid4() - }, - new CRCBlock - { - DataType = CRCBlockType.STRING, - KeyAsStr = "SppPkeyChannelId", - ValueAsStr = pkey.Channel - }, - new CRCBlock + byte[] pkeyData; + + if (version == PSVersion.Vista) { - DataType = CRCBlockType.STRING, - KeyAsStr = "SppPkeyBindingEditionId", - ValueAsStr = pkey.Edition - }, - new CRCBlock + 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) { - DataType = CRCBlockType.BINARY, - KeyAsStr = (version == PSVersion.Win7) ? "SppPkeyShortAuthenticator" : "SppPkeyPhoneActivationData", - Value = pkey.GetPhoneData(version) - }, - new CRCBlock + pkeyData = pkb.GetBlock("SppPkeyShortAuthenticator").Value; + } + else { - DataType = CRCBlockType.BINARY, - KeyAsStr = "SppPkeyBindingMiscData", - Value = new byte[] { } + pkeyData = pkb.GetBlock("SppPkeyPhoneActivationData").Value; } - }); - Guid appId = SLApi.GetAppId(actId); - string pkeyId = pkey.GetPkeyId().ToString(); - bool isAddon = SLApi.IsAddon(actId); - string currEdition = SLApi.GetMetaStr(actId, "Family"); + pkb.DeleteBlock("SppPkeyVirtual"); + store.SetBlock(key, pkeyId.ToString(), pkb.Serialize()); - if (appId == SLApi.WINDOWS_APP_ID && !isAddon) + BinaryWriter writer = new BinaryWriter(new MemoryStream()); + writer.Write(iidHash.Length); + writer.Write(iidHash); + writer.Write(hwidBlock.Length); + writer.Write(hwidBlock); + byte[] tsHwidData = writer.GetBytes(); + + writer = new BinaryWriter(new MemoryStream()); + writer.Write(iidHash.Length); + writer.Write(iidHash); + writer.Write(pkeyData.Length); + writer.Write(pkeyData); + byte[] tsPkeyInfoData = writer.GetBytes(); + + 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 + { + Type = BlockType.NAMED, + Flags = 0, + KeyAsStr = key, + ValueAsStr = hwidBlockName, + Data = tsHwidData + }, + new PSBlock + { + Type = BlockType.NAMED, + Flags = 0, + KeyAsStr = key, + ValueAsStr = pkeyInfoName, + Data = tsPkeyInfoData + } + }); + } + + if (version != PSVersion.Vista && version != PSVersion.Win7) { - SLApi.UninstallAllProductKeys(appId); + Deposit(actId, instId); } - Utils.KillSPP(); + SPPUtils.RestartSPP(version); + SLApi.FireStateChangedEvent(appId); + Logger.WriteLine("Activated using ZeroCID successfully."); + } + } +} - using (IPhysicalStore ps = Utils.GetStore(version, production)) - { - using (ITokenStore tks = Utils.GetTokenStore(version)) - { - Logger.WriteLine("Writing to physical store and token store..."); - string suffix = (version == PSVersion.Win8 || version == PSVersion.WinBlue || version == PSVersion.WinModern) ? "_--" : ""; - string metSuffix = suffix + "_met"; +// TokenStore/Common.cs +namespace LibTSforge.TokenStore +{ + using System.Collections.Generic; + using System.IO; - if (appId == SLApi.WINDOWS_APP_ID && !isAddon) - { - string edTokName = "msft:spp/token/windows/productkeyid/" + currEdition; + public class TokenEntry + { + public string Name; + public string Extension; + public byte[] Data; + public bool Populated; + } - TokenMeta edToken = tks.GetMetaEntry(edTokName); - edToken.Data["windowsComponentEditionPkeyId"] = pkeyId; - edToken.Data["windowsComponentEditionSkuId"] = actId.ToString(); - tks.SetEntry(edTokName, "xml", edToken.Serialize()); + public class TokenMeta + { + public string Name; + public readonly Dictionary Data = new Dictionary(); - WritePkey2005RegistryValues(version, pkey); - } + public byte[] Serialize() + { + BinaryWriter writer = new BinaryWriter(new MemoryStream()); + writer.Write(1); + byte[] nameBytes = Utils.EncodeString(Name); + writer.Write(nameBytes.Length); + writer.Write(nameBytes); - string uriMapName = "msft:spp/token/PKeyIdUriMapper" + metSuffix; - TokenMeta uriMap = tks.GetMetaEntry(uriMapName); - uriMap.Data[pkeyId] = pkey.GetAlgoUri(); - tks.SetEntry(uriMapName, "xml", uriMap.Serialize()); + foreach (KeyValuePair kv in Data) + { + byte[] keyBytes = Utils.EncodeString(kv.Key); + byte[] valueBytes = Utils.EncodeString(kv.Value); + writer.Write(keyBytes.Length); + writer.Write(valueBytes.Length); + writer.Write(keyBytes); + writer.Write(valueBytes); + } - string skuMetaName = actId.ToString() + metSuffix; - TokenMeta skuMeta = tks.GetMetaEntry(skuMetaName); + return writer.GetBytes(); + } - foreach (string k in skuMeta.Data.Keys) - { - if (k.StartsWith("pkeyId_")) - { - skuMeta.Data.Remove(k); - break; - } - } + private void Deserialize(byte[] data) + { + BinaryReader reader = new BinaryReader(new MemoryStream(data)); + reader.ReadInt32(); + int nameLen = reader.ReadInt32(); + Name = reader.ReadNullTerminatedString(nameLen); - skuMeta.Data["pkeyId"] = pkeyId; - skuMeta.Data["pkeyIdList"] = pkeyId; - tks.SetEntry(skuMetaName, "xml", skuMeta.Serialize()); + while (reader.BaseStream.Position < data.Length - 0x8) + { + int keyLen = reader.ReadInt32(); + int valueLen = reader.ReadInt32(); + string key = reader.ReadNullTerminatedString(keyLen); + string value = reader.ReadNullTerminatedString(valueLen); + Data[key] = value; + } + } - string psKey = string.Format("SPPSVC\\{0}\\{1}", appId, actId); - ps.DeleteBlock(psKey, pkeyId); - ps.AddBlock(new PSBlock - { - Type = BlockType.NAMED, - Flags = (version == PSVersion.WinModern) ? (uint)0x402 : 0x2, - KeyAsStr = psKey, - ValueAsStr = pkeyId, - Data = pkb.Serialize() - }); + public TokenMeta(byte[] data) + { + Deserialize(data); + } - string cachePath = Utils.GetTokensPath(version).Replace("tokens.dat", @"cache\cache.dat"); - if (File.Exists(cachePath)) File.Delete(cachePath); - } - } + public TokenMeta() + { - SLApi.RefreshTrustedTime(actId); - Logger.WriteLine("Successfully deposited fake product key."); } } } -// Modifiers/GracePeriodReset.cs -namespace LibTSforge.Modifiers +// TokenStore/ITokenStore.cs +namespace LibTSforge.TokenStore { using System; - using System.Collections.Generic; - using System.Linq; - using LibTSforge.PhysicalStore; - public static class GracePeriodReset + public interface ITokenStore : IDisposable { - public static void Reset(PSVersion version, bool production) - { - Utils.KillSPP(); - Logger.WriteLine("Writing TrustedStore data..."); - - using (IPhysicalStore store = Utils.GetStore(version, production)) - { - string value = "msft:sl/timer"; - List blocks = store.FindBlocks(value).ToList(); - - foreach (PSBlock block in blocks) - { - store.DeleteBlock(block.KeyAsStr, block.ValueAsStr); - } - } - - Logger.WriteLine("Successfully reset all grace and evaluation period timers."); - } + void Deserialize(); + void Serialize(); + void AddEntry(TokenEntry entry); + void AddEntries(TokenEntry[] entries); + void DeleteEntry(string name, string ext); + void DeleteUnpopEntry(string name, string ext); + TokenEntry GetEntry(string name, string ext); + TokenMeta GetMetaEntry(string name); + void SetEntry(string name, string ext, byte[] data); } } -// Modifiers/KeyChangeLockDelete.cs -namespace LibTSforge.Modifiers +// TokenStore/TokenStoreModern.cs +namespace LibTSforge.TokenStore { + using System; using System.Collections.Generic; + using System.IO; using System.Linq; - using LibTSforge.PhysicalStore; - using LibTSforge; - public static class KeyChangeLockDelete + using Crypto; + + public class TokenStoreModern : ITokenStore { - public static void Delete(PSVersion version, bool production) - { - Utils.KillSPP(); - Logger.WriteLine("Writing TrustedStore data..."); - using (IPhysicalStore store = Utils.GetStore(version, production)) - { - List values = new List - { - "msft:spp/timebased/AB", - "msft:spp/timebased/CD" - }; - List blocks = new List(); - foreach (string value in values) - { - blocks.AddRange(store.FindBlocks(value).ToList()); - } - foreach (PSBlock block in blocks) - { - store.DeleteBlock(block.KeyAsStr, block.ValueAsStr); - } - } - Logger.WriteLine("Successfully removed the key change lock."); - } - } -} + private static readonly uint VERSION = 3; + private static readonly int ENTRY_SIZE = 0x9E; + private static readonly int BLOCK_SIZE = 0x4020; + private static readonly int ENTRIES_PER_BLOCK = BLOCK_SIZE / ENTRY_SIZE; + private static readonly int BLOCK_PAD_SIZE = 0x66; + private static readonly byte[] CONTS_HEADER = Enumerable.Repeat((byte)0x55, 0x20).ToArray(); + private static readonly byte[] CONTS_FOOTER = Enumerable.Repeat((byte)0xAA, 0x20).ToArray(); -// Modifiers/KMSHostCharge.cs -namespace LibTSforge.Modifiers -{ - using System; - using System.IO; - using LibTSforge.PhysicalStore; - using LibTSforge.SPP; + private List Entries = new List(); + private readonly FileStream TokensFile; - public static class KMSHostCharge - { - public static void Charge(PSVersion version, Guid actId, bool production) + public void Deserialize() { - if (actId == Guid.Empty) - { - actId = SLApi.GetDefaultActivationID(SLApi.WINDOWS_APP_ID, true); + if (TokensFile.Length < BLOCK_SIZE) return; - if (actId == Guid.Empty) - { - throw new NotSupportedException("No applicable activation IDs found."); - } - } + TokensFile.Seek(0x24, SeekOrigin.Begin); + uint nextBlock; - if (SLApi.GetPKeyChannel(SLApi.GetInstalledPkeyID(actId)) != "Volume:CSVLK") + BinaryReader reader = new BinaryReader(TokensFile); + do { - throw new NotSupportedException("Non-Volume:CSVLK product key installed."); - } + reader.ReadUInt32(); + nextBlock = reader.ReadUInt32(); - Guid appId = SLApi.GetAppId(actId); - int totalClients = 50; - int currClients = 25; - byte[] hwidBlock = Constants.UniversalHWIDBlock; - string key = string.Format("SPPSVC\\{0}", appId); - long ldapTimestamp = DateTime.Now.ToFileTime(); + for (int i = 0; i < ENTRIES_PER_BLOCK; i++) + { + uint curOffset = reader.ReadUInt32(); + bool populated = reader.ReadUInt32() == 1; + uint contentOffset = reader.ReadUInt32(); + uint contentLength = reader.ReadUInt32(); + uint allocLength = reader.ReadUInt32(); + byte[] contentData = { }; - BinaryWriter writer = new BinaryWriter(new MemoryStream()); + if (populated) + { + reader.BaseStream.Seek(contentOffset + 0x20, SeekOrigin.Begin); + uint dataLength = reader.ReadUInt32(); - for (int i = 0; i < currClients; i++) - { - writer.Write(ldapTimestamp - (10 * (i + 1))); - writer.Write(Guid.NewGuid().ToByteArray()); - } + if (dataLength != contentLength) + { + throw new FormatException("Data length in tokens content is inconsistent with entry."); + } - byte[] cmidGuids = writer.GetBytes(); + reader.ReadBytes(0x20); + contentData = reader.ReadBytes((int)contentLength); + } - writer = new BinaryWriter(new MemoryStream()); + reader.BaseStream.Seek(curOffset + 0x14, SeekOrigin.Begin); - writer.Write(new byte[40]); + Entries.Add(new TokenEntry + { + Name = reader.ReadNullTerminatedString(0x82), + Extension = reader.ReadNullTerminatedString(0x8), + Data = contentData, + Populated = populated + }); + } - writer.Seek(4, SeekOrigin.Begin); - writer.Write((byte)currClients); + reader.BaseStream.Seek(nextBlock, SeekOrigin.Begin); + } while (nextBlock != 0); + } - writer.Seek(24, SeekOrigin.Begin); - writer.Write((byte)currClients); - byte[] reqCounts = writer.GetBytes(); + public void Serialize() + { + MemoryStream tokens = new MemoryStream(); - Utils.KillSPP(); + using (BinaryWriter writer = new BinaryWriter(tokens)) + { + writer.Write(VERSION); + writer.Write(CONTS_HEADER); - Logger.WriteLine("Writing TrustedStore data..."); + int curBlockOffset = (int)writer.BaseStream.Position; + int curEntryOffset = curBlockOffset + 0x8; + int curContsOffset = curBlockOffset + BLOCK_SIZE; - using (IPhysicalStore store = Utils.GetStore(version, production)) - { - VariableBag kmsCountData = new VariableBag(); - kmsCountData.Blocks.AddRange(new CRCBlock[] + for (int eIndex = 0; eIndex < ((Entries.Count / ENTRIES_PER_BLOCK) + 1) * ENTRIES_PER_BLOCK; eIndex++) { - new CRCBlock - { - DataType = CRCBlockType.BINARY, - KeyAsStr = "SppBindingLicenseData", - Value = hwidBlock - }, - new CRCBlock - { - DataType = CRCBlockType.UINT, - Key = new byte[] { }, - ValueAsInt = (uint)totalClients - }, - new CRCBlock - { - DataType = CRCBlockType.UINT, - Key = new byte[] { }, - ValueAsInt = 1051200000 - }, - new CRCBlock - { - DataType = CRCBlockType.UINT, - Key = new byte[] { }, - ValueAsInt = (uint)currClients - }, - new CRCBlock + TokenEntry entry; + + if (eIndex < Entries.Count) { - DataType = CRCBlockType.BINARY, - Key = new byte[] { }, - Value = cmidGuids - }, - new CRCBlock + entry = Entries[eIndex]; + } + else { - DataType = CRCBlockType.BINARY, - Key = new byte[] { }, - Value = reqCounts + entry = new TokenEntry + { + Name = "", + Extension = "", + Populated = false, + Data = new byte[] { } + }; } - }); - - byte[] kmsChargeData = kmsCountData.Serialize(); - string countVal = string.Format("msft:spp/kms/host/2.0/store/counters/{0}", appId); - - store.DeleteBlock(key, countVal); - store.AddBlock(new PSBlock - { - Type = BlockType.NAMED, - Flags = (version == PSVersion.WinModern) ? (uint)0x400 : 0, - KeyAsStr = key, - ValueAsStr = countVal, - Data = kmsChargeData - }); - - Logger.WriteLine(string.Format("Set charge count to {0} successfully.", currClients)); - } - } - } -} + writer.BaseStream.Seek(curBlockOffset, SeekOrigin.Begin); + writer.Write(curBlockOffset); + writer.Write(0); -// Modifiers/RearmReset.cs -namespace LibTSforge.Modifiers -{ - using System; - using System.Collections.Generic; - using System.Linq; - using LibTSforge.PhysicalStore; + writer.BaseStream.Seek(curEntryOffset, SeekOrigin.Begin); + writer.Write(curEntryOffset); + writer.Write(entry.Populated ? 1 : 0); + writer.Write(entry.Populated ? curContsOffset : 0); + writer.Write(entry.Populated ? entry.Data.Length : -1); + writer.Write(entry.Populated ? entry.Data.Length : -1); + writer.WriteFixedString16(entry.Name, 0x82); + writer.WriteFixedString16(entry.Extension, 0x8); + curEntryOffset = (int)writer.BaseStream.Position; - public static class RearmReset - { - public static void Reset(PSVersion version, bool production) - { - Utils.KillSPP(); + if (entry.Populated) + { + writer.BaseStream.Seek(curContsOffset, SeekOrigin.Begin); + writer.Write(CONTS_HEADER); + writer.Write(entry.Data.Length); + writer.Write(CryptoUtils.SHA256Hash(entry.Data)); + writer.Write(entry.Data); + writer.Write(CONTS_FOOTER); + curContsOffset = (int)writer.BaseStream.Position; + } - Logger.WriteLine("Writing TrustedStore data..."); + if ((eIndex + 1) % ENTRIES_PER_BLOCK == 0 && eIndex != 0) + { + if (eIndex < Entries.Count) + { + writer.BaseStream.Seek(curBlockOffset + 0x4, SeekOrigin.Begin); + writer.Write(curContsOffset); + } - using (IPhysicalStore store = Utils.GetStore(version, production)) - { - List blocks; + writer.BaseStream.Seek(curEntryOffset, SeekOrigin.Begin); + writer.WritePadding(BLOCK_PAD_SIZE); - if (version == PSVersion.Win7) - { - blocks = store.FindBlocks(0xA0000).ToList(); - } - else - { - blocks = store.FindBlocks("__##USERSEP-RESERVED##__$$REARM-COUNT$$").ToList(); - } + writer.BaseStream.Seek(curBlockOffset, SeekOrigin.Begin); + byte[] blockData = new byte[BLOCK_SIZE - 0x20]; - foreach (PSBlock block in blocks) - { - if (version == PSVersion.Win7) - { - store.SetBlock(block.KeyAsStr, block.ValueAsInt, new byte[8]); - } - else - { - store.SetBlock(block.KeyAsStr, block.ValueAsStr, new byte[8]); + tokens.Read(blockData, 0, BLOCK_SIZE - 0x20); + byte[] blockHash = CryptoUtils.SHA256Hash(blockData); + + writer.BaseStream.Seek(curBlockOffset + BLOCK_SIZE - 0x20, SeekOrigin.Begin); + writer.Write(blockHash); + + curBlockOffset = curContsOffset; + curEntryOffset = curBlockOffset + 0x8; + curContsOffset = curBlockOffset + BLOCK_SIZE; } } - Logger.WriteLine("Successfully reset all rearm counters."); + tokens.SetLength(curBlockOffset); } - } - } -} - -// Modifiers/TamperedFlagsDelete.cs -namespace LibTSforge.Modifiers -{ - using System; - using System.Linq; - using LibTSforge.PhysicalStore; - - public static class TamperedFlagsDelete - { - public static void DeleteTamperFlags(PSVersion version, bool production) - { - Utils.KillSPP(); + byte[] tokensData = tokens.ToArray(); + byte[] tokensHash = CryptoUtils.SHA256Hash(tokensData.Take(0x4).Concat(tokensData.Skip(0x24)).ToArray()); - Logger.WriteLine("Writing TrustedStore data..."); + tokens = new MemoryStream(tokensData); - using (IPhysicalStore store = Utils.GetStore(version, production)) + BinaryWriter tokWriter = new BinaryWriter(TokensFile); + using (BinaryReader reader = new BinaryReader(tokens)) { - if (version != PSVersion.Win7) - { - string recreatedFlag = "__##USERSEP-RESERVED##__$$RECREATED-FLAG$$"; - string recoveredFlag = "__##USERSEP-RESERVED##__$$RECOVERED-FLAG$$"; - - DeleteFlag(store, recreatedFlag); - DeleteFlag(store, recoveredFlag); - } - else - { - SetFlag(store, 0xA0001); - } - - Logger.WriteLine("Successfully cleared the tamper state."); + TokensFile.Seek(0, SeekOrigin.Begin); + TokensFile.SetLength(tokens.Length); + tokWriter.Write(reader.ReadBytes(0x4)); + reader.ReadBytes(0x20); + tokWriter.Write(tokensHash); + tokWriter.Write(reader.ReadBytes((int)reader.BaseStream.Length - 0x4)); } } - private static void DeleteFlag(IPhysicalStore store, string flag) + public void AddEntry(TokenEntry entry) { - store.FindBlocks(flag).ToList().ForEach(block => store.DeleteBlock(block.KeyAsStr, block.ValueAsStr)); + Entries.Add(entry); } - private static void SetFlag(IPhysicalStore store, uint flag) + public void AddEntries(TokenEntry[] entries) { - store.FindBlocks(flag).ToList().ForEach(block => store.SetBlock(block.KeyAsStr, block.ValueAsInt, new byte[8])); + Entries.AddRange(entries); } - } -} - - -// Modifiers/UniqueIdDelete.cs -namespace LibTSforge.Modifiers -{ - using System; - using LibTSforge.PhysicalStore; - using LibTSforge.SPP; - public static class UniqueIdDelete - { - public static void DeleteUniqueId(PSVersion version, bool production, Guid actId) + public void DeleteEntry(string name, string ext) { - Guid appId; - - if (actId == Guid.Empty) + foreach (TokenEntry entry in Entries) { - appId = SLApi.WINDOWS_APP_ID; - actId = SLApi.GetDefaultActivationID(appId, true); - - if (actId == Guid.Empty) + if (entry.Name == name && entry.Extension == ext) { - throw new Exception("No applicable activation IDs found."); + Entries.Remove(entry); + return; } } - else - { - appId = SLApi.GetAppId(actId); - } - - string instId = SLApi.GetInstallationID(actId); - Guid pkeyId = SLApi.GetInstalledPkeyID(actId); - - Utils.KillSPP(); - - Logger.WriteLine("Writing TrustedStore data..."); + } - using (IPhysicalStore store = Utils.GetStore(version, production)) + public void DeleteUnpopEntry(string name, string ext) + { + List delEntries = new List(); + foreach (TokenEntry entry in Entries) { - string key = string.Format("SPPSVC\\{0}\\{1}", appId, actId); - PSBlock keyBlock = store.GetBlock(key, pkeyId.ToString()); - - if (keyBlock == null) + if (entry.Name == name && entry.Extension == ext && !entry.Populated) { - throw new Exception("No product key found."); + delEntries.Add(entry); } - - VariableBag pkb = new VariableBag(keyBlock.Data); - - pkb.DeleteBlock("SppPkeyUniqueIdToken"); - - store.SetBlock(key, pkeyId.ToString(), pkb.Serialize()); } - Logger.WriteLine("Successfully removed Unique ID for product key ID " + pkeyId); + Entries = Entries.Except(delEntries).ToList(); } - } -} - - -// Activators/ZeroCID.cs -namespace LibTSforge.Activators -{ - using System; - using System.IO; - using LibTSforge.Crypto; - using LibTSforge.PhysicalStore; - using LibTSforge.SPP; - public static class ZeroCID - { - public static void Deposit(Guid actId, string instId) + public TokenEntry GetEntry(string name, string ext) { - uint status = SLApi.DepositConfirmationID(actId, instId, Constants.ZeroCID); - Logger.WriteLine(string.Format("Depositing fake CID status {0:X}", status)); - - if (status != 0) + foreach (TokenEntry entry in Entries) { - throw new InvalidOperationException("Failed to deposit fake CID."); + if (entry.Name == name && entry.Extension == ext) + { + if (!entry.Populated) continue; + return entry; + } } + + return null; } - public static void Activate(PSVersion version, bool production, Guid actId) + public TokenMeta GetMetaEntry(string name) { - Guid appId; + DeleteUnpopEntry(name, "xml"); + TokenEntry entry = GetEntry(name, "xml"); + TokenMeta meta; - if (actId == Guid.Empty) + if (entry == null) { - appId = SLApi.WINDOWS_APP_ID; - actId = SLApi.GetDefaultActivationID(appId, false); - - if (actId == Guid.Empty) + meta = new TokenMeta { - throw new NotSupportedException("No applicable activation IDs found."); - } + Name = name + }; } else { - appId = SLApi.GetAppId(actId); - } - - if (!SLApi.IsPhoneActivatable(actId)) - { - throw new NotSupportedException("Phone license is unavailable for this product."); - } - - string instId = SLApi.GetInstallationID(actId); - Guid pkeyId = SLApi.GetInstalledPkeyID(actId); - - if (version == PSVersion.Win7) - { - Deposit(actId, instId); + meta = new TokenMeta(entry.Data); } - Utils.KillSPP(); - - Logger.WriteLine("Writing TrustedStore data..."); + return meta; + } - using (IPhysicalStore store = Utils.GetStore(version, production)) + public void SetEntry(string name, string ext, byte[] data) + { + for (int i = 0; i < Entries.Count; i++) { - byte[] hwidBlock = Constants.UniversalHWIDBlock; - - Logger.WriteLine("Activation ID: " + actId); - Logger.WriteLine("Installation ID: " + instId); - Logger.WriteLine("Product Key ID: " + pkeyId); - - byte[] iidHash; - - if (version == PSVersion.Win7) - { - iidHash = CryptoUtils.SHA256Hash(Utils.EncodeString(instId)); - } - else - { - iidHash = CryptoUtils.SHA256Hash(Utils.EncodeString(instId + '\0' + Constants.ZeroCID)); - } - - 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); - - byte[] pkeyData; + TokenEntry entry = Entries[i]; - if (version == PSVersion.Win7) - { - pkeyData = pkb.GetBlock("SppPkeyShortAuthenticator").Value; - } - else + if (entry.Name == name && entry.Extension == ext && entry.Populated) { - pkeyData = pkb.GetBlock("SppPkeyPhoneActivationData").Value; + entry.Data = data; + Entries[i] = entry; + return; } - - pkb.DeleteBlock("SppPkeyVirtual"); - store.SetBlock(key, pkeyId.ToString(), pkb.Serialize()); - - BinaryWriter writer = new BinaryWriter(new MemoryStream()); - writer.Write(0x20); - writer.Write(iidHash); - writer.Write(hwidBlock.Length); - writer.Write(hwidBlock); - byte[] tsHwidData = writer.GetBytes(); - - writer = new BinaryWriter(new MemoryStream()); - writer.Write(0x20); - writer.Write(iidHash); - writer.Write(pkeyData.Length); - writer.Write(pkeyData); - byte[] tsPkeyInfoData = writer.GetBytes(); - - store.AddBlocks(new PSBlock[] { - new PSBlock - { - Type = BlockType.NAMED, - Flags = 0, - KeyAsStr = key, - ValueAsStr = "msft:Windows/7.0/Phone/Cached/HwidBlock/" + pkeyId, - Data = tsHwidData - }, - new PSBlock - { - Type = BlockType.NAMED, - Flags = 0, - KeyAsStr = key, - ValueAsStr = "msft:Windows/7.0/Phone/Cached/PKeyInfo/" + pkeyId, - Data = tsPkeyInfoData - } - }); } - if (version != PSVersion.Win7) - { - Deposit(actId, instId); - } + Entries.Add(new TokenEntry + { + Populated = true, + Name = name, + Extension = ext, + Data = data + }); + } + + public TokenStoreModern(string tokensPath) + { + TokensFile = File.Open(tokensPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); + Deserialize(); + } - SLApi.RefreshLicenseStatus(); - SLApi.FireStateChangedEvent(appId); - Logger.WriteLine("Activated using ZeroCID successfully."); + public void Dispose() + { + Serialize(); + TokensFile.Close(); } } } -// TokenStore/Common.cs -namespace LibTSforge.TokenStore +// PhysicalStore/Common.cs +namespace LibTSforge.PhysicalStore { - using System.Collections.Generic; - using System.IO; + using System.Runtime.InteropServices; - public class TokenEntry + public enum BlockType : uint { - public string Name; - public string Extension; - public byte[] Data; - public bool Populated; + NONE, + NAMED, + ATTRIBUTE, + TIMER } - public class TokenMeta + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct Timer { - public string Name; - public Dictionary Data = new Dictionary(); + public ulong Unknown; + public ulong Time1; + public ulong Time2; + public ulong Expiry; + } - public byte[] Serialize() - { - BinaryWriter writer = new BinaryWriter(new MemoryStream()); - writer.Write(1); - byte[] nameBytes = Utils.EncodeString(Name); - writer.Write(nameBytes.Length); - writer.Write(nameBytes); + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct VistaTimer + { + public ulong Time; + public ulong Expiry; + } +} - foreach (KeyValuePair kv in Data) + +// PhysicalStore/IPhysicalStore.cs +namespace LibTSforge.PhysicalStore +{ + using System; + using System.Collections.Generic; + + public class PSBlock + { + public BlockType Type; + public uint Flags; + public uint Unknown = 0; + public byte[] Key; + public string KeyAsStr + { + get { - byte[] keyBytes = Utils.EncodeString(kv.Key); - byte[] valueBytes = Utils.EncodeString(kv.Value); - writer.Write(keyBytes.Length); - writer.Write(valueBytes.Length); - writer.Write(keyBytes); - writer.Write(valueBytes); + return Utils.DecodeString(Key); + } + set + { + Key = Utils.EncodeString(value); } - - return writer.GetBytes(); } - - public void Deserialize(byte[] data) + public byte[] Value; + public string ValueAsStr { - BinaryReader reader = new BinaryReader(new MemoryStream(data)); - reader.ReadInt32(); - int nameLen = reader.ReadInt32(); - Name = reader.ReadNullTerminatedString(nameLen); - - while (reader.BaseStream.Position < data.Length - 0x8) + get { - int keyLen = reader.ReadInt32(); - int valueLen = reader.ReadInt32(); - string key = reader.ReadNullTerminatedString(keyLen); - string value = reader.ReadNullTerminatedString(valueLen); - Data[key] = value; + return Utils.DecodeString(Value); + } + set + { + Value = Utils.EncodeString(value); } } - - public TokenMeta(byte[] data) + public uint ValueAsInt { - Deserialize(data); + get + { + return BitConverter.ToUInt32(Value, 0); + } + set + { + Value = BitConverter.GetBytes(value); + } } - - public TokenMeta() + 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); + } } } -} - - -// TokenStore/ITokenStore.cs -namespace LibTSforge.TokenStore -{ - using System; - public interface ITokenStore : IDisposable + public interface IPhysicalStore : IDisposable { - void Deserialize(); - void Serialize(); - void AddEntry(TokenEntry entry); - void AddEntries(TokenEntry[] entries); - void DeleteEntry(string name, string ext); - void DeleteUnpopEntry(string name, string ext); - TokenEntry GetEntry(string name, string ext); - TokenMeta GetMetaEntry(string name); - void SetEntry(string name, string ext, byte[] data); + PSBlock GetBlock(string key, string value); + PSBlock GetBlock(string key, uint value); + void AddBlock(PSBlock block); + void AddBlocks(IEnumerable blocks); + void SetBlock(string key, string value, byte[] data); + void SetBlock(string key, string value, string data); + void SetBlock(string key, string value, uint data); + void SetBlock(string key, uint value, byte[] data); + void SetBlock(string key, uint value, string data); + void SetBlock(string key, uint value, uint data); + void DeleteBlock(string key, string value); + void DeleteBlock(string key, uint value); + byte[] Serialize(); + void Deserialize(byte[] data); + byte[] ReadRaw(); + void WriteRaw(byte[] data); + IEnumerable FindBlocks(string valueSearch); + IEnumerable FindBlocks(uint valueSearch); } } -// TokenStore/TokenStoreModern.cs -namespace LibTSforge.TokenStore +// PhysicalStore/PhysicalStoreModern.cs +namespace LibTSforge.PhysicalStore { using System; using System.Collections.Generic; using System.IO; - using System.Linq; - using LibTSforge.Crypto; + using Crypto; - public class TokenStoreModern : ITokenStore + public class ModernBlock { - private static readonly uint VERSION = 3; - private static readonly int ENTRY_SIZE = 0x9E; - private static readonly int BLOCK_SIZE = 0x4020; - private static readonly int ENTRIES_PER_BLOCK = BLOCK_SIZE / ENTRY_SIZE; - private static readonly int BLOCK_PAD_SIZE = 0x66; - - private static readonly byte[] CONTS_HEADER = Enumerable.Repeat((byte)0x55, 0x20).ToArray(); - private static readonly byte[] CONTS_FOOTER = Enumerable.Repeat((byte)0xAA, 0x20).ToArray(); + public BlockType Type; + public uint Flags; + public uint Unknown; + 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); + } + } - private List Entries = new List(); - public FileStream TokensFile; + public void Encode(BinaryWriter writer) + { + writer.Write((uint)Type); + writer.Write(Flags); + writer.Write((uint)Value.Length); + writer.Write((uint)Data.Length); + writer.Write(Unknown); + writer.Write(Value); + writer.Write(Data); + } - public void Deserialize() + public static ModernBlock Decode(BinaryReader reader) { - if (TokensFile.Length < BLOCK_SIZE) return; + uint type = reader.ReadUInt32(); + uint flags = reader.ReadUInt32(); - TokensFile.Seek(0x24, SeekOrigin.Begin); - uint nextBlock = 0; + uint valueLen = reader.ReadUInt32(); + uint dataLen = reader.ReadUInt32(); + uint unk3 = reader.ReadUInt32(); - BinaryReader reader = new BinaryReader(TokensFile); - do - { - uint curOffset = reader.ReadUInt32(); - nextBlock = reader.ReadUInt32(); + byte[] value = reader.ReadBytes((int)valueLen); + byte[] data = reader.ReadBytes((int)dataLen); - for (int i = 0; i < ENTRIES_PER_BLOCK; i++) - { - curOffset = reader.ReadUInt32(); - bool populated = reader.ReadUInt32() == 1; - uint contentOffset = reader.ReadUInt32(); - uint contentLength = reader.ReadUInt32(); - uint allocLength = reader.ReadUInt32(); - byte[] contentData = new byte[] { }; + return new ModernBlock + { + Type = (BlockType)type, + Flags = flags, + Unknown = unk3, + Value = value, + Data = data, + }; + } + } - if (populated) - { - reader.BaseStream.Seek(contentOffset + 0x20, SeekOrigin.Begin); - uint dataLength = reader.ReadUInt32(); + public sealed class PhysicalStoreModern : IPhysicalStore + { + private byte[] PreHeaderBytes = { }; + private readonly Dictionary> Data = new Dictionary>(); + private readonly FileStream TSFile; + private readonly PSVersion Version; + private readonly bool Production; - if (dataLength != contentLength) - { - throw new FormatException("Data length in tokens content is inconsistent with entry."); - } + public byte[] Serialize() + { + BinaryWriter writer = new BinaryWriter(new MemoryStream()); + writer.Write(PreHeaderBytes); + writer.Write(Data.Keys.Count); - reader.ReadBytes(0x20); - contentData = reader.ReadBytes((int)contentLength); - } + foreach (string key in Data.Keys) + { + List blocks = Data[key]; + byte[] keyNameEnc = Utils.EncodeString(key); - reader.BaseStream.Seek(curOffset + 0x14, SeekOrigin.Begin); + writer.Write(keyNameEnc.Length); + writer.Write(keyNameEnc); + writer.Write(blocks.Count); + writer.Align(4); - Entries.Add(new TokenEntry - { - Name = reader.ReadNullTerminatedString(0x82), - Extension = reader.ReadNullTerminatedString(0x8), - Data = contentData, - Populated = populated - }); + foreach (ModernBlock block in blocks) + { + block.Encode(writer); + writer.Align(4); } + } - reader.BaseStream.Seek(nextBlock, SeekOrigin.Begin); - } while (nextBlock != 0); + return writer.GetBytes(); } - public void Serialize() + public void Deserialize(byte[] data) { - MemoryStream tokens = new MemoryStream(); + BinaryReader reader = new BinaryReader(new MemoryStream(data)); + PreHeaderBytes = reader.ReadBytes(8); - using (BinaryWriter writer = new BinaryWriter(tokens)) + while (reader.BaseStream.Position < data.Length - 0x4) { - writer.Write(VERSION); - writer.Write(CONTS_HEADER); - - int curBlockOffset = (int)writer.BaseStream.Position; - int curEntryOffset = curBlockOffset + 0x8; - int curContsOffset = curBlockOffset + BLOCK_SIZE; + uint numKeys = reader.ReadUInt32(); - for (int eIndex = 0; eIndex < ((Entries.Count / ENTRIES_PER_BLOCK) + 1) * ENTRIES_PER_BLOCK; eIndex++) + for (int i = 0; i < numKeys; i++) { - TokenEntry entry; - - if (eIndex < Entries.Count) - { - entry = Entries[eIndex]; - } - else - { - entry = new TokenEntry - { - Name = "", - Extension = "", - Populated = false, - Data = new byte[] { } - }; - } - - writer.BaseStream.Seek(curBlockOffset, SeekOrigin.Begin); - writer.Write(curBlockOffset); - writer.Write(0); + uint lenKeyName = reader.ReadUInt32(); + string keyName = Utils.DecodeString(reader.ReadBytes((int)lenKeyName)); uint numValues = reader.ReadUInt32(); - writer.BaseStream.Seek(curEntryOffset, SeekOrigin.Begin); - writer.Write(curEntryOffset); - writer.Write(entry.Populated ? 1 : 0); - writer.Write(entry.Populated ? curContsOffset : 0); - writer.Write(entry.Populated ? entry.Data.Length : -1); - writer.Write(entry.Populated ? entry.Data.Length : -1); - writer.WriteFixedString16(entry.Name, 0x82); - writer.WriteFixedString16(entry.Extension, 0x8); - curEntryOffset = (int)writer.BaseStream.Position; + reader.Align(4); - if (entry.Populated) - { - writer.BaseStream.Seek(curContsOffset, SeekOrigin.Begin); - writer.Write(CONTS_HEADER); - writer.Write(entry.Data.Length); - writer.Write(CryptoUtils.SHA256Hash(entry.Data)); - writer.Write(entry.Data); - writer.Write(CONTS_FOOTER); - curContsOffset = (int)writer.BaseStream.Position; - } + Data[keyName] = new List(); - if ((eIndex + 1) % ENTRIES_PER_BLOCK == 0 && eIndex != 0) + for (int j = 0; j < numValues; j++) { - if (eIndex < Entries.Count) - { - writer.BaseStream.Seek(curBlockOffset + 0x4, SeekOrigin.Begin); - writer.Write(curContsOffset); - } - - writer.BaseStream.Seek(curEntryOffset, SeekOrigin.Begin); - writer.WritePadding(BLOCK_PAD_SIZE); - - writer.BaseStream.Seek(curBlockOffset, SeekOrigin.Begin); - byte[] blockHash; - byte[] blockData = new byte[BLOCK_SIZE - 0x20]; - - tokens.Read(blockData, 0, BLOCK_SIZE - 0x20); - blockHash = CryptoUtils.SHA256Hash(blockData); - - writer.BaseStream.Seek(curBlockOffset + BLOCK_SIZE - 0x20, SeekOrigin.Begin); - writer.Write(blockHash); - - curBlockOffset = curContsOffset; - curEntryOffset = curBlockOffset + 0x8; - curContsOffset = curBlockOffset + BLOCK_SIZE; + Data[keyName].Add(ModernBlock.Decode(reader)); + reader.Align(4); } } - - tokens.SetLength(curBlockOffset); - } - - byte[] tokensData = tokens.ToArray(); - byte[] tokensHash = CryptoUtils.SHA256Hash(tokensData.Take(0x4).Concat(tokensData.Skip(0x24)).ToArray()); - - tokens = new MemoryStream(tokensData); - - BinaryWriter tokWriter = new BinaryWriter(TokensFile); - using (BinaryReader reader = new BinaryReader(tokens)) - { - TokensFile.Seek(0, SeekOrigin.Begin); - TokensFile.SetLength(tokens.Length); - tokWriter.Write(reader.ReadBytes(0x4)); - reader.ReadBytes(0x20); - tokWriter.Write(tokensHash); - tokWriter.Write(reader.ReadBytes((int)reader.BaseStream.Length - 0x4)); } } - public void AddEntry(TokenEntry entry) + public void AddBlock(PSBlock block) { - Entries.Add(entry); - } + if (!Data.ContainsKey(block.KeyAsStr)) + { + Data[block.KeyAsStr] = new List(); + } - public void AddEntries(TokenEntry[] entries) - { - Entries.AddRange(entries); + Data[block.KeyAsStr].Add(new ModernBlock + { + Type = block.Type, + Flags = block.Flags, + Unknown = block.Unknown, + Value = block.Value, + Data = block.Data + }); } - public void DeleteEntry(string name, string ext) + public void AddBlocks(IEnumerable blocks) { - foreach (TokenEntry entry in Entries) + foreach (PSBlock block in blocks) { - if (entry.Name == name && entry.Extension == ext) - { - Entries.Remove(entry); - return; - } + AddBlock(block); } } - public void DeleteUnpopEntry(string name, string ext) + public PSBlock GetBlock(string key, string value) { - List delEntries = new List(); - foreach (TokenEntry entry in Entries) + List blocks = Data[key]; + + foreach (ModernBlock block in blocks) { - if (entry.Name == name && entry.Extension == ext && !entry.Populated) + if (block.ValueAsStr == value) { - delEntries.Add(entry); + return new PSBlock + { + Type = block.Type, + Flags = block.Flags, + Key = Utils.EncodeString(key), + Value = block.Value, + Data = block.Data + }; } } - Entries = Entries.Except(delEntries).ToList(); + return null; } - public TokenEntry GetEntry(string name, string ext) + public PSBlock GetBlock(string key, uint value) { - foreach (TokenEntry entry in Entries) + List blocks = Data[key]; + + foreach (ModernBlock block in blocks) { - if (entry.Name == name && entry.Extension == ext) + if (block.ValueAsInt == value) { - if (!entry.Populated) continue; - return entry; + return new PSBlock + { + Type = block.Type, + Flags = block.Flags, + Key = Utils.EncodeString(key), + Value = block.Value, + Data = block.Data + }; } } return null; } - public TokenMeta GetMetaEntry(string name) + public void SetBlock(string key, string value, byte[] data) { - DeleteUnpopEntry(name, "xml"); - TokenEntry entry = GetEntry(name, "xml"); - TokenMeta meta; + List blocks = Data[key]; - if (entry == null) - { - meta = new TokenMeta - { - Name = name - }; - } - else + for (int i = 0; i < blocks.Count; i++) { - meta = new TokenMeta(entry.Data); + ModernBlock block = blocks[i]; + + if (block.ValueAsStr == value) + { + block.Data = data; + blocks[i] = block; + break; + } } - return meta; + Data[key] = blocks; } - public void SetEntry(string name, string ext, byte[] data) + public void SetBlock(string key, uint value, byte[] data) { - for (int i = 0; i < Entries.Count; i++) + List blocks = Data[key]; + + for (int i = 0; i < blocks.Count; i++) { - TokenEntry entry = Entries[i]; + ModernBlock block = blocks[i]; - if (entry.Name == name && entry.Extension == ext && entry.Populated) + if (block.ValueAsInt == value) { - entry.Data = data; - Entries[i] = entry; - return; + block.Data = data; + blocks[i] = block; + break; } } - Entries.Add(new TokenEntry - { - Populated = true, - Name = name, - Extension = ext, - Data = data - }); + Data[key] = blocks; } - public TokenStoreModern(string tokensPath) + public void SetBlock(string key, string value, string data) { - TokensFile = File.Open(tokensPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); - Deserialize(); + SetBlock(key, value, Utils.EncodeString(data)); } - public TokenStoreModern() + public void SetBlock(string key, string value, uint data) { - + SetBlock(key, value, BitConverter.GetBytes(data)); } - public void Dispose() + public void SetBlock(string key, uint value, string data) { - Serialize(); - TokensFile.Close(); + SetBlock(key, value, Utils.EncodeString(data)); } - } -} - - -// PhysicalStore/Common.cs -namespace LibTSforge.PhysicalStore -{ - using System.Runtime.InteropServices; - - public enum BlockType : uint - { - NONE, - NAMED, - ATTRIBUTE, - TIMER - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct Timer - { - public ulong Unknown; - public ulong Time1; - public ulong Time2; - public ulong Expiry; - } -} - -// PhysicalStore/IPhysicalStore.cs -namespace LibTSforge.PhysicalStore -{ - using System; - using System.Collections.Generic; + public void SetBlock(string key, uint value, uint data) + { + SetBlock(key, value, BitConverter.GetBytes(data)); + } - public class PSBlock - { - public BlockType Type; - public uint Flags; - public uint Unknown = 0; - public byte[] Key; - public string KeyAsStr + public void DeleteBlock(string key, string value) { - get + if (!Data.ContainsKey(key)) { - return Utils.DecodeString(Key); + return; } - set + + List blocks = Data[key]; + + foreach (ModernBlock block in blocks) { - Key = Utils.EncodeString(value); + if (block.ValueAsStr == value) + { + blocks.Remove(block); + break; + } } + + Data[key] = blocks; } - public byte[] Value; - public string ValueAsStr + + public void DeleteBlock(string key, uint value) { - get + if (!Data.ContainsKey(key)) { - return Utils.DecodeString(Value); + return; } - set + + List blocks = Data[key]; + + foreach (ModernBlock block in blocks) { - Value = Utils.EncodeString(value); + if (block.ValueAsInt == value) + { + blocks.Remove(block); + break; + } } + + Data[key] = blocks; } - public uint ValueAsInt + + public PhysicalStoreModern(string tsPath, bool production, PSVersion version) { - get - { - return BitConverter.ToUInt32(Value, 0); - } - set - { - Value = BitConverter.GetBytes(value); - } + TSFile = File.Open(tsPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); + Deserialize(PhysStoreCrypto.DecryptPhysicalStore(TSFile.ReadAllBytes(), production, version)); + TSFile.Seek(0, SeekOrigin.Begin); + Version = version; + Production = production; } - public byte[] Data; - public string DataAsStr + + public void Dispose() { - get - { - return Utils.DecodeString(Data); - } - set + if (TSFile.CanWrite) { - Data = Utils.EncodeString(value); + byte[] data = PhysStoreCrypto.EncryptPhysicalStore(Serialize(), Production, Version); + TSFile.SetLength(data.LongLength); + TSFile.Seek(0, SeekOrigin.Begin); + TSFile.WriteAllBytes(data); + TSFile.Close(); } } - public uint DataAsInt + + public byte[] ReadRaw() { - get + byte[] data = PhysStoreCrypto.DecryptPhysicalStore(TSFile.ReadAllBytes(), Production, Version); + TSFile.Seek(0, SeekOrigin.Begin); + return data; + } + + public void WriteRaw(byte[] data) + { + byte[] encrData = PhysStoreCrypto.EncryptPhysicalStore(data, Production, Version); + TSFile.SetLength(encrData.LongLength); + TSFile.Seek(0, SeekOrigin.Begin); + TSFile.WriteAllBytes(encrData); + TSFile.Close(); + } + + public IEnumerable FindBlocks(string valueSearch) + { + List results = new List(); + + foreach (string key in Data.Keys) { - return BitConverter.ToUInt32(Data, 0); + List values = Data[key]; + + foreach (ModernBlock block in values) + { + if (block.ValueAsStr.Contains(valueSearch)) + { + results.Add(new PSBlock + { + Type = block.Type, + Flags = block.Flags, + KeyAsStr = key, + Value = block.Value, + Data = block.Data + }); + } + } } - set + + return results; + } + + public IEnumerable FindBlocks(uint valueSearch) + { + List results = new List(); + + foreach (string key in Data.Keys) { - Data = BitConverter.GetBytes(value); + List values = Data[key]; + + foreach (ModernBlock block in values) + { + if (block.ValueAsInt == valueSearch) + { + results.Add(new PSBlock + { + Type = block.Type, + Flags = block.Flags, + KeyAsStr = key, + Value = block.Value, + Data = block.Data + }); + } + } } - } - } - public interface IPhysicalStore : IDisposable - { - PSBlock GetBlock(string key, string value); - PSBlock GetBlock(string key, uint value); - void AddBlock(PSBlock block); - void AddBlocks(IEnumerable blocks); - void SetBlock(string key, string value, byte[] data); - void SetBlock(string key, string value, string data); - void SetBlock(string key, string value, uint data); - void SetBlock(string key, uint value, byte[] data); - void SetBlock(string key, uint value, string data); - void SetBlock(string key, uint value, uint data); - void DeleteBlock(string key, string value); - void DeleteBlock(string key, uint value); - byte[] Serialize(); - void Deserialize(byte[] data); - byte[] ReadRaw(); - void WriteRaw(byte[] data); - IEnumerable FindBlocks(string valueSearch); - IEnumerable FindBlocks(uint valueSearch); + return results; + } } } -// PhysicalStore/PhysicalStoreModern.cs +// PhysicalStore/PhysicalStoreVista.cs namespace LibTSforge.PhysicalStore { using System; using System.Collections.Generic; using System.IO; - using LibTSforge.Crypto; + using Crypto; - public class ModernBlock + public class VistaBlock { public BlockType Type; public uint Flags; - public uint Unknown; public byte[] Value; public string ValueAsStr { @@ -7921,69 +8801,53 @@ namespace LibTSforge.PhysicalStore } } - public void Encode(BinaryWriter writer) + internal void Encode(BinaryWriter writer) { - writer.Write((uint)Type); - writer.Write(Flags); - writer.Write((uint)Value.Length); - writer.Write((uint)Data.Length); - writer.Write(Unknown); + writer.Write((uint)Type); + writer.Write(Flags); + writer.Write(Value.Length); + writer.Write(Data.Length); writer.Write(Value); writer.Write(Data); } - public static ModernBlock Decode(BinaryReader reader) + internal static VistaBlock Decode(BinaryReader reader) { uint type = reader.ReadUInt32(); uint flags = reader.ReadUInt32(); - uint valueLen = reader.ReadUInt32(); - uint dataLen = reader.ReadUInt32(); - uint unk3 = reader.ReadUInt32(); - - byte[] value = reader.ReadBytes((int)valueLen); - byte[] data = reader.ReadBytes((int)dataLen); + int valueLen = reader.ReadInt32(); + int dataLen = reader.ReadInt32(); - return new ModernBlock + byte[] value = reader.ReadBytes(valueLen); + byte[] data = reader.ReadBytes(dataLen); + return new VistaBlock { Type = (BlockType)type, Flags = flags, - Unknown = unk3, Value = value, Data = data, }; } } - public sealed class PhysicalStoreModern : IPhysicalStore + public sealed class PhysicalStoreVista : IPhysicalStore { - private byte[] PreHeaderBytes = new byte[] { }; - private readonly Dictionary> Data = new Dictionary>(); - private readonly FileStream TSFile; - private readonly PSVersion Version; + private byte[] PreHeaderBytes = { }; + private readonly List Blocks = new List(); + private readonly FileStream TSPrimary; + private readonly FileStream TSSecondary; private readonly bool Production; public byte[] Serialize() { BinaryWriter writer = new BinaryWriter(new MemoryStream()); writer.Write(PreHeaderBytes); - writer.Write(Data.Keys.Count); - foreach (string key in Data.Keys) + foreach (VistaBlock block in Blocks) { - List blocks = Data[key]; - byte[] keyNameEnc = Utils.EncodeString(key); - - writer.Write(keyNameEnc.Length); - writer.Write(keyNameEnc); - writer.Write(blocks.Count); + block.Encode(writer); writer.Align(4); - - foreach (ModernBlock block in blocks) - { - block.Encode(writer); - writer.Align(4); - } } return writer.GetBytes(); @@ -7991,43 +8855,24 @@ namespace LibTSforge.PhysicalStore public void Deserialize(byte[] data) { + int len = data.Length; + BinaryReader reader = new BinaryReader(new MemoryStream(data)); PreHeaderBytes = reader.ReadBytes(8); - while (reader.BaseStream.Position < data.Length - 0x4) + while (reader.BaseStream.Position < len - 0x14) { - uint numKeys = reader.ReadUInt32(); - - for (int i = 0; i < numKeys; i++) - { - uint lenKeyName = reader.ReadUInt32(); - string keyName = Utils.DecodeString(reader.ReadBytes((int)lenKeyName)); uint numValues = reader.ReadUInt32(); - - reader.Align(4); - - Data[keyName] = new List(); - - for (int j = 0; j < numValues; j++) - { - Data[keyName].Add(ModernBlock.Decode(reader)); - reader.Align(4); - } - } + Blocks.Add(VistaBlock.Decode(reader)); + reader.Align(4); } } public void AddBlock(PSBlock block) { - if (!Data.ContainsKey(block.KeyAsStr)) - { - Data[block.KeyAsStr] = new List(); - } - - Data[block.KeyAsStr].Add(new ModernBlock + Blocks.Add(new VistaBlock { Type = block.Type, Flags = block.Flags, - Unknown = block.Unknown, Value = block.Value, Data = block.Data }); @@ -8043,9 +8888,7 @@ namespace LibTSforge.PhysicalStore public PSBlock GetBlock(string key, string value) { - List blocks = Data[key]; - - foreach (ModernBlock block in blocks) + foreach (VistaBlock block in Blocks) { if (block.ValueAsStr == value) { @@ -8053,7 +8896,7 @@ namespace LibTSforge.PhysicalStore { Type = block.Type, Flags = block.Flags, - Key = Utils.EncodeString(key), + Key = new byte[0], Value = block.Value, Data = block.Data }; @@ -8065,9 +8908,7 @@ namespace LibTSforge.PhysicalStore public PSBlock GetBlock(string key, uint value) { - List blocks = Data[key]; - - foreach (ModernBlock block in blocks) + foreach (VistaBlock block in Blocks) { if (block.ValueAsInt == value) { @@ -8075,7 +8916,7 @@ namespace LibTSforge.PhysicalStore { Type = block.Type, Flags = block.Flags, - Key = Utils.EncodeString(key), + Key = new byte[0], Value = block.Value, Data = block.Data }; @@ -8087,40 +8928,32 @@ namespace LibTSforge.PhysicalStore public void SetBlock(string key, string value, byte[] data) { - List blocks = Data[key]; - - for (int i = 0; i < blocks.Count; i++) + for (int i = 0; i < Blocks.Count; i++) { - ModernBlock block = blocks[i]; + VistaBlock block = Blocks[i]; if (block.ValueAsStr == value) { block.Data = data; - blocks[i] = block; + Blocks[i] = block; break; } } - - Data[key] = blocks; } public void SetBlock(string key, uint value, byte[] data) { - List blocks = Data[key]; - - for (int i = 0; i < blocks.Count; i++) + for (int i = 0; i < Blocks.Count; i++) { - ModernBlock block = blocks[i]; + VistaBlock block = Blocks[i]; if (block.ValueAsInt == value) { block.Data = data; - blocks[i] = block; + Blocks[i] = block; break; } } - - Data[key] = blocks; } public void SetBlock(string key, string value, string data) @@ -8145,100 +8978,98 @@ namespace LibTSforge.PhysicalStore public void DeleteBlock(string key, string value) { - if (Data.ContainsKey(key)) + foreach (VistaBlock block in Blocks) { - List blocks = Data[key]; - - foreach (ModernBlock block in blocks) + if (block.ValueAsStr == value) { - if (block.ValueAsStr == value) - { - blocks.Remove(block); - break; - } + Blocks.Remove(block); + return; } - - Data[key] = blocks; } } public void DeleteBlock(string key, uint value) { - if (Data.ContainsKey(key)) + foreach (VistaBlock block in Blocks) { - List blocks = Data[key]; - - foreach (ModernBlock block in blocks) + if (block.ValueAsInt == value) { - if (block.ValueAsInt == value) - { - blocks.Remove(block); - break; - } + Blocks.Remove(block); + return; } - - Data[key] = blocks; } } - public PhysicalStoreModern(string tsPath, bool production, PSVersion version) + public PhysicalStoreVista(string primaryPath, bool production) { - TSFile = File.Open(tsPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); - Deserialize(PhysStoreCrypto.DecryptPhysicalStore(TSFile.ReadAllBytes(), production)); - TSFile.Seek(0, SeekOrigin.Begin); - Version = version; + 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 (TSFile.CanWrite) + if (TSPrimary.CanWrite && TSSecondary.CanWrite) { - byte[] data = PhysStoreCrypto.EncryptPhysicalStore(Serialize(), Production, Version); - TSFile.SetLength(data.LongLength); - TSFile.Seek(0, SeekOrigin.Begin); - TSFile.WriteAllBytes(data); - TSFile.Close(); + 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(TSFile.ReadAllBytes(), Production); - TSFile.Seek(0, SeekOrigin.Begin); + 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, Version); - TSFile.SetLength(encrData.LongLength); - TSFile.Seek(0, SeekOrigin.Begin); - TSFile.WriteAllBytes(encrData); - TSFile.Close(); + 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 FindBlocks(string valueSearch) { List results = new List(); - foreach (string key in Data.Keys) + foreach (VistaBlock block in Blocks) { - List values = Data[key]; - - foreach (ModernBlock block in values) + if (block.ValueAsStr.Contains(valueSearch)) { - if (block.ValueAsStr.Contains(valueSearch)) + results.Add(new PSBlock { - results.Add(new PSBlock - { - Type = block.Type, - Flags = block.Flags, - KeyAsStr = key, - Value = block.Value, - Data = block.Data - }); - } + Type = block.Type, + Flags = block.Flags, + Key = new byte[0], + Value = block.Value, + Data = block.Data + }); } } @@ -8249,23 +9080,18 @@ namespace LibTSforge.PhysicalStore { List results = new List(); - foreach (string key in Data.Keys) + foreach (VistaBlock block in Blocks) { - List values = Data[key]; - - foreach (ModernBlock block in values) + if (block.ValueAsInt == valueSearch) { - if (block.ValueAsInt == valueSearch) + results.Add(new PSBlock { - results.Add(new PSBlock - { - Type = block.Type, - Flags = block.Flags, - KeyAsStr = key, - Value = block.Value, - Data = block.Data - }); - } + Type = block.Type, + Flags = block.Flags, + Key = new byte[0], + Value = block.Value, + Data = block.Data + }); } } @@ -8281,7 +9107,7 @@ namespace LibTSforge.PhysicalStore using System; using System.Collections.Generic; using System.IO; - using LibTSforge.Crypto; + using Crypto; public class Win7Block { @@ -8383,7 +9209,7 @@ namespace LibTSforge.PhysicalStore public sealed class PhysicalStoreWin7 : IPhysicalStore { - private byte[] PreHeaderBytes = new byte[] { }; + private byte[] PreHeaderBytes = { }; private readonly List Blocks = new List(); private readonly FileStream TSPrimary; private readonly FileStream TSSecondary; @@ -8557,7 +9383,7 @@ namespace LibTSforge.PhysicalStore TSSecondary = File.Open(primaryPath.Replace("-0.", "-1."), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); Production = production; - Deserialize(PhysStoreCrypto.DecryptPhysicalStore(TSPrimary.ReadAllBytes(), production)); + Deserialize(PhysStoreCrypto.DecryptPhysicalStore(TSPrimary.ReadAllBytes(), production, PSVersion.Win7)); TSPrimary.Seek(0, SeekOrigin.Begin); } @@ -8583,7 +9409,7 @@ namespace LibTSforge.PhysicalStore public byte[] ReadRaw() { - byte[] data = PhysStoreCrypto.DecryptPhysicalStore(TSPrimary.ReadAllBytes(), Production); + byte[] data = PhysStoreCrypto.DecryptPhysicalStore(TSPrimary.ReadAllBytes(), Production, PSVersion.Win7); TSPrimary.Seek(0, SeekOrigin.Begin); return data; } @@ -8666,7 +9492,7 @@ namespace LibTSforge.PhysicalStore BINARY = 1 << 2 } - public class CRCBlock + public abstract class CRCBlock { public CRCBlockType DataType; public byte[] Key; @@ -8705,7 +9531,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(); writer.Write(crc); @@ -8720,7 +9596,7 @@ namespace LibTSforge.PhysicalStore writer.Align(8); } - public static CRCBlock Decode(BinaryReader reader) + public override void Decode(BinaryReader reader) { uint crc = reader.ReadUInt32(); uint type = reader.ReadUInt32(); @@ -8733,22 +9609,17 @@ namespace LibTSforge.PhysicalStore byte[] value = reader.ReadBytes((int)lenVal); reader.Align(8); - CRCBlock block = new CRCBlock - { - DataType = (CRCBlockType)type, - Key = key, - Value = value, - }; + DataType = (CRCBlockType)type; + Key = key; + Value = value; - if (block.CRC() != crc) + if (CRC() != crc) { throw new InvalidDataException("Invalid CRC in variable bag."); } - - return block; } - public uint CRC() + public override uint CRC() { BinaryWriter wtemp = new BinaryWriter(new MemoryStream()); wtemp.Write(0); @@ -8764,8 +9635,9 @@ namespace LibTSforge.PhysicalStore public class VariableBag { public List Blocks = new List(); + private readonly PSVersion Version; - public void Deserialize(byte[] data) + private void Deserialize(byte[] data) { int len = data.Length; @@ -8773,7 +9645,19 @@ namespace LibTSforge.PhysicalStore 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); } } @@ -8783,7 +9667,13 @@ namespace LibTSforge.PhysicalStore foreach (CRCBlock block in Blocks) { - block.Encode(writer); + if (Version == PSVersion.Vista) + { + ((CRCBlockVista)block).Encode(writer); + } else + { + ((CRCBlockModern)block).Encode(writer); + } } return writer.GetBytes(); @@ -8829,14 +9719,15 @@ namespace LibTSforge.PhysicalStore } } - public VariableBag(byte[] data) + public VariableBag(byte[] data, PSVersion version) { + Version = version; Deserialize(data); } - public VariableBag() + public VariableBag(PSVersion version) { - + Version = version; } } } @@ -8866,7 +9757,7 @@ if ($env:_debug -eq '0') { [LibTSforge.Logger]::HideOutput = $true } $ver = [LibTSforge.Utils]::DetectVersion() -$prod = [LibTSforge.Utils]::DetectCurrentKey() +$prod = [LibTSforge.SPP.SPPUtils]::DetectCurrentKey() $tsactids = @($args) function Get-WmiInfo { @@ -8918,7 +9809,7 @@ if ($env:resetstuff -eq $null) { $licenseStatus = Get-WmiInfo -tsactid $tsactid -property "LicenseStatus" if ($licenseStatus -eq 1) { if ($prodDes -match 'KMS' -and $prodDes -notmatch 'CLIENT') { - [LibTSforge.Modifiers.KMSHostCharge]::Charge($ver, $tsactid, $prod) + [LibTSforge.Modifiers.KMSHostCharge]::Charge($ver, $prod, $tsactid) Write-Host "[$prodName] CSVLK is permanently activated with ZeroCID." -ForegroundColor White -BackgroundColor DarkGreen Write-Host "[$prodName] CSVLK is charged with 25 clients for 30 days." -ForegroundColor White -BackgroundColor DarkGreen } diff --git a/MAS/Separate-Files-Version/Activators/TSforge_Activation.cmd b/MAS/Separate-Files-Version/Activators/TSforge_Activation.cmd index 641f92d..350ae2a 100644 --- a/MAS/Separate-Files-Version/Activators/TSforge_Activation.cmd +++ b/MAS/Separate-Files-Version/Activators/TSforge_Activation.cmd @@ -2834,23 +2834,16 @@ $src = @' // Common.cs namespace LibTSforge { - using Microsoft.Win32; using System; using System.IO; using System.Linq; using System.Runtime.InteropServices; - using System.ServiceProcess; using System.Text; - using LibTSforge.Crypto; - using LibTSforge.PhysicalStore; - using LibTSforge.SPP; - using LibTSforge.TokenStore; public enum PSVersion { Vista, Win7, - Win8Early, Win8, WinBlue, WinModern @@ -2921,8 +2914,8 @@ namespace LibTSforge 0x92, 0xA6, 0x56, 0x96 }; - // 2^31 - 1 minutes - public static ulong TimerMax = (ulong)TimeSpan.FromMinutes(2147483647).Ticks; + // 2^31 - 8 minutes + public static readonly ulong TimerMax = (ulong)TimeSpan.FromMinutes(2147483640).Ticks; public static readonly string ZeroCID = new string('0', 48); } @@ -2990,20 +2983,6 @@ namespace LibTSforge } return result; } - - public static T CastToStruct(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 @@ -3024,6 +3003,12 @@ namespace LibTSforge 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) { return Encoding.Unicode.GetString(data).Trim('\0'); @@ -3034,9 +3019,6 @@ namespace LibTSforge return Encoding.Unicode.GetBytes(str + '\0'); } - [DllImport("kernel32.dll")] - public static extern uint GetSystemDefaultLCID(); - public static uint CRC32(byte[] data) { const uint polynomial = 0x04C11DB7; @@ -3060,157 +3042,6 @@ namespace LibTSforge 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() { string arch = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE", EnvironmentVariableTarget.Machine).ToUpperInvariant(); @@ -3226,65 +3057,7 @@ namespace LibTSforge if (build >= 7600 && build <= 7602) return PSVersion.Win7; if (build == 9200) return PSVersion.Win8; - throw new NotSupportedException("Unable to auto-detect version info, please specify one manually using the /ver argument."); - } - - 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."); + throw new NotSupportedException("Unable to auto-detect version info"); } } @@ -3377,8 +3150,8 @@ namespace LibTSforge.SPP public class PKeyConfig { - public Dictionary Products = new Dictionary(); - private List loadedPkeyConfigs = new List(); + public readonly Dictionary Products = new Dictionary(); + private readonly List loadedPkeyConfigs = new List(); public void LoadConfig(Guid actId) { @@ -3439,12 +3212,14 @@ namespace LibTSforge.SPP ranges[refActIdStr] = new List(); } - KeyRange keyRange = new KeyRange(); - keyRange.Start = int.Parse(rangeNode.SelectSingleNode("./p:Start", nsmgr).InnerText); - keyRange.End = int.Parse(rangeNode.SelectSingleNode("./p:End", nsmgr).InnerText); - keyRange.EulaType = rangeNode.SelectSingleNode("./p:EulaType", nsmgr).InnerText; - keyRange.PartNumber = rangeNode.SelectSingleNode("./p:PartNumber", nsmgr).InnerText; - keyRange.Valid = rangeNode.SelectSingleNode("./p:IsValid", nsmgr).InnerText.ToLower() == "true"; + KeyRange keyRange = new KeyRange + { + Start = int.Parse(rangeNode.SelectSingleNode("./p:Start", nsmgr).InnerText), + End = int.Parse(rangeNode.SelectSingleNode("./p:End", nsmgr).InnerText), + EulaType = rangeNode.SelectSingleNode("./p:EulaType", nsmgr).InnerText, + PartNumber = rangeNode.SelectSingleNode("./p:PartNumber", nsmgr).InnerText, + Valid = rangeNode.SelectSingleNode("./p:IsValid", nsmgr).InnerText.ToLower() == "true" + }; ranges[refActIdStr].Add(keyRange); } @@ -3458,15 +3233,17 @@ namespace LibTSforge.SPP if (keyRanges.Count > 0 && !Products.ContainsKey(refActId)) { - ProductConfig productConfig = new ProductConfig(); - productConfig.GroupId = group; - productConfig.Edition = configNode.SelectSingleNode("./p:EditionId", nsmgr).InnerText; - productConfig.Description = configNode.SelectSingleNode("./p:ProductDescription", nsmgr).InnerText; - productConfig.Channel = configNode.SelectSingleNode("./p:ProductKeyType", nsmgr).InnerText; - productConfig.Randomized = configNode.SelectSingleNode("./p:ProductKeyType", nsmgr).InnerText.ToLower() == "true"; - productConfig.Algorithm = algorithms[group]; - productConfig.Ranges = keyRanges; - productConfig.ActivationId = refActId; + ProductConfig productConfig = new ProductConfig + { + GroupId = group, + Edition = configNode.SelectSingleNode("./p:EditionId", nsmgr).InnerText, + Description = configNode.SelectSingleNode("./p:ProductDescription", nsmgr).InnerText, + Channel = configNode.SelectSingleNode("./p:ProductKeyType", nsmgr).InnerText, + Randomized = configNode.SelectSingleNode("./p:ProductKeyType", nsmgr).InnerText.ToLower() == "true", + Algorithm = algorithms[group], + Ranges = keyRanges, + ActivationId = refActId + }; Products[refActId] = productConfig; } @@ -3509,11 +3286,6 @@ namespace LibTSforge.SPP } } } - - public PKeyConfig() - { - - } } } @@ -3524,8 +3296,8 @@ namespace LibTSforge.SPP using System; using System.IO; using System.Linq; - using LibTSforge.Crypto; - using LibTSforge.PhysicalStore; + using Crypto; + using PhysicalStore; public class ProductKey { @@ -3539,11 +3311,11 @@ namespace LibTSforge.SPP public ulong Security; public bool Upgrade; public PKeyAlgorithm Algorithm; - public string EulaType; - public string PartNumber; - public string Edition; - public string Channel; - public Guid ActivationId; + public readonly string EulaType; + public readonly string PartNumber; + public readonly string Edition; + public readonly string Channel; + public readonly Guid ActivationId; private string mpc; private string pid2; @@ -3553,6 +3325,11 @@ namespace LibTSforge.SPP get { return BitConverter.GetBytes(klow).Concat(BitConverter.GetBytes(khigh)).ToArray(); } } + public ProductKey() + { + + } + public ProductKey(int serial, ulong security, bool upgrade, PKeyAlgorithm algorithm, ProductConfig config, KeyRange range) { Group = config.GroupId; @@ -3581,22 +3358,22 @@ namespace LibTSforge.SPP public Guid GetPkeyId() { - VariableBag pkb = new VariableBag(); - pkb.Blocks.AddRange(new CRCBlock[] + VariableBag pkb = new VariableBag(PSVersion.WinModern); + pkb.Blocks.AddRange(new[] { - new CRCBlock + new CRCBlockModern { DataType = CRCBlockType.STRING, KeyAsStr = "SppPkeyBindingProductKey", ValueAsStr = ToString() }, - new CRCBlock + new CRCBlockModern { DataType = CRCBlockType.BINARY, KeyAsStr = "SppPkeyBindingMiscData", Value = new byte[] { } }, - new CRCBlock + new CRCBlockModern { DataType = CRCBlockType.STRING, KeyAsStr = "SppPkeyBindingAlgorithm", @@ -3607,16 +3384,6 @@ namespace LibTSforge.SPP return new Guid(CryptoUtils.SHA256Hash(pkb.Serialize()).Take(16).ToArray()); } - public string GetDefaultMPC() - { - int build = Environment.OSVersion.Version.Build; - string defaultMPC = build >= 10240 ? "03612" : - build >= 9600 ? "06401" : - build >= 9200 ? "05426" : - "55041"; - return defaultMPC; - } - public string GetMPC() { if (mpc != null) @@ -3624,10 +3391,15 @@ namespace LibTSforge.SPP return mpc; } - mpc = GetDefaultMPC(); + int build = Environment.OSVersion.Version.Build; + + mpc = build >= 10240 ? "03612" : + build >= 9600 ? "06401" : + build >= 9200 ? "05426" : + "55041"; // setup.cfg doesn't exist in Windows 8+ - string setupcfg = string.Format("{0}\\oobe\\{1}", Environment.SystemDirectory, "setup.cfg"); + string setupcfg = string.Format(@"{0}\oobe\{1}", Environment.SystemDirectory, "setup.cfg"); if (!File.Exists(setupcfg) || Edition.Contains(";")) { @@ -3765,17 +3537,17 @@ namespace LibTSforge.SPP { if (version == PSVersion.Win7) { - Random rnd = new Random(Group * 1000000000 + Serial); - byte[] data = new byte[8]; - rnd.NextBytes(data); - return data; + ulong shortauth = ((ulong)Group << 41) | (Security << 31) | ((ulong)Serial << 1) | (Upgrade ? (ulong)1 : 0); + return BitConverter.GetBytes(shortauth); } int serialHigh = Serial / 1000000; int serialLow = Serial % 1000000; BinaryWriter writer = new BinaryWriter(new MemoryStream()); - writer.Write(new Guid("B8731595-A2F6-430B-A799-FBFFB81A8D73").ToByteArray()); + string algoId = Algorithm == PKeyAlgorithm.PKEY2005 ? "B8731595-A2F6-430B-A799-FBFFB81A8D73" : "660672EF-7809-4CFD-8D54-41B7FB738988"; + + writer.Write(new Guid(algoId).ToByteArray()); writer.Write(Group); writer.Write(serialHigh); writer.Write(serialLow); @@ -3881,40 +3653,40 @@ namespace LibTSforge.SPP public static readonly Guid WINDOWS_APP_ID = new Guid("55c92734-d682-4d71-983e-d6ec3f16059f"); - [DllImport("sppc.dll", CharSet = CharSet.Unicode, PreserveSig = false)] + [DllImport("slc.dll", CharSet = CharSet.Unicode, PreserveSig = false)] private static extern void SLOpen(out IntPtr hSLC); - [DllImport("sppc.dll", CharSet = CharSet.Unicode, PreserveSig = false)] + [DllImport("slc.dll", CharSet = CharSet.Unicode, PreserveSig = false)] private static extern void SLClose(IntPtr hSLC); [DllImport("slc.dll", CharSet = CharSet.Unicode)] private static extern uint SLGetWindowsInformationDWORD(string ValueName, ref int Value); - [DllImport("sppc.dll", CharSet = CharSet.Unicode)] + [DllImport("slc.dll", CharSet = CharSet.Unicode)] private static extern uint SLInstallProofOfPurchase(IntPtr hSLC, string pwszPKeyAlgorithm, string pwszPKeyString, uint cbPKeySpecificData, byte[] pbPKeySpecificData, ref Guid PKeyId); - [DllImport("sppc.dll", CharSet = CharSet.Unicode)] + [DllImport("slc.dll", CharSet = CharSet.Unicode)] private static extern uint SLUninstallProofOfPurchase(IntPtr hSLC, ref Guid PKeyId); - [DllImport("sppc.dll", CharSet = CharSet.Unicode)] + [DllImport("slc.dll", CharSet = CharSet.Unicode)] private static extern uint SLGetPKeyInformation(IntPtr hSLC, ref Guid pPKeyId, string pwszValueName, out SLDATATYPE peDataType, out uint pcbValue, out IntPtr ppbValue); - [DllImport("sppcext.dll", CharSet = CharSet.Unicode)] + [DllImport("slcext.dll", CharSet = CharSet.Unicode)] private static extern uint SLActivateProduct(IntPtr hSLC, ref Guid pProductSkuId, byte[] cbAppSpecificData, byte[] pvAppSpecificData, byte[] pActivationInfo, string pwszProxyServer, ushort wProxyPort); - [DllImport("sppc.dll", CharSet = CharSet.Unicode)] + [DllImport("slc.dll", CharSet = CharSet.Unicode)] private static extern uint SLGenerateOfflineInstallationId(IntPtr hSLC, ref Guid pProductSkuId, ref string ppwszInstallationId); - [DllImport("sppc.dll", CharSet = CharSet.Unicode)] + [DllImport("slc.dll", CharSet = CharSet.Unicode)] private static extern uint SLDepositOfflineConfirmationId(IntPtr hSLC, ref Guid pProductSkuId, string pwszInstallationId, string pwszConfirmationId); - [DllImport("sppc.dll", CharSet = CharSet.Unicode)] + [DllImport("slc.dll", CharSet = CharSet.Unicode)] private static extern uint SLGetSLIDList(IntPtr hSLC, SLIDTYPE eQueryIdType, ref Guid pQueryId, SLIDTYPE eReturnIdType, out uint pnReturnIds, out IntPtr ppReturnIds); - [DllImport("sppc.dll", CharSet = CharSet.Unicode, PreserveSig = false)] + [DllImport("slc.dll", CharSet = CharSet.Unicode, PreserveSig = false)] private static extern void SLGetLicensingStatusInformation(IntPtr hSLC, ref Guid pAppID, IntPtr pProductSkuId, string pwszRightName, out uint pnStatusCount, out IntPtr ppLicensingStatus); - [DllImport("sppc.dll", CharSet = CharSet.Unicode)] + [DllImport("slc.dll", CharSet = CharSet.Unicode)] private static extern uint SLGetInstalledProductKeyIds(IntPtr hSLC, ref Guid pProductSkuId, out uint pnProductKeyIds, out IntPtr ppProductKeyIds); [DllImport("slc.dll", CharSet = CharSet.Unicode)] @@ -3923,9 +3695,6 @@ namespace LibTSforge.SPP [DllImport("slc.dll", CharSet = CharSet.Unicode)] private static extern uint SLGetProductSkuInformation(IntPtr hSLC, ref Guid pProductSkuId, string pwszValueName, out SLDATATYPE peDataType, out uint pcbValue, out IntPtr ppbValue); - [DllImport("slc.dll", CharSet = CharSet.Unicode)] - private static extern uint SLGetProductSkuInformation(IntPtr hSLC, ref Guid pProductSkuId, string pwszValueName, IntPtr peDataType, out uint pcbValue, out IntPtr ppbValue); - [DllImport("slc.dll", CharSet = CharSet.Unicode)] private static extern uint SLGetLicense(IntPtr hSLC, ref Guid pLicenseFileId, out uint pcbLicenseFile, out IntPtr ppbLicenseFile); @@ -3935,7 +3704,7 @@ namespace LibTSforge.SPP [DllImport("slc.dll", CharSet = CharSet.Unicode)] private static extern uint SLFireEvent(IntPtr hSLC, string pwszEventId, ref Guid pApplicationId); - public class SLContext : IDisposable + private class SLContext : IDisposable { public readonly IntPtr Handle; @@ -3998,11 +3767,10 @@ namespace LibTSforge.SPP { using (SLContext sl = new SLContext()) { - uint status; uint count; IntPtr pProductKeyIds; - status = SLGetInstalledProductKeyIds(sl.Handle, ref actId, out count, out pProductKeyIds); + uint status = SLGetSLIDList(sl.Handle, SLIDTYPE.SL_ID_PRODUCT_SKU, ref actId, SLIDTYPE.SL_ID_PKEY, out count, out pProductKeyIds); if (status != 0 || count == 0) { @@ -4026,7 +3794,7 @@ namespace LibTSforge.SPP SLConsumeWindowsRight(0); } - public static bool RefreshTrustedTime(Guid actId) + public static void RefreshTrustedTime(Guid actId) { using (SLContext sl = new SLContext()) { @@ -4034,8 +3802,7 @@ namespace LibTSforge.SPP uint count; IntPtr ppbValue; - uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "TrustedTime", out type, out count, out ppbValue); - return (int)status >= 0 && status != 0xC004F012; + SLGetProductSkuInformation(sl.Handle, ref actId, "TrustedTime", out type, out count, out ppbValue); } } @@ -4051,11 +3818,10 @@ namespace LibTSforge.SPP { using (SLContext sl = new SLContext()) { - uint status; uint count; IntPtr pAppIds; - status = SLGetSLIDList(sl.Handle, SLIDTYPE.SL_ID_PRODUCT_SKU, ref actId, SLIDTYPE.SL_ID_APPLICATION, out count, out pAppIds); + uint status = SLGetSLIDList(sl.Handle, SLIDTYPE.SL_ID_PRODUCT_SKU, ref actId, SLIDTYPE.SL_ID_APPLICATION, out count, out pAppIds); if (status != 0 || count == 0) { @@ -4083,11 +3849,10 @@ namespace LibTSforge.SPP { using (SLContext sl = new SLContext()) { - uint status; uint count; IntPtr ppReturnLics; - status = SLGetSLIDList(sl.Handle, SLIDTYPE.SL_ID_LICENSE, ref licId, SLIDTYPE.SL_ID_LICENSE_FILE, out count, out ppReturnLics); + uint status = SLGetSLIDList(sl.Handle, SLIDTYPE.SL_ID_LICENSE, ref licId, SLIDTYPE.SL_ID_LICENSE_FILE, out count, out ppReturnLics); if (status != 0 || count == 0) { @@ -4149,7 +3914,7 @@ namespace LibTSforge.SPP IntPtr ppbValue; uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "msft:sl/EUL/PHONE/PUBLIC", out type, out count, out ppbValue); - return status >= 0 && status != 0xC004F012; + return status != 0xC004F012; } } @@ -4232,11 +3997,11 @@ namespace LibTSforge.SPP } } - public static uint UninstallProductKey(Guid pkeyId) + public static void UninstallProductKey(Guid pkeyId) { using (SLContext sl = new SLContext()) { - return SLUninstallProofOfPurchase(sl.Handle, ref pkeyId); + SLUninstallProofOfPurchase(sl.Handle, ref pkeyId); } } @@ -4254,1509 +4019,2624 @@ namespace LibTSforge.SPP } -// Crypto/CryptoUtils.cs -namespace LibTSforge.Crypto +// SPP/SPPUtils.cs +namespace LibTSforge.SPP { + using Microsoft.Win32; using System; + using System.IO; using System.Linq; - using System.Security.Cryptography; + using System.ServiceProcess; + using Crypto; + using PhysicalStore; + using TokenStore; - public static class CryptoUtils + public static class SPPUtils { - public static byte[] GenerateRandomKey(int len) + public static void KillSPP(PSVersion version) { - byte[] rand = new byte[len]; - Random r = new Random(); - r.NextBytes(rand); + ServiceController sc; - return rand; - } + string svcName = version == PSVersion.Vista ? "slsvc" : "sppsvc"; - public static byte[] AESEncrypt(byte[] data, byte[] key) - { - using (Aes aes = Aes.Create()) + try { - aes.Key = key; - aes.Mode = CipherMode.CBC; - aes.Padding = PaddingMode.PKCS7; + sc = new ServiceController(svcName); - ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, Enumerable.Repeat((byte)0, 16).ToArray()); - byte[] encryptedData = encryptor.TransformFinalBlock(data, 0, data.Length); - return encryptedData; + if (sc.Status == ServiceControllerStatus.Stopped) + return; } - } - - public static byte[] AESDecrypt(byte[] data, byte[] key) - { - using (Aes aes = Aes.Create()) + catch (InvalidOperationException ex) { - aes.Key = key; - aes.Mode = CipherMode.CBC; - aes.Padding = PaddingMode.PKCS7; - - ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, Enumerable.Repeat((byte)0, 16).ToArray()); - byte[] decryptedData = decryptor.TransformFinalBlock(data, 0, data.Length); - return decryptedData; + throw new InvalidOperationException(string.Format("Unable to access {0}: ", svcName) + ex.Message); } - } - public static byte[] RSADecrypt(byte[] rsaKey, byte[] data) - { + Logger.WriteLine(string.Format("Stopping {0}...", svcName)); - using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) - { - rsa.ImportCspBlob(rsaKey); - return rsa.Decrypt(data, false); - } - } + bool stopped = false; - public static byte[] RSAEncrypt(byte[] rsaKey, byte[] data) - { - using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) + for (int i = 0; stopped == false && i < 1080; i++) { - rsa.ImportCspBlob(rsaKey); - return rsa.Encrypt(data, false); + 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; } - } - public static byte[] RSASign(byte[] rsaKey, byte[] data) - { - using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) + 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()) { - rsa.ImportCspBlob(rsaKey); - RSAPKCS1SignatureFormatter formatter = new RSAPKCS1SignatureFormatter(rsa); - formatter.SetHashAlgorithm("SHA1"); + Logger.WriteLine("Unloading spsys..."); - byte[] hash; - using (SHA1 sha1 = SHA1.Create()) + int status = SPSys.ControlSpSys(false); + + if (status < 0) { - hash = sha1.ComputeHash(data); + throw new IOException("Failed to unload spsys"); } - return formatter.CreateSignature(hash); + Logger.WriteLine("spsys unloaded successfully."); } } - public static bool RSAVerifySignature(byte[] rsaKey, byte[] data, byte[] signature) + public static void RestartSPP(PSVersion version) { - using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) + if (version == PSVersion.Vista) { - rsa.ImportCspBlob(rsaKey); - RSAPKCS1SignatureDeformatter deformatter = new RSAPKCS1SignatureDeformatter(rsa); - deformatter.SetHashAlgorithm("SHA1"); + ServiceController sc; - byte[] hash; - using (SHA1 sha1 = SHA1.Create()) + try { - hash = sha1.ComputeHash(data); - } + sc = new ServiceController("slsvc"); - return deformatter.VerifySignature(hash, signature); - } - } + if (sc.Status == ServiceControllerStatus.Running) + return; + } + catch (InvalidOperationException ex) + { + throw new InvalidOperationException("Unable to access slsvc: " + ex.Message); + } - public static byte[] HMACSign(byte[] key, byte[] data) - { - HMACSHA1 hmac = new HMACSHA1(key); - return hmac.ComputeHash(data); - } + Logger.WriteLine("Starting slsvc..."); - public static bool HMACVerify(byte[] key, byte[] data, byte[] signature) - { - HMACSHA1 hmac = new HMACSHA1(key); - return Enumerable.SequenceEqual(signature, HMACSign(key, data)); - } + bool started = false; - public static byte[] SHA256Hash(byte[] data) - { - using (SHA256 sha256 = SHA256.Create()) - { - return sha256.ComputeHash(data); - } - } - } -} + 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; + } -// Crypto/Keys.cs -namespace LibTSforge.Crypto -{ - public static class Keys - { - public static readonly byte[] PRODUCTION = { - 0x07, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32, 0x00, 0x04, 0x00, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x29, 0x87, 0xBA, 0x3F, 0x52, 0x90, 0x57, 0xD8, 0x12, 0x26, 0x6B, 0x38, - 0xB2, 0x3B, 0xF9, 0x67, 0x08, 0x4F, 0xDD, 0x8B, 0xF5, 0xE3, 0x11, 0xB8, 0x61, 0x3A, 0x33, 0x42, - 0x51, 0x65, 0x05, 0x86, 0x1E, 0x00, 0x41, 0xDE, 0xC5, 0xDD, 0x44, 0x60, 0x56, 0x3D, 0x14, 0x39, - 0xB7, 0x43, 0x65, 0xE9, 0xF7, 0x2B, 0xA5, 0xF0, 0xA3, 0x65, 0x68, 0xE9, 0xE4, 0x8B, 0x5C, 0x03, - 0x2D, 0x36, 0xFE, 0x28, 0x4C, 0xD1, 0x3C, 0x3D, 0xC1, 0x90, 0x75, 0xF9, 0x6E, 0x02, 0xE0, 0x58, - 0x97, 0x6A, 0xCA, 0x80, 0x02, 0x42, 0x3F, 0x6C, 0x15, 0x85, 0x4D, 0x83, 0x23, 0x6A, 0x95, 0x9E, - 0x38, 0x52, 0x59, 0x38, 0x6A, 0x99, 0xF0, 0xB5, 0xCD, 0x53, 0x7E, 0x08, 0x7C, 0xB5, 0x51, 0xD3, - 0x8F, 0xA3, 0x0D, 0xA0, 0xFA, 0x8D, 0x87, 0x3C, 0xFC, 0x59, 0x21, 0xD8, 0x2E, 0xD9, 0x97, 0x8B, - 0x40, 0x60, 0xB1, 0xD7, 0x2B, 0x0A, 0x6E, 0x60, 0xB5, 0x50, 0xCC, 0x3C, 0xB1, 0x57, 0xE4, 0xB7, - 0xDC, 0x5A, 0x4D, 0xE1, 0x5C, 0xE0, 0x94, 0x4C, 0x5E, 0x28, 0xFF, 0xFA, 0x80, 0x6A, 0x13, 0x53, - 0x52, 0xDB, 0xF3, 0x04, 0x92, 0x43, 0x38, 0xB9, 0x1B, 0xD9, 0x85, 0x54, 0x7B, 0x14, 0xC7, 0x89, - 0x16, 0x8A, 0x4B, 0x82, 0xA1, 0x08, 0x02, 0x99, 0x23, 0x48, 0xDD, 0x75, 0x9C, 0xC8, 0xC1, 0xCE, - 0xB0, 0xD7, 0x1B, 0xD8, 0xFB, 0x2D, 0xA7, 0x2E, 0x47, 0xA7, 0x18, 0x4B, 0xF6, 0x29, 0x69, 0x44, - 0x30, 0x33, 0xBA, 0xA7, 0x1F, 0xCE, 0x96, 0x9E, 0x40, 0xE1, 0x43, 0xF0, 0xE0, 0x0D, 0x0A, 0x32, - 0xB4, 0xEE, 0xA1, 0xC3, 0x5E, 0x9B, 0xC7, 0x7F, 0xF5, 0x9D, 0xD8, 0xF2, 0x0F, 0xD9, 0x8F, 0xAD, - 0x75, 0x0A, 0x00, 0xD5, 0x25, 0x43, 0xF7, 0xAE, 0x51, 0x7F, 0xB7, 0xDE, 0xB7, 0xAD, 0xFB, 0xCE, - 0x83, 0xE1, 0x81, 0xFF, 0xDD, 0xA2, 0x77, 0xFE, 0xEB, 0x27, 0x1F, 0x10, 0xFA, 0x82, 0x37, 0xF4, - 0x7E, 0xCC, 0xE2, 0xA1, 0x58, 0xC8, 0xAF, 0x1D, 0x1A, 0x81, 0x31, 0x6E, 0xF4, 0x8B, 0x63, 0x34, - 0xF3, 0x05, 0x0F, 0xE1, 0xCC, 0x15, 0xDC, 0xA4, 0x28, 0x7A, 0x9E, 0xEB, 0x62, 0xD8, 0xD8, 0x8C, - 0x85, 0xD7, 0x07, 0x87, 0x90, 0x2F, 0xF7, 0x1C, 0x56, 0x85, 0x2F, 0xEF, 0x32, 0x37, 0x07, 0xAB, - 0xB0, 0xE6, 0xB5, 0x02, 0x19, 0x35, 0xAF, 0xDB, 0xD4, 0xA2, 0x9C, 0x36, 0x80, 0xC6, 0xDC, 0x82, - 0x08, 0xE0, 0xC0, 0x5F, 0x3C, 0x59, 0xAA, 0x4E, 0x26, 0x03, 0x29, 0xB3, 0x62, 0x58, 0x41, 0x59, - 0x3A, 0x37, 0x43, 0x35, 0xE3, 0x9F, 0x34, 0xE2, 0xA1, 0x04, 0x97, 0x12, 0x9D, 0x8C, 0xAD, 0xF7, - 0xFB, 0x8C, 0xA1, 0xA2, 0xE9, 0xE4, 0xEF, 0xD9, 0xC5, 0xE5, 0xDF, 0x0E, 0xBF, 0x4A, 0xE0, 0x7A, - 0x1E, 0x10, 0x50, 0x58, 0x63, 0x51, 0xE1, 0xD4, 0xFE, 0x57, 0xB0, 0x9E, 0xD7, 0xDA, 0x8C, 0xED, - 0x7D, 0x82, 0xAC, 0x2F, 0x25, 0x58, 0x0A, 0x58, 0xE6, 0xA4, 0xF4, 0x57, 0x4B, 0xA4, 0x1B, 0x65, - 0xB9, 0x4A, 0x87, 0x46, 0xEB, 0x8C, 0x0F, 0x9A, 0x48, 0x90, 0xF9, 0x9F, 0x76, 0x69, 0x03, 0x72, - 0x77, 0xEC, 0xC1, 0x42, 0x4C, 0x87, 0xDB, 0x0B, 0x3C, 0xD4, 0x74, 0xEF, 0xE5, 0x34, 0xE0, 0x32, - 0x45, 0xB0, 0xF8, 0xAB, 0xD5, 0x26, 0x21, 0xD7, 0xD2, 0x98, 0x54, 0x8F, 0x64, 0x88, 0x20, 0x2B, - 0x14, 0xE3, 0x82, 0xD5, 0x2A, 0x4B, 0x8F, 0x4E, 0x35, 0x20, 0x82, 0x7E, 0x1B, 0xFE, 0xFA, 0x2C, - 0x79, 0x6C, 0x6E, 0x66, 0x94, 0xBB, 0x0A, 0xEB, 0xBA, 0xD9, 0x70, 0x61, 0xE9, 0x47, 0xB5, 0x82, - 0xFC, 0x18, 0x3C, 0x66, 0x3A, 0x09, 0x2E, 0x1F, 0x61, 0x74, 0xCA, 0xCB, 0xF6, 0x7A, 0x52, 0x37, - 0x1D, 0xAC, 0x8D, 0x63, 0x69, 0x84, 0x8E, 0xC7, 0x70, 0x59, 0xDD, 0x2D, 0x91, 0x1E, 0xF7, 0xB1, - 0x56, 0xED, 0x7A, 0x06, 0x9D, 0x5B, 0x33, 0x15, 0xDD, 0x31, 0xD0, 0xE6, 0x16, 0x07, 0x9B, 0xA5, - 0x94, 0x06, 0x7D, 0xC1, 0xE9, 0xD6, 0xC8, 0xAF, 0xB4, 0x1E, 0x2D, 0x88, 0x06, 0xA7, 0x63, 0xB8, - 0xCF, 0xC8, 0xA2, 0x6E, 0x84, 0xB3, 0x8D, 0xE5, 0x47, 0xE6, 0x13, 0x63, 0x8E, 0xD1, 0x7F, 0xD4, - 0x81, 0x44, 0x38, 0xBF - }; + started = true; + } - public static readonly byte[] TEST = { - 0x07, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32, 0x00, 0x04, 0x00, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x0F, 0xBE, 0x77, 0xB8, 0xDD, 0x54, 0x36, 0xDD, 0x67, 0xD4, 0x17, 0x66, - 0xC4, 0x13, 0xD1, 0x3F, 0x1E, 0x16, 0x0C, 0x16, 0x35, 0xAB, 0x6D, 0x3D, 0x34, 0x51, 0xED, 0x3F, - 0x57, 0x14, 0xB6, 0xB7, 0x08, 0xE9, 0xD9, 0x7A, 0x80, 0xB3, 0x5F, 0x9B, 0x3A, 0xFD, 0x9E, 0x37, - 0x3A, 0x53, 0x72, 0x67, 0x92, 0x60, 0xC3, 0xEF, 0xB5, 0x8E, 0x1E, 0xCF, 0x9D, 0x9C, 0xD3, 0x90, - 0xE5, 0xDD, 0xF4, 0xDB, 0xF3, 0xD6, 0x65, 0xB3, 0xC1, 0xBD, 0x69, 0xE1, 0x76, 0x95, 0xD9, 0x37, - 0xB8, 0x5E, 0xCA, 0x3D, 0x98, 0xFC, 0x50, 0x5C, 0x98, 0xAE, 0xE3, 0x7C, 0x4C, 0x27, 0xC3, 0xD0, - 0xCE, 0x78, 0x06, 0x51, 0x68, 0x23, 0xE6, 0x70, 0xF8, 0x7C, 0xAE, 0x36, 0xBE, 0x41, 0x57, 0xE2, - 0xC3, 0x2D, 0xAF, 0x21, 0xB1, 0xB3, 0x15, 0x81, 0x19, 0x26, 0x6B, 0x10, 0xB3, 0xE9, 0xD1, 0x45, - 0x21, 0x77, 0x9C, 0xF6, 0xE1, 0xDD, 0xB6, 0x78, 0x9D, 0x1D, 0x32, 0x61, 0xBC, 0x2B, 0xDB, 0x86, - 0xFB, 0x07, 0x24, 0x10, 0x19, 0x4F, 0x09, 0x6D, 0x03, 0x90, 0xD4, 0x5E, 0x30, 0x85, 0xC5, 0x58, - 0x7E, 0x5D, 0xAE, 0x9F, 0x64, 0x93, 0x04, 0x82, 0x09, 0x0E, 0x1C, 0x66, 0xA8, 0x95, 0x91, 0x51, - 0xB2, 0xED, 0x9A, 0x75, 0x04, 0x87, 0x50, 0xAC, 0xCC, 0x20, 0x06, 0x45, 0xB9, 0x7B, 0x42, 0x53, - 0x9A, 0xD1, 0x29, 0xFC, 0xEF, 0xB9, 0x47, 0x16, 0x75, 0x69, 0x05, 0x87, 0x2B, 0xCB, 0x54, 0x9C, - 0x21, 0x2D, 0x50, 0x8E, 0x12, 0xDE, 0xD3, 0x6B, 0xEC, 0x92, 0xA1, 0xB1, 0xE9, 0x4B, 0xBF, 0x6B, - 0x9A, 0x38, 0xC7, 0x13, 0xFA, 0x78, 0xA1, 0x3C, 0x1E, 0xBB, 0x38, 0x31, 0xBB, 0x0C, 0x9F, 0x70, - 0x1A, 0x31, 0x00, 0xD7, 0x5A, 0xA5, 0x84, 0x24, 0x89, 0x80, 0xF5, 0x88, 0xC2, 0x31, 0x18, 0xDC, - 0x53, 0x05, 0x5D, 0xFA, 0x81, 0xDC, 0xE1, 0xCE, 0xA4, 0xAA, 0xBA, 0x07, 0xDA, 0x28, 0x4F, 0x64, - 0x0E, 0x84, 0x9B, 0x06, 0xDE, 0xC8, 0x78, 0x66, 0x2F, 0x17, 0x25, 0xA8, 0x9C, 0x99, 0xFC, 0xBC, - 0x7D, 0x01, 0x42, 0xD7, 0x35, 0xBF, 0x19, 0xF6, 0x3F, 0x20, 0xD9, 0x98, 0x9B, 0x5D, 0xDD, 0x39, - 0xBE, 0x81, 0x00, 0x0B, 0xDE, 0x6F, 0x14, 0xCA, 0x7E, 0xF8, 0xC0, 0x26, 0xA8, 0x1D, 0xD1, 0x16, - 0x88, 0x64, 0x87, 0x36, 0x45, 0x37, 0x50, 0xDA, 0x6C, 0xEB, 0x85, 0xB5, 0x43, 0x29, 0x88, 0x6F, - 0x2F, 0xFE, 0x8D, 0x12, 0x8B, 0x72, 0xB7, 0x5A, 0xCB, 0x66, 0xC2, 0x2E, 0x1D, 0x7D, 0x42, 0xA6, - 0xF4, 0xFE, 0x26, 0x5D, 0x54, 0x9E, 0x77, 0x1D, 0x97, 0xC2, 0xF3, 0xFD, 0x60, 0xB3, 0x22, 0x88, - 0xCA, 0x27, 0x99, 0xDF, 0xC8, 0xB1, 0xD7, 0xC6, 0x54, 0xA6, 0x50, 0xB9, 0x54, 0xF5, 0xDE, 0xFE, - 0xE1, 0x81, 0xA2, 0xBE, 0x81, 0x9F, 0x48, 0xFF, 0x2F, 0xB8, 0xA4, 0xB3, 0x17, 0xD8, 0xC1, 0xB9, - 0x5D, 0x21, 0x3D, 0xA2, 0xED, 0x1C, 0x96, 0x66, 0xEE, 0x1F, 0x47, 0xCF, 0x62, 0xFA, 0xD6, 0xC1, - 0x87, 0x5B, 0xC4, 0xE5, 0xD9, 0x08, 0x38, 0x22, 0xFA, 0x21, 0xBD, 0xF2, 0x88, 0xDA, 0xE2, 0x24, - 0x25, 0x1F, 0xF1, 0x0B, 0x2D, 0xAE, 0x04, 0xBE, 0xA6, 0x7F, 0x75, 0x8C, 0xD9, 0x97, 0xE1, 0xCA, - 0x35, 0xB9, 0xFC, 0x6F, 0x01, 0x68, 0x11, 0xD3, 0x68, 0x32, 0xD0, 0xC1, 0x69, 0xA3, 0xCF, 0x9B, - 0x10, 0xE4, 0x69, 0xA7, 0xCF, 0xE1, 0xFE, 0x2A, 0x07, 0x9E, 0xC1, 0x37, 0x84, 0x68, 0xE5, 0xC5, - 0xAB, 0x25, 0xEC, 0x7D, 0x7D, 0x74, 0x6A, 0xD1, 0xD5, 0x4D, 0xD7, 0xE1, 0x7D, 0xDE, 0x30, 0x4B, - 0xE6, 0x5D, 0xCD, 0x91, 0x59, 0xF6, 0x80, 0xFD, 0xC6, 0x3C, 0xDD, 0x94, 0x7F, 0x15, 0x9D, 0xEF, - 0x2F, 0x00, 0x62, 0xD7, 0xDA, 0xB9, 0xB3, 0xD9, 0x8D, 0xE8, 0xD7, 0x3C, 0x96, 0x45, 0x5D, 0x1E, - 0x50, 0xFB, 0xAA, 0x43, 0xD3, 0x47, 0x77, 0x81, 0xE9, 0x67, 0xE4, 0xFE, 0xDF, 0x42, 0x79, 0xCB, - 0xA7, 0xAD, 0x5D, 0x48, 0xF5, 0xB7, 0x74, 0x96, 0x12, 0x23, 0x06, 0x70, 0x42, 0x68, 0x7A, 0x44, - 0xFC, 0xA0, 0x31, 0x7F, 0x68, 0xCA, 0xA2, 0x14, 0x5D, 0xA3, 0xCF, 0x42, 0x23, 0xAB, 0x47, 0xF6, - 0xB2, 0xFC, 0x6D, 0xF1 - }; - } -} + if (!started) + throw new System.TimeoutException("Failed to start slsvc"); + Logger.WriteLine("slsvc started successfully."); + } -// Crypto/PhysStoreCrypto.cs -namespace LibTSforge.Crypto -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using System.Text; + SLApi.RefreshLicenseStatus(); + } - public static class PhysStoreCrypto - { - public static byte[] DecryptPhysicalStore(byte[] data, bool production) + public static bool DetectCurrentKey() { - byte[] rsaKey = production ? Keys.PRODUCTION : Keys.TEST; - BinaryReader br = new BinaryReader(new MemoryStream(data)); - br.BaseStream.Seek(0x10, SeekOrigin.Begin); - byte[] aesKeySig = br.ReadBytes(0x80); - byte[] encAesKey = br.ReadBytes(0x80); + SLApi.RefreshLicenseStatus(); - if (CryptoUtils.RSAVerifySignature(rsaKey, encAesKey, aesKeySig)) + using (RegistryKey wpaKey = Registry.LocalMachine.OpenSubKey(@"SYSTEM\WPA")) { - byte[] aesKey = CryptoUtils.RSADecrypt(rsaKey, encAesKey); - 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)) + foreach (string subKey in wpaKey.GetSubKeyNames()) { - Logger.WriteLine("Warning: Failed to verify HMAC. Physical store is either corrupt or in Vista format."); + if (subKey.StartsWith("8DEC0AF1")) + { + return subKey.Contains("P"); + } } - - return psData; } - throw new Exception("Failed to decrypt physical store."); + throw new FileNotFoundException("Failed to autodetect key type, specify physical store key with /prod or /test arguments."); } - public static byte[] EncryptPhysicalStore(byte[] data, bool production, PSVersion version) + public static string GetPSPath(PSVersion version) { - Dictionary versionTable = new Dictionary + switch (version) { - {PSVersion.Win7, 5}, - {PSVersion.Win8, 1}, - {PSVersion.WinBlue, 2}, - {PSVersion.WinModern, 3} - }; - - byte[] rsaKey = production ? Keys.PRODUCTION : Keys.TEST; - - byte[] aesKey = Encoding.UTF8.GetBytes("massgrave.dev :3"); - byte[] hmacKey = CryptoUtils.GenerateRandomKey(0x10); - - byte[] encAesKey = CryptoUtils.RSAEncrypt(rsaKey, aesKey); - byte[] aesKeySig = CryptoUtils.RSASign(rsaKey, encAesKey); - byte[] hmacSig = CryptoUtils.HMACSign(hmacKey, data); + 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"); - byte[] decData = new byte[] { }; - decData = decData.Concat(hmacKey).Concat(hmacSig).Concat(BitConverter.GetBytes(0)).Concat(data).ToArray(); - byte[] encData = CryptoUtils.AESEncrypt(decData, aesKey); + if (string.IsNullOrEmpty(psDir) || !File.Exists(psPath)) + { + string[] psDirs = + { + @"spp\store", + @"spp\store\2.0", + @"spp\store_test", + @"spp\store_test\2.0" + }; - BinaryWriter bw = new BinaryWriter(new MemoryStream()); - bw.Write(versionTable[version]); - bw.Write(Encoding.UTF8.GetBytes("UNTRUSTSTORE")); - bw.Write(aesKeySig); - bw.Write(encAesKey); - bw.Write(encData); + 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; + } - return bw.GetBytes(); + throw new FileNotFoundException("Failed to locate physical store."); + } } - } -} - -// Modifiers/GenPKeyInstall.cs -namespace LibTSforge.Modifiers -{ - using System; - using System.IO; - using Microsoft.Win32; - using LibTSforge.PhysicalStore; - using LibTSforge.SPP; - using LibTSforge.TokenStore; - - public static class GenPKeyInstall - { - private static void WritePkey2005RegistryValues(PSVersion version, ProductKey pkey) + public static string GetTokensPath(PSVersion version) { - Logger.WriteLine("Writing registry data for Windows product key..."); - Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ProductId", pkey.GetPid2()); - Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "DigitalProductId", pkey.GetPid3()); - Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "DigitalProductId4", pkey.GetPid4()); + 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."); + } + } +} + + +// SPP/SPSys.cs +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; + } + } +} + + +// Crypto/CryptoUtils.cs +namespace LibTSforge.Crypto +{ + using System; + using System.Linq; + using System.Security.Cryptography; + + public static class CryptoUtils + { + public static byte[] GenerateRandomKey(int len) + { + byte[] rand = new byte[len]; + Random r = new Random(); + r.NextBytes(rand); + + return rand; + } + + public static byte[] AESEncrypt(byte[] data, byte[] key) + { + using (Aes aes = Aes.Create()) + { + aes.Key = key; + aes.Mode = CipherMode.CBC; + aes.Padding = PaddingMode.PKCS7; + + ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, Enumerable.Repeat((byte)0, 16).ToArray()); + byte[] encryptedData = encryptor.TransformFinalBlock(data, 0, data.Length); + return encryptedData; + } + } + + public static byte[] AESDecrypt(byte[] data, byte[] key) + { + using (Aes aes = Aes.Create()) + { + aes.Key = key; + aes.Mode = CipherMode.CBC; + aes.Padding = PaddingMode.PKCS7; + + ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, Enumerable.Repeat((byte)0, 16).ToArray()); + byte[] decryptedData = decryptor.TransformFinalBlock(data, 0, data.Length); + return decryptedData; + } + } + + public static byte[] RSADecrypt(byte[] rsaKey, byte[] data) + { + + using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) + { + rsa.ImportCspBlob(rsaKey); + return rsa.Decrypt(data, false); + } + } + + public static byte[] RSAEncrypt(byte[] rsaKey, byte[] data) + { + using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) + { + rsa.ImportCspBlob(rsaKey); + return rsa.Encrypt(data, false); + } + } + + public static byte[] RSASign(byte[] rsaKey, byte[] data) + { + using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) + { + rsa.ImportCspBlob(rsaKey); + RSAPKCS1SignatureFormatter formatter = new RSAPKCS1SignatureFormatter(rsa); + formatter.SetHashAlgorithm("SHA1"); + + byte[] hash; + using (SHA1 sha1 = SHA1.Create()) + { + hash = sha1.ComputeHash(data); + } + + return formatter.CreateSignature(hash); + } + } + + public static bool RSAVerifySignature(byte[] rsaKey, byte[] data, byte[] signature) + { + using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) + { + rsa.ImportCspBlob(rsaKey); + RSAPKCS1SignatureDeformatter deformatter = new RSAPKCS1SignatureDeformatter(rsa); + deformatter.SetHashAlgorithm("SHA1"); + + byte[] hash; + using (SHA1 sha1 = SHA1.Create()) + { + hash = sha1.ComputeHash(data); + } + + return deformatter.VerifySignature(hash, signature); + } + } + + public static byte[] HMACSign(byte[] key, byte[] data) + { + HMACSHA1 hmac = new HMACSHA1(key); + return hmac.ComputeHash(data); + } + + public static bool HMACVerify(byte[] key, byte[] data, byte[] signature) + { + 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) + { + using (SHA256 sha256 = SHA256.Create()) + { + return sha256.ComputeHash(data); + } + } + } +} + + +// Crypto/Keys.cs +namespace LibTSforge.Crypto +{ + public static class Keys + { + public static readonly byte[] PRODUCTION = { + 0x07, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32, 0x00, 0x04, 0x00, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x29, 0x87, 0xBA, 0x3F, 0x52, 0x90, 0x57, 0xD8, 0x12, 0x26, 0x6B, 0x38, + 0xB2, 0x3B, 0xF9, 0x67, 0x08, 0x4F, 0xDD, 0x8B, 0xF5, 0xE3, 0x11, 0xB8, 0x61, 0x3A, 0x33, 0x42, + 0x51, 0x65, 0x05, 0x86, 0x1E, 0x00, 0x41, 0xDE, 0xC5, 0xDD, 0x44, 0x60, 0x56, 0x3D, 0x14, 0x39, + 0xB7, 0x43, 0x65, 0xE9, 0xF7, 0x2B, 0xA5, 0xF0, 0xA3, 0x65, 0x68, 0xE9, 0xE4, 0x8B, 0x5C, 0x03, + 0x2D, 0x36, 0xFE, 0x28, 0x4C, 0xD1, 0x3C, 0x3D, 0xC1, 0x90, 0x75, 0xF9, 0x6E, 0x02, 0xE0, 0x58, + 0x97, 0x6A, 0xCA, 0x80, 0x02, 0x42, 0x3F, 0x6C, 0x15, 0x85, 0x4D, 0x83, 0x23, 0x6A, 0x95, 0x9E, + 0x38, 0x52, 0x59, 0x38, 0x6A, 0x99, 0xF0, 0xB5, 0xCD, 0x53, 0x7E, 0x08, 0x7C, 0xB5, 0x51, 0xD3, + 0x8F, 0xA3, 0x0D, 0xA0, 0xFA, 0x8D, 0x87, 0x3C, 0xFC, 0x59, 0x21, 0xD8, 0x2E, 0xD9, 0x97, 0x8B, + 0x40, 0x60, 0xB1, 0xD7, 0x2B, 0x0A, 0x6E, 0x60, 0xB5, 0x50, 0xCC, 0x3C, 0xB1, 0x57, 0xE4, 0xB7, + 0xDC, 0x5A, 0x4D, 0xE1, 0x5C, 0xE0, 0x94, 0x4C, 0x5E, 0x28, 0xFF, 0xFA, 0x80, 0x6A, 0x13, 0x53, + 0x52, 0xDB, 0xF3, 0x04, 0x92, 0x43, 0x38, 0xB9, 0x1B, 0xD9, 0x85, 0x54, 0x7B, 0x14, 0xC7, 0x89, + 0x16, 0x8A, 0x4B, 0x82, 0xA1, 0x08, 0x02, 0x99, 0x23, 0x48, 0xDD, 0x75, 0x9C, 0xC8, 0xC1, 0xCE, + 0xB0, 0xD7, 0x1B, 0xD8, 0xFB, 0x2D, 0xA7, 0x2E, 0x47, 0xA7, 0x18, 0x4B, 0xF6, 0x29, 0x69, 0x44, + 0x30, 0x33, 0xBA, 0xA7, 0x1F, 0xCE, 0x96, 0x9E, 0x40, 0xE1, 0x43, 0xF0, 0xE0, 0x0D, 0x0A, 0x32, + 0xB4, 0xEE, 0xA1, 0xC3, 0x5E, 0x9B, 0xC7, 0x7F, 0xF5, 0x9D, 0xD8, 0xF2, 0x0F, 0xD9, 0x8F, 0xAD, + 0x75, 0x0A, 0x00, 0xD5, 0x25, 0x43, 0xF7, 0xAE, 0x51, 0x7F, 0xB7, 0xDE, 0xB7, 0xAD, 0xFB, 0xCE, + 0x83, 0xE1, 0x81, 0xFF, 0xDD, 0xA2, 0x77, 0xFE, 0xEB, 0x27, 0x1F, 0x10, 0xFA, 0x82, 0x37, 0xF4, + 0x7E, 0xCC, 0xE2, 0xA1, 0x58, 0xC8, 0xAF, 0x1D, 0x1A, 0x81, 0x31, 0x6E, 0xF4, 0x8B, 0x63, 0x34, + 0xF3, 0x05, 0x0F, 0xE1, 0xCC, 0x15, 0xDC, 0xA4, 0x28, 0x7A, 0x9E, 0xEB, 0x62, 0xD8, 0xD8, 0x8C, + 0x85, 0xD7, 0x07, 0x87, 0x90, 0x2F, 0xF7, 0x1C, 0x56, 0x85, 0x2F, 0xEF, 0x32, 0x37, 0x07, 0xAB, + 0xB0, 0xE6, 0xB5, 0x02, 0x19, 0x35, 0xAF, 0xDB, 0xD4, 0xA2, 0x9C, 0x36, 0x80, 0xC6, 0xDC, 0x82, + 0x08, 0xE0, 0xC0, 0x5F, 0x3C, 0x59, 0xAA, 0x4E, 0x26, 0x03, 0x29, 0xB3, 0x62, 0x58, 0x41, 0x59, + 0x3A, 0x37, 0x43, 0x35, 0xE3, 0x9F, 0x34, 0xE2, 0xA1, 0x04, 0x97, 0x12, 0x9D, 0x8C, 0xAD, 0xF7, + 0xFB, 0x8C, 0xA1, 0xA2, 0xE9, 0xE4, 0xEF, 0xD9, 0xC5, 0xE5, 0xDF, 0x0E, 0xBF, 0x4A, 0xE0, 0x7A, + 0x1E, 0x10, 0x50, 0x58, 0x63, 0x51, 0xE1, 0xD4, 0xFE, 0x57, 0xB0, 0x9E, 0xD7, 0xDA, 0x8C, 0xED, + 0x7D, 0x82, 0xAC, 0x2F, 0x25, 0x58, 0x0A, 0x58, 0xE6, 0xA4, 0xF4, 0x57, 0x4B, 0xA4, 0x1B, 0x65, + 0xB9, 0x4A, 0x87, 0x46, 0xEB, 0x8C, 0x0F, 0x9A, 0x48, 0x90, 0xF9, 0x9F, 0x76, 0x69, 0x03, 0x72, + 0x77, 0xEC, 0xC1, 0x42, 0x4C, 0x87, 0xDB, 0x0B, 0x3C, 0xD4, 0x74, 0xEF, 0xE5, 0x34, 0xE0, 0x32, + 0x45, 0xB0, 0xF8, 0xAB, 0xD5, 0x26, 0x21, 0xD7, 0xD2, 0x98, 0x54, 0x8F, 0x64, 0x88, 0x20, 0x2B, + 0x14, 0xE3, 0x82, 0xD5, 0x2A, 0x4B, 0x8F, 0x4E, 0x35, 0x20, 0x82, 0x7E, 0x1B, 0xFE, 0xFA, 0x2C, + 0x79, 0x6C, 0x6E, 0x66, 0x94, 0xBB, 0x0A, 0xEB, 0xBA, 0xD9, 0x70, 0x61, 0xE9, 0x47, 0xB5, 0x82, + 0xFC, 0x18, 0x3C, 0x66, 0x3A, 0x09, 0x2E, 0x1F, 0x61, 0x74, 0xCA, 0xCB, 0xF6, 0x7A, 0x52, 0x37, + 0x1D, 0xAC, 0x8D, 0x63, 0x69, 0x84, 0x8E, 0xC7, 0x70, 0x59, 0xDD, 0x2D, 0x91, 0x1E, 0xF7, 0xB1, + 0x56, 0xED, 0x7A, 0x06, 0x9D, 0x5B, 0x33, 0x15, 0xDD, 0x31, 0xD0, 0xE6, 0x16, 0x07, 0x9B, 0xA5, + 0x94, 0x06, 0x7D, 0xC1, 0xE9, 0xD6, 0xC8, 0xAF, 0xB4, 0x1E, 0x2D, 0x88, 0x06, 0xA7, 0x63, 0xB8, + 0xCF, 0xC8, 0xA2, 0x6E, 0x84, 0xB3, 0x8D, 0xE5, 0x47, 0xE6, 0x13, 0x63, 0x8E, 0xD1, 0x7F, 0xD4, + 0x81, 0x44, 0x38, 0xBF + }; + + public static readonly byte[] TEST = { + 0x07, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32, 0x00, 0x04, 0x00, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x0F, 0xBE, 0x77, 0xB8, 0xDD, 0x54, 0x36, 0xDD, 0x67, 0xD4, 0x17, 0x66, + 0xC4, 0x13, 0xD1, 0x3F, 0x1E, 0x16, 0x0C, 0x16, 0x35, 0xAB, 0x6D, 0x3D, 0x34, 0x51, 0xED, 0x3F, + 0x57, 0x14, 0xB6, 0xB7, 0x08, 0xE9, 0xD9, 0x7A, 0x80, 0xB3, 0x5F, 0x9B, 0x3A, 0xFD, 0x9E, 0x37, + 0x3A, 0x53, 0x72, 0x67, 0x92, 0x60, 0xC3, 0xEF, 0xB5, 0x8E, 0x1E, 0xCF, 0x9D, 0x9C, 0xD3, 0x90, + 0xE5, 0xDD, 0xF4, 0xDB, 0xF3, 0xD6, 0x65, 0xB3, 0xC1, 0xBD, 0x69, 0xE1, 0x76, 0x95, 0xD9, 0x37, + 0xB8, 0x5E, 0xCA, 0x3D, 0x98, 0xFC, 0x50, 0x5C, 0x98, 0xAE, 0xE3, 0x7C, 0x4C, 0x27, 0xC3, 0xD0, + 0xCE, 0x78, 0x06, 0x51, 0x68, 0x23, 0xE6, 0x70, 0xF8, 0x7C, 0xAE, 0x36, 0xBE, 0x41, 0x57, 0xE2, + 0xC3, 0x2D, 0xAF, 0x21, 0xB1, 0xB3, 0x15, 0x81, 0x19, 0x26, 0x6B, 0x10, 0xB3, 0xE9, 0xD1, 0x45, + 0x21, 0x77, 0x9C, 0xF6, 0xE1, 0xDD, 0xB6, 0x78, 0x9D, 0x1D, 0x32, 0x61, 0xBC, 0x2B, 0xDB, 0x86, + 0xFB, 0x07, 0x24, 0x10, 0x19, 0x4F, 0x09, 0x6D, 0x03, 0x90, 0xD4, 0x5E, 0x30, 0x85, 0xC5, 0x58, + 0x7E, 0x5D, 0xAE, 0x9F, 0x64, 0x93, 0x04, 0x82, 0x09, 0x0E, 0x1C, 0x66, 0xA8, 0x95, 0x91, 0x51, + 0xB2, 0xED, 0x9A, 0x75, 0x04, 0x87, 0x50, 0xAC, 0xCC, 0x20, 0x06, 0x45, 0xB9, 0x7B, 0x42, 0x53, + 0x9A, 0xD1, 0x29, 0xFC, 0xEF, 0xB9, 0x47, 0x16, 0x75, 0x69, 0x05, 0x87, 0x2B, 0xCB, 0x54, 0x9C, + 0x21, 0x2D, 0x50, 0x8E, 0x12, 0xDE, 0xD3, 0x6B, 0xEC, 0x92, 0xA1, 0xB1, 0xE9, 0x4B, 0xBF, 0x6B, + 0x9A, 0x38, 0xC7, 0x13, 0xFA, 0x78, 0xA1, 0x3C, 0x1E, 0xBB, 0x38, 0x31, 0xBB, 0x0C, 0x9F, 0x70, + 0x1A, 0x31, 0x00, 0xD7, 0x5A, 0xA5, 0x84, 0x24, 0x89, 0x80, 0xF5, 0x88, 0xC2, 0x31, 0x18, 0xDC, + 0x53, 0x05, 0x5D, 0xFA, 0x81, 0xDC, 0xE1, 0xCE, 0xA4, 0xAA, 0xBA, 0x07, 0xDA, 0x28, 0x4F, 0x64, + 0x0E, 0x84, 0x9B, 0x06, 0xDE, 0xC8, 0x78, 0x66, 0x2F, 0x17, 0x25, 0xA8, 0x9C, 0x99, 0xFC, 0xBC, + 0x7D, 0x01, 0x42, 0xD7, 0x35, 0xBF, 0x19, 0xF6, 0x3F, 0x20, 0xD9, 0x98, 0x9B, 0x5D, 0xDD, 0x39, + 0xBE, 0x81, 0x00, 0x0B, 0xDE, 0x6F, 0x14, 0xCA, 0x7E, 0xF8, 0xC0, 0x26, 0xA8, 0x1D, 0xD1, 0x16, + 0x88, 0x64, 0x87, 0x36, 0x45, 0x37, 0x50, 0xDA, 0x6C, 0xEB, 0x85, 0xB5, 0x43, 0x29, 0x88, 0x6F, + 0x2F, 0xFE, 0x8D, 0x12, 0x8B, 0x72, 0xB7, 0x5A, 0xCB, 0x66, 0xC2, 0x2E, 0x1D, 0x7D, 0x42, 0xA6, + 0xF4, 0xFE, 0x26, 0x5D, 0x54, 0x9E, 0x77, 0x1D, 0x97, 0xC2, 0xF3, 0xFD, 0x60, 0xB3, 0x22, 0x88, + 0xCA, 0x27, 0x99, 0xDF, 0xC8, 0xB1, 0xD7, 0xC6, 0x54, 0xA6, 0x50, 0xB9, 0x54, 0xF5, 0xDE, 0xFE, + 0xE1, 0x81, 0xA2, 0xBE, 0x81, 0x9F, 0x48, 0xFF, 0x2F, 0xB8, 0xA4, 0xB3, 0x17, 0xD8, 0xC1, 0xB9, + 0x5D, 0x21, 0x3D, 0xA2, 0xED, 0x1C, 0x96, 0x66, 0xEE, 0x1F, 0x47, 0xCF, 0x62, 0xFA, 0xD6, 0xC1, + 0x87, 0x5B, 0xC4, 0xE5, 0xD9, 0x08, 0x38, 0x22, 0xFA, 0x21, 0xBD, 0xF2, 0x88, 0xDA, 0xE2, 0x24, + 0x25, 0x1F, 0xF1, 0x0B, 0x2D, 0xAE, 0x04, 0xBE, 0xA6, 0x7F, 0x75, 0x8C, 0xD9, 0x97, 0xE1, 0xCA, + 0x35, 0xB9, 0xFC, 0x6F, 0x01, 0x68, 0x11, 0xD3, 0x68, 0x32, 0xD0, 0xC1, 0x69, 0xA3, 0xCF, 0x9B, + 0x10, 0xE4, 0x69, 0xA7, 0xCF, 0xE1, 0xFE, 0x2A, 0x07, 0x9E, 0xC1, 0x37, 0x84, 0x68, 0xE5, 0xC5, + 0xAB, 0x25, 0xEC, 0x7D, 0x7D, 0x74, 0x6A, 0xD1, 0xD5, 0x4D, 0xD7, 0xE1, 0x7D, 0xDE, 0x30, 0x4B, + 0xE6, 0x5D, 0xCD, 0x91, 0x59, 0xF6, 0x80, 0xFD, 0xC6, 0x3C, 0xDD, 0x94, 0x7F, 0x15, 0x9D, 0xEF, + 0x2F, 0x00, 0x62, 0xD7, 0xDA, 0xB9, 0xB3, 0xD9, 0x8D, 0xE8, 0xD7, 0x3C, 0x96, 0x45, 0x5D, 0x1E, + 0x50, 0xFB, 0xAA, 0x43, 0xD3, 0x47, 0x77, 0x81, 0xE9, 0x67, 0xE4, 0xFE, 0xDF, 0x42, 0x79, 0xCB, + 0xA7, 0xAD, 0x5D, 0x48, 0xF5, 0xB7, 0x74, 0x96, 0x12, 0x23, 0x06, 0x70, 0x42, 0x68, 0x7A, 0x44, + 0xFC, 0xA0, 0x31, 0x7F, 0x68, 0xCA, 0xA2, 0x14, 0x5D, 0xA3, 0xCF, 0x42, 0x23, 0xAB, 0x47, 0xF6, + 0xB2, 0xFC, 0x6D, 0xF1 + }; + } +} + + +// Crypto/PhysStoreCrypto.cs +namespace LibTSforge.Crypto +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Text; + + public static class PhysStoreCrypto + { + public static byte[] DecryptPhysicalStore(byte[] data, bool production, PSVersion version) + { + byte[] rsaKey = production ? Keys.PRODUCTION : Keys.TEST; + BinaryReader br = new BinaryReader(new MemoryStream(data)); + br.BaseStream.Seek(0x10, SeekOrigin.Begin); + byte[] aesKeySig = br.ReadBytes(0x80); + byte[] encAesKey = br.ReadBytes(0x80); + + if (!CryptoUtils.RSAVerifySignature(rsaKey, encAesKey, aesKeySig)) + { + 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) + { + Dictionary versionTable = new Dictionary + { + {PSVersion.Vista, 2}, + {PSVersion.Win7, 5}, + {PSVersion.Win8, 1}, + {PSVersion.WinBlue, 2}, + {PSVersion.WinModern, 3} + }; + + byte[] rsaKey = production ? Keys.PRODUCTION : Keys.TEST; + + byte[] aesKey = Encoding.UTF8.GetBytes("massgrave.dev :3"); + byte[] hmacKey = CryptoUtils.GenerateRandomKey(0x10); + + byte[] encAesKey = CryptoUtils.RSAEncrypt(rsaKey, aesKey); + byte[] aesKeySig = CryptoUtils.RSASign(rsaKey, encAesKey); + byte[] hmacSig = version != PSVersion.Vista ? CryptoUtils.HMACSign(hmacKey, data) : CryptoUtils.SaltSHASum(hmacKey, data); + + byte[] decData = { }; + decData = decData.Concat(hmacKey).Concat(hmacSig).Concat(BitConverter.GetBytes(0)).Concat(data).ToArray(); + byte[] encData = CryptoUtils.AESEncrypt(decData, aesKey); + + BinaryWriter bw = new BinaryWriter(new MemoryStream()); + bw.Write(versionTable[version]); + bw.Write(Encoding.UTF8.GetBytes("UNTRUSTSTORE")); + bw.Write(aesKeySig); + bw.Write(encAesKey); + bw.Write(encData); + + return bw.GetBytes(); + } + } +} + + +// Modifiers/GenPKeyInstall.cs +namespace LibTSforge.Modifiers +{ + using System; + using System.IO; + using Microsoft.Win32; + using PhysicalStore; + using SPP; + using TokenStore; + + public static class GenPKeyInstall + { + private static void WritePkey2005RegistryValues(PSVersion version, ProductKey pkey) + { + Logger.WriteLine("Writing registry data for Windows product key..."); + Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ProductId", pkey.GetPid2()); + Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "DigitalProductId", pkey.GetPid3()); + Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "DigitalProductId4", pkey.GetPid4()); + + if (Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Registration", "ProductId", null) != null) + { + Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Registration", "ProductId", pkey.GetPid2()); + Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Registration", "DigitalProductId", pkey.GetPid3()); + Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Registration", "DigitalProductId4", pkey.GetPid4()); + } + + if (pkey.Channel == "Volume:CSVLK" && version != PSVersion.Win7) + { + Registry.SetValue(@"HKEY_USERS\S-1-5-20\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform", "KmsHostConfig", 1); + } + } + + 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."); + + PKeyConfig pkc = new PKeyConfig(); + + try + { + pkc.LoadConfig(actId); + } + catch (ArgumentException) + { + pkc.LoadAllConfigs(SLApi.GetAppId(actId)); + } + + ProductConfig config; + pkc.Products.TryGetValue(actId, out config); + + if (config == null) throw new ArgumentException("Activation ID " + actId + " not found in PKeyConfig."); + + ProductKey pkey = config.GetRandomKey(); + + Guid instPkeyId = SLApi.GetInstalledPkeyID(actId); + if (instPkeyId != Guid.Empty) SLApi.UninstallProductKey(instPkeyId); + + if (pkey.Algorithm == PKeyAlgorithm.PKEY2009) + { + uint status = SLApi.InstallProductKey(pkey); + Logger.WriteLine(string.Format("Installing generated product key {0} status {1:X}", pkey, status)); + + if ((int)status < 0) + { + throw new ApplicationException("Failed to install generated product key."); + } + + Logger.WriteLine("Successfully deposited generated product key."); + return; + } + + Logger.WriteLine("Key range is PKEY2005, creating fake key data..."); + + if (pkey.Channel == "Volume:GVLK" && version == PSVersion.Win7) throw new NotSupportedException("Fake GVLK generation is not supported on Windows 7."); + + VariableBag pkb = new VariableBag(version); + pkb.Blocks.AddRange(new[] + { + new CRCBlockModern + { + DataType = CRCBlockType.STRING, + KeyAsStr = "SppPkeyBindingProductKey", + ValueAsStr = pkey.ToString() + }, + new CRCBlockModern + { + DataType = CRCBlockType.STRING, + KeyAsStr = "SppPkeyBindingMPC", + ValueAsStr = pkey.GetMPC() + }, + new CRCBlockModern { + DataType = CRCBlockType.BINARY, + KeyAsStr = "SppPkeyBindingPid2", + ValueAsStr = pkey.GetPid2() + }, + new CRCBlockModern + { + DataType = CRCBlockType.BINARY, + KeyAsStr = "SppPkeyBindingPid3", + Value = pkey.GetPid3() + }, + new CRCBlockModern + { + DataType = CRCBlockType.BINARY, + KeyAsStr = "SppPkeyBindingPid4", + Value = pkey.GetPid4() + }, + new CRCBlockModern + { + DataType = CRCBlockType.STRING, + KeyAsStr = "SppPkeyChannelId", + ValueAsStr = pkey.Channel + }, + new CRCBlockModern + { + DataType = CRCBlockType.STRING, + KeyAsStr = "SppPkeyBindingEditionId", + ValueAsStr = pkey.Edition + }, + new CRCBlockModern + { + DataType = CRCBlockType.BINARY, + KeyAsStr = (version == PSVersion.Win7) ? "SppPkeyShortAuthenticator" : "SppPkeyPhoneActivationData", + Value = pkey.GetPhoneData(version) + }, + new CRCBlockModern + { + DataType = CRCBlockType.BINARY, + KeyAsStr = "SppPkeyBindingMiscData", + Value = new byte[] { } + } + }); + + Guid appId = SLApi.GetAppId(actId); + string pkeyId = pkey.GetPkeyId().ToString(); + bool isAddon = SLApi.IsAddon(actId); + string currEdition = SLApi.GetMetaStr(actId, "Family"); + + if (appId == SLApi.WINDOWS_APP_ID && !isAddon) + { + SLApi.UninstallAllProductKeys(appId); + } + + SPPUtils.KillSPP(version); + + using (IPhysicalStore ps = SPPUtils.GetStore(version, production)) + { + using (ITokenStore tks = SPPUtils.GetTokenStore(version)) + { + Logger.WriteLine("Writing to physical store and token store..."); + + string suffix = (version == PSVersion.Win8 || version == PSVersion.WinBlue || version == PSVersion.WinModern) ? "_--" : ""; + string metSuffix = suffix + "_met"; + + if (appId == SLApi.WINDOWS_APP_ID && !isAddon) + { + string edTokName = "msft:spp/token/windows/productkeyid/" + currEdition; + + TokenMeta edToken = tks.GetMetaEntry(edTokName); + edToken.Data["windowsComponentEditionPkeyId"] = pkeyId; + edToken.Data["windowsComponentEditionSkuId"] = actId.ToString(); + tks.SetEntry(edTokName, "xml", edToken.Serialize()); + + WritePkey2005RegistryValues(version, pkey); + } + + string uriMapName = "msft:spp/token/PKeyIdUriMapper" + metSuffix; + TokenMeta uriMap = tks.GetMetaEntry(uriMapName); + uriMap.Data[pkeyId] = pkey.GetAlgoUri(); + tks.SetEntry(uriMapName, "xml", uriMap.Serialize()); + + string skuMetaName = actId + metSuffix; + TokenMeta skuMeta = tks.GetMetaEntry(skuMetaName); + + foreach (string k in skuMeta.Data.Keys) + { + if (k.StartsWith("pkeyId_")) + { + skuMeta.Data.Remove(k); + break; + } + } + + skuMeta.Data["pkeyId"] = pkeyId; + skuMeta.Data["pkeyIdList"] = pkeyId; + tks.SetEntry(skuMetaName, "xml", skuMeta.Serialize()); + + string psKey = string.Format("SPPSVC\\{0}\\{1}", appId, actId); + ps.DeleteBlock(psKey, pkeyId); + ps.AddBlock(new PSBlock + { + Type = BlockType.NAMED, + Flags = (version == PSVersion.WinModern) ? (uint)0x402 : 0x2, + KeyAsStr = psKey, + ValueAsStr = pkeyId, + Data = pkb.Serialize() + }); + + string cachePath = SPPUtils.GetTokensPath(version).Replace("tokens.dat", @"cache\cache.dat"); + if (File.Exists(cachePath)) File.Delete(cachePath); + } + } + + SLApi.RefreshTrustedTime(actId); + Logger.WriteLine("Successfully deposited fake product key."); + } + } +} + + +// Modifiers/GracePeriodReset.cs +namespace LibTSforge.Modifiers +{ + using System.Collections.Generic; + using System.Linq; + using PhysicalStore; + using SPP; + + public static class GracePeriodReset + { + public static void Reset(PSVersion version, bool production) + { + SPPUtils.KillSPP(version); + Logger.WriteLine("Writing TrustedStore data..."); + + using (IPhysicalStore store = SPPUtils.GetStore(version, production)) + { + string value = "msft:sl/timer"; + List blocks = store.FindBlocks(value).ToList(); + + foreach (PSBlock block in blocks) + { + store.DeleteBlock(block.KeyAsStr, block.ValueAsStr); + } + } + + SPPUtils.RestartSPP(version); + Logger.WriteLine("Successfully reset all grace and evaluation period timers."); + } + } +} + + +// Modifiers/KeyChangeLockDelete.cs +namespace LibTSforge.Modifiers +{ + using System.Collections.Generic; + using System.Linq; + using PhysicalStore; + using SPP; + using System; + + public static class KeyChangeLockDelete + { + public static void Delete(PSVersion version, bool production) + { + 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..."); + using (IPhysicalStore store = SPPUtils.GetStore(version, production)) + { + List values = new List + { + "msft:spp/timebased/AB", + "msft:spp/timebased/CD" + }; + List blocks = new List(); + foreach (string value in values) + { + blocks.AddRange(store.FindBlocks(value).ToList()); + } + foreach (PSBlock block in blocks) + { + store.DeleteBlock(block.KeyAsStr, block.ValueAsStr); + } + } + Logger.WriteLine("Successfully removed the key change lock."); + } + } +} + + +// Modifiers/KMSHostCharge.cs +namespace LibTSforge.Modifiers +{ + using System; + using System.IO; + using PhysicalStore; + using SPP; + + public static class KMSHostCharge + { + public static void Charge(PSVersion version, bool production, Guid actId) + { + if (actId == Guid.Empty) + { + actId = SLApi.GetDefaultActivationID(SLApi.WINDOWS_APP_ID, true); + + if (actId == Guid.Empty) + { + throw new NotSupportedException("No applicable activation IDs found."); + } + } + + if (SLApi.GetPKeyChannel(SLApi.GetInstalledPkeyID(actId)) != "Volume:CSVLK") + { + throw new NotSupportedException("Non-Volume:CSVLK product key installed."); + } + + Guid appId = SLApi.GetAppId(actId); + int totalClients = 50; + int currClients = 25; + byte[] hwidBlock = Constants.UniversalHWIDBlock; + string key = string.Format("SPPSVC\\{0}", appId); + long ldapTimestamp = DateTime.Now.ToFileTime(); + + byte[] cmidGuids = { }; + byte[] reqCounts = { }; + byte[] kmsChargeData = { }; + + BinaryWriter writer = new BinaryWriter(new MemoryStream()); + + if (version == PSVersion.Vista) + { + writer.Write(new byte[44]); + 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(); + } + + SPPUtils.KillSPP(version); + + Logger.WriteLine("Writing TrustedStore data..."); + + using (IPhysicalStore store = SPPUtils.GetStore(version, production)) + { + if (version != PSVersion.Vista) + { + VariableBag kmsCountData = new VariableBag(version); + kmsCountData.Blocks.AddRange(new[] + { + new CRCBlockModern + { + DataType = CRCBlockType.BINARY, + KeyAsStr = "SppBindingLicenseData", + Value = hwidBlock + }, + new CRCBlockModern + { + DataType = CRCBlockType.UINT, + Key = new byte[] { }, + ValueAsInt = (uint)totalClients + }, + new CRCBlockModern + { + DataType = CRCBlockType.UINT, + Key = new byte[] { }, + ValueAsInt = 1051200000 + }, + new CRCBlockModern + { + DataType = CRCBlockType.UINT, + Key = new byte[] { }, + ValueAsInt = (uint)currClients + }, + new CRCBlockModern + { + DataType = CRCBlockType.BINARY, + Key = new byte[] { }, + Value = cmidGuids + }, + new CRCBlockModern + { + DataType = CRCBlockType.BINARY, + Key = new byte[] { }, + Value = reqCounts + } + }); + + kmsChargeData = kmsCountData.Serialize(); + } + + 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.AddBlock(new PSBlock + { + Type = BlockType.NAMED, + Flags = (version == PSVersion.WinModern) ? (uint)0x400 : 0, + KeyAsStr = key, + ValueAsStr = countVal, + Data = kmsChargeData + }); + + Logger.WriteLine(string.Format("Set charge count to {0} successfully.", currClients)); + } + + SPPUtils.RestartSPP(version); + } + } +} + + +// Modifiers/RearmReset.cs +namespace LibTSforge.Modifiers +{ + using System.Collections.Generic; + using System.Linq; + using PhysicalStore; + using SPP; + + public static class RearmReset + { + public static void Reset(PSVersion version, bool production) + { + SPPUtils.KillSPP(version); + + Logger.WriteLine("Writing TrustedStore data..."); + + using (IPhysicalStore store = SPPUtils.GetStore(version, production)) + { + List blocks; + + if (version == PSVersion.Vista) + { + blocks = store.FindBlocks("740D70D8-6448-4b2f-9063-4A7A463600C5").ToList(); + } + else if (version == PSVersion.Win7) + { + blocks = store.FindBlocks(0xA0000).ToList(); + } + else + { + blocks = store.FindBlocks("__##USERSEP-RESERVED##__$$REARM-COUNT$$").ToList(); + } + + foreach (PSBlock block in blocks) + { + if (version == PSVersion.Vista) + { + store.DeleteBlock(block.KeyAsStr, block.ValueAsStr); + } + else if (version == PSVersion.Win7) + { + store.SetBlock(block.KeyAsStr, block.ValueAsInt, new byte[8]); + } + else + { + store.SetBlock(block.KeyAsStr, block.ValueAsStr, new byte[8]); + } + } + + Logger.WriteLine("Successfully reset all rearm counters."); + } + } + } +} - if (Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Registration", "ProductId", null) != null) + +// Modifiers/SetIIDParams.cs +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."); + } + } +} + + +// Modifiers/TamperedFlagsDelete.cs +namespace LibTSforge.Modifiers +{ + using System.Linq; + using PhysicalStore; + using SPP; + + public static class TamperedFlagsDelete + { + public static void DeleteTamperFlags(PSVersion version, bool production) + { + SPPUtils.KillSPP(version); + + Logger.WriteLine("Writing TrustedStore data..."); + + using (IPhysicalStore store = SPPUtils.GetStore(version, production)) + { + if (version == PSVersion.Vista) + { + DeleteFlag(store, "6BE8425B-E3CF-4e86-A6AF-5863E3DCB606"); + } + else if (version == PSVersion.Win7) + { + SetFlag(store, 0xA0001); + } + else + { + DeleteFlag(store, "__##USERSEP-RESERVED##__$$RECREATED-FLAG$$"); + DeleteFlag(store, "__##USERSEP-RESERVED##__$$RECOVERED-FLAG$$"); + } + + Logger.WriteLine("Successfully cleared the tamper state."); + } + + SPPUtils.RestartSPP(version); + } + + private static void DeleteFlag(IPhysicalStore store, string flag) + { + store.FindBlocks(flag).ToList().ForEach(block => store.DeleteBlock(block.KeyAsStr, block.ValueAsStr)); + } + + private static void SetFlag(IPhysicalStore store, uint flag) + { + store.FindBlocks(flag).ToList().ForEach(block => store.SetBlock(block.KeyAsStr, block.ValueAsInt, new byte[8])); + } + } +} + + +// Modifiers/UniqueIdDelete.cs +namespace LibTSforge.Modifiers +{ + using System; + using PhysicalStore; + using SPP; + + public static class UniqueIdDelete + { + 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; + + 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 Exception("No product key found."); + } + + VariableBag pkb = new VariableBag(keyBlock.Data, version); + + pkb.DeleteBlock("SppPkeyUniqueIdToken"); + + store.SetBlock(key, pkeyId.ToString(), pkb.Serialize()); + } + + Logger.WriteLine("Successfully removed Unique ID for product key ID " + pkeyId); + } + } +} + + +// Activators/AVMA4K.cs +namespace LibTSforge.Activators +{ + using System; + using PhysicalStore; + using SPP; + + public static class AVMA4k + { + public static void Activate(PSVersion version, bool production, Guid actId) + { + if (version != PSVersion.WinModern && version != PSVersion.WinBlue) + { + throw new NotSupportedException("AVMA licenses are not available for this product."); + } + + Guid appId; + if (actId == Guid.Empty) + { + appId = SLApi.WINDOWS_APP_ID; + actId = SLApi.GetDefaultActivationID(appId, false); + + if (actId == Guid.Empty) + { + throw new NotSupportedException("No applicable activation IDs found."); + } + } + else + { + appId = SLApi.GetAppId(actId); + } + + if (SLApi.GetPKeyChannel(SLApi.GetInstalledPkeyID(actId)) != "VT:IA") + { + throw new NotSupportedException("Non-VT:IA product key installed."); + } + + SPPUtils.KillSPP(version); + + Logger.WriteLine("Writing TrustedStore data..."); + + using (IPhysicalStore store = SPPUtils.GetStore(version, production)) + { + string key = string.Format("SPPSVC\\{0}\\{1}", appId, actId); + + 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 deltaTime = BitConverter.ToInt64(store.GetBlock(key, "__##USERSEP-RESERVED##__$$UP-TIME-DELTA$$").Data, 0); + + const ulong unknown = 0; + ulong time1 = (ulong)(creationTime + tickCount + deltaTime); + ulong crcBindTime = (ulong)DateTime.UtcNow.ToFileTime(); + ulong timerTime = crcBindTime / 10000; + ulong expiry = Constants.TimerMax / 10000; + + VariableBag avmaBinding = new VariableBag(version); + + avmaBinding.Blocks.AddRange(new[] + { + new CRCBlockModern + { + DataType = CRCBlockType.BINARY, + Key = new byte[] { }, + Value = BitConverter.GetBytes(crcBindTime), + }, + new CRCBlockModern + { + DataType = CRCBlockType.STRING, + Key = new byte[] { }, + ValueAsStr = "AVMA4K", + }, + new CRCBlockModern + { + DataType = CRCBlockType.STRING, + Key = new byte[] { }, + ValueAsStr = "00491-50000-00001-AA666", + } + }); + + byte[] avmaBindingData = avmaBinding.Serialize(); + + Timer avmaTimer = new Timer + { + Unknown = unknown, + Time1 = time1, + Time2 = timerTime, + Expiry = expiry + }; + + string storeVal = string.Format("msft:spp/ia/bind/1.0/store/{0}/{1}", appId, actId); + string timerVal = string.Format("msft:spp/ia/bind/1.0/timer/{0}/{1}", appId, actId); + + store.DeleteBlock(key, storeVal); + store.DeleteBlock(key, timerVal); + + store.AddBlocks(new[] + { + new PSBlock + { + Type = BlockType.NAMED, + Flags = 0x400, + KeyAsStr = key, + ValueAsStr = storeVal, + Data = avmaBindingData, + }, + new PSBlock + { + Type = BlockType.TIMER, + Flags = 0x4, + KeyAsStr = key, + ValueAsStr = timerVal, + Data = avmaTimer.CastToArray() + } + }); + } + + SLApi.RefreshLicenseStatus(); + SLApi.FireStateChangedEvent(appId); + Logger.WriteLine("Activated using AVMA4k successfully."); + } + } +} + + +// Activators/ZeroCID.cs +namespace LibTSforge.Activators +{ + using System; + using System.IO; + using System.Linq; + using Crypto; + using PhysicalStore; + using SPP; + + public static class ZeroCID + { + private static void Deposit(Guid actId, string instId) + { + uint status = SLApi.DepositConfirmationID(actId, instId, Constants.ZeroCID); + Logger.WriteLine(string.Format("Depositing fake CID status {0:X}", status)); + + if (status != 0) + { + throw new InvalidOperationException("Failed to deposit fake CID."); + } + } + + public static void Activate(PSVersion version, bool production, Guid actId) + { + Guid appId; + + if (actId == Guid.Empty) + { + appId = SLApi.WINDOWS_APP_ID; + actId = SLApi.GetDefaultActivationID(appId, false); + + if (actId == Guid.Empty) + { + throw new NotSupportedException("No applicable activation IDs found."); + } + } + else { - Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Registration", "ProductId", pkey.GetPid2()); - Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Registration", "DigitalProductId", pkey.GetPid3()); - Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Registration", "DigitalProductId4", pkey.GetPid4()); + appId = SLApi.GetAppId(actId); } - if (pkey.Channel == "Volume:CSVLK" && version != PSVersion.Win7) + if (!SLApi.IsPhoneActivatable(actId)) { - Registry.SetValue(@"HKEY_USERS\S-1-5-20\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform", "KmsHostConfig", 1); + throw new NotSupportedException("Phone license is unavailable for this product."); } - } - public static void InstallGenPKey(PSVersion version, bool production, Guid actId) - { - if (actId == Guid.Empty) throw new ArgumentException("Activation ID must be specified for generated product key install."); + string instId = SLApi.GetInstallationID(actId); + Guid pkeyId = SLApi.GetInstalledPkeyID(actId); - PKeyConfig pkc = new PKeyConfig(); - - try - { - pkc.LoadConfig(actId); - } - catch (ArgumentException) + if (version == PSVersion.Vista || version == PSVersion.Win7) { - pkc.LoadAllConfigs(SLApi.GetAppId(actId)); + Deposit(actId, instId); } - ProductConfig config; - pkc.Products.TryGetValue(actId, out config); + SPPUtils.KillSPP(version); - if (config == null) throw new ArgumentException("Activation ID " + actId + " not found in PKeyConfig."); + Logger.WriteLine("Writing TrustedStore data..."); - ProductKey pkey = config.GetRandomKey(); + using (IPhysicalStore store = SPPUtils.GetStore(version, production)) + { + byte[] hwidBlock = Constants.UniversalHWIDBlock; - Guid instPkeyId = SLApi.GetInstalledPkeyID(actId); - if (instPkeyId != Guid.Empty) SLApi.UninstallProductKey(instPkeyId); + Logger.WriteLine("Activation ID: " + actId); + Logger.WriteLine("Installation ID: " + instId); + Logger.WriteLine("Product Key ID: " + pkeyId); - if (pkey.Algorithm == PKeyAlgorithm.PKEY2009) - { - uint status = SLApi.InstallProductKey(pkey); - Logger.WriteLine(string.Format("Installing generated product key {0} status {1:X}", pkey.ToString(), status)); + byte[] iidHash; - if ((int)status < 0) + if (version == PSVersion.Vista) { - throw new ApplicationException("Failed to install generated product key."); + iidHash = CryptoUtils.SHA256Hash(Utils.EncodeString(instId)).Take(0x10).ToArray(); + } + else if (version == PSVersion.Win7) + { + iidHash = CryptoUtils.SHA256Hash(Utils.EncodeString(instId)); + } + else + { + iidHash = CryptoUtils.SHA256Hash(Utils.EncodeString(instId + '\0' + Constants.ZeroCID)); } - Logger.WriteLine("Successfully deposited generated product key."); - return; - } + string key = string.Format("SPPSVC\\{0}\\{1}", appId, actId); + PSBlock keyBlock = store.GetBlock(key, pkeyId.ToString()); - Logger.WriteLine("Key range is PKEY2005, creating fake key data..."); + if (keyBlock == null) + { + throw new InvalidDataException("Failed to get product key data for activation ID " + actId + "."); + } - if (pkey.Channel == "Volume:GVLK" && version == PSVersion.Win7) throw new NotSupportedException("Fake GVLK generation is not supported on Windows 7."); + VariableBag pkb = new VariableBag(keyBlock.Data, version); - VariableBag pkb = new VariableBag(); - pkb.Blocks.AddRange(new CRCBlock[] - { - new CRCBlock - { - DataType = CRCBlockType.STRING, - KeyAsStr = "SppPkeyBindingProductKey", - ValueAsStr = pkey.ToString() - }, - new CRCBlock - { - DataType = CRCBlockType.STRING, - KeyAsStr = "SppPkeyBindingMPC", - ValueAsStr = pkey.GetMPC() - }, - new CRCBlock { - DataType = CRCBlockType.BINARY, - KeyAsStr = "SppPkeyBindingPid2", - ValueAsStr = pkey.GetPid2() - }, - new CRCBlock - { - DataType = CRCBlockType.BINARY, - KeyAsStr = "SppPkeyBindingPid3", - Value = pkey.GetPid3() - }, - new CRCBlock - { - DataType = CRCBlockType.BINARY, - KeyAsStr = "SppPkeyBindingPid4", - Value = pkey.GetPid4() - }, - new CRCBlock - { - DataType = CRCBlockType.STRING, - KeyAsStr = "SppPkeyChannelId", - ValueAsStr = pkey.Channel - }, - new CRCBlock + byte[] pkeyData; + + if (version == PSVersion.Vista) { - DataType = CRCBlockType.STRING, - KeyAsStr = "SppPkeyBindingEditionId", - ValueAsStr = pkey.Edition - }, - new CRCBlock + 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) { - DataType = CRCBlockType.BINARY, - KeyAsStr = (version == PSVersion.Win7) ? "SppPkeyShortAuthenticator" : "SppPkeyPhoneActivationData", - Value = pkey.GetPhoneData(version) - }, - new CRCBlock + pkeyData = pkb.GetBlock("SppPkeyShortAuthenticator").Value; + } + else { - DataType = CRCBlockType.BINARY, - KeyAsStr = "SppPkeyBindingMiscData", - Value = new byte[] { } + pkeyData = pkb.GetBlock("SppPkeyPhoneActivationData").Value; } - }); - Guid appId = SLApi.GetAppId(actId); - string pkeyId = pkey.GetPkeyId().ToString(); - bool isAddon = SLApi.IsAddon(actId); - string currEdition = SLApi.GetMetaStr(actId, "Family"); + pkb.DeleteBlock("SppPkeyVirtual"); + store.SetBlock(key, pkeyId.ToString(), pkb.Serialize()); - if (appId == SLApi.WINDOWS_APP_ID && !isAddon) + BinaryWriter writer = new BinaryWriter(new MemoryStream()); + writer.Write(iidHash.Length); + writer.Write(iidHash); + writer.Write(hwidBlock.Length); + writer.Write(hwidBlock); + byte[] tsHwidData = writer.GetBytes(); + + writer = new BinaryWriter(new MemoryStream()); + writer.Write(iidHash.Length); + writer.Write(iidHash); + writer.Write(pkeyData.Length); + writer.Write(pkeyData); + byte[] tsPkeyInfoData = writer.GetBytes(); + + 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 + { + Type = BlockType.NAMED, + Flags = 0, + KeyAsStr = key, + ValueAsStr = hwidBlockName, + Data = tsHwidData + }, + new PSBlock + { + Type = BlockType.NAMED, + Flags = 0, + KeyAsStr = key, + ValueAsStr = pkeyInfoName, + Data = tsPkeyInfoData + } + }); + } + + if (version != PSVersion.Vista && version != PSVersion.Win7) { - SLApi.UninstallAllProductKeys(appId); + Deposit(actId, instId); } - Utils.KillSPP(); + SPPUtils.RestartSPP(version); + SLApi.FireStateChangedEvent(appId); + Logger.WriteLine("Activated using ZeroCID successfully."); + } + } +} - using (IPhysicalStore ps = Utils.GetStore(version, production)) - { - using (ITokenStore tks = Utils.GetTokenStore(version)) - { - Logger.WriteLine("Writing to physical store and token store..."); - string suffix = (version == PSVersion.Win8 || version == PSVersion.WinBlue || version == PSVersion.WinModern) ? "_--" : ""; - string metSuffix = suffix + "_met"; +// TokenStore/Common.cs +namespace LibTSforge.TokenStore +{ + using System.Collections.Generic; + using System.IO; - if (appId == SLApi.WINDOWS_APP_ID && !isAddon) - { - string edTokName = "msft:spp/token/windows/productkeyid/" + currEdition; + public class TokenEntry + { + public string Name; + public string Extension; + public byte[] Data; + public bool Populated; + } - TokenMeta edToken = tks.GetMetaEntry(edTokName); - edToken.Data["windowsComponentEditionPkeyId"] = pkeyId; - edToken.Data["windowsComponentEditionSkuId"] = actId.ToString(); - tks.SetEntry(edTokName, "xml", edToken.Serialize()); + public class TokenMeta + { + public string Name; + public readonly Dictionary Data = new Dictionary(); - WritePkey2005RegistryValues(version, pkey); - } + public byte[] Serialize() + { + BinaryWriter writer = new BinaryWriter(new MemoryStream()); + writer.Write(1); + byte[] nameBytes = Utils.EncodeString(Name); + writer.Write(nameBytes.Length); + writer.Write(nameBytes); - string uriMapName = "msft:spp/token/PKeyIdUriMapper" + metSuffix; - TokenMeta uriMap = tks.GetMetaEntry(uriMapName); - uriMap.Data[pkeyId] = pkey.GetAlgoUri(); - tks.SetEntry(uriMapName, "xml", uriMap.Serialize()); + foreach (KeyValuePair kv in Data) + { + byte[] keyBytes = Utils.EncodeString(kv.Key); + byte[] valueBytes = Utils.EncodeString(kv.Value); + writer.Write(keyBytes.Length); + writer.Write(valueBytes.Length); + writer.Write(keyBytes); + writer.Write(valueBytes); + } - string skuMetaName = actId.ToString() + metSuffix; - TokenMeta skuMeta = tks.GetMetaEntry(skuMetaName); + return writer.GetBytes(); + } - foreach (string k in skuMeta.Data.Keys) - { - if (k.StartsWith("pkeyId_")) - { - skuMeta.Data.Remove(k); - break; - } - } + private void Deserialize(byte[] data) + { + BinaryReader reader = new BinaryReader(new MemoryStream(data)); + reader.ReadInt32(); + int nameLen = reader.ReadInt32(); + Name = reader.ReadNullTerminatedString(nameLen); - skuMeta.Data["pkeyId"] = pkeyId; - skuMeta.Data["pkeyIdList"] = pkeyId; - tks.SetEntry(skuMetaName, "xml", skuMeta.Serialize()); + while (reader.BaseStream.Position < data.Length - 0x8) + { + int keyLen = reader.ReadInt32(); + int valueLen = reader.ReadInt32(); + string key = reader.ReadNullTerminatedString(keyLen); + string value = reader.ReadNullTerminatedString(valueLen); + Data[key] = value; + } + } - string psKey = string.Format("SPPSVC\\{0}\\{1}", appId, actId); - ps.DeleteBlock(psKey, pkeyId); - ps.AddBlock(new PSBlock - { - Type = BlockType.NAMED, - Flags = (version == PSVersion.WinModern) ? (uint)0x402 : 0x2, - KeyAsStr = psKey, - ValueAsStr = pkeyId, - Data = pkb.Serialize() - }); + public TokenMeta(byte[] data) + { + Deserialize(data); + } - string cachePath = Utils.GetTokensPath(version).Replace("tokens.dat", @"cache\cache.dat"); - if (File.Exists(cachePath)) File.Delete(cachePath); - } - } + public TokenMeta() + { - SLApi.RefreshTrustedTime(actId); - Logger.WriteLine("Successfully deposited fake product key."); } } } -// Modifiers/GracePeriodReset.cs -namespace LibTSforge.Modifiers +// TokenStore/ITokenStore.cs +namespace LibTSforge.TokenStore { using System; - using System.Collections.Generic; - using System.Linq; - using LibTSforge.PhysicalStore; - public static class GracePeriodReset + public interface ITokenStore : IDisposable { - public static void Reset(PSVersion version, bool production) - { - Utils.KillSPP(); - Logger.WriteLine("Writing TrustedStore data..."); - - using (IPhysicalStore store = Utils.GetStore(version, production)) - { - string value = "msft:sl/timer"; - List blocks = store.FindBlocks(value).ToList(); - - foreach (PSBlock block in blocks) - { - store.DeleteBlock(block.KeyAsStr, block.ValueAsStr); - } - } - - Logger.WriteLine("Successfully reset all grace and evaluation period timers."); - } + void Deserialize(); + void Serialize(); + void AddEntry(TokenEntry entry); + void AddEntries(TokenEntry[] entries); + void DeleteEntry(string name, string ext); + void DeleteUnpopEntry(string name, string ext); + TokenEntry GetEntry(string name, string ext); + TokenMeta GetMetaEntry(string name); + void SetEntry(string name, string ext, byte[] data); } } -// Modifiers/KeyChangeLockDelete.cs -namespace LibTSforge.Modifiers +// TokenStore/TokenStoreModern.cs +namespace LibTSforge.TokenStore { + using System; using System.Collections.Generic; + using System.IO; using System.Linq; - using LibTSforge.PhysicalStore; - using LibTSforge; - public static class KeyChangeLockDelete + using Crypto; + + public class TokenStoreModern : ITokenStore { - public static void Delete(PSVersion version, bool production) - { - Utils.KillSPP(); - Logger.WriteLine("Writing TrustedStore data..."); - using (IPhysicalStore store = Utils.GetStore(version, production)) - { - List values = new List - { - "msft:spp/timebased/AB", - "msft:spp/timebased/CD" - }; - List blocks = new List(); - foreach (string value in values) - { - blocks.AddRange(store.FindBlocks(value).ToList()); - } - foreach (PSBlock block in blocks) - { - store.DeleteBlock(block.KeyAsStr, block.ValueAsStr); - } - } - Logger.WriteLine("Successfully removed the key change lock."); - } - } -} + private static readonly uint VERSION = 3; + private static readonly int ENTRY_SIZE = 0x9E; + private static readonly int BLOCK_SIZE = 0x4020; + private static readonly int ENTRIES_PER_BLOCK = BLOCK_SIZE / ENTRY_SIZE; + private static readonly int BLOCK_PAD_SIZE = 0x66; + private static readonly byte[] CONTS_HEADER = Enumerable.Repeat((byte)0x55, 0x20).ToArray(); + private static readonly byte[] CONTS_FOOTER = Enumerable.Repeat((byte)0xAA, 0x20).ToArray(); -// Modifiers/KMSHostCharge.cs -namespace LibTSforge.Modifiers -{ - using System; - using System.IO; - using LibTSforge.PhysicalStore; - using LibTSforge.SPP; + private List Entries = new List(); + private readonly FileStream TokensFile; - public static class KMSHostCharge - { - public static void Charge(PSVersion version, Guid actId, bool production) + public void Deserialize() { - if (actId == Guid.Empty) - { - actId = SLApi.GetDefaultActivationID(SLApi.WINDOWS_APP_ID, true); + if (TokensFile.Length < BLOCK_SIZE) return; - if (actId == Guid.Empty) - { - throw new NotSupportedException("No applicable activation IDs found."); - } - } + TokensFile.Seek(0x24, SeekOrigin.Begin); + uint nextBlock; - if (SLApi.GetPKeyChannel(SLApi.GetInstalledPkeyID(actId)) != "Volume:CSVLK") + BinaryReader reader = new BinaryReader(TokensFile); + do { - throw new NotSupportedException("Non-Volume:CSVLK product key installed."); - } + reader.ReadUInt32(); + nextBlock = reader.ReadUInt32(); - Guid appId = SLApi.GetAppId(actId); - int totalClients = 50; - int currClients = 25; - byte[] hwidBlock = Constants.UniversalHWIDBlock; - string key = string.Format("SPPSVC\\{0}", appId); - long ldapTimestamp = DateTime.Now.ToFileTime(); + for (int i = 0; i < ENTRIES_PER_BLOCK; i++) + { + uint curOffset = reader.ReadUInt32(); + bool populated = reader.ReadUInt32() == 1; + uint contentOffset = reader.ReadUInt32(); + uint contentLength = reader.ReadUInt32(); + uint allocLength = reader.ReadUInt32(); + byte[] contentData = { }; - BinaryWriter writer = new BinaryWriter(new MemoryStream()); + if (populated) + { + reader.BaseStream.Seek(contentOffset + 0x20, SeekOrigin.Begin); + uint dataLength = reader.ReadUInt32(); - for (int i = 0; i < currClients; i++) - { - writer.Write(ldapTimestamp - (10 * (i + 1))); - writer.Write(Guid.NewGuid().ToByteArray()); - } + if (dataLength != contentLength) + { + throw new FormatException("Data length in tokens content is inconsistent with entry."); + } - byte[] cmidGuids = writer.GetBytes(); + reader.ReadBytes(0x20); + contentData = reader.ReadBytes((int)contentLength); + } - writer = new BinaryWriter(new MemoryStream()); + reader.BaseStream.Seek(curOffset + 0x14, SeekOrigin.Begin); - writer.Write(new byte[40]); + Entries.Add(new TokenEntry + { + Name = reader.ReadNullTerminatedString(0x82), + Extension = reader.ReadNullTerminatedString(0x8), + Data = contentData, + Populated = populated + }); + } - writer.Seek(4, SeekOrigin.Begin); - writer.Write((byte)currClients); + reader.BaseStream.Seek(nextBlock, SeekOrigin.Begin); + } while (nextBlock != 0); + } - writer.Seek(24, SeekOrigin.Begin); - writer.Write((byte)currClients); - byte[] reqCounts = writer.GetBytes(); + public void Serialize() + { + MemoryStream tokens = new MemoryStream(); - Utils.KillSPP(); + using (BinaryWriter writer = new BinaryWriter(tokens)) + { + writer.Write(VERSION); + writer.Write(CONTS_HEADER); - Logger.WriteLine("Writing TrustedStore data..."); + int curBlockOffset = (int)writer.BaseStream.Position; + int curEntryOffset = curBlockOffset + 0x8; + int curContsOffset = curBlockOffset + BLOCK_SIZE; - using (IPhysicalStore store = Utils.GetStore(version, production)) - { - VariableBag kmsCountData = new VariableBag(); - kmsCountData.Blocks.AddRange(new CRCBlock[] + for (int eIndex = 0; eIndex < ((Entries.Count / ENTRIES_PER_BLOCK) + 1) * ENTRIES_PER_BLOCK; eIndex++) { - new CRCBlock - { - DataType = CRCBlockType.BINARY, - KeyAsStr = "SppBindingLicenseData", - Value = hwidBlock - }, - new CRCBlock - { - DataType = CRCBlockType.UINT, - Key = new byte[] { }, - ValueAsInt = (uint)totalClients - }, - new CRCBlock - { - DataType = CRCBlockType.UINT, - Key = new byte[] { }, - ValueAsInt = 1051200000 - }, - new CRCBlock - { - DataType = CRCBlockType.UINT, - Key = new byte[] { }, - ValueAsInt = (uint)currClients - }, - new CRCBlock + TokenEntry entry; + + if (eIndex < Entries.Count) { - DataType = CRCBlockType.BINARY, - Key = new byte[] { }, - Value = cmidGuids - }, - new CRCBlock + entry = Entries[eIndex]; + } + else { - DataType = CRCBlockType.BINARY, - Key = new byte[] { }, - Value = reqCounts + entry = new TokenEntry + { + Name = "", + Extension = "", + Populated = false, + Data = new byte[] { } + }; } - }); - - byte[] kmsChargeData = kmsCountData.Serialize(); - string countVal = string.Format("msft:spp/kms/host/2.0/store/counters/{0}", appId); - - store.DeleteBlock(key, countVal); - store.AddBlock(new PSBlock - { - Type = BlockType.NAMED, - Flags = (version == PSVersion.WinModern) ? (uint)0x400 : 0, - KeyAsStr = key, - ValueAsStr = countVal, - Data = kmsChargeData - }); - - Logger.WriteLine(string.Format("Set charge count to {0} successfully.", currClients)); - } - } - } -} + writer.BaseStream.Seek(curBlockOffset, SeekOrigin.Begin); + writer.Write(curBlockOffset); + writer.Write(0); -// Modifiers/RearmReset.cs -namespace LibTSforge.Modifiers -{ - using System; - using System.Collections.Generic; - using System.Linq; - using LibTSforge.PhysicalStore; + writer.BaseStream.Seek(curEntryOffset, SeekOrigin.Begin); + writer.Write(curEntryOffset); + writer.Write(entry.Populated ? 1 : 0); + writer.Write(entry.Populated ? curContsOffset : 0); + writer.Write(entry.Populated ? entry.Data.Length : -1); + writer.Write(entry.Populated ? entry.Data.Length : -1); + writer.WriteFixedString16(entry.Name, 0x82); + writer.WriteFixedString16(entry.Extension, 0x8); + curEntryOffset = (int)writer.BaseStream.Position; - public static class RearmReset - { - public static void Reset(PSVersion version, bool production) - { - Utils.KillSPP(); + if (entry.Populated) + { + writer.BaseStream.Seek(curContsOffset, SeekOrigin.Begin); + writer.Write(CONTS_HEADER); + writer.Write(entry.Data.Length); + writer.Write(CryptoUtils.SHA256Hash(entry.Data)); + writer.Write(entry.Data); + writer.Write(CONTS_FOOTER); + curContsOffset = (int)writer.BaseStream.Position; + } - Logger.WriteLine("Writing TrustedStore data..."); + if ((eIndex + 1) % ENTRIES_PER_BLOCK == 0 && eIndex != 0) + { + if (eIndex < Entries.Count) + { + writer.BaseStream.Seek(curBlockOffset + 0x4, SeekOrigin.Begin); + writer.Write(curContsOffset); + } - using (IPhysicalStore store = Utils.GetStore(version, production)) - { - List blocks; + writer.BaseStream.Seek(curEntryOffset, SeekOrigin.Begin); + writer.WritePadding(BLOCK_PAD_SIZE); - if (version == PSVersion.Win7) - { - blocks = store.FindBlocks(0xA0000).ToList(); - } - else - { - blocks = store.FindBlocks("__##USERSEP-RESERVED##__$$REARM-COUNT$$").ToList(); - } + writer.BaseStream.Seek(curBlockOffset, SeekOrigin.Begin); + byte[] blockData = new byte[BLOCK_SIZE - 0x20]; - foreach (PSBlock block in blocks) - { - if (version == PSVersion.Win7) - { - store.SetBlock(block.KeyAsStr, block.ValueAsInt, new byte[8]); - } - else - { - store.SetBlock(block.KeyAsStr, block.ValueAsStr, new byte[8]); + tokens.Read(blockData, 0, BLOCK_SIZE - 0x20); + byte[] blockHash = CryptoUtils.SHA256Hash(blockData); + + writer.BaseStream.Seek(curBlockOffset + BLOCK_SIZE - 0x20, SeekOrigin.Begin); + writer.Write(blockHash); + + curBlockOffset = curContsOffset; + curEntryOffset = curBlockOffset + 0x8; + curContsOffset = curBlockOffset + BLOCK_SIZE; } } - Logger.WriteLine("Successfully reset all rearm counters."); + tokens.SetLength(curBlockOffset); } - } - } -} - -// Modifiers/TamperedFlagsDelete.cs -namespace LibTSforge.Modifiers -{ - using System; - using System.Linq; - using LibTSforge.PhysicalStore; - - public static class TamperedFlagsDelete - { - public static void DeleteTamperFlags(PSVersion version, bool production) - { - Utils.KillSPP(); + byte[] tokensData = tokens.ToArray(); + byte[] tokensHash = CryptoUtils.SHA256Hash(tokensData.Take(0x4).Concat(tokensData.Skip(0x24)).ToArray()); - Logger.WriteLine("Writing TrustedStore data..."); + tokens = new MemoryStream(tokensData); - using (IPhysicalStore store = Utils.GetStore(version, production)) + BinaryWriter tokWriter = new BinaryWriter(TokensFile); + using (BinaryReader reader = new BinaryReader(tokens)) { - if (version != PSVersion.Win7) - { - string recreatedFlag = "__##USERSEP-RESERVED##__$$RECREATED-FLAG$$"; - string recoveredFlag = "__##USERSEP-RESERVED##__$$RECOVERED-FLAG$$"; - - DeleteFlag(store, recreatedFlag); - DeleteFlag(store, recoveredFlag); - } - else - { - SetFlag(store, 0xA0001); - } - - Logger.WriteLine("Successfully cleared the tamper state."); + TokensFile.Seek(0, SeekOrigin.Begin); + TokensFile.SetLength(tokens.Length); + tokWriter.Write(reader.ReadBytes(0x4)); + reader.ReadBytes(0x20); + tokWriter.Write(tokensHash); + tokWriter.Write(reader.ReadBytes((int)reader.BaseStream.Length - 0x4)); } } - private static void DeleteFlag(IPhysicalStore store, string flag) + public void AddEntry(TokenEntry entry) { - store.FindBlocks(flag).ToList().ForEach(block => store.DeleteBlock(block.KeyAsStr, block.ValueAsStr)); + Entries.Add(entry); } - private static void SetFlag(IPhysicalStore store, uint flag) + public void AddEntries(TokenEntry[] entries) { - store.FindBlocks(flag).ToList().ForEach(block => store.SetBlock(block.KeyAsStr, block.ValueAsInt, new byte[8])); + Entries.AddRange(entries); } - } -} - - -// Modifiers/UniqueIdDelete.cs -namespace LibTSforge.Modifiers -{ - using System; - using LibTSforge.PhysicalStore; - using LibTSforge.SPP; - public static class UniqueIdDelete - { - public static void DeleteUniqueId(PSVersion version, bool production, Guid actId) + public void DeleteEntry(string name, string ext) { - Guid appId; - - if (actId == Guid.Empty) + foreach (TokenEntry entry in Entries) { - appId = SLApi.WINDOWS_APP_ID; - actId = SLApi.GetDefaultActivationID(appId, true); - - if (actId == Guid.Empty) + if (entry.Name == name && entry.Extension == ext) { - throw new Exception("No applicable activation IDs found."); + Entries.Remove(entry); + return; } } - else - { - appId = SLApi.GetAppId(actId); - } - - string instId = SLApi.GetInstallationID(actId); - Guid pkeyId = SLApi.GetInstalledPkeyID(actId); - - Utils.KillSPP(); - - Logger.WriteLine("Writing TrustedStore data..."); + } - using (IPhysicalStore store = Utils.GetStore(version, production)) + public void DeleteUnpopEntry(string name, string ext) + { + List delEntries = new List(); + foreach (TokenEntry entry in Entries) { - string key = string.Format("SPPSVC\\{0}\\{1}", appId, actId); - PSBlock keyBlock = store.GetBlock(key, pkeyId.ToString()); - - if (keyBlock == null) + if (entry.Name == name && entry.Extension == ext && !entry.Populated) { - throw new Exception("No product key found."); + delEntries.Add(entry); } - - VariableBag pkb = new VariableBag(keyBlock.Data); - - pkb.DeleteBlock("SppPkeyUniqueIdToken"); - - store.SetBlock(key, pkeyId.ToString(), pkb.Serialize()); } - Logger.WriteLine("Successfully removed Unique ID for product key ID " + pkeyId); + Entries = Entries.Except(delEntries).ToList(); } - } -} - - -// Activators/ZeroCID.cs -namespace LibTSforge.Activators -{ - using System; - using System.IO; - using LibTSforge.Crypto; - using LibTSforge.PhysicalStore; - using LibTSforge.SPP; - public static class ZeroCID - { - public static void Deposit(Guid actId, string instId) + public TokenEntry GetEntry(string name, string ext) { - uint status = SLApi.DepositConfirmationID(actId, instId, Constants.ZeroCID); - Logger.WriteLine(string.Format("Depositing fake CID status {0:X}", status)); - - if (status != 0) + foreach (TokenEntry entry in Entries) { - throw new InvalidOperationException("Failed to deposit fake CID."); + if (entry.Name == name && entry.Extension == ext) + { + if (!entry.Populated) continue; + return entry; + } } + + return null; } - public static void Activate(PSVersion version, bool production, Guid actId) + public TokenMeta GetMetaEntry(string name) { - Guid appId; + DeleteUnpopEntry(name, "xml"); + TokenEntry entry = GetEntry(name, "xml"); + TokenMeta meta; - if (actId == Guid.Empty) + if (entry == null) { - appId = SLApi.WINDOWS_APP_ID; - actId = SLApi.GetDefaultActivationID(appId, false); - - if (actId == Guid.Empty) + meta = new TokenMeta { - throw new NotSupportedException("No applicable activation IDs found."); - } + Name = name + }; } else { - appId = SLApi.GetAppId(actId); - } - - if (!SLApi.IsPhoneActivatable(actId)) - { - throw new NotSupportedException("Phone license is unavailable for this product."); - } - - string instId = SLApi.GetInstallationID(actId); - Guid pkeyId = SLApi.GetInstalledPkeyID(actId); - - if (version == PSVersion.Win7) - { - Deposit(actId, instId); + meta = new TokenMeta(entry.Data); } - Utils.KillSPP(); - - Logger.WriteLine("Writing TrustedStore data..."); + return meta; + } - using (IPhysicalStore store = Utils.GetStore(version, production)) + public void SetEntry(string name, string ext, byte[] data) + { + for (int i = 0; i < Entries.Count; i++) { - byte[] hwidBlock = Constants.UniversalHWIDBlock; - - Logger.WriteLine("Activation ID: " + actId); - Logger.WriteLine("Installation ID: " + instId); - Logger.WriteLine("Product Key ID: " + pkeyId); - - byte[] iidHash; - - if (version == PSVersion.Win7) - { - iidHash = CryptoUtils.SHA256Hash(Utils.EncodeString(instId)); - } - else - { - iidHash = CryptoUtils.SHA256Hash(Utils.EncodeString(instId + '\0' + Constants.ZeroCID)); - } - - 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); - - byte[] pkeyData; + TokenEntry entry = Entries[i]; - if (version == PSVersion.Win7) - { - pkeyData = pkb.GetBlock("SppPkeyShortAuthenticator").Value; - } - else + if (entry.Name == name && entry.Extension == ext && entry.Populated) { - pkeyData = pkb.GetBlock("SppPkeyPhoneActivationData").Value; + entry.Data = data; + Entries[i] = entry; + return; } - - pkb.DeleteBlock("SppPkeyVirtual"); - store.SetBlock(key, pkeyId.ToString(), pkb.Serialize()); - - BinaryWriter writer = new BinaryWriter(new MemoryStream()); - writer.Write(0x20); - writer.Write(iidHash); - writer.Write(hwidBlock.Length); - writer.Write(hwidBlock); - byte[] tsHwidData = writer.GetBytes(); - - writer = new BinaryWriter(new MemoryStream()); - writer.Write(0x20); - writer.Write(iidHash); - writer.Write(pkeyData.Length); - writer.Write(pkeyData); - byte[] tsPkeyInfoData = writer.GetBytes(); - - store.AddBlocks(new PSBlock[] { - new PSBlock - { - Type = BlockType.NAMED, - Flags = 0, - KeyAsStr = key, - ValueAsStr = "msft:Windows/7.0/Phone/Cached/HwidBlock/" + pkeyId, - Data = tsHwidData - }, - new PSBlock - { - Type = BlockType.NAMED, - Flags = 0, - KeyAsStr = key, - ValueAsStr = "msft:Windows/7.0/Phone/Cached/PKeyInfo/" + pkeyId, - Data = tsPkeyInfoData - } - }); } - if (version != PSVersion.Win7) - { - Deposit(actId, instId); - } + Entries.Add(new TokenEntry + { + Populated = true, + Name = name, + Extension = ext, + Data = data + }); + } + + public TokenStoreModern(string tokensPath) + { + TokensFile = File.Open(tokensPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); + Deserialize(); + } - SLApi.RefreshLicenseStatus(); - SLApi.FireStateChangedEvent(appId); - Logger.WriteLine("Activated using ZeroCID successfully."); + public void Dispose() + { + Serialize(); + TokensFile.Close(); } } } -// TokenStore/Common.cs -namespace LibTSforge.TokenStore +// PhysicalStore/Common.cs +namespace LibTSforge.PhysicalStore { - using System.Collections.Generic; - using System.IO; + using System.Runtime.InteropServices; - public class TokenEntry + public enum BlockType : uint { - public string Name; - public string Extension; - public byte[] Data; - public bool Populated; + NONE, + NAMED, + ATTRIBUTE, + TIMER } - public class TokenMeta + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct Timer { - public string Name; - public Dictionary Data = new Dictionary(); + public ulong Unknown; + public ulong Time1; + public ulong Time2; + public ulong Expiry; + } - public byte[] Serialize() - { - BinaryWriter writer = new BinaryWriter(new MemoryStream()); - writer.Write(1); - byte[] nameBytes = Utils.EncodeString(Name); - writer.Write(nameBytes.Length); - writer.Write(nameBytes); + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct VistaTimer + { + public ulong Time; + public ulong Expiry; + } +} - foreach (KeyValuePair kv in Data) + +// PhysicalStore/IPhysicalStore.cs +namespace LibTSforge.PhysicalStore +{ + using System; + using System.Collections.Generic; + + public class PSBlock + { + public BlockType Type; + public uint Flags; + public uint Unknown = 0; + public byte[] Key; + public string KeyAsStr + { + get { - byte[] keyBytes = Utils.EncodeString(kv.Key); - byte[] valueBytes = Utils.EncodeString(kv.Value); - writer.Write(keyBytes.Length); - writer.Write(valueBytes.Length); - writer.Write(keyBytes); - writer.Write(valueBytes); + return Utils.DecodeString(Key); + } + set + { + Key = Utils.EncodeString(value); } - - return writer.GetBytes(); } - - public void Deserialize(byte[] data) + public byte[] Value; + public string ValueAsStr { - BinaryReader reader = new BinaryReader(new MemoryStream(data)); - reader.ReadInt32(); - int nameLen = reader.ReadInt32(); - Name = reader.ReadNullTerminatedString(nameLen); - - while (reader.BaseStream.Position < data.Length - 0x8) + get { - int keyLen = reader.ReadInt32(); - int valueLen = reader.ReadInt32(); - string key = reader.ReadNullTerminatedString(keyLen); - string value = reader.ReadNullTerminatedString(valueLen); - Data[key] = value; + return Utils.DecodeString(Value); + } + set + { + Value = Utils.EncodeString(value); } } - - public TokenMeta(byte[] data) + public uint ValueAsInt { - Deserialize(data); + get + { + return BitConverter.ToUInt32(Value, 0); + } + set + { + Value = BitConverter.GetBytes(value); + } } - - public TokenMeta() + 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); + } } } -} - - -// TokenStore/ITokenStore.cs -namespace LibTSforge.TokenStore -{ - using System; - public interface ITokenStore : IDisposable + public interface IPhysicalStore : IDisposable { - void Deserialize(); - void Serialize(); - void AddEntry(TokenEntry entry); - void AddEntries(TokenEntry[] entries); - void DeleteEntry(string name, string ext); - void DeleteUnpopEntry(string name, string ext); - TokenEntry GetEntry(string name, string ext); - TokenMeta GetMetaEntry(string name); - void SetEntry(string name, string ext, byte[] data); + PSBlock GetBlock(string key, string value); + PSBlock GetBlock(string key, uint value); + void AddBlock(PSBlock block); + void AddBlocks(IEnumerable blocks); + void SetBlock(string key, string value, byte[] data); + void SetBlock(string key, string value, string data); + void SetBlock(string key, string value, uint data); + void SetBlock(string key, uint value, byte[] data); + void SetBlock(string key, uint value, string data); + void SetBlock(string key, uint value, uint data); + void DeleteBlock(string key, string value); + void DeleteBlock(string key, uint value); + byte[] Serialize(); + void Deserialize(byte[] data); + byte[] ReadRaw(); + void WriteRaw(byte[] data); + IEnumerable FindBlocks(string valueSearch); + IEnumerable FindBlocks(uint valueSearch); } } -// TokenStore/TokenStoreModern.cs -namespace LibTSforge.TokenStore +// PhysicalStore/PhysicalStoreModern.cs +namespace LibTSforge.PhysicalStore { using System; using System.Collections.Generic; using System.IO; - using System.Linq; - using LibTSforge.Crypto; + using Crypto; - public class TokenStoreModern : ITokenStore + public class ModernBlock { - private static readonly uint VERSION = 3; - private static readonly int ENTRY_SIZE = 0x9E; - private static readonly int BLOCK_SIZE = 0x4020; - private static readonly int ENTRIES_PER_BLOCK = BLOCK_SIZE / ENTRY_SIZE; - private static readonly int BLOCK_PAD_SIZE = 0x66; - - private static readonly byte[] CONTS_HEADER = Enumerable.Repeat((byte)0x55, 0x20).ToArray(); - private static readonly byte[] CONTS_FOOTER = Enumerable.Repeat((byte)0xAA, 0x20).ToArray(); + public BlockType Type; + public uint Flags; + public uint Unknown; + 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); + } + } - private List Entries = new List(); - public FileStream TokensFile; + public void Encode(BinaryWriter writer) + { + writer.Write((uint)Type); + writer.Write(Flags); + writer.Write((uint)Value.Length); + writer.Write((uint)Data.Length); + writer.Write(Unknown); + writer.Write(Value); + writer.Write(Data); + } - public void Deserialize() + public static ModernBlock Decode(BinaryReader reader) { - if (TokensFile.Length < BLOCK_SIZE) return; + uint type = reader.ReadUInt32(); + uint flags = reader.ReadUInt32(); - TokensFile.Seek(0x24, SeekOrigin.Begin); - uint nextBlock = 0; + uint valueLen = reader.ReadUInt32(); + uint dataLen = reader.ReadUInt32(); + uint unk3 = reader.ReadUInt32(); - BinaryReader reader = new BinaryReader(TokensFile); - do - { - uint curOffset = reader.ReadUInt32(); - nextBlock = reader.ReadUInt32(); + byte[] value = reader.ReadBytes((int)valueLen); + byte[] data = reader.ReadBytes((int)dataLen); - for (int i = 0; i < ENTRIES_PER_BLOCK; i++) - { - curOffset = reader.ReadUInt32(); - bool populated = reader.ReadUInt32() == 1; - uint contentOffset = reader.ReadUInt32(); - uint contentLength = reader.ReadUInt32(); - uint allocLength = reader.ReadUInt32(); - byte[] contentData = new byte[] { }; + return new ModernBlock + { + Type = (BlockType)type, + Flags = flags, + Unknown = unk3, + Value = value, + Data = data, + }; + } + } - if (populated) - { - reader.BaseStream.Seek(contentOffset + 0x20, SeekOrigin.Begin); - uint dataLength = reader.ReadUInt32(); + public sealed class PhysicalStoreModern : IPhysicalStore + { + private byte[] PreHeaderBytes = { }; + private readonly Dictionary> Data = new Dictionary>(); + private readonly FileStream TSFile; + private readonly PSVersion Version; + private readonly bool Production; - if (dataLength != contentLength) - { - throw new FormatException("Data length in tokens content is inconsistent with entry."); - } + public byte[] Serialize() + { + BinaryWriter writer = new BinaryWriter(new MemoryStream()); + writer.Write(PreHeaderBytes); + writer.Write(Data.Keys.Count); - reader.ReadBytes(0x20); - contentData = reader.ReadBytes((int)contentLength); - } + foreach (string key in Data.Keys) + { + List blocks = Data[key]; + byte[] keyNameEnc = Utils.EncodeString(key); - reader.BaseStream.Seek(curOffset + 0x14, SeekOrigin.Begin); + writer.Write(keyNameEnc.Length); + writer.Write(keyNameEnc); + writer.Write(blocks.Count); + writer.Align(4); - Entries.Add(new TokenEntry - { - Name = reader.ReadNullTerminatedString(0x82), - Extension = reader.ReadNullTerminatedString(0x8), - Data = contentData, - Populated = populated - }); + foreach (ModernBlock block in blocks) + { + block.Encode(writer); + writer.Align(4); } + } - reader.BaseStream.Seek(nextBlock, SeekOrigin.Begin); - } while (nextBlock != 0); + return writer.GetBytes(); } - public void Serialize() + public void Deserialize(byte[] data) { - MemoryStream tokens = new MemoryStream(); + BinaryReader reader = new BinaryReader(new MemoryStream(data)); + PreHeaderBytes = reader.ReadBytes(8); - using (BinaryWriter writer = new BinaryWriter(tokens)) + while (reader.BaseStream.Position < data.Length - 0x4) { - writer.Write(VERSION); - writer.Write(CONTS_HEADER); - - int curBlockOffset = (int)writer.BaseStream.Position; - int curEntryOffset = curBlockOffset + 0x8; - int curContsOffset = curBlockOffset + BLOCK_SIZE; + uint numKeys = reader.ReadUInt32(); - for (int eIndex = 0; eIndex < ((Entries.Count / ENTRIES_PER_BLOCK) + 1) * ENTRIES_PER_BLOCK; eIndex++) + for (int i = 0; i < numKeys; i++) { - TokenEntry entry; - - if (eIndex < Entries.Count) - { - entry = Entries[eIndex]; - } - else - { - entry = new TokenEntry - { - Name = "", - Extension = "", - Populated = false, - Data = new byte[] { } - }; - } - - writer.BaseStream.Seek(curBlockOffset, SeekOrigin.Begin); - writer.Write(curBlockOffset); - writer.Write(0); + uint lenKeyName = reader.ReadUInt32(); + string keyName = Utils.DecodeString(reader.ReadBytes((int)lenKeyName)); uint numValues = reader.ReadUInt32(); - writer.BaseStream.Seek(curEntryOffset, SeekOrigin.Begin); - writer.Write(curEntryOffset); - writer.Write(entry.Populated ? 1 : 0); - writer.Write(entry.Populated ? curContsOffset : 0); - writer.Write(entry.Populated ? entry.Data.Length : -1); - writer.Write(entry.Populated ? entry.Data.Length : -1); - writer.WriteFixedString16(entry.Name, 0x82); - writer.WriteFixedString16(entry.Extension, 0x8); - curEntryOffset = (int)writer.BaseStream.Position; + reader.Align(4); - if (entry.Populated) - { - writer.BaseStream.Seek(curContsOffset, SeekOrigin.Begin); - writer.Write(CONTS_HEADER); - writer.Write(entry.Data.Length); - writer.Write(CryptoUtils.SHA256Hash(entry.Data)); - writer.Write(entry.Data); - writer.Write(CONTS_FOOTER); - curContsOffset = (int)writer.BaseStream.Position; - } + Data[keyName] = new List(); - if ((eIndex + 1) % ENTRIES_PER_BLOCK == 0 && eIndex != 0) + for (int j = 0; j < numValues; j++) { - if (eIndex < Entries.Count) - { - writer.BaseStream.Seek(curBlockOffset + 0x4, SeekOrigin.Begin); - writer.Write(curContsOffset); - } - - writer.BaseStream.Seek(curEntryOffset, SeekOrigin.Begin); - writer.WritePadding(BLOCK_PAD_SIZE); - - writer.BaseStream.Seek(curBlockOffset, SeekOrigin.Begin); - byte[] blockHash; - byte[] blockData = new byte[BLOCK_SIZE - 0x20]; - - tokens.Read(blockData, 0, BLOCK_SIZE - 0x20); - blockHash = CryptoUtils.SHA256Hash(blockData); - - writer.BaseStream.Seek(curBlockOffset + BLOCK_SIZE - 0x20, SeekOrigin.Begin); - writer.Write(blockHash); - - curBlockOffset = curContsOffset; - curEntryOffset = curBlockOffset + 0x8; - curContsOffset = curBlockOffset + BLOCK_SIZE; + Data[keyName].Add(ModernBlock.Decode(reader)); + reader.Align(4); } } - - tokens.SetLength(curBlockOffset); - } - - byte[] tokensData = tokens.ToArray(); - byte[] tokensHash = CryptoUtils.SHA256Hash(tokensData.Take(0x4).Concat(tokensData.Skip(0x24)).ToArray()); - - tokens = new MemoryStream(tokensData); - - BinaryWriter tokWriter = new BinaryWriter(TokensFile); - using (BinaryReader reader = new BinaryReader(tokens)) - { - TokensFile.Seek(0, SeekOrigin.Begin); - TokensFile.SetLength(tokens.Length); - tokWriter.Write(reader.ReadBytes(0x4)); - reader.ReadBytes(0x20); - tokWriter.Write(tokensHash); - tokWriter.Write(reader.ReadBytes((int)reader.BaseStream.Length - 0x4)); } } - public void AddEntry(TokenEntry entry) + public void AddBlock(PSBlock block) { - Entries.Add(entry); - } + if (!Data.ContainsKey(block.KeyAsStr)) + { + Data[block.KeyAsStr] = new List(); + } - public void AddEntries(TokenEntry[] entries) - { - Entries.AddRange(entries); + Data[block.KeyAsStr].Add(new ModernBlock + { + Type = block.Type, + Flags = block.Flags, + Unknown = block.Unknown, + Value = block.Value, + Data = block.Data + }); } - public void DeleteEntry(string name, string ext) + public void AddBlocks(IEnumerable blocks) { - foreach (TokenEntry entry in Entries) + foreach (PSBlock block in blocks) { - if (entry.Name == name && entry.Extension == ext) - { - Entries.Remove(entry); - return; - } + AddBlock(block); } } - public void DeleteUnpopEntry(string name, string ext) + public PSBlock GetBlock(string key, string value) { - List delEntries = new List(); - foreach (TokenEntry entry in Entries) + List blocks = Data[key]; + + foreach (ModernBlock block in blocks) { - if (entry.Name == name && entry.Extension == ext && !entry.Populated) + if (block.ValueAsStr == value) { - delEntries.Add(entry); + return new PSBlock + { + Type = block.Type, + Flags = block.Flags, + Key = Utils.EncodeString(key), + Value = block.Value, + Data = block.Data + }; } } - Entries = Entries.Except(delEntries).ToList(); + return null; } - public TokenEntry GetEntry(string name, string ext) + public PSBlock GetBlock(string key, uint value) { - foreach (TokenEntry entry in Entries) + List blocks = Data[key]; + + foreach (ModernBlock block in blocks) { - if (entry.Name == name && entry.Extension == ext) + if (block.ValueAsInt == value) { - if (!entry.Populated) continue; - return entry; + return new PSBlock + { + Type = block.Type, + Flags = block.Flags, + Key = Utils.EncodeString(key), + Value = block.Value, + Data = block.Data + }; } } return null; } - public TokenMeta GetMetaEntry(string name) + public void SetBlock(string key, string value, byte[] data) { - DeleteUnpopEntry(name, "xml"); - TokenEntry entry = GetEntry(name, "xml"); - TokenMeta meta; + List blocks = Data[key]; - if (entry == null) - { - meta = new TokenMeta - { - Name = name - }; - } - else + for (int i = 0; i < blocks.Count; i++) { - meta = new TokenMeta(entry.Data); + ModernBlock block = blocks[i]; + + if (block.ValueAsStr == value) + { + block.Data = data; + blocks[i] = block; + break; + } } - return meta; + Data[key] = blocks; } - public void SetEntry(string name, string ext, byte[] data) + public void SetBlock(string key, uint value, byte[] data) { - for (int i = 0; i < Entries.Count; i++) + List blocks = Data[key]; + + for (int i = 0; i < blocks.Count; i++) { - TokenEntry entry = Entries[i]; + ModernBlock block = blocks[i]; - if (entry.Name == name && entry.Extension == ext && entry.Populated) + if (block.ValueAsInt == value) { - entry.Data = data; - Entries[i] = entry; - return; + block.Data = data; + blocks[i] = block; + break; } } - Entries.Add(new TokenEntry - { - Populated = true, - Name = name, - Extension = ext, - Data = data - }); + Data[key] = blocks; } - public TokenStoreModern(string tokensPath) + public void SetBlock(string key, string value, string data) { - TokensFile = File.Open(tokensPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); - Deserialize(); + SetBlock(key, value, Utils.EncodeString(data)); } - public TokenStoreModern() + public void SetBlock(string key, string value, uint data) { - + SetBlock(key, value, BitConverter.GetBytes(data)); } - public void Dispose() + public void SetBlock(string key, uint value, string data) { - Serialize(); - TokensFile.Close(); + SetBlock(key, value, Utils.EncodeString(data)); } - } -} - - -// PhysicalStore/Common.cs -namespace LibTSforge.PhysicalStore -{ - using System.Runtime.InteropServices; - - public enum BlockType : uint - { - NONE, - NAMED, - ATTRIBUTE, - TIMER - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct Timer - { - public ulong Unknown; - public ulong Time1; - public ulong Time2; - public ulong Expiry; - } -} - -// PhysicalStore/IPhysicalStore.cs -namespace LibTSforge.PhysicalStore -{ - using System; - using System.Collections.Generic; + public void SetBlock(string key, uint value, uint data) + { + SetBlock(key, value, BitConverter.GetBytes(data)); + } - public class PSBlock - { - public BlockType Type; - public uint Flags; - public uint Unknown = 0; - public byte[] Key; - public string KeyAsStr + public void DeleteBlock(string key, string value) { - get + if (!Data.ContainsKey(key)) { - return Utils.DecodeString(Key); + return; } - set + + List blocks = Data[key]; + + foreach (ModernBlock block in blocks) { - Key = Utils.EncodeString(value); + if (block.ValueAsStr == value) + { + blocks.Remove(block); + break; + } } + + Data[key] = blocks; } - public byte[] Value; - public string ValueAsStr + + public void DeleteBlock(string key, uint value) { - get + if (!Data.ContainsKey(key)) { - return Utils.DecodeString(Value); + return; } - set + + List blocks = Data[key]; + + foreach (ModernBlock block in blocks) { - Value = Utils.EncodeString(value); + if (block.ValueAsInt == value) + { + blocks.Remove(block); + break; + } } + + Data[key] = blocks; } - public uint ValueAsInt + + public PhysicalStoreModern(string tsPath, bool production, PSVersion version) { - get - { - return BitConverter.ToUInt32(Value, 0); - } - set - { - Value = BitConverter.GetBytes(value); - } + TSFile = File.Open(tsPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); + Deserialize(PhysStoreCrypto.DecryptPhysicalStore(TSFile.ReadAllBytes(), production, version)); + TSFile.Seek(0, SeekOrigin.Begin); + Version = version; + Production = production; } - public byte[] Data; - public string DataAsStr + + public void Dispose() { - get - { - return Utils.DecodeString(Data); - } - set + if (TSFile.CanWrite) { - Data = Utils.EncodeString(value); + byte[] data = PhysStoreCrypto.EncryptPhysicalStore(Serialize(), Production, Version); + TSFile.SetLength(data.LongLength); + TSFile.Seek(0, SeekOrigin.Begin); + TSFile.WriteAllBytes(data); + TSFile.Close(); } } - public uint DataAsInt + + public byte[] ReadRaw() { - get + byte[] data = PhysStoreCrypto.DecryptPhysicalStore(TSFile.ReadAllBytes(), Production, Version); + TSFile.Seek(0, SeekOrigin.Begin); + return data; + } + + public void WriteRaw(byte[] data) + { + byte[] encrData = PhysStoreCrypto.EncryptPhysicalStore(data, Production, Version); + TSFile.SetLength(encrData.LongLength); + TSFile.Seek(0, SeekOrigin.Begin); + TSFile.WriteAllBytes(encrData); + TSFile.Close(); + } + + public IEnumerable FindBlocks(string valueSearch) + { + List results = new List(); + + foreach (string key in Data.Keys) { - return BitConverter.ToUInt32(Data, 0); + List values = Data[key]; + + foreach (ModernBlock block in values) + { + if (block.ValueAsStr.Contains(valueSearch)) + { + results.Add(new PSBlock + { + Type = block.Type, + Flags = block.Flags, + KeyAsStr = key, + Value = block.Value, + Data = block.Data + }); + } + } } - set + + return results; + } + + public IEnumerable FindBlocks(uint valueSearch) + { + List results = new List(); + + foreach (string key in Data.Keys) { - Data = BitConverter.GetBytes(value); + List values = Data[key]; + + foreach (ModernBlock block in values) + { + if (block.ValueAsInt == valueSearch) + { + results.Add(new PSBlock + { + Type = block.Type, + Flags = block.Flags, + KeyAsStr = key, + Value = block.Value, + Data = block.Data + }); + } + } } - } - } - public interface IPhysicalStore : IDisposable - { - PSBlock GetBlock(string key, string value); - PSBlock GetBlock(string key, uint value); - void AddBlock(PSBlock block); - void AddBlocks(IEnumerable blocks); - void SetBlock(string key, string value, byte[] data); - void SetBlock(string key, string value, string data); - void SetBlock(string key, string value, uint data); - void SetBlock(string key, uint value, byte[] data); - void SetBlock(string key, uint value, string data); - void SetBlock(string key, uint value, uint data); - void DeleteBlock(string key, string value); - void DeleteBlock(string key, uint value); - byte[] Serialize(); - void Deserialize(byte[] data); - byte[] ReadRaw(); - void WriteRaw(byte[] data); - IEnumerable FindBlocks(string valueSearch); - IEnumerable FindBlocks(uint valueSearch); + return results; + } } } -// PhysicalStore/PhysicalStoreModern.cs +// PhysicalStore/PhysicalStoreVista.cs namespace LibTSforge.PhysicalStore { using System; using System.Collections.Generic; using System.IO; - using LibTSforge.Crypto; + using Crypto; - public class ModernBlock + public class VistaBlock { public BlockType Type; public uint Flags; - public uint Unknown; public byte[] Value; public string ValueAsStr { @@ -5804,69 +6684,53 @@ namespace LibTSforge.PhysicalStore } } - public void Encode(BinaryWriter writer) + internal void Encode(BinaryWriter writer) { - writer.Write((uint)Type); - writer.Write(Flags); - writer.Write((uint)Value.Length); - writer.Write((uint)Data.Length); - writer.Write(Unknown); + writer.Write((uint)Type); + writer.Write(Flags); + writer.Write(Value.Length); + writer.Write(Data.Length); writer.Write(Value); writer.Write(Data); } - public static ModernBlock Decode(BinaryReader reader) + internal static VistaBlock Decode(BinaryReader reader) { uint type = reader.ReadUInt32(); uint flags = reader.ReadUInt32(); - uint valueLen = reader.ReadUInt32(); - uint dataLen = reader.ReadUInt32(); - uint unk3 = reader.ReadUInt32(); - - byte[] value = reader.ReadBytes((int)valueLen); - byte[] data = reader.ReadBytes((int)dataLen); + int valueLen = reader.ReadInt32(); + int dataLen = reader.ReadInt32(); - return new ModernBlock + byte[] value = reader.ReadBytes(valueLen); + byte[] data = reader.ReadBytes(dataLen); + return new VistaBlock { Type = (BlockType)type, Flags = flags, - Unknown = unk3, Value = value, Data = data, }; } } - public sealed class PhysicalStoreModern : IPhysicalStore + public sealed class PhysicalStoreVista : IPhysicalStore { - private byte[] PreHeaderBytes = new byte[] { }; - private readonly Dictionary> Data = new Dictionary>(); - private readonly FileStream TSFile; - private readonly PSVersion Version; + private byte[] PreHeaderBytes = { }; + private readonly List Blocks = new List(); + private readonly FileStream TSPrimary; + private readonly FileStream TSSecondary; private readonly bool Production; public byte[] Serialize() { BinaryWriter writer = new BinaryWriter(new MemoryStream()); writer.Write(PreHeaderBytes); - writer.Write(Data.Keys.Count); - foreach (string key in Data.Keys) + foreach (VistaBlock block in Blocks) { - List blocks = Data[key]; - byte[] keyNameEnc = Utils.EncodeString(key); - - writer.Write(keyNameEnc.Length); - writer.Write(keyNameEnc); - writer.Write(blocks.Count); + block.Encode(writer); writer.Align(4); - - foreach (ModernBlock block in blocks) - { - block.Encode(writer); - writer.Align(4); - } } return writer.GetBytes(); @@ -5874,43 +6738,24 @@ namespace LibTSforge.PhysicalStore public void Deserialize(byte[] data) { + int len = data.Length; + BinaryReader reader = new BinaryReader(new MemoryStream(data)); PreHeaderBytes = reader.ReadBytes(8); - while (reader.BaseStream.Position < data.Length - 0x4) + while (reader.BaseStream.Position < len - 0x14) { - uint numKeys = reader.ReadUInt32(); - - for (int i = 0; i < numKeys; i++) - { - uint lenKeyName = reader.ReadUInt32(); - string keyName = Utils.DecodeString(reader.ReadBytes((int)lenKeyName)); uint numValues = reader.ReadUInt32(); - - reader.Align(4); - - Data[keyName] = new List(); - - for (int j = 0; j < numValues; j++) - { - Data[keyName].Add(ModernBlock.Decode(reader)); - reader.Align(4); - } - } + Blocks.Add(VistaBlock.Decode(reader)); + reader.Align(4); } } public void AddBlock(PSBlock block) { - if (!Data.ContainsKey(block.KeyAsStr)) - { - Data[block.KeyAsStr] = new List(); - } - - Data[block.KeyAsStr].Add(new ModernBlock + Blocks.Add(new VistaBlock { Type = block.Type, Flags = block.Flags, - Unknown = block.Unknown, Value = block.Value, Data = block.Data }); @@ -5926,9 +6771,7 @@ namespace LibTSforge.PhysicalStore public PSBlock GetBlock(string key, string value) { - List blocks = Data[key]; - - foreach (ModernBlock block in blocks) + foreach (VistaBlock block in Blocks) { if (block.ValueAsStr == value) { @@ -5936,7 +6779,7 @@ namespace LibTSforge.PhysicalStore { Type = block.Type, Flags = block.Flags, - Key = Utils.EncodeString(key), + Key = new byte[0], Value = block.Value, Data = block.Data }; @@ -5948,9 +6791,7 @@ namespace LibTSforge.PhysicalStore public PSBlock GetBlock(string key, uint value) { - List blocks = Data[key]; - - foreach (ModernBlock block in blocks) + foreach (VistaBlock block in Blocks) { if (block.ValueAsInt == value) { @@ -5958,7 +6799,7 @@ namespace LibTSforge.PhysicalStore { Type = block.Type, Flags = block.Flags, - Key = Utils.EncodeString(key), + Key = new byte[0], Value = block.Value, Data = block.Data }; @@ -5970,40 +6811,32 @@ namespace LibTSforge.PhysicalStore public void SetBlock(string key, string value, byte[] data) { - List blocks = Data[key]; - - for (int i = 0; i < blocks.Count; i++) + for (int i = 0; i < Blocks.Count; i++) { - ModernBlock block = blocks[i]; + VistaBlock block = Blocks[i]; if (block.ValueAsStr == value) { block.Data = data; - blocks[i] = block; + Blocks[i] = block; break; } } - - Data[key] = blocks; } public void SetBlock(string key, uint value, byte[] data) { - List blocks = Data[key]; - - for (int i = 0; i < blocks.Count; i++) + for (int i = 0; i < Blocks.Count; i++) { - ModernBlock block = blocks[i]; + VistaBlock block = Blocks[i]; if (block.ValueAsInt == value) { block.Data = data; - blocks[i] = block; + Blocks[i] = block; break; } } - - Data[key] = blocks; } public void SetBlock(string key, string value, string data) @@ -6028,100 +6861,98 @@ namespace LibTSforge.PhysicalStore public void DeleteBlock(string key, string value) { - if (Data.ContainsKey(key)) + foreach (VistaBlock block in Blocks) { - List blocks = Data[key]; - - foreach (ModernBlock block in blocks) + if (block.ValueAsStr == value) { - if (block.ValueAsStr == value) - { - blocks.Remove(block); - break; - } + Blocks.Remove(block); + return; } - - Data[key] = blocks; } } public void DeleteBlock(string key, uint value) { - if (Data.ContainsKey(key)) + foreach (VistaBlock block in Blocks) { - List blocks = Data[key]; - - foreach (ModernBlock block in blocks) + if (block.ValueAsInt == value) { - if (block.ValueAsInt == value) - { - blocks.Remove(block); - break; - } + Blocks.Remove(block); + return; } - - Data[key] = blocks; } } - public PhysicalStoreModern(string tsPath, bool production, PSVersion version) + public PhysicalStoreVista(string primaryPath, bool production) { - TSFile = File.Open(tsPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); - Deserialize(PhysStoreCrypto.DecryptPhysicalStore(TSFile.ReadAllBytes(), production)); - TSFile.Seek(0, SeekOrigin.Begin); - Version = version; + 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 (TSFile.CanWrite) + if (TSPrimary.CanWrite && TSSecondary.CanWrite) { - byte[] data = PhysStoreCrypto.EncryptPhysicalStore(Serialize(), Production, Version); - TSFile.SetLength(data.LongLength); - TSFile.Seek(0, SeekOrigin.Begin); - TSFile.WriteAllBytes(data); - TSFile.Close(); + 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(TSFile.ReadAllBytes(), Production); - TSFile.Seek(0, SeekOrigin.Begin); + 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, Version); - TSFile.SetLength(encrData.LongLength); - TSFile.Seek(0, SeekOrigin.Begin); - TSFile.WriteAllBytes(encrData); - TSFile.Close(); + 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 FindBlocks(string valueSearch) { List results = new List(); - foreach (string key in Data.Keys) + foreach (VistaBlock block in Blocks) { - List values = Data[key]; - - foreach (ModernBlock block in values) + if (block.ValueAsStr.Contains(valueSearch)) { - if (block.ValueAsStr.Contains(valueSearch)) + results.Add(new PSBlock { - results.Add(new PSBlock - { - Type = block.Type, - Flags = block.Flags, - KeyAsStr = key, - Value = block.Value, - Data = block.Data - }); - } + Type = block.Type, + Flags = block.Flags, + Key = new byte[0], + Value = block.Value, + Data = block.Data + }); } } @@ -6132,23 +6963,18 @@ namespace LibTSforge.PhysicalStore { List results = new List(); - foreach (string key in Data.Keys) + foreach (VistaBlock block in Blocks) { - List values = Data[key]; - - foreach (ModernBlock block in values) + if (block.ValueAsInt == valueSearch) { - if (block.ValueAsInt == valueSearch) + results.Add(new PSBlock { - results.Add(new PSBlock - { - Type = block.Type, - Flags = block.Flags, - KeyAsStr = key, - Value = block.Value, - Data = block.Data - }); - } + Type = block.Type, + Flags = block.Flags, + Key = new byte[0], + Value = block.Value, + Data = block.Data + }); } } @@ -6164,7 +6990,7 @@ namespace LibTSforge.PhysicalStore using System; using System.Collections.Generic; using System.IO; - using LibTSforge.Crypto; + using Crypto; public class Win7Block { @@ -6266,7 +7092,7 @@ namespace LibTSforge.PhysicalStore public sealed class PhysicalStoreWin7 : IPhysicalStore { - private byte[] PreHeaderBytes = new byte[] { }; + private byte[] PreHeaderBytes = { }; private readonly List Blocks = new List(); private readonly FileStream TSPrimary; private readonly FileStream TSSecondary; @@ -6440,7 +7266,7 @@ namespace LibTSforge.PhysicalStore TSSecondary = File.Open(primaryPath.Replace("-0.", "-1."), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); Production = production; - Deserialize(PhysStoreCrypto.DecryptPhysicalStore(TSPrimary.ReadAllBytes(), production)); + Deserialize(PhysStoreCrypto.DecryptPhysicalStore(TSPrimary.ReadAllBytes(), production, PSVersion.Win7)); TSPrimary.Seek(0, SeekOrigin.Begin); } @@ -6466,7 +7292,7 @@ namespace LibTSforge.PhysicalStore public byte[] ReadRaw() { - byte[] data = PhysStoreCrypto.DecryptPhysicalStore(TSPrimary.ReadAllBytes(), Production); + byte[] data = PhysStoreCrypto.DecryptPhysicalStore(TSPrimary.ReadAllBytes(), Production, PSVersion.Win7); TSPrimary.Seek(0, SeekOrigin.Begin); return data; } @@ -6549,7 +7375,7 @@ namespace LibTSforge.PhysicalStore BINARY = 1 << 2 } - public class CRCBlock + public abstract class CRCBlock { public CRCBlockType DataType; public byte[] Key; @@ -6588,7 +7414,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(); writer.Write(crc); @@ -6603,7 +7479,7 @@ namespace LibTSforge.PhysicalStore writer.Align(8); } - public static CRCBlock Decode(BinaryReader reader) + public override void Decode(BinaryReader reader) { uint crc = reader.ReadUInt32(); uint type = reader.ReadUInt32(); @@ -6616,22 +7492,17 @@ namespace LibTSforge.PhysicalStore byte[] value = reader.ReadBytes((int)lenVal); reader.Align(8); - CRCBlock block = new CRCBlock - { - DataType = (CRCBlockType)type, - Key = key, - Value = value, - }; + DataType = (CRCBlockType)type; + Key = key; + Value = value; - if (block.CRC() != crc) + if (CRC() != crc) { throw new InvalidDataException("Invalid CRC in variable bag."); } - - return block; } - public uint CRC() + public override uint CRC() { BinaryWriter wtemp = new BinaryWriter(new MemoryStream()); wtemp.Write(0); @@ -6647,8 +7518,9 @@ namespace LibTSforge.PhysicalStore public class VariableBag { public List Blocks = new List(); + private readonly PSVersion Version; - public void Deserialize(byte[] data) + private void Deserialize(byte[] data) { int len = data.Length; @@ -6656,7 +7528,19 @@ namespace LibTSforge.PhysicalStore 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); } } @@ -6666,7 +7550,13 @@ namespace LibTSforge.PhysicalStore foreach (CRCBlock block in Blocks) { - block.Encode(writer); + if (Version == PSVersion.Vista) + { + ((CRCBlockVista)block).Encode(writer); + } else + { + ((CRCBlockModern)block).Encode(writer); + } } return writer.GetBytes(); @@ -6712,14 +7602,15 @@ namespace LibTSforge.PhysicalStore } } - public VariableBag(byte[] data) + public VariableBag(byte[] data, PSVersion version) { + Version = version; Deserialize(data); } - public VariableBag() + public VariableBag(PSVersion version) { - + Version = version; } } } @@ -6749,7 +7640,7 @@ if ($env:_debug -eq '0') { [LibTSforge.Logger]::HideOutput = $true } $ver = [LibTSforge.Utils]::DetectVersion() -$prod = [LibTSforge.Utils]::DetectCurrentKey() +$prod = [LibTSforge.SPP.SPPUtils]::DetectCurrentKey() $tsactids = @($args) function Get-WmiInfo { @@ -6801,7 +7692,7 @@ if ($env:resetstuff -eq $null) { $licenseStatus = Get-WmiInfo -tsactid $tsactid -property "LicenseStatus" if ($licenseStatus -eq 1) { if ($prodDes -match 'KMS' -and $prodDes -notmatch 'CLIENT') { - [LibTSforge.Modifiers.KMSHostCharge]::Charge($ver, $tsactid, $prod) + [LibTSforge.Modifiers.KMSHostCharge]::Charge($ver, $prod, $tsactid) Write-Host "[$prodName] CSVLK is permanently activated with ZeroCID." -ForegroundColor White -BackgroundColor DarkGreen Write-Host "[$prodName] CSVLK is charged with 25 clients for 30 days." -ForegroundColor White -BackgroundColor DarkGreen }