using System; using System.Reflection; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Diagnostics; using System.Threading; using System.Collections.Generic; using System.Text; // ReSharper disable MemberCanBePrivate.Global // ReSharper disable UnusedParameter.Global // ReSharper disable UnusedMember.Global // ReSharper disable once CheckNamespace [assembly: SuppressIldasmAttribute()] [assembly: Obfuscation(Feature = "renaming", Exclude = true)] namespace VMProtect { /// /// Serial number status flags /// [Flags] public enum SerialState { /// /// No problems. /// Success = 0x00000000, /// /// Licensing module is corrupted. This may be caused by cracking attempts. Usually you will never get this flag. /// Corrupted = 0x00000001, /// /// Serial number is invalid. You will get this flag if licensing module will be unable to decrypt serial number or /// if the serial number is not yet set or it is empty. /// Invalid = 0x00000002, /// /// Serial number is correct, but it was blacklisted in VMProtect. /// Blacklisted = 0x00000004, /// /// Serial number is expired. You will get this flag if serial number has expiration date chunk and this date is in the past. /// You may read the expiration date by calling GetSerialNumberData() function. /// DateExpired = 0x00000008, /// /// Running time limit for this session is over. You may read limit value by calling GetSerialNumberData() function. /// RunningTimeOver = 0x00000010, /// /// Serial number is locked to another hardware identifier. /// BadHwid = 0x00000020, /// /// Serial number will not work with this version of application, because it has "Max Build Date" block and the application was /// build after those date. You may read maximal build date by calling GetSerialNumberData() function. /// MaxBuildExpired = 0x00000040, }; /// /// Serial number contents /// public class SerialNumberData { /// /// Serial number status /// public SerialState State; /// /// End user name /// public string UserName; /// /// End user E-Mail /// public string EMail; /// /// Serial number expiration date. /// public DateTime Expires; /// /// Max date of build, that will accept this key /// public DateTime MaxBuild; /// /// Running time in minutes /// public int RunningTime; /// /// Up to 255 bytes of user data /// public byte[] UserData; public SerialNumberData() { State = SerialState.Invalid; Expires = DateTime.MaxValue; MaxBuild = DateTime.MaxValue; RunningTime = 0; UserData = new byte[0]; UserName = ""; EMail = ""; } }; /// /// Activation API status codes /// public enum ActivationStatus { /// /// Activation successful, the serial field contains a serial number. /// Ok, /// /// The activation module was unable to connect the Web License Manager. /// NoConnection, /// /// The server returned unexpected reply. This means configuration problems or probably a cracking attempt. /// BadReply, /// /// The activation code is blocked on the server. This doesn't mean that the number of possible activations is exceeded, /// this means that this exactly code is banned by the vendor, so the user is trying to cheat you. /// Banned, /// /// Something goes really wrong here. The error means that the internal activation stuff is not working, /// it is not safe to continue with the activation, registration and so on. /// Corrupted, /// /// The code has been successfully passed to the server and it was unable to find it in the database. /// Probably the user made a mistake, so it is worth asking the user to check the entered code for mistakes. /// BadCode, /// /// The code has been used too many times and cannot be used more. This doesn't mean the code is bad or banned, it is OK. /// The user may contact vendor to ask/purchase more activations, or the user may deactivate some installations to increase /// the number of activations available for that code. /// AlreadyUsed, /// /// This is the deactivation error code that means that the server can't find the serial number that the user tries to deactivate. /// SerialUnknown, /// /// The code is expired. /// Expired, /// /// Activation/deactivation features are not available. /// NotAvailable }; [Flags] [VMProtect.DeleteOnCompilation] enum CoreOption { MEMORY_PROTECTION = 0x1, CHECK_DEBUGGER = 0x2 } public class Core { public static bool IsProtected() { return true; } public static bool IsDebuggerPresent(bool checkKernelMode) { if (GlobalData.IsDebuggerDetected()) return true; if (Debugger.IsAttached || Debugger.IsLogging()) return true; if (Win32.IsDebuggerPresent() || Win32.CheckRemoteDebuggerPresent()) return true; return false; } internal static bool FindFirmwareVendor(byte[] data) { for (var i = 0; i < data.Length; i++) { if (i + 3 < data.Length && data[i + 0] == 'Q' && data[i + 1] == 'E' && data[i + 2] == 'M' && data[i + 3] == 'U') return true; if (i + 8 < data.Length && data[i + 0] == 'M' && data[i + 1] == 'i' && data[i + 2] == 'c' && data[i + 3] == 'r' && data[i + 4] == 'o' && data[i + 5] == 's' && data[i + 6] == 'o' && data[i + 7] == 'f' && data[i + 8] == 't') return true; if (i + 6 < data.Length && data[i + 0] == 'i' && data[i + 1] == 'n' && data[i + 2] == 'n' && data[i + 3] == 'o' && data[i + 4] == 't' && data[i + 5] == 'e' && data[i + 6] == 'k') return true; if (i + 9 < data.Length && data[i + 0] == 'V' && data[i + 1] == 'i' && data[i + 2] == 'r' && data[i + 3] == 't' && data[i + 4] == 'u' && data[i + 5] == 'a' && data[i + 6] == 'l' && data[i + 7] == 'B' && data[i + 8] == 'o' && data[i + 9] == 'x') return true; if (i + 5 < data.Length && data[i + 0] == 'V' && data[i + 1] == 'M' && data[i + 2] == 'w' && data[i + 3] == 'a' && data[i + 4] == 'r' && data[i + 5] == 'e') return true; if (i + 8 < data.Length && data[i + 0] == 'P' && data[i + 1] == 'a' && data[i + 2] == 'r' && data[i + 3] == 'a' && data[i + 4] == 'l' && data[i + 5] == 'l' && data[i + 6] == 'e' && data[i + 7] == 'l' && data[i + 8] == 's') return true; } return false; } public static bool IsVirtualMachinePresent() { var info = CpuId.Invoke(1); if (((info[2] >> 31) & 1) != 0) { // check Hyper-V root partition info = CpuId.Invoke(0x40000000); if (info[1] == 0x7263694d && info[2] == 0x666f736f && info[3] == 0x76482074) // "Microsoft Hv" { info = CpuId.Invoke(0x40000003); if ((info[1] & 1) != 0) return false; } return true; } else { int size; uint tableSignature = (byte)'R' << 24 | (byte)'S' << 16 | (byte)'M' << 8 | (byte)'B'; try { size = (int)Win32.EnumSystemFirmwareTables(tableSignature, IntPtr.Zero, 0); } catch (EntryPointNotFoundException) { size = 0; } if (size > 0) { IntPtr nativeBuffer = Marshal.AllocHGlobal(size); Win32.EnumSystemFirmwareTables(tableSignature, nativeBuffer, (uint)size); byte[] buffer = new byte[size]; Marshal.Copy(nativeBuffer, buffer, 0, size); Marshal.FreeHGlobal(nativeBuffer); for (var i = 0; i < size / sizeof(uint); i += sizeof(uint)) { uint tableId = BitConverter.ToUInt32(buffer, i); int dataSize = (int)Win32.GetSystemFirmwareTable(tableSignature, tableId, IntPtr.Zero, 0); if (dataSize > 0) { nativeBuffer = Marshal.AllocHGlobal(dataSize); Win32.GetSystemFirmwareTable(tableSignature, tableId, nativeBuffer, (uint)dataSize); byte[] data = new byte[dataSize]; Marshal.Copy(nativeBuffer, data, 0, dataSize); Marshal.FreeHGlobal(nativeBuffer); if (FindFirmwareVendor(data)) return true; } } } } return false; } public static bool IsValidImageCRC() { if (GlobalData.IsPatchDetected()) return false; long instance = Marshal.GetHINSTANCE(typeof(Core).Module).ToInt64(); // check memory CRC var crcSize = (uint)Marshal.ReadInt32(new IntPtr(instance + (uint)Faces.CRC_TABLE_SIZE)); var crcPosition = (uint)Faces.CRC_TABLE_ENTRY; bool isValid = true; var crcInfo = new byte[12]; var crc32 = new CRC32(); var crcHash = (uint)Marshal.ReadInt32(new IntPtr(instance + (uint)Faces.CRC_TABLE_HASH)); if (crcHash != crc32.Hash(new IntPtr(instance + crcPosition), crcSize)) isValid = false; { var crcCryptor = new CRCValueCryptor(); for (var i = 0; i < crcSize; i += crcInfo.Length) { Marshal.Copy(new IntPtr(instance + crcPosition + i), crcInfo, 0, crcInfo.Length); uint address = crcCryptor.Decrypt(BitConverter.ToUInt32(crcInfo, 0)); uint size = crcCryptor.Decrypt(BitConverter.ToUInt32(crcInfo, 4)); uint hash = crcCryptor.Decrypt(BitConverter.ToUInt32(crcInfo, 8)); if (crc32.Hash(new IntPtr(instance + address), size) != hash) isValid = false; } } // check header and loader CRC crcSize = (uint)Marshal.ReadInt32(new IntPtr(instance + GlobalData.LoaderCrcSize())); crcPosition = GlobalData.LoaderCrcInfo(); crcHash = (uint)Marshal.ReadInt32(new IntPtr(instance + GlobalData.LoaderCrcHash())); if (crcHash != crc32.Hash(new IntPtr(instance + crcPosition), crcSize)) isValid = false; { var crcCryptor = new CRCValueCryptor(); for (var i = 0; i < crcSize; i += crcInfo.Length) { Marshal.Copy(new IntPtr(instance + crcPosition + i), crcInfo, 0, crcInfo.Length); uint address = crcCryptor.Decrypt(BitConverter.ToUInt32(crcInfo, 0)); uint size = crcCryptor.Decrypt(BitConverter.ToUInt32(crcInfo, 4)); uint hash = crcCryptor.Decrypt(BitConverter.ToUInt32(crcInfo, 8)); if (crc32.Hash(new IntPtr(instance + address), size) != hash) isValid = false; } } return isValid; } public static string DecryptString() { return DecryptString((uint)Faces.STORAGE_INFO); } public static bool FreeString(ref string value) { value = null; return true; } public static SerialState SetSerialNumber(string serial) { LicensingManager licensing_manager = Instance.LicensingManager; return licensing_manager != null ? licensing_manager.SetSerialNumber(serial) : SerialState.Corrupted; } public static SerialState GetSerialNumberState() { LicensingManager licensing_manager = Instance.LicensingManager; return licensing_manager != null ? licensing_manager.GetSerialNumberState() : SerialState.Corrupted; } public static bool GetSerialNumberData(out SerialNumberData data) { data = new SerialNumberData(); LicensingManager licensing_manager = Instance.LicensingManager; return licensing_manager != null ? licensing_manager.GetSerialNumberData(data) : false; } public static string GetCurrentHWID() { return Instance.HWID.ToString(); } public static ActivationStatus ActivateLicense(string code, out string serial) { serial = string.Empty; LicensingManager licensing_manager = Instance.LicensingManager; return licensing_manager != null ? licensing_manager.ActivateLicense(code, out serial) : ActivationStatus.NotAvailable; } public static ActivationStatus DeactivateLicense(string serial) { LicensingManager licensing_manager = Instance.LicensingManager; return licensing_manager != null ? licensing_manager.DeactivateLicense(serial) : ActivationStatus.NotAvailable; } public static ActivationStatus GetOfflineActivationString(string code, out string buf) { buf = string.Empty; LicensingManager licensing_manager = Instance.LicensingManager; return licensing_manager != null ? licensing_manager.GetOfflineActivationString(code, out buf) : ActivationStatus.NotAvailable; } public static ActivationStatus GetOfflineDeactivationString(string serial, out string buf) { buf = string.Empty; LicensingManager licensing_manager = Instance.LicensingManager; return licensing_manager != null ? licensing_manager.GetOfflineDeactivationString(serial, out buf) : ActivationStatus.NotAvailable; } public static readonly Core Instance = new Core(); public HardwareID HWID { get; private set; } public StringManager StringManager { get; private set; } public LicensingManager LicensingManager { get; private set; } public ResourceManager ResourceManager { get; private set; } private static string DecryptString(uint stringId) { return Instance.StringManager.DecryptString(stringId); } public static void ShowMessage(string message) { Win32.ShowMessage(message, Assembly.GetExecutingAssembly().GetName().Name, MessageBoxButtons.OK, MessageBoxIcon.Error); } private static void AntidebugThread() { Win32.NtSetInformationThread(Win32.CurrentThread, Win32.THREADINFOCLASS.ThreadHideFromDebugger, IntPtr.Zero, 0); while (true) { if (Debugger.IsAttached || Debugger.IsLogging()) Environment.FailFast(""); if (Win32.IsDebuggerPresent() || Win32.CheckRemoteDebuggerPresent()) Environment.FailFast(""); Thread.Sleep(1000); } } public bool Init(long instance) { var options = (uint)Faces.CORE_OPTIONS; if ((options & (uint)CoreOption.CHECK_DEBUGGER) != 0) { var thread = new Thread(AntidebugThread); thread.IsBackground = true; thread.Start(); } HWID = new HardwareID(); var pos = (uint)Faces.STRING_INFO; if (pos != 0) StringManager = new StringManager(instance); pos = (uint)Faces.LICENSE_INFO; if (pos != 0) LicensingManager = new LicensingManager(instance); pos = (uint)Faces.TRIAL_HWID; if (pos != 0) { var key = new byte[8]; Marshal.Copy(new IntPtr(instance + (uint)Faces.KEY_INFO), key, 0, key.Length); var entry = new byte[64]; Marshal.Copy(new IntPtr(instance + pos), entry, 0, entry.Length); CipherRC5 cipher = new CipherRC5(key); entry = cipher.Decrypt(entry); var value = new byte[(uint)Faces.TRIAL_HWID_SIZE]; Array.Copy(entry, 0, value, 0, value.Length); if (!HWID.IsCorrect(value)) { ShowMessage("This application cannot be executed on this computer."); return false; } } pos = (uint)Faces.RESOURCE_INFO; if (pos != 0) ResourceManager = new ResourceManager(instance); return true; } public static uint DecryptBuffer(uint p3, uint p2, uint p1, uint p0) { return Instance.LicensingManager.DecryptBuffer(p3, p2, p1, p0); } #if !RUNTIME public readonly Random RndGenerator = new Random(); public uint Rand32() { var a4 = new byte[4]; RndGenerator.NextBytes(a4); return BitConverter.ToUInt32(a4, 0); } public ulong Rand64() { return (Rand32() << 32) | Rand32(); } #endif } public class ResourceManager { public ResourceManager(long instance) { _instance = instance; var key = new byte[8]; Marshal.Copy(new IntPtr(instance + (uint)Faces.KEY_INFO), key, 0, key.Length); _cipher = new CipherRC5(key); var resourceInfo = new byte[16]; var pos = (uint)Faces.RESOURCE_INFO; var buffer = new byte[1024]; for (var i = 0; ;i += resourceInfo.Length) { Marshal.Copy(new IntPtr(instance + pos + i), resourceInfo, 0, resourceInfo.Length); byte[] entry = _cipher.Decrypt(resourceInfo); uint nameOffset = BitConverter.ToUInt32(entry, 0); if (nameOffset == 0) break; for (var j = 0; j < buffer.Length / 2; j++) { var c = (ushort)(Marshal.ReadInt16(new IntPtr(instance + nameOffset + j * 2)) ^ (BitRotate.Left((uint)Faces.STRING_DECRYPT_KEY, j) + j)); if (c == 0) { _entries.Add(Encoding.Unicode.GetString(buffer, 0, j * 2), (uint)(pos + i)); break; } buffer[j * 2] = (byte)c; buffer[j * 2 + 1] = (byte)(c >> 8); } } AppDomain.CurrentDomain.AssemblyResolve += Handler; } private void DecryptData(ref byte[] data, uint key) { for (var c = 0; c < data.Length; c++) { data[c] = (byte)(data[c] ^ BitRotate.Left(key, c) + c); } } private Assembly Handler(object sender, ResolveEventArgs args) { uint pos; if (_entries.TryGetValue(args.Name, out pos)) { var resourceInfo = new byte[16]; Marshal.Copy(new IntPtr(_instance + pos), resourceInfo, 0, resourceInfo.Length); byte[] entry = _cipher.Decrypt(resourceInfo); uint dataOffset = BitConverter.ToUInt32(entry, 4); var data = new byte[BitConverter.ToUInt32(entry, 8)]; Marshal.Copy(new IntPtr(_instance + dataOffset), data, 0, data.Length); DecryptData(ref data, (uint)Faces.STRING_DECRYPT_KEY); try { var assembly = Assembly.Load(data); return assembly; } catch (Exception) { } } return null; } private long _instance; private CipherRC5 _cipher; private readonly Dictionary _entries = new Dictionary(); } }