526 lines
17 KiB
C#
526 lines
17 KiB
C#
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
|
|
{
|
|
/// <summary>
|
|
/// Serial number status flags
|
|
/// </summary>
|
|
[Flags]
|
|
public enum SerialState
|
|
{
|
|
/// <summary>
|
|
/// No problems.
|
|
/// </summary>
|
|
Success = 0x00000000,
|
|
/// <summary>
|
|
/// Licensing module is corrupted. This may be caused by cracking attempts. Usually you will never get this flag.
|
|
/// </summary>
|
|
Corrupted = 0x00000001,
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
Invalid = 0x00000002,
|
|
/// <summary>
|
|
/// Serial number is correct, but it was blacklisted in VMProtect.
|
|
/// </summary>
|
|
Blacklisted = 0x00000004,
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
DateExpired = 0x00000008,
|
|
/// <summary>
|
|
/// Running time limit for this session is over. You may read limit value by calling GetSerialNumberData() function.
|
|
/// </summary>
|
|
RunningTimeOver = 0x00000010,
|
|
/// <summary>
|
|
/// Serial number is locked to another hardware identifier.
|
|
/// </summary>
|
|
BadHwid = 0x00000020,
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
MaxBuildExpired = 0x00000040,
|
|
};
|
|
|
|
/// <summary>
|
|
/// Serial number contents
|
|
/// </summary>
|
|
public class SerialNumberData
|
|
{
|
|
/// <summary>
|
|
/// Serial number status
|
|
/// </summary>
|
|
public SerialState State;
|
|
|
|
/// <summary>
|
|
/// End user name
|
|
/// </summary>
|
|
public string UserName;
|
|
|
|
/// <summary>
|
|
/// End user E-Mail
|
|
/// </summary>
|
|
public string EMail;
|
|
|
|
/// <summary>
|
|
/// Serial number expiration date.
|
|
/// </summary>
|
|
public DateTime Expires;
|
|
|
|
/// <summary>
|
|
/// Max date of build, that will accept this key
|
|
/// </summary>
|
|
public DateTime MaxBuild;
|
|
|
|
/// <summary>
|
|
/// Running time in minutes
|
|
/// </summary>
|
|
public int RunningTime;
|
|
|
|
/// <summary>
|
|
/// Up to 255 bytes of user data
|
|
/// </summary>
|
|
public byte[] UserData;
|
|
|
|
public SerialNumberData()
|
|
{
|
|
State = SerialState.Invalid;
|
|
Expires = DateTime.MaxValue;
|
|
MaxBuild = DateTime.MaxValue;
|
|
RunningTime = 0;
|
|
UserData = new byte[0];
|
|
UserName = "";
|
|
EMail = "";
|
|
}
|
|
};
|
|
|
|
/// <summary>
|
|
/// Activation API status codes
|
|
/// </summary>
|
|
public enum ActivationStatus
|
|
{
|
|
/// <summary>
|
|
/// Activation successful, the serial field contains a serial number.
|
|
/// </summary>
|
|
Ok,
|
|
/// <summary>
|
|
/// The activation module was unable to connect the Web License Manager.
|
|
/// </summary>
|
|
NoConnection,
|
|
/// <summary>
|
|
/// The server returned unexpected reply. This means configuration problems or probably a cracking attempt.
|
|
/// </summary>
|
|
BadReply,
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
Banned,
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
Corrupted,
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
BadCode,
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
AlreadyUsed,
|
|
/// <summary>
|
|
/// This is the deactivation error code that means that the server can't find the serial number that the user tries to deactivate.
|
|
/// </summary>
|
|
SerialUnknown,
|
|
/// <summary>
|
|
/// The code is expired.
|
|
/// </summary>
|
|
Expired,
|
|
/// <summary>
|
|
/// Activation/deactivation features are not available.
|
|
/// </summary>
|
|
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<string, uint> _entries = new Dictionary<string, uint>();
|
|
}
|
|
} |