aboutsummaryrefslogtreecommitdiff
path: root/runtime/VMProtect.Runtime/HardwareID.cs
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/VMProtect.Runtime/HardwareID.cs')
-rw-r--r--runtime/VMProtect.Runtime/HardwareID.cs266
1 files changed, 266 insertions, 0 deletions
diff --git a/runtime/VMProtect.Runtime/HardwareID.cs b/runtime/VMProtect.Runtime/HardwareID.cs
new file mode 100644
index 0000000..4288e0a
--- /dev/null
+++ b/runtime/VMProtect.Runtime/HardwareID.cs
@@ -0,0 +1,266 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Net.NetworkInformation;
+using System.Net.Sockets;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Text;
+
+// ReSharper disable once CheckNamespace
+namespace VMProtect
+{
+ public class HardwareID
+ {
+ private const int OldMethodBlocks = 8;
+ private const int MaxBlocks = 16 + OldMethodBlocks;
+ private const uint TypeMask = 3;
+
+ private enum BlockType {
+ Cpu,
+ Host,
+ Mac,
+ Hdd
+ };
+
+ private readonly int _startBlock;
+ private readonly List<uint> _blocks = new List<uint>();
+
+ public HardwareID()
+ {
+ // old methods
+ GetCpu(0);
+ GetCpu(1);
+ _startBlock = _blocks.Count;
+ // new methods, we'll return HWID starting from this DWORD
+ GetCpu(2);
+ GetMachineName();
+ GetHdd();
+ GetMacAddresses();
+ }
+
+ private void AddBlock(byte[] p, BlockType type)
+ {
+ if (_blocks.Count == MaxBlocks) return; // no free space
+ if (p.Length == 0) return;
+
+ using (var hash = new SHA1Managed())
+ {
+ var h = hash.ComputeHash(p);
+ var block = (uint)((h[0] << 24) | (h[1] << 16) | (h[2] << 8) | h[3]);
+ block &= ~TypeMask; // zero two lower bits
+ block |= (uint)type & TypeMask; // set type bits
+
+ // check existing blocks
+ for (var i = _blocks.Count; i > _startBlock; i--) {
+ var prevBlock = _blocks[i - 1];
+ if (prevBlock == block)
+ return;
+ if ((prevBlock & TypeMask) != (block & TypeMask))
+ break;
+ }
+
+ _blocks.Add(block);
+ }
+ }
+
+ private void GetCpu(int method)
+ {
+ //TODO: foreach cpu:
+ var info = CpuId.Invoke(1);
+ if ((info[0] & 0xFF0) == 0xFE0)
+ info[0] ^= 0x20; // fix Athlon bug
+ info[1] &= 0x00FFFFFF; // mask out APIC Physical ID
+
+ if (method == 2) {
+ info[2] = 0;
+ } else if (method == 1) {
+ info[2] &= ~(1 << 27);
+ }
+
+ var infob = new byte[16];
+ Buffer.BlockCopy(info, 0, infob, 0, infob.Length);
+ AddBlock(infob, BlockType.Cpu);
+ }
+
+ private void GetMachineName()
+ {
+ try
+ {
+ var hn = Encoding.Unicode.GetBytes(Dns.GetHostName().ToUpperInvariant());
+ AddBlock(hn, BlockType.Host);
+ }
+ catch (SocketException)
+ {
+
+ }
+ }
+
+ private void ProcessMac(byte[] p)
+ {
+ // this big IF construction allows to put constants to the code, not to the data segment
+ // it is harder to find them in the code after virtualisation
+ var dw = (p[0] << 16) + (p[1] << 8) + p[2];
+ if (dw == 0x000569 || dw == 0x000C29 || dw == 0x001C14 || dw == 0x005056 || // vmware
+ dw == 0x0003FF || dw == 0x000D3A || dw == 0x00125A || dw == 0x00155D || dw == 0x0017FA || dw == 0x001DD8 || dw == 0x002248 || dw == 0x0025AE || dw == 0x0050F2 || // microsoft
+ dw == 0x001C42 || // parallels
+ dw == 0x0021F6) // virtual iron
+ return;
+
+ AddBlock(p, BlockType.Mac);
+ }
+
+ private void GetMacAddresses()
+ {
+ var blockCountNoMac = _blocks.Count;
+ byte[] paBytes = null;
+ foreach (var nic in NetworkInterface.GetAllNetworkInterfaces())
+ {
+ if(nic.NetworkInterfaceType != NetworkInterfaceType.Ethernet)
+ continue;
+ paBytes = nic.GetPhysicalAddress().GetAddressBytes();
+ if (paBytes.Length >= 3)
+ ProcessMac(paBytes);
+ }
+ if (blockCountNoMac == _blocks.Count && paBytes != null && paBytes.Length >= 3)
+ AddBlock(paBytes, BlockType.Mac);
+ }
+
+ private void GetHdd()
+ {
+ try
+ {
+ switch (Environment.OSVersion.Platform)
+ {
+ case PlatformID.MacOSX:
+ //TODO
+ /*
+ DASessionRef session = DASessionCreate(NULL);
+ if (session) {
+ struct statfs statFS;
+ statfs ("/", &statFS);
+ DADiskRef disk = DADiskCreateFromBSDName(NULL, session, statFS.f_mntfromname);
+ if (disk) {
+ CFDictionaryRef descDict = DADiskCopyDescription(disk);
+ if (descDict) {
+ CFUUIDRef value = (CFUUIDRef)CFDictionaryGetValue(descDict, CFSTR("DAVolumeUUID"));
+ CFUUIDBytes bytes = CFUUIDGetUUIDBytes(value);
+ AddBlock(&bytes, sizeof(bytes), BLOCK_HDD);
+ CFRelease(descDict);
+ }
+ CFRelease(disk);
+ }
+ CFRelease(session);
+ }
+ */
+ break;
+ case PlatformID.Unix:
+ //TODO: нет ли здесь лишних дисков?
+ var rootUuids = new DirectoryInfo ("/dev/disk/by-uuid");
+ var uuids = new StringBuilder();
+ foreach (var f in rootUuids.GetFiles("*"))
+ {
+ uuids.Append(f.Name);
+ }
+ if(uuids.Length > 0)
+ AddBlock(Encoding.UTF8.GetBytes(uuids.ToString()), BlockType.Hdd);
+ break;
+ default:
+ /*
+ * mono for windows: unimplemented
+ *
+ * var moType = Assembly.Load("System.Management, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a").
+ GetType("System.Management.ManagementObject");
+ var disk = Activator.CreateInstance(moType,
+ BindingFlags.CreateInstance, null,
+ new object[] { string.Format("Win32_LogicalDisk.DeviceID='{0}:'", Environment.SystemDirectory[0]) },
+ CultureInfo.InvariantCulture);
+ var props = moType.InvokeMember("Properties", BindingFlags.GetProperty, null, disk, null);
+ var sn = props.GetType().GetMethod("get_Item").Invoke(props, new object[] { "volumeSerialNumber" });
+ var snv = sn.GetType().GetMethod("get_Value").Invoke(sn, null).ToString();
+ Console.WriteLine("GetHdd volumeSerialNumber = {0}", snv);
+ var bytes = BitConverter.GetBytes(Convert.ToUInt32(snv, 16));*/
+
+ var driveLetter = Path.GetPathRoot(Environment.SystemDirectory);
+ uint serialNumber = 0;
+ uint maxComponentLength = 0, fileSystemFlags = 0;
+ if (Win32.GetVolumeInformation(driveLetter, null,
+ 0, ref serialNumber, ref maxComponentLength,
+ ref fileSystemFlags, null, 0) && serialNumber != 0)
+ {
+ AddBlock(BitConverter.GetBytes(serialNumber), BlockType.Hdd);
+ }
+ break;
+ }
+ }
+ catch (Exception)
+ {
+ // ignored
+ }
+ }
+
+ public byte[] GetBytes()
+ {
+ var ms = new MemoryStream();
+ for (var i = _startBlock; i < _blocks.Count; i++)
+ {
+ ms.Write(BitConverter.GetBytes(_blocks[i]), 0, 4);
+ }
+ return ms.ToArray();
+ }
+
+ public override string ToString()
+ {
+ return Convert.ToBase64String(GetBytes());
+ }
+
+ public bool IsCorrect(byte[] p)
+ {
+ if (p.Length == 0 || (p.Length & 3) != 0)
+ return false;
+
+ var equals = new bool[4];
+ var found = new bool[4];
+
+ foreach (var id1 in _blocks)
+ {
+ found[id1 & 3] = true;
+ for (var i = 0; i < p.Length; i += 4) {
+ var id2 = BitConverter.ToUInt32(p, i);
+ if (id1 == id2) {
+ equals[id1 & 3] = true;
+ break;
+ }
+ }
+ }
+
+ // 1. check CPU
+ if (!equals[0])
+ return false;
+
+ // 2. check if at least 2 of 3 items are OK
+ var n = 0;
+ var c = 0;
+ for (var i = 0; i < 4; i++) {
+ if (found[i])
+ c++;
+ if (equals[i])
+ n++;
+ }
+ return n == c || n >= 3;
+ }
+
+ /*public bool IsCorrect(CryptoContainer &cont, size_t offset, size_t size)
+ {
+ if (size == 0 || (size & 3) || size > MAX_BLOCKS * sizeof(uint32_t))
+ return false;
+
+ uint32_t buff[MAX_BLOCKS];
+ for (size_t i = 0; i < size / sizeof(uint32_t); i++) {
+ buff[i] = cont.GetDWord(offset + i * sizeof(uint32_t));
+ }
+ return IsCorrect(reinterpret_cast<uint8_t *>(buff), size);
+ }*/
+ }
+} \ No newline at end of file