Initial commit

This commit is contained in:
Lasse Lauwerys
2025-02-20 16:33:04 +01:00
commit f20cf222a8
36 changed files with 4758 additions and 0 deletions
+281
View File
@@ -0,0 +1,281 @@
using Microsoft.Win32;
using System;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.ServiceProcess;
using System.Text;
using System.Collections.Generic;
//using MetroUnlocker.Crypto;
//using MetroUnlocker.PhysicalStore;
using MetroUnlocker.LibTSForge.SPP;
//using MetroUnlocker.TokenStore;
// Common.cs
namespace MetroUnlocker
{
public enum PSVersion
{
Win8Early,
Win8,
WinBlue,
WinModern
}
public enum BlockType : uint
{
NONE,
NAMED,
ATTRIBUTE,
TIMER
}
public static class Constants
{
public static readonly string ZeroCID = new string('0', 48);
public static readonly byte[] UniversalHWIDBlock =
{
0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x0c, 0x01, 0x00
};
}
public static class Utils
{
[DllImport("kernel32.dll")]
public static extern uint GetSystemDefaultLCID();
public static string GetArchitecture()
{
string arch = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE", EnvironmentVariableTarget.Machine).ToUpperInvariant();
return arch == "AMD64" ? "X64" : arch;
}
public static void WritePadding(this BinaryWriter writer, int len)
{
writer.Write(Enumerable.Repeat((byte)0, len).ToArray());
}
public static void WriteFixedString(this BinaryWriter writer, string str, int bLen)
{
writer.Write(Encoding.ASCII.GetBytes(str));
writer.WritePadding(bLen - str.Length);
}
public static void WriteFixedString16(this BinaryWriter writer, string str, int bLen)
{
byte[] bstr = Utils.EncodeString(str);
writer.Write(bstr);
writer.WritePadding(bLen - bstr.Length);
}
public static void Align(this BinaryWriter writer, int to)
{
int pos = (int)writer.BaseStream.Position;
writer.Write(Enumerable.Repeat((byte)0, -pos & (to - 1)).ToArray());
}
public static void Align(this BinaryReader reader, int to)
{
int pos = (int)reader.BaseStream.Position;
reader.BaseStream.Seek(-pos & (to - 1), SeekOrigin.Current);
}
public static string ReadNullTerminatedString(this BinaryReader reader, int maxLen)
{
return Encoding.Unicode.GetString(reader.ReadBytes(maxLen)).Split(new char[] { '\0' }, 2)[0];
}
public static byte[] GetBytes(this BinaryWriter writer)
{
return ((MemoryStream)writer.BaseStream).ToArray();
}
public static void WriteAllBytes(FileStream fs, byte[] data)
{
fs.Seek(0, SeekOrigin.Begin);
fs.SetLength(data.Length);
fs.Write(data, 0, data.Length);
}
public static byte[] ReadAllBytes(FileStream fs)
{
BinaryReader br = new BinaryReader(fs);
return br.ReadBytes((int)fs.Length);
}
public static uint CRC32(byte[] data)
{
const uint polynomial = 0x04C11DB7;
uint crc = 0xffffffff;
foreach (byte b in data)
{
crc ^= (uint)b << 24;
for (int bit = 0; bit < 8; bit++)
{
if ((crc & 0x80000000) != 0)
{
crc = (crc << 1) ^ polynomial;
}
else
{
crc <<= 1;
}
}
}
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 PSVersion DetectVersion()
{
int build = Environment.OSVersion.Version.Build;
if (build >= 9600) return PSVersion.WinModern;
//if (build >= 6000 && build <= 6003) return PSVersion.Vista;
//if (build >= 7600 && build <= 7602) return PSVersion.Win7;
if (build == 9200) return PSVersion.Win8;
throw new NotSupportedException("This version of Windows is not supported. (build " + build + ")");
}
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 string DecodeString(byte[] data)
{
return Encoding.Unicode.GetString(data).Trim('\0');
}
public static byte[] EncodeString(string str)
{
return Encoding.Unicode.GetBytes(str + '\0');
}
internal static string GetTokenStorePath()
{
return (string)Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform", "TokenStore", string.Empty);
}
}
public class TokenMeta
{
public string Name;
public Dictionary<string, string> Data = new Dictionary<string, string>();
public byte[] Serialize()
{
BinaryWriter writer = new BinaryWriter(new MemoryStream());
writer.Write(1);
byte[] nameBytes = Utils.EncodeString(Name);
writer.Write(nameBytes.Length);
writer.Write(nameBytes);
foreach (KeyValuePair<string, string> 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);
}
return writer.GetBytes();
}
public void Deserialize(byte[] data)
{
BinaryReader reader = new BinaryReader(new MemoryStream(data));
reader.ReadInt32();
int nameLen = reader.ReadInt32();
Name = reader.ReadNullTerminatedString(nameLen);
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;
}
}
public TokenMeta(byte[] data)
{
Deserialize(data);
}
public TokenMeta()
{
}
}
}
@@ -0,0 +1,121 @@
using System;
using System.Linq;
using System.Security.Cryptography;
namespace MetroUnlocker.LibTSForge.Crypto
{
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)
{
HMACSHA1 hmac = new HMACSHA1(key);
return Enumerable.SequenceEqual(signature, HMACSign(key, data));
}
public static byte[] SHA256Hash(byte[] data)
{
using (SHA256 sha256 = SHA256.Create())
{
return sha256.ComputeHash(data);
}
}
}
}
+87
View File
@@ -0,0 +1,87 @@
namespace MetroUnlocker.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
};
}
}
@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using MetroUnlocker.LibTSForge;
namespace MetroUnlocker.LibTSForge.Crypto
{
public static class PhysicalStoreCrypto
{
public static byte[] DecryptPhysicalStore(byte[] data, bool production)
{
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();
byte[] hmacSig = decData.Skip(0x10).Take(0x14).ToArray();
byte[] psData = decData.Skip(0x28).ToArray();
if (!CryptoUtils.HMACVerify(hmacKey, psData, hmacSig))
throw new Exception("Failed to verify HMAC. Physical store is either corrupt or in Vista format.");
return psData;
}
public static byte[] EncryptPhysicalStore(byte[] data, bool production, PSVersion version)
{
Dictionary<PSVersion, int> versionTable = new Dictionary<PSVersion, int>
{
{PSVersion.Win8, 1},
{PSVersion.WinBlue, 2},
{PSVersion.WinModern, 3}
};
byte[] rsaKey = production ? Keys.PRODUCTION : Keys.TEST;
byte[] aesKey = Encoding.UTF8.GetBytes("Boop Foxyz nose!");
byte[] hmacKey = CryptoUtils.GenerateRandomKey(0x10);
byte[] encAesKey = CryptoUtils.RSAEncrypt(rsaKey, aesKey);
byte[] aesKeySig = CryptoUtils.RSASign(rsaKey, encAesKey);
byte[] hmacSig = CryptoUtils.HMACSign(hmacKey, data);
byte[] decData = new byte[] { };
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();
}
}
}
@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MetroUnlocker.LibTSForge.Modifiers
{
using System;
using System.IO;
using Microsoft.Win32;
using MetroUnlocker.LibTSForge.PhysicalStore;
using MetroUnlocker.LibTSForge.SPP;
using MetroUnlocker.LibTSForge.TokenStore;
public static class GenPKeyInstall
{
public static void InstallGenPKey(PSVersion version, bool production, Guid actId)
{
PKeyConfig pkc = new PKeyConfig();
pkc.LoadConfig(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)
throw new Exception("The key algorithm isn't 2009");
uint status = SLApi.InstallProductKey(pkey);
if (status != 0)
throw new ApplicationException("Failed to install generated product key.");
return;
}
}
}
@@ -0,0 +1,111 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace MetroUnlocker.LibTSForge.PhysicalStore
{
public enum CRCBlockType : uint
{
UINT = 1 << 0,
STRING = 1 << 1,
BINARY = 1 << 2
}
public class CRCBlock
{
public CRCBlockType DataType;
public byte[] Key;
public string KeyAsStr
{
get
{
return Utils.DecodeString(Key);
}
set
{
Key = Utils.EncodeString(value);
}
}
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 void Encode(BinaryWriter writer)
{
uint crc = CRC();
writer.Write(crc);
writer.Write((uint)DataType);
writer.Write(Key.Length);
writer.Write(Value.Length);
writer.Write(Key);
writer.Align(8);
writer.Write(Value);
writer.Align(8);
}
public static CRCBlock Decode(BinaryReader reader)
{
uint crc = reader.ReadUInt32();
uint type = reader.ReadUInt32();
uint lenName = reader.ReadUInt32();
uint lenVal = reader.ReadUInt32();
byte[] key = reader.ReadBytes((int)lenName);
reader.Align(8);
byte[] value = reader.ReadBytes((int)lenVal);
reader.Align(8);
CRCBlock block = new CRCBlock
{
DataType = (CRCBlockType)type,
Key = key,
Value = value,
};
if (block.CRC() != crc)
{
throw new InvalidDataException("Invalid CRC in variable bag.");
}
return block;
}
public uint CRC()
{
BinaryWriter wtemp = new BinaryWriter(new MemoryStream());
wtemp.Write(0);
wtemp.Write((uint)DataType);
wtemp.Write(Key.Length);
wtemp.Write(Value.Length);
wtemp.Write(Key);
wtemp.Write(Value);
return Utils.CRC32(((MemoryStream)wtemp.BaseStream).ToArray());
}
}
}
@@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace MetroUnlocker.LibTSForge.PhysicalStore
{
public class ModernBlock
{
public BlockType Type;
public uint Flags;
public uint Unknown;
public byte[] Key;
public string KeyAsStr
{
get
{
return Utils.DecodeString(Key);
}
set
{
Key = Utils.EncodeString(value);
}
}
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);
}
}
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 static ModernBlock 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);
return new ModernBlock
{
Type = (BlockType)type,
Flags = flags,
Unknown = unk3,
Value = value,
Data = data,
};
}
}
}
@@ -0,0 +1,282 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Microsoft.Win32;
using MetroUnlocker.LibTSForge.Crypto;
namespace MetroUnlocker.LibTSForge.PhysicalStore
{
public sealed class PhysicalStore : IDisposable
{
private byte[] PreHeaderBytes = new byte[] { };
private readonly Dictionary<string, List<ModernBlock>> Data = new Dictionary<string, List<ModernBlock>>();
private readonly FileStream TSFile;
private readonly PSVersion Version;
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)
{
List<ModernBlock> blocks = Data[key];
byte[] keyNameEnc = Utils.EncodeString(key);
writer.Write(keyNameEnc.Length);
writer.Write(keyNameEnc);
writer.Write(blocks.Count);
writer.Align(4);
foreach (ModernBlock block in blocks)
{
block.Encode(writer);
writer.Align(4);
}
}
return Utils.GetBytes(writer);
}
public void Deserialize(byte[] data)
{
BinaryReader reader = new BinaryReader(new MemoryStream(data));
PreHeaderBytes = reader.ReadBytes(8);
while (reader.BaseStream.Position < data.Length - 0x4)
{
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<ModernBlock>();
for (int j = 0; j < numValues; j++)
{
Data[keyName].Add(ModernBlock.Decode(reader));
reader.Align(4);
}
}
}
}
public void AddBlock(ModernBlock block)
{
if (!Data.ContainsKey(block.KeyAsStr))
{
Data[block.KeyAsStr] = new List<ModernBlock>();
}
Data[block.KeyAsStr].Add(new ModernBlock
{
Type = block.Type,
Flags = block.Flags,
Unknown = block.Unknown,
Value = block.Value,
Data = block.Data
});
}
public void AddBlocks(IEnumerable<ModernBlock> blocks)
{
foreach (ModernBlock block in blocks)
{
AddBlock(block);
}
}
public ModernBlock GetBlock(string key, string value)
{
List<ModernBlock> blocks = Data[key];
foreach (ModernBlock block in blocks)
{
if (block.ValueAsStr == value)
{
return new ModernBlock
{
Type = block.Type,
Flags = block.Flags,
Key = Utils.EncodeString(key),
Value = block.Value,
Data = block.Data
};
}
}
return null;
}
public ModernBlock GetBlock(string key, uint value)
{
List<ModernBlock> blocks = Data[key];
foreach (ModernBlock block in blocks)
{
if (block.ValueAsInt == value)
{
return new ModernBlock
{
Type = block.Type,
Flags = block.Flags,
Key = Utils.EncodeString(key),
Value = block.Value,
Data = block.Data
};
}
}
return null;
}
public void SetBlock(string key, string value, byte[] data)
{
List<ModernBlock> blocks = Data[key];
for (int i = 0; i < blocks.Count; i++)
{
ModernBlock block = blocks[i];
if (block.ValueAsStr == value)
{
block.Data = data;
blocks[i] = block;
break;
}
}
Data[key] = blocks;
}
public void SetBlock(string key, uint value, byte[] data)
{
List<ModernBlock> blocks = Data[key];
for (int i = 0; i < blocks.Count; i++)
{
ModernBlock block = blocks[i];
if (block.ValueAsInt == value)
{
block.Data = data;
blocks[i] = block;
break;
}
}
Data[key] = blocks;
}
public void SetBlock(string key, string value, string data)
{
SetBlock(key, value, Utils.EncodeString(data));
}
public void SetBlock(string key, string value, uint data)
{
SetBlock(key, value, BitConverter.GetBytes(data));
}
public void SetBlock(string key, uint value, string data)
{
SetBlock(key, value, Utils.EncodeString(data));
}
public void SetBlock(string key, uint value, uint data)
{
SetBlock(key, value, BitConverter.GetBytes(data));
}
public void DeleteBlock(string key, string value)
{
if (Data.ContainsKey(key))
{
List<ModernBlock> blocks = Data[key];
foreach (ModernBlock block in blocks)
{
if (block.ValueAsStr == value)
{
blocks.Remove(block);
break;
}
}
Data[key] = blocks;
}
}
public void DeleteBlock(string key, uint value)
{
if (Data.ContainsKey(key))
{
List<ModernBlock> blocks = Data[key];
foreach (ModernBlock block in blocks)
{
if (block.ValueAsInt == value)
{
blocks.Remove(block);
break;
}
}
Data[key] = blocks;
}
}
public static string GetPath()
{
string sppRoot = Utils.GetTokenStorePath();
return Path.Combine(Environment.ExpandEnvironmentVariables(sppRoot), "data.dat");
}
public PhysicalStore(PSVersion version, bool production)
{
Version = version;
Production = production;
TSFile = File.Open(GetPath(), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
Deserialize(ReadRaw());
}
public void Dispose()
{
WriteRaw(Serialize());
}
public byte[] ReadRaw()
{
byte[] data = PhysicalStoreCrypto.DecryptPhysicalStore(Utils.ReadAllBytes(TSFile), Production);
TSFile.Seek(0, SeekOrigin.Begin);
return data;
}
public void WriteRaw(byte[] data)
{
if (TSFile.CanWrite)
{
byte[] encrData = PhysicalStoreCrypto.EncryptPhysicalStore(data, Production, Version);
TSFile.SetLength(encrData.LongLength);
TSFile.Seek(0, SeekOrigin.Begin);
Utils.WriteAllBytes(TSFile, encrData);
TSFile.Close();
}
}
}
}
@@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace MetroUnlocker.LibTSForge.PhysicalStore
{
public class VariableBag
{
public List<CRCBlock> Blocks = new List<CRCBlock>();
public VariableBag() { }
public VariableBag(byte[] data)
{
Deserialize(data);
}
public void Deserialize(byte[] data)
{
int len = data.Length;
BinaryReader reader = new BinaryReader(new MemoryStream(data));
while (reader.BaseStream.Position < len - 0x10)
{
Blocks.Add(CRCBlock.Decode(reader));
}
}
public byte[] Serialize()
{
BinaryWriter writer = new BinaryWriter(new MemoryStream());
foreach (CRCBlock block in Blocks)
block.Encode(writer);
return ((MemoryStream)writer.BaseStream).ToArray();
}
public CRCBlock GetBlock(string key)
{
foreach (CRCBlock block in Blocks)
{
if (block.KeyAsStr == key)
{
return block;
}
}
return null;
}
public void SetBlock(string key, byte[] value)
{
for (int i = 0; i < Blocks.Count; i++)
{
CRCBlock block = Blocks[i];
if (block.KeyAsStr == key)
{
block.Value = value;
Blocks[i] = block;
break;
}
}
}
public void DeleteBlock(string key)
{
foreach (CRCBlock block in Blocks)
if (block.KeyAsStr == key)
{
Blocks.Remove(block);
return;
}
}
}
}
+202
View File
@@ -0,0 +1,202 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Xml;
namespace MetroUnlocker.LibTSForge.SPP
{
public enum PKeyAlgorithm
{
PKEY2005,
PKEY2009
}
public class KeyRange
{
public int Start;
public int End;
public string EulaType;
public string PartNumber;
public bool Valid;
public bool Contains(int n)
{
return Start <= n && End <= n;
}
}
public class ProductConfig
{
public int GroupId;
public string Edition;
public string Description;
public string Channel;
public bool Randomized;
public PKeyAlgorithm Algorithm;
public List<KeyRange> Ranges;
public Guid ActivationId;
private List<KeyRange> GetPkeyRanges()
{
if (Ranges.Count == 0)
{
throw new ArgumentException("No key ranges.");
}
if (Algorithm == PKeyAlgorithm.PKEY2005)
{
return Ranges;
}
List<KeyRange> FilteredRanges = Ranges.Where(r => !r.EulaType.Contains("WAU")).ToList();
if (FilteredRanges.Count == 0)
{
throw new NotSupportedException("Specified Activation ID is usable only for Windows Anytime Upgrade. Please use a non-WAU Activation ID instead.");
}
return FilteredRanges;
}
public ProductKey GetRandomKey()
{
List<KeyRange> KeyRanges = GetPkeyRanges();
Random rnd = new Random();
KeyRange range = KeyRanges[rnd.Next(KeyRanges.Count)];
int serial = rnd.Next(range.Start, range.End);
return new ProductKey(serial, 0, false, Algorithm, this, range);
}
}
public class PKeyConfig
{
public Dictionary<Guid, ProductConfig> Products = new Dictionary<Guid, ProductConfig>();
private List<Guid> loadedPkeyConfigs = new List<Guid>();
public void LoadConfig(Guid actId)
{
string pkcData;
Guid pkcFileId = SLApi.GetPkeyConfigFileId(actId);
if (loadedPkeyConfigs.Contains(pkcFileId)) return;
string licConts = SLApi.GetLicenseContents(pkcFileId);
using (TextReader tr = new StringReader(licConts))
{
XmlDocument lic = new XmlDocument();
lic.Load(tr);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(lic.NameTable);
nsmgr.AddNamespace("rg", "urn:mpeg:mpeg21:2003:01-REL-R-NS");
nsmgr.AddNamespace("r", "urn:mpeg:mpeg21:2003:01-REL-R-NS");
nsmgr.AddNamespace("tm", "http://www.microsoft.com/DRM/XrML2/TM/v2");
XmlNode root = lic.DocumentElement;
XmlNode pkcDataNode = root.SelectSingleNode("/rg:licenseGroup/r:license/r:otherInfo/tm:infoTables/tm:infoList/tm:infoBin[@name=\"pkeyConfigData\"]", nsmgr);
pkcData = Encoding.UTF8.GetString(Convert.FromBase64String(pkcDataNode.InnerText));
}
using (TextReader tr = new StringReader(pkcData))
{
XmlDocument lic = new XmlDocument();
lic.Load(tr);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(lic.NameTable);
nsmgr.AddNamespace("p", "http://www.microsoft.com/DRM/PKEY/Configuration/2.0");
XmlNodeList configNodes = lic.SelectNodes("//p:ProductKeyConfiguration/p:Configurations/p:Configuration", nsmgr);
XmlNodeList rangeNodes = lic.SelectNodes("//p:ProductKeyConfiguration/p:KeyRanges/p:KeyRange", nsmgr);
XmlNodeList pubKeyNodes = lic.SelectNodes("//p:ProductKeyConfiguration/p:PublicKeys/p:PublicKey", nsmgr);
Dictionary<int, PKeyAlgorithm> algorithms = new Dictionary<int, PKeyAlgorithm>();
Dictionary<string, List<KeyRange>> ranges = new Dictionary<string, List<KeyRange>>();
Dictionary<string, PKeyAlgorithm> algoConv = new Dictionary<string, PKeyAlgorithm>
{
{ "msft:rm/algorithm/pkey/2005", PKeyAlgorithm.PKEY2005 },
{ "msft:rm/algorithm/pkey/2009", PKeyAlgorithm.PKEY2009 }
};
foreach (XmlNode pubKeyNode in pubKeyNodes)
{
int group = int.Parse(pubKeyNode.SelectSingleNode("./p:GroupId", nsmgr).InnerText);
algorithms[group] = algoConv[pubKeyNode.SelectSingleNode("./p:AlgorithmId", nsmgr).InnerText];
}
foreach (XmlNode rangeNode in rangeNodes)
{
string refActIdStr = rangeNode.SelectSingleNode("./p:RefActConfigId", nsmgr).InnerText;
if (!ranges.ContainsKey(refActIdStr))
{
ranges[refActIdStr] = new List<KeyRange>();
}
KeyRange keyRange = new KeyRange();
keyRange.Start = int.Parse(rangeNode.SelectSingleNode("./p:Start", nsmgr).InnerText);
keyRange.End = int.Parse(rangeNode.SelectSingleNode("./p:End", nsmgr).InnerText);
keyRange.EulaType = rangeNode.SelectSingleNode("./p:EulaType", nsmgr).InnerText;
keyRange.PartNumber = rangeNode.SelectSingleNode("./p:PartNumber", nsmgr).InnerText;
keyRange.Valid = rangeNode.SelectSingleNode("./p:IsValid", nsmgr).InnerText.ToLower() == "true";
ranges[refActIdStr].Add(keyRange);
}
foreach (XmlNode configNode in configNodes)
{
string refActIdStr = configNode.SelectSingleNode("./p:ActConfigId", nsmgr).InnerText;
Guid refActId = new Guid(refActIdStr);
int group = int.Parse(configNode.SelectSingleNode("./p:RefGroupId", nsmgr).InnerText);
List<KeyRange> keyRanges = ranges[refActIdStr];
if (keyRanges.Count > 0 && !Products.ContainsKey(refActId))
{
ProductConfig productConfig = new ProductConfig();
productConfig.GroupId = group;
productConfig.Edition = configNode.SelectSingleNode("./p:EditionId", nsmgr).InnerText;
productConfig.Description = configNode.SelectSingleNode("./p:ProductDescription", nsmgr).InnerText;
productConfig.Channel = configNode.SelectSingleNode("./p:ProductKeyType", nsmgr).InnerText;
productConfig.Randomized = configNode.SelectSingleNode("./p:ProductKeyType", nsmgr).InnerText.ToLower() == "true";
productConfig.Algorithm = algorithms[group];
productConfig.Ranges = keyRanges;
productConfig.ActivationId = refActId;
Products[refActId] = productConfig;
}
}
}
loadedPkeyConfigs.Add(pkcFileId);
}
public ProductConfig MatchParams(int group, int serial)
{
foreach (ProductConfig config in Products.Values)
{
if (config.GroupId == group)
{
foreach (KeyRange range in config.Ranges)
{
if (range.Contains(serial))
{
return config;
}
}
}
}
throw new FileNotFoundException("Failed to find product matching supplied product key parameters.");
}
public PKeyConfig()
{
}
}
}
+310
View File
@@ -0,0 +1,310 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using MetroUnlocker.LibTSForge.Crypto;
using MetroUnlocker.LibTSForge.PhysicalStore;
namespace MetroUnlocker.LibTSForge.SPP
{
public class ProductKey
{
private static readonly string ALPHABET = "BCDFGHJKMPQRTVWXY2346789";
private readonly ulong klow;
private readonly ulong khigh;
public int Group;
public int Serial;
public ulong Security;
public bool Upgrade;
public PKeyAlgorithm Algorithm;
public string EulaType;
public string PartNumber;
public string Edition;
public string Channel;
public Guid ActivationId;
private string mpc;
private string pid2;
public byte[] KeyBytes
{
get { return BitConverter.GetBytes(klow).Concat(BitConverter.GetBytes(khigh)).ToArray(); }
}
public ProductKey(int serial, ulong security, bool upgrade, PKeyAlgorithm algorithm, ProductConfig config, KeyRange range)
{
Group = config.GroupId;
Serial = serial;
Security = security;
Upgrade = upgrade;
Algorithm = algorithm;
EulaType = range.EulaType;
PartNumber = range.PartNumber.Split(':', ';')[0];
Edition = config.Edition;
Channel = config.Channel;
ActivationId = config.ActivationId;
klow = ((security & 0x3fff) << 50 | ((ulong)serial & 0x3fffffff) << 20 | ((ulong)Group & 0xfffff));
khigh = ((upgrade ? (ulong)1 : 0) << 49 | ((security >> 14) & 0x7fffffffff));
uint checksum = Utils.CRC32(KeyBytes) & 0x3ff;
khigh |= ((ulong)checksum << 39);
}
public string GetAlgoUri()
{
return "msft:rm/algorithm/pkey/" + (Algorithm == PKeyAlgorithm.PKEY2005 ? "2005" : (Algorithm == PKeyAlgorithm.PKEY2009 ? "2009" : "Unknown"));
}
public Guid GetPkeyId()
{
VariableBag pkb = new VariableBag();
pkb.Blocks.AddRange(new CRCBlock[]
{
new CRCBlock
{
DataType = CRCBlockType.STRING,
KeyAsStr = "SppPkeyBindingProductKey",
ValueAsStr = ToString()
},
new CRCBlock
{
DataType = CRCBlockType.BINARY,
KeyAsStr = "SppPkeyBindingMiscData",
Value = new byte[] { }
},
new CRCBlock
{
DataType = CRCBlockType.STRING,
KeyAsStr = "SppPkeyBindingAlgorithm",
ValueAsStr = GetAlgoUri()
}
});
return new Guid(CryptoUtils.SHA256Hash(pkb.Serialize()).Take(16).ToArray());
}
public string GetDefaultMPC()
{
int build = Environment.OSVersion.Version.Build;
string defaultMPC = build >= 10240 ? "03612" :
build >= 9600 ? "06401" :
build >= 9200 ? "05426" :
"55041";
return defaultMPC;
}
public string GetMPC()
{
if (mpc != null)
{
return mpc;
}
mpc = GetDefaultMPC();
// setup.cfg doesn't exist in Windows 8+
string setupcfg = string.Format("{0}\\oobe\\{1}", Environment.SystemDirectory, "setup.cfg");
if (!File.Exists(setupcfg) || Edition.Contains(";"))
{
return mpc;
}
string mpcKey = string.Format("{0}.{1}=", Utils.GetArchitecture(), Edition);
string localMPC = File.ReadAllLines(setupcfg).FirstOrDefault(line => line.Contains(mpcKey));
if (localMPC != null)
{
mpc = localMPC.Split('=')[1].Trim();
}
return mpc;
}
public string GetPid2()
{
if (pid2 != null)
{
return pid2;
}
pid2 = "";
if (Algorithm == PKeyAlgorithm.PKEY2005)
{
string mpc = GetMPC();
string serialHigh;
int serialLow;
int lastPart;
if (EulaType == "OEM")
{
serialHigh = "OEM";
serialLow = ((Group / 2) % 100) * 10000 + (Serial / 100000);
lastPart = Serial % 100000;
}
else
{
serialHigh = (Serial / 1000000).ToString("D3");
serialLow = Serial % 1000000;
lastPart = ((Group / 2) % 100) * 1000 + new Random().Next(1000);
}
int checksum = 0;
foreach (char c in serialLow.ToString())
{
checksum += int.Parse(c.ToString());
}
checksum = 7 - (checksum % 7);
pid2 = string.Format("{0}-{1}-{2:D6}{3}-{4:D5}", mpc, serialHigh, serialLow, checksum, lastPart);
}
return pid2;
}
public byte[] GetPid3()
{
BinaryWriter writer = new BinaryWriter(new MemoryStream());
writer.Write(0xA4);
writer.Write(0x3);
writer.WriteFixedString(GetPid2(), 24);
writer.Write(Group);
writer.WriteFixedString(PartNumber, 16);
writer.WritePadding(0x6C);
byte[] data = writer.GetBytes();
byte[] crc = BitConverter.GetBytes(~Utils.CRC32(data.Reverse().ToArray())).Reverse().ToArray();
writer.Write(crc);
return writer.GetBytes();
}
public byte[] GetPid4()
{
BinaryWriter writer = new BinaryWriter(new MemoryStream());
writer.Write(0x4F8);
writer.Write(0x4);
writer.WriteFixedString16(GetExtendedPid(), 0x80);
writer.WriteFixedString16(ActivationId.ToString(), 0x80);
writer.WritePadding(0x10);
writer.WriteFixedString16(Edition, 0x208);
writer.Write(Upgrade ? (ulong)1 : 0);
writer.WritePadding(0x50);
writer.WriteFixedString16(PartNumber, 0x80);
writer.WriteFixedString16(Channel, 0x80);
writer.WriteFixedString16(EulaType, 0x80);
return writer.GetBytes();
}
public string GetExtendedPid()
{
string mpc = GetMPC();
int serialHigh = Serial / 1000000;
int serialLow = Serial % 1000000;
int licenseType;
uint lcid = Utils.GetSystemDefaultLCID();
int build = Environment.OSVersion.Version.Build;
int dayOfYear = DateTime.Now.DayOfYear;
int year = DateTime.Now.Year;
switch (EulaType)
{
case "OEM":
licenseType = 2;
break;
case "Volume":
licenseType = 3;
break;
default:
licenseType = 0;
break;
}
return string.Format(
"{0}-{1:D5}-{2:D3}-{3:D6}-{4:D2}-{5:D4}-{6:D4}.0000-{7:D3}{8:D4}",
mpc,
Group,
serialHigh,
serialLow,
licenseType,
lcid,
build,
dayOfYear,
year
);
}
public byte[] GetPhoneData(PSVersion version)
{
int serialHigh = Serial / 1000000;
int serialLow = Serial % 1000000;
BinaryWriter writer = new BinaryWriter(new MemoryStream());
writer.Write(new Guid("B8731595-A2F6-430B-A799-FBFFB81A8D73").ToByteArray());
writer.Write(Group);
writer.Write(serialHigh);
writer.Write(serialLow);
writer.Write(Upgrade ? 1 : 0);
writer.Write(Security);
return writer.GetBytes();
}
public override string ToString()
{
string keyStr = "";
Random rnd = new Random(Group * 1000000000 + Serial);
if (Algorithm == PKeyAlgorithm.PKEY2005)
{
keyStr = "H4X3DH4X3DH4X3DH4X3D";
for (int i = 0; i < 5; i++)
{
keyStr += ALPHABET[rnd.Next(24)];
}
}
else if (Algorithm == PKeyAlgorithm.PKEY2009)
{
int last = 0;
byte[] bKey = KeyBytes;
for (int i = 24; i >= 0; i--)
{
int current = 0;
for (int j = 14; j >= 0; j--)
{
current *= 0x100;
current += bKey[j];
bKey[j] = (byte)(current / 24);
current %= 24;
last = current;
}
keyStr = ALPHABET[current] + keyStr;
}
keyStr = keyStr.Substring(1, last) + "N" + keyStr.Substring(last + 1, keyStr.Length - last - 1);
}
for (int i = 5; i < keyStr.Length; i += 6)
{
keyStr = keyStr.Insert(i, "-");
}
return keyStr;
}
}
}
+307
View File
@@ -0,0 +1,307 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace MetroUnlocker.LibTSForge.SPP
{
public static class SLApi
{
private enum SLIDTYPE
{
SL_ID_APPLICATION,
SL_ID_PRODUCT_SKU,
SL_ID_LICENSE_FILE,
SL_ID_LICENSE,
SL_ID_PKEY,
SL_ID_ALL_LICENSES,
SL_ID_ALL_LICENSE_FILES,
SL_ID_STORE_TOKEN,
SL_ID_LAST
}
private enum SLDATATYPE
{
SL_DATA_NONE,
SL_DATA_SZ,
SL_DATA_DWORD,
SL_DATA_BINARY,
SL_DATA_MULTI_SZ,
SL_DATA_SUM
}
[StructLayout(LayoutKind.Sequential)]
private struct SL_LICENSING_STATUS
{
public Guid SkuId;
public uint eStatus;
public uint dwGraceTime;
public uint dwTotalGraceDays;
public uint hrReason;
public ulong qwValidityExpiration;
}
public static readonly Guid WINDOWS_APP_ID = new Guid("55c92734-d682-4d71-983e-d6ec3f16059f");
[DllImport("sppc.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
private static extern void SLOpen(out IntPtr hSLC);
[DllImport("sppc.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
private static extern void SLClose(IntPtr hSLC);
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLGetWindowsInformationDWORD(string ValueName, ref int Value);
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLInstallProofOfPurchase(IntPtr hSLC, string pwszPKeyAlgorithm, string pwszPKeyString, uint cbPKeySpecificData, byte[] pbPKeySpecificData, ref Guid PKeyId);
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLUninstallProofOfPurchase(IntPtr hSLC, ref Guid PKeyId);
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLGetPKeyInformation(IntPtr hSLC, ref Guid pPKeyId, string pwszValueName, out SLDATATYPE peDataType, out uint pcbValue, out IntPtr ppbValue);
[DllImport("sppcext.dll", CharSet = CharSet.Unicode)]
private static extern uint SLActivateProduct(IntPtr hSLC, ref Guid pProductSkuId, byte[] cbAppSpecificData, byte[] pvAppSpecificData, byte[] pActivationInfo, string pwszProxyServer, ushort wProxyPort);
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLGenerateOfflineInstallationId(IntPtr hSLC, ref Guid pProductSkuId, ref string ppwszInstallationId);
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLDepositOfflineConfirmationId(IntPtr hSLC, ref Guid pProductSkuId, string pwszInstallationId, string pwszConfirmationId);
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLGetSLIDList(IntPtr hSLC, SLIDTYPE eQueryIdType, ref Guid pQueryId, SLIDTYPE eReturnIdType, out uint pnReturnIds, out IntPtr ppReturnIds);
[DllImport("sppc.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
private static extern void SLGetLicensingStatusInformation(IntPtr hSLC, ref Guid pAppID, IntPtr pProductSkuId, string pwszRightName, out uint pnStatusCount, out IntPtr ppLicensingStatus);
[DllImport("sppc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLGetInstalledProductKeyIds(IntPtr hSLC, ref Guid pProductSkuId, out uint pnProductKeyIds, out IntPtr ppProductKeyIds);
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLConsumeWindowsRight(uint unknown);
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLGetProductSkuInformation(IntPtr hSLC, ref Guid pProductSkuId, string pwszValueName, out SLDATATYPE peDataType, out uint pcbValue, out IntPtr ppbValue);
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLGetProductSkuInformation(IntPtr hSLC, ref Guid pProductSkuId, string pwszValueName, IntPtr peDataType, out uint pcbValue, out IntPtr ppbValue);
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLGetLicense(IntPtr hSLC, ref Guid pLicenseFileId, out uint pcbLicenseFile, out IntPtr ppbLicenseFile);
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLSetCurrentProductKey(IntPtr hSLC, ref Guid pProductSkuId, ref Guid pProductKeyId);
[DllImport("slc.dll", CharSet = CharSet.Unicode)]
private static extern uint SLFireEvent(IntPtr hSLC, string pwszEventId, ref Guid pApplicationId);
public class SLContext : IDisposable
{
public readonly IntPtr Handle;
public SLContext()
{
SLOpen(out Handle);
}
public void Dispose()
{
SLClose(Handle);
GC.SuppressFinalize(this);
}
~SLContext()
{
Dispose();
}
}
public static Guid GetPkeyConfigFileId(Guid actId)
{
using (SLContext sl = new SLContext())
{
SLDATATYPE type;
uint len;
IntPtr ppReturnLics;
uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "pkeyConfigLicenseId", out type, out len, out ppReturnLics);
if (status != 0 || len == 0)
{
return Guid.Empty;
}
Guid pkcId = new Guid(Marshal.PtrToStringAuto(ppReturnLics));
return GetLicenseFileId(pkcId);
}
}
public static Guid GetLicenseFileId(Guid licId)
{
using (SLContext sl = new SLContext())
{
uint status;
uint count;
IntPtr ppReturnLics;
status = SLGetSLIDList(sl.Handle, SLIDTYPE.SL_ID_LICENSE, ref licId, SLIDTYPE.SL_ID_LICENSE_FILE, out count, out ppReturnLics);
return (status == 0 && count != 0) ? (Guid)Marshal.PtrToStructure(ppReturnLics, typeof(Guid)) : Guid.Empty;//new Guid(Marshal.PtrToStringAuto(ppReturnLics));
}
}
public static string GetLicenseContents(Guid fileId)
{
if (fileId == Guid.Empty) throw new ArgumentException("License contents could not be retrieved.");
using (SLContext sl = new SLContext())
{
uint dataLen;
IntPtr dataPtr;
if (SLGetLicense(sl.Handle, ref fileId, out dataLen, out dataPtr) != 0)
{
return null;
}
byte[] data = new byte[dataLen];
Marshal.Copy(dataPtr, data, 0, (int)dataLen);
data = data.Skip(Array.IndexOf(data, (byte)'<')).ToArray();
return Encoding.UTF8.GetString(data);
}
}
public static string GetMetaStr(Guid actId, string value)
{
using (SLContext sl = new SLContext())
{
uint len;
SLDATATYPE type;
IntPtr ppbValue;
uint status = SLGetProductSkuInformation(sl.Handle, ref actId, value, out type, out len, out ppbValue);
if (status != 0 || len == 0 || type != SLDATATYPE.SL_DATA_SZ)
{
return null;
}
return Marshal.PtrToStringAuto(ppbValue);
}
}
public static string GetInstallationId(Guid actId)
{
using (SLContext sl = new SLContext())
{
string installationId = null;
var status = SLGenerateOfflineInstallationId(sl.Handle, ref actId, ref installationId);
if (status != 0)
throw new Exception(string.Format("Failed to get installation ID: 0x{0}. Your data.dat is probably corrupt at the moment. Try again later.", status.ToString("X")));
return installationId;
}
}
public static Guid GetInstalledPkeyId(Guid actId)
{
using (SLContext sl = new SLContext())
{
uint status;
uint count;
IntPtr pProductKeyIds;
status = SLGetInstalledProductKeyIds(sl.Handle, ref actId, out count, out pProductKeyIds);
//unsafe { return *(Guid*)pProductKeyIds; }
return (status == 0 && count != 0) ? (Guid)Marshal.PtrToStructure(pProductKeyIds, typeof(Guid)) : Guid.Empty;
}
}
public static uint DepositConfirmationId(Guid actId, string installationId, string confirmationId)
{
using (SLContext sl = new SLContext())
return SLDepositOfflineConfirmationId(sl.Handle, ref actId, installationId, confirmationId);
}
public static void RefreshLicenseStatus()
{
SLConsumeWindowsRight(0);
}
public static bool RefreshTrustedTime(Guid actId)
{
using (SLContext sl = new SLContext())
{
SLDATATYPE type;
uint count;
IntPtr ppbValue;
uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "TrustedTime", out type, out count, out ppbValue);
return (int)status >= 0 && status != 0xC004F012;
}
}
public static void FireStateChangedEvent(Guid appId)
{
using (SLContext sl = new SLContext())
{
SLFireEvent(sl.Handle, "msft:rm/event/licensingstatechanged", ref appId);
}
}
public static Guid GetAppId(Guid actId)
{
using (SLContext sl = new SLContext())
{
uint count;
IntPtr 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)
return Guid.Empty;
return (Guid)Marshal.PtrToStructure(pAppIds, typeof(Guid));
}
}
public static bool IsAddon(Guid actId)
{
using (SLContext sl = new SLContext())
{
uint count;
SLDATATYPE type;
IntPtr ppbValue;
uint status = SLGetProductSkuInformation(sl.Handle, ref actId, "DependsOn", out type, out count, out ppbValue);
return (int)status >= 0 && status != 0xC004F012;
}
}
public static uint InstallProductKey(ProductKey pkey)
{
using (SLContext sl = new SLContext())
{
Guid pkeyId = Guid.Empty;
return SLInstallProofOfPurchase(sl.Handle, pkey.GetAlgoUri(), pkey.ToString(), 0, null, ref pkeyId);
}
}
public static uint UninstallProductKey(Guid pkeyId)
{
using (SLContext sl = new SLContext())
return SLUninstallProofOfPurchase(sl.Handle, ref pkeyId);
}
}
}
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MetroUnlocker.LibTSForge.TokenStore
{
public class TokenEntry
{
public string Name;
public string Extension;
public byte[] Data;
public bool Populated;
}
}
@@ -0,0 +1,292 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using MetroUnlocker.LibTSForge.Crypto;
namespace MetroUnlocker.LibTSForge.TokenStore
{
public class TokenStore : IDisposable
{
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();
private List<TokenEntry> Entries = new List<TokenEntry>();
public FileStream TokensFile;
public void Deserialize()
{
if (TokensFile.Length < BLOCK_SIZE) return;
TokensFile.Seek(0x24, SeekOrigin.Begin);
uint nextBlock = 0;
BinaryReader reader = new BinaryReader(TokensFile);
do
{
uint curOffset = reader.ReadUInt32();
nextBlock = reader.ReadUInt32();
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[] { };
if (populated)
{
reader.BaseStream.Seek(contentOffset + 0x20, SeekOrigin.Begin);
uint dataLength = reader.ReadUInt32();
if (dataLength != contentLength)
{
throw new FormatException("Data length in tokens content is inconsistent with entry.");
}
reader.ReadBytes(0x20);
contentData = reader.ReadBytes((int)contentLength);
}
reader.BaseStream.Seek(curOffset + 0x14, SeekOrigin.Begin);
Entries.Add(new TokenEntry
{
Name = reader.ReadNullTerminatedString(0x82),
Extension = reader.ReadNullTerminatedString(0x8),
Data = contentData,
Populated = populated
});
}
reader.BaseStream.Seek(nextBlock, SeekOrigin.Begin);
} while (nextBlock != 0);
}
public void Serialize()
{
MemoryStream tokens = new MemoryStream();
using (BinaryWriter writer = new BinaryWriter(tokens))
{
writer.Write(VERSION);
writer.Write(CONTS_HEADER);
int curBlockOffset = (int)writer.BaseStream.Position;
int curEntryOffset = curBlockOffset + 0x8;
int curContsOffset = curBlockOffset + BLOCK_SIZE;
for (int eIndex = 0; eIndex < ((Entries.Count / ENTRIES_PER_BLOCK) + 1) * ENTRIES_PER_BLOCK; eIndex++)
{
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);
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;
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;
}
if ((eIndex + 1) % ENTRIES_PER_BLOCK == 0 && eIndex != 0)
{
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;
}
}
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)
{
Entries.Add(entry);
}
public void AddEntries(TokenEntry[] entries)
{
Entries.AddRange(entries);
}
public void DeleteEntry(string name, string ext)
{
foreach (TokenEntry entry in Entries)
{
if (entry.Name == name && entry.Extension == ext)
{
Entries.Remove(entry);
return;
}
}
}
public void DeleteUnpopEntry(string name, string ext)
{
List<TokenEntry> delEntries = new List<TokenEntry>();
foreach (TokenEntry entry in Entries)
{
if (entry.Name == name && entry.Extension == ext && !entry.Populated)
{
delEntries.Add(entry);
}
}
Entries = Entries.Except(delEntries).ToList();
}
public TokenEntry GetEntry(string name, string ext)
{
foreach (TokenEntry entry in Entries)
{
if (entry.Name == name && entry.Extension == ext)
{
if (!entry.Populated) continue;
return entry;
}
}
return null;
}
public TokenMeta GetMetaEntry(string name)
{
DeleteUnpopEntry(name, "xml");
TokenEntry entry = GetEntry(name, "xml");
TokenMeta meta;
if (entry == null)
{
meta = new TokenMeta
{
Name = name
};
}
else
{
meta = new TokenMeta(entry.Data);
}
return meta;
}
public void SetEntry(string name, string ext, byte[] data)
{
for (int i = 0; i < Entries.Count; i++)
{
TokenEntry entry = Entries[i];
if (entry.Name == name && entry.Extension == ext && entry.Populated)
{
entry.Data = data;
Entries[i] = entry;
return;
}
}
Entries.Add(new TokenEntry
{
Populated = true,
Name = name,
Extension = ext,
Data = data
});
}
public static string GetPath()
{
return Path.Combine(Environment.ExpandEnvironmentVariables(Utils.GetTokenStorePath()), "tokens.dat");
}
public TokenStore()
{
string tokensPath = GetPath();
TokensFile = File.Open(tokensPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
Deserialize();
}
public void Dispose()
{
Serialize();
TokensFile.Close();
}
}
}
+98
View File
@@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Microsoft.Win32;
using MetroUnlocker.LibTSForge.SPP;
using MetroUnlocker.LibTSForge.PhysicalStore;
using MetroUnlocker.LibTSForge.Crypto;
namespace MetroUnlocker
{
class ZeroCID
{
public static void Deposit(Guid actId, string instId)
{
uint status = SLApi.DepositConfirmationId(actId, instId, Constants.ZeroCID);
if (status != 0)
throw new InvalidOperationException(string.Format("Failed to deposit fake CID. Status code: 0x{0}", status.ToString("X")));
}
public static void Activate(PSVersion version, bool production, Guid actId)
{
Guid appId = SLApi.GetAppId(actId);
string instId = SLApi.GetInstallationId(actId);
Guid pkeyId = SLApi.GetInstalledPkeyId(actId);
Utils.KillSPP();
using (PhysicalStore store = new PhysicalStore(version, production))
{
byte[] hwidBlock = Constants.UniversalHWIDBlock;
byte[] iidHash = CryptoUtils.SHA256Hash(Utils.EncodeString(instId + '\0' + Constants.ZeroCID));
string key = string.Format("SPPSVC\\{0}\\{1}", appId, actId);
ModernBlock keyBlock = store.GetBlock(key, pkeyId.ToString());
if (keyBlock == null)
{
throw new InvalidDataException("Failed to get product key data for activation ID: 0x" + actId + ".");
}
VariableBag pkb = new VariableBag(keyBlock.Data);
byte[] pkeyData = pkb.GetBlock("SppPkeyPhoneActivationData").Value;
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 = Utils.GetBytes(writer);
writer = new BinaryWriter(new MemoryStream());
writer.Write(0x20);
writer.Write(iidHash);
writer.Write(pkeyData.Length);
writer.Write(pkeyData);
byte[] tsPkeyInfoData = Utils.GetBytes(writer);
store.AddBlocks(new ModernBlock[] {
new ModernBlock
{
Type = BlockType.NAMED,
Flags = 0,
KeyAsStr = key,
ValueAsStr = "msft:Windows/7.0/Phone/Cached/HwidBlock/" + pkeyId,
Data = tsHwidData
},
new ModernBlock
{
Type = BlockType.NAMED,
Flags = 0,
KeyAsStr = key,
ValueAsStr = "msft:Windows/7.0/Phone/Cached/PKeyInfo/" + pkeyId,
Data = tsPkeyInfoData
}
});
}
Deposit(actId, instId);
SLApi.RefreshLicenseStatus();
SLApi.FireStateChangedEvent(appId);
}
}
}